A couple of weeks ago, Unity has released a new version, 2017.1. In this version, the most anticipated feature, TAP and Async-await support, finally came out as a beta feature, with .NET 4.6 Experimental Equivalent. This is not a coincidence. With the Microsoft HoloLens and Windows MR platform strategic layout gradually being mature, many of Unity developers began to study how to interact with the UWP API to obtain the necessary support from windows platform.
As a 3D scripting engine, Unity 5.X and earlier provide only limited. NET 2.0-4. x, c # 4 support. To access a comprehensive asynchronous API still requires a lot of adaptive work. If you are unfamiliar with UWP and TAP the underlying implementations, the developer is hard to port TAP into Unity existing Update Check/Coroutine model development process. In the other hand, experienced UWP developers are also eager to XR world,, but are suffering from lacking async-await/TAP , misunderstanding Coroutine asynchronous model. (I was one of the struggled member.)
Now, with the constant maturity of .net standard libs, which is trying to smooth all platform differences. With efforts from Unity, Microsoft and geeks in community , Unity developers and UWP developers are finally able to develop using the Coroutine and TAP at the same time. That is the kind of news makes me laugh out loud in my dream.
While celebrating, we still should realize that this brings new challenges. We update the function is not to all overturn everything to start again, whetheryou are a Unity master developer, you may have projects that need porting to the UWP platform, or you are a novice of unity but a UWP developer, you may want to upgrade your 2D XAML application to Windows MR platform. Or, if you are completely new to both,just want a lot of Unity and UWP code examples find your App technical feasibility. No matter who you are, , you will eventually encounter this problem: how to interact with Unity Coroutine and. Net TAP correctly.
This article aims to provide you with a clear reference, or to be inspired by the tools provided in this article, to provide better productivity for later work and study.
As most of the code snippets only dependents on Unity Editor Console printout, you can have use Unity 2017.1 to proceed.
Project Setting Up The sample project needs to configure your Unity project to start .NET 4.6 and async support. If you are not familiar with this, it is recommended that you follow the steps below to set up your new project.
1. Start Unity
2. Click on the "New" icon, enter the project name "AsyncExample"
3. Click the "Create Project" button
4. Click on the menu "File-> Build Settings"
5. Click "Player Settings" on the bottom.
Look at your "Inspector" window, there will be some property tabs. Unfold "Other Settings" tab.
6. Find the "Configuration" property group. Change the value of "Scripting Runtime Version *" "Stable (.NET 3.5 Equivalent)" to "Experinmental (.NET 4.6 Equivalent) "
7. Unity Editor needs a complete reboot after your modification, you will see following message.
Select "Restart" to restart the Unity. After restart, at the same location, properties should be
At this point, Unity Editor obtained the ability to execute c# 6.0, some previously unrecognized class library and syntax will be able to be tested and debugged at the Editor Player, without the need for conditional compilation delay to other platforms to run.
8. In the "Project" window, create a new child folder "Scripts" as child folder of "Assets". Create a new C# script "AsyncExample.cs" in "Scripts"
9. In the "Hierarchy" window, create a new, empty object named "ConsoleScripts"
10. Drag the script you have created into "ConsoleScripts" Game Object
Basic codes Next, we need to prepare for some infrastructure, allows us to create some simple behaviors for our tests.
Logging
Log output code is very simple, it will help us to Unity Console output format information. First of all, we add the following code in the script:
using System.Collections;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class AsyncExample : MonoBehaviour
{
Stopwatch stopwatch;
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
}
void LogToTUnityConsole(object content, string flag, [CallerMemberName] string callerName = null)
{
UnityEngine.Debug.Log($"{callerName}:\t{flag} {content}\t at { stopwatch.ElapsedMilliseconds } \t in thread {Thread.CurrentThread.ManagedThreadId}");
}
}
Stopwatch object can help us trace calling time. When the Unity scene enters the running state, the stopwatch will start, we can clearly see a thread at a certain time, in which function to do what.
Next, In order to study how multiple asynchronous tasks directly link and call, we often need to pre-design some tasks , we often need to design a typical template. which can be easy to control and the output sequence. My choice was Count Down Task.
public IEnumerator CoroutineCountDown(int count, string flag = "")
{
for (int i = count; i >= 0; i--)
{
LogToTUnityConsole(i, flag);
yield return new WaitForSeconds(1);
}
}
If you are a beginner of Unity, you can see this is a yield function returns a enumerator, by your c# experience. Unity can use IEnumerator returned this by method, which can populate sequence of YieldInstruction objects (WaitForSeconds). This sequence is consumed by dispatcher in the base class, MonoBehavior. In each of the YieldInstruction consumption, when the asynchronous operation is complete, the dispatcher will join execution back to the main thread of Unity and calls the IEnumerator MoveNext() method to get the next YieldInstruction. Execution: CoroutineCountDown
Execute separately
Put the following code in the Start method as below, we can run game in Editor and get console output
You can see, in the logs, execution thread is always Thread1, count down by 1, every 1 second. Execute in parallel
As this code snippet runs asynchronously, in Unity in this method execution will not affect another operation executed in main thread. It also does not prevent multiple execution..
When we called twice in a row, we'll see the two tasks transformed themselves into slices, and weaved in the execution of the main thread.
Execution in linear
If two or more Coroutines require convergence (including other process controls, such as if / switch / loop), an additional parent Coroutine is required to be scheduled in Unity. We can create the following code:
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
StartCoroutine(CoroutineCountDownSeq(3, "BasicCoCallA", "BasicCoCallB"));
}
public IEnumerator CoroutineCountDownSeq(int countDown, params string[] flags)
{
foreach (var flag in flags)
{
yield return StartCoroutine(CoroutineCountDown(3, flag));
}
}
You can see that parent method enumerates a IEnumerator waiting YieldInstructions (this time UnityEngine.Coroutine class) , so dispatcher can schedule YieldInstructions sequences as one, back to top Scheduler.
Results:
Combining code snippet above, we can also implement complex patterns, such as Timer, Event Recognizer, Fork-Join etc.. We are not unfold all of them here.
public async Task TaskAsyncCountDown(int count, string flag = "")
{
for (int i = count; i >= 0; i--)
{
LogToTUnityConsole(i, flag);
await Task.Delay(1000);
}
}
This version of the code is very similar to the Coroutine version: same CPS transformation, only using await instead of yield return, and using Task instead if Coroutine. Another way to achieve same is "async void function".
public async void VoidAsyncCountDown(int count, string flag = "")
{
for (int i = count; i >= 0; i--)
{
LogToTUnityConsole(i, flag);
await Task.Delay(1000);
}
}
In community articles and multiple versions of the documents we mentioned, In addition to using the void function as an event handler, "async void functions" are strongly not recommended . Because the functions dose not return anything Task scheduler can access. This code snippet is presented as a negative example here, for your reference.
When we do not need to do anything for this asynchronous task and just start it, the Task object async method returns is relatively meaningless, we can call an async function the in the Start function directly. Although this will be in the Visual Studio with a green wavy line warning, but this is actually a legitimate usage.
In order to avoid the occurrence of such noise, returned could be received by a temporary variable without any operation on it. Like what:
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
var _ = TaskAsyncCountDown(3, "BasicAsyncCall");
}
Result just like Coroutine
As you can see, await in the async functions use the default Task choreographer, completed Task will be executed each time the County asked after conversion back to the Unity of the main thread.
If we want to change this behavior, we can modify the TaskAsyncCountDown Function, modify the following code
public async Task TaskAsyncCountDown(int count, string flag = "")
{
for (int i = count; i >= 0; i--)
{
LogToTUnityConsole(i, flag);
await Task.Delay(1000).ConfigureAwait(false);
}
}
Await Scheduler uses the thread pool, and each step of await is no longer be forced to return to game's main thread, which might improve execution speed. In this case operations to some objects that need be operate in main thread (such as Texture Read-write) will fail.CPU intensive computation are recommended to be scheduled in the thread pool, in order to unblock render updates, which can make same effect as reduce workload in Update() method.
Execute in parallel from main thread
Using the Task, multiple operations can start and return to the main thread.
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
var a = TaskAsyncCountDown(3, "BasicAsyncCallA");
var b = TaskAsyncCountDown(3, "BasicAsyncCallB");
}
Execute in linear from main thread
Like the Coroutine, async methods can be linked one after another:
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
var t = TaskAsyncCountDownSeq(3, "BasicAsyncCallA", "BasicAsyncCallB");
}
public async Task TaskAsyncCountDownSeq(int countDown, params string[] flags)
{
foreach (var flag in flags)
{
await TaskAsyncCountDown(3, flag);
}
}
>Execution results
Execute in thread pooling
If you are careful enough, you will find out that in ConfigureAwait(false) code execution result, thread id value in first line was 1 .
Before the first await keyword, operations will execute on the caller's thread in typical async executions. In extreme cases, if an asynchronous function executes CPU-intensive or long-running synchronous IO operations at the entrance, main thread of Unity will still be blocked. This can be optimized in the following way:
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
var _ = Task.Run(() => TaskAsyncCountDown(3, "BasicAsyncCall"));
}
At this point the function entry is called by the thread pool scheduler. Since the thread in the thread pool does not synchronize the context, all subsequent calls will randomly use the available threads in the thread pool. Even if you forced it by setting parameter of .ConfigureAwait () to true, it would not help. Please pay attention to the potential impact of such calls: you will lose the ability to go return to the main thread contexts.
Is there another way to have synchronization context and run steps in thread pool?
Execute with Mixed Scheduler
In order to address the questions raised by the end of the previous section, I have designed this use case:
Assume that following steps are demanded in a business logic:
a. computing n! (n=150)
b. 1 seconds waiting
c. output
So we get the following code (in order to expand the execution load, I added sleep time in loops):
public void CPUBigHead(int n)
{
double result = 1;
LogToTUnityConsole(result, $"n!(n={n}) start");
for (int i = 1; i <= n; i++)
{
result = result * i;
Thread.Sleep(10);
}
LogToTUnityConsole(result, $"n!(n={n}) stop");
Thread.Sleep(1000);
//Texture change logic puts here
LogToTUnityConsole(result, $"n!(n={n}) output");
}
n! calculation is a CPU-intensive operation. We want it executing in other threads, and output the results in the UI layer called texture changes, you need to manipulate the thread Id is 1. On this basis, I modified synchronized code into async to achieve.
public async Task CPUBigHeadAsync(int n)
{
double result = 1;
await Task.Run(() =>
{
LogToTUnityConsole(result, $"n!(n={n}) start");
for (int i = 1; i <= n; i++)
{
result = result * i;
Thread.Sleep(10);
}
LogToTUnityConsole(result, $"n!(n={n}) stop");
}); //Scheduler will contiue execution in main thread here
await Task.Delay(1000);
//Texture change logic puts here
LogToTUnityConsole(result, $"n!(n={n}) output");
}
> Get the following results:
Can see that we make sure that CPU-intensive operations are not running in the main thread. This modification ensures a relatively smooth rendering update.
Comparison summary From the above examples, we can see that the new Task API / async syntax brings new optimization possibilities for Unity. Old Coroutine mechanisms can be logically split into small sections, but it have less power to control each part running in thread freely. With new Task API you can easily do operations in a thread pool, and make calculations easier.
In addition, Task/await also has some other advantages
· Highly integrated with the UWP API, you can use the simple await/AsTask () extension method to convert.
· To maintain async job's lifetime at the Application level.。
· Control timer/manual interruption of the execution tree by CancellationToke
· Fast package of Event/thread/IAsyncResult, provides a simple unified calling pattern.
As I mentioned at the beginning of this article, new member, Task/async will exist with Coroutine side by side, and the ecosystem will need them interactive with each other. So how to interactive one to another ?
>interactive with each other,means that we are able to Coroutine call the Async method, as well as the calling Coroutine in the Async method. Examples of concurrent execution and no different from basic calls, here we show you how to call one another and calling the next one after the implementation of process implementation.
If you want to call a Coroutine and in the async methods, we need to wrap the Coroutine implementation to a simple Task.
There are no callbacks or wait handle in YeildInstruction class of Unity. So we need a parent's Coroutine method to monitor completion of the target Coroutine.
public IEnumerator CoroutineAwaitATask()
{
yield return CoroutineCountDown(2, "pretask");
var task = TaskAsyncCountDown(3, "task");
yield return new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);
//Check task's return;
if (task.IsCompleted)
{
LogToTUnityConsole("TDone", "task");
}
yield return CoroutineCountDown(2, "posttask");
}
Execution:
void Start()
{
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
StartCoroutine(CoroutineAwaitATask());
}
You can see, after the executions of the TaskAsyncCountDown "task" Async method, Unity dispatcher continued to execute the CoroutineCountDown "posttask"
Code snippets above shows us how to make Task and Coroutine call each other. So do we have a way of simplifying this process, makes operations more productive?
Because we were using the. NET 4.6 subset already , wrapping these operations into extension methods is very easy. So I created CoTaskHelper class. to simplify calling.
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
public static class CoTaskHelper
{
public static async Task ExecuteCoroutineAsync(this MonoBehaviour monoBehavior, IEnumerator coroutine)
{
var tcs = new System.Threading.Tasks.TaskCompletionSource<object>();
monoBehavior.StartCoroutine(
tempCoroutine(
coroutine,
() => tcs.TrySetResult(null)));
await tcs.Task;
}
static IEnumerator tempCoroutine(IEnumerator coro, System.Action afterExecutionCallback)
{
yield return coro;
afterExecutionCallback();
}
public static IEnumerator WaitAsCoroutine(this Task task)
{
yield return new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);
}
}
In this article, we briefly introduce and compare the Unity native Coroutine programming approach and the .NET 4.6 subset + TAP programming approach introduced in the Unity 2017.1, also release and provide examples of code that two methods interact with each other. Hopefully these examples can inspire readers and become the help of using Unity to increase productivity.
P.S.
After practice with projects, I have written a better version, and added YeildInstruction support. Please feel free give me feedback in comments 🙂
/// <summary>
/// Coroutine and Task Async Interactive Helper
/// Based on artical https://blogs.msdn.microsoft.com/appconsult/2017/09/01/unity-coroutine-tap-en-us/
/// </summary>
public static class CoroutineTaskHelper
{
/// <summary>
/// Translate a coroutine to Task and run. It needs a Mono Behavior to locate Unity thread context.
/// </summary>
/// <param name="monoBehavior">The Mono Behavior that managing coroutines</param>
/// <param name="coroutine">the coroutine that needs to run </param>
/// <returns>Task that can be await</returns>
public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, IEnumerator coroutine)
{
var tcs = new TaskCompletionSource<object>();
monoBehavior
.StartCoroutine(
emptyCoroutine(
coroutine,
tcs));
await tcs.Task;
}
/// <summary>
/// Translate a YieldInstruction to Task and run. It needs a Mono Behavior to locate Unity thread context.
/// </summary>
/// <param name="monoBehavior">The Mono Behavior that managing coroutines</param>
/// <param name="yieldInstruction"></param>
/// <returns>Task that can be await</returns>
public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, YieldInstruction yieldInstruction)
{
var tcs = new TaskCompletionSource<object>();
monoBehavior
.StartCoroutine(
emptyCoroutine(
yieldInstruction,
tcs));
await tcs.Task;
}
/// <summary>
/// Wrap a Task as a Coroutine.
/// </summary>
/// <param name="task">The target task.</param>
/// <returns>Wrapped Coroutine</returns>
public static CoroutineWithTask<System.Object> AsCoroutine(this Task task)
{
var coroutine = new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);
return new CoroutineWithTask<object>(task);
}
/// <summary>
/// Wrap a Task as a Coroutine.
/// </summary>
/// <param name="task">The target task.</param>
/// <returns>Wrapped Coroutine</returns>
public static CoroutineWithTask<T> AsCoroutine<T>(this Task<T> task)
{
return new CoroutineWithTask<T>(task);
}
private static IEnumerator emptyCoroutine(YieldInstruction coro, TaskCompletionSource<object> completion)
{
yield return coro;
completion.TrySetResult(null);
}
private static IEnumerator emptyCoroutine(IEnumerator coro, TaskCompletionSource<object> completion)
{
yield return coro;
completion.TrySetResult(null);
}
/// <summary>
/// Wrapped Task, behaves like a coroutine
/// </summary>
public struct CoroutineWithTask<T> : IEnumerator
{
private IEnumerator _coreCoroutine;
/// <summary>
/// Constructor for Task with a return value;
/// </summary>
/// <param name="coreTask">Task that need wrap</param>
public CoroutineWithTask(Task<T> coreTask)
{
WrappedTask = coreTask;
_coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);
}
/// <summary>
/// Constructor for Task without a return value;
/// </summary>
/// <param name="coreTask">Task that need wrap</param>
public CoroutineWithTask(Task coreTask)
{
WrappedTask = Task.Run(async () =>
{
await coreTask;
return default(T);
});
_coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);
}
/// <summary>
/// The task have wrapped in this coroutine.
/// </summary>
public Task<T> WrappedTask { get; private set; }
/// <summary>
/// Task result, if it have. Calling this property will wait execution synchronously.
/// </summary>
public T Result { get { return WrappedTask.Result; } }
/// <summary>
/// Gets the current element in the collection.
/// </summary>
public object Current => _coreCoroutine.Current;
/// <summary>
/// Advances the enumerator to the next element of the collection.
/// </summary>
/// <returns>
/// true if the enumerator was successfully advanced to the next element; false if
/// the enumerator has passed the end of the collection.
/// </returns>
public bool MoveNext()
{
return _coreCoroutine.MoveNext();
}
/// <summary>
/// Sets the enumerator to its initial position, which is before the first element
/// in the collection.
/// </summary>
public void Reset()
{
_coreCoroutine.Reset();
}
}
}
Thank you very much for such a detailed and meaningful article. I learned a lot and got a cool experience)
"}},"componentScriptGroups({\"componentId\":\"custom.widget.MicrosoftFooter\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/QueryHandler\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageCoverImage\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageCoverImage-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeTitle\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeTitle-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTimeToRead\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTimeToRead-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserRank\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserRank-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageCustomFields\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageCustomFields-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRevision\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRevision-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageReplyButton\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageReplyButton-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageAuthorBio\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/ranks/UserRankLabel\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserRegistrationDate\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserRegistrationDate-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeAvatar-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeDescription\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeDescription-1745505309750"}],"message({\"id\":\"message:4142359\"})":{"__ref":"BlogReplyMessage:message:4142359"},"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"components/tags/TagView/TagViewChip\"]})":[{"__ref":"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1745505309750"}],"cachedText({\"lastModified\":\"1745505309750\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745505309750"}]},"CachedAsset:pages-1745486122162":{"__typename":"CachedAsset","id":"pages-1745486122162","value":[{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"UserBlogPermissions.Page","type":"COMMUNITY","urlPath":"/c/user-blog-permissions/page","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllEvents","type":"CUSTOM","urlPath":"/Events","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"CommunityHub.Page","type":"CUSTOM","urlPath":"/Directory","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllBlogs.Page","type":"CUSTOM","urlPath":"/blogs","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1745486122162,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Deleted","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"MMM dd yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":"en","possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"Category:category:microsoft365":{"__typename":"Category","id":"category:microsoft365","entityType":"CATEGORY","displayId":"microsoft365","nodeType":"category","depth":3,"title":"Microsoft 365","shortTitle":"Microsoft 365","parent":{"__ref":"Category:category:products-services"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top","entityType":"CATEGORY","shortTitle":"Top"},"Category:category:communities":{"__typename":"Category","id":"category:communities","displayId":"communities","nodeType":"category","depth":1,"parent":{"__ref":"Category:category:top"},"title":"Communities","entityType":"CATEGORY","shortTitle":"Communities"},"Category:category:products-services":{"__typename":"Category","id":"category:products-services","displayId":"products-services","nodeType":"category","depth":2,"parent":{"__ref":"Category:category:communities"},"title":"Products","entityType":"CATEGORY","shortTitle":"Products"},"Blog:board:ModernWorkAppConsult":{"__typename":"Blog","id":"board:ModernWorkAppConsult","entityType":"BLOG","displayId":"ModernWorkAppConsult","nodeType":"board","depth":4,"conversationStyle":"BLOG","title":"Modern Work App Consult Blog","description":"","avatar":null,"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:microsoft365"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:gxcuf89792"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:communities"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:products-services"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:microsoft365"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"boardPolicies":{"__typename":"BoardPolicies","canPublishArticleOnCreate":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","args":[]}}},"shortTitle":"Modern Work App Consult Blog","repliesProperties":{"__typename":"RepliesProperties","sortOrder":"REVERSE_PUBLISH_TIME","repliesFormat":"threaded"},"eventPath":"category:microsoft365/category:products-services/category:communities/community:gxcuf89792board:ModernWorkAppConsult/","tagProperties":{"__typename":"TagNodeProperties","tagsEnabled":{"__typename":"PolicyResult","failureReason":null}},"requireTags":true,"tagType":"PRESET_ONLY"},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/cmstNC05WEo0blc\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/cmstNC05WEo0blc","height":512,"width":512,"mimeType":"image/png"},"Rank:rank:4":{"__typename":"Rank","id":"rank:4","position":6,"name":"Microsoft","color":"333333","icon":{"__ref":"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/cmstNC05WEo0blc\"}"},"rankStyle":"OUTLINE"},"User:user:263726":{"__typename":"User","id":"user:263726","uid":263726,"login":"WayneWangMSFT","deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/m_assets/avatars/default/avatar-7.svg?time=0"},"rank":{"__ref":"Rank:rank:4"},"email":"","messagesCount":0,"biography":null,"topicsCount":0,"kudosReceivedCount":1,"kudosGivenCount":0,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":null,"registrationTime":"2019-01-10T21:03:05.772-08:00","confirmEmailStatus":null},"followersCount":null,"solutionsCount":0},"BlogTopicMessage:message:316851":{"__typename":"BlogTopicMessage","uid":316851,"subject":"Asynchronous programming in Unity, Using Coroutine and TAP","id":"message:316851","revisionNum":8,"repliesCount":1,"author":{"__ref":"User:user:263726"},"depth":0,"hasGivenKudo":false,"board":{"__ref":"Blog:board:ModernWorkAppConsult"},"conversation":{"__ref":"Conversation:conversation:316851"},"messagePolicies":{"__typename":"MessagePolicies","canPublishArticleOnEdit":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","args":[]}},"canModerateSpamMessage":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","key":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","args":[]}}},"contentWorkflow":{"__typename":"ContentWorkflow","state":"PUBLISH","scheduledPublishTime":null,"scheduledTimezone":null,"userContext":{"__typename":"MessageWorkflowContext","canSubmitForReview":null,"canEdit":false,"canRecall":null,"canSubmitForPublication":null,"canReturnToAuthor":null,"canPublish":null,"canReturnToReview":null,"canSchedule":false},"shortScheduledTimezone":null},"readOnly":false,"editFrozen":false,"moderationData":{"__ref":"ModerationData:moderation_data:316851"},"teaser":"
A couple of weeks ago, Unity has released a new version, 2017.1. In this version, the most anticipated feature, TAP and Async-await support, finally came out as a beta feature, with .NET 4.6 Experimental Equivalent. This is not a coincidence. With the Microsoft HoloLens and Windows MR platform strategic layout gradually being mature, many of Unity developers began to study how to interact with the UWP API to obtain the necessary support from windows platform.
As a 3D scripting engine, Unity 5.X and earlier provide only limited. NET 2.0-4. x, c # 4 support. To access a comprehensive asynchronous API still requires a lot of adaptive work. If you are unfamiliar with UWP and TAP the underlying implementations, the developer is hard to port TAP into Unity existing Update Check/Coroutine model development process. In the other hand, experienced UWP developers are also eager to XR world,, but are suffering from lacking async-await/TAP , misunderstanding Coroutine asynchronous model. (I was one of the struggled member.)
Now, with the constant maturity of .net standard libs, which is trying to smooth all platform differences. With efforts from Unity, Microsoft and geeks in community , Unity developers and UWP developers are finally able to develop using the Coroutine and TAP at the same time. That is the kind of news makes me laugh out loud in my dream.
While celebrating, we still should realize that this brings new challenges. We update the function is not to all overturn everything to start again, whetheryou are a Unity master developer, you may have projects that need porting to the UWP platform, or you are a novice of unity but a UWP developer, you may want to upgrade your 2D XAML application to Windows MR platform. Or, if you are completely new to both,just want a lot of Unity and UWP code examples find your App technical feasibility. No matter who you are, , you will eventually encounter this problem: how to interact with Unity Coroutine and. Net TAP correctly.
This article aims to provide you with a clear reference, or to be inspired by the tools provided in this article, to provide better productivity for later work and study.
As most of the code snippets only dependents on Unity Editor Console printout, you can have use Unity 2017.1 to proceed.
Project Setting Up The sample project needs to configure your Unity project to start .NET 4.6 and async support. If you are not familiar with this, it is recommended that you follow the steps below to set up your new project.
\n
1. Start Unity
\n
\n
2. Click on the \"New\" icon, enter the project name \"AsyncExample\"
\n
\n
3. Click the \"Create Project\" button
\n
\n
4. Click on the menu \"File-> Build Settings\"
\n
\n
5. Click \"Player Settings\" on the bottom.
\n
Look at your \"Inspector\" window, there will be some property tabs. Unfold \"Other Settings\" tab.
\n
6. Find the \"Configuration\" property group. Change the value of \"Scripting Runtime Version *\" \"Stable (.NET 3.5 Equivalent)\" to \"Experinmental (.NET 4.6 Equivalent) \"
\n
\n
7. Unity Editor needs a complete reboot after your modification, you will see following message.
\n
Select \"Restart\" to restart the Unity. After restart, at the same location, properties should be
At this point, Unity Editor obtained the ability to execute c# 6.0, some previously unrecognized class library and syntax will be able to be tested and debugged at the Editor Player, without the need for conditional compilation delay to other platforms to run.
\n
8. In the \"Project\" window, create a new child folder \"Scripts\" as child folder of \"Assets\". Create a new C# script \"AsyncExample.cs\" in \"Scripts\"
\n
\n
9. In the \"Hierarchy\" window, create a new, empty object named \"ConsoleScripts\"
\n
\n
10. Drag the script you have created into \"ConsoleScripts\" Game Object
\n
\n
\n
Basic codes Next, we need to prepare for some infrastructure, allows us to create some simple behaviors for our tests.
Logging
Log output code is very simple, it will help us to Unity Console output format information. First of all, we add the following code in the script:
\n
\n
\n
\n
\n
using System.Collections;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing UnityEngine;\n\npublic class AsyncExample : MonoBehaviour\n{\n\n Stopwatch stopwatch;\n void Start()\n {\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n }\n\n void LogToTUnityConsole(object content, string flag, [CallerMemberName] string callerName = null)\n {\n UnityEngine.Debug.Log($\"{callerName}:\\t{flag} {content}\\t at { stopwatch.ElapsedMilliseconds } \\t in thread {Thread.CurrentThread.ManagedThreadId}\");\n }\n\n}
\n
\n
\n
\n
\n
Stopwatch object can help us trace calling time. When the Unity scene enters the running state, the stopwatch will start, we can clearly see a thread at a certain time, in which function to do what.
Next, In order to study how multiple asynchronous tasks directly link and call, we often need to pre-design some tasks , we often need to design a typical template. which can be easy to control and the output sequence. My choice was Count Down Task.
public IEnumerator CoroutineCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n yield return new WaitForSeconds(1);\n }\n}
\n
\n
\n
\n
\n
If you are a beginner of Unity, you can see this is a yield function returns a enumerator, by your c# experience. Unity can use IEnumerator returned this by method, which can populate sequence of YieldInstruction objects (WaitForSeconds). This sequence is consumed by dispatcher in the base class, MonoBehavior. In each of the YieldInstruction consumption, when the asynchronous operation is complete, the dispatcher will join execution back to the main thread of Unity and calls the IEnumerator MoveNext() method to get the next YieldInstruction. Execution: CoroutineCountDown
Execute separately
Put the following code in the Start method as below, we can run game in Editor and get console output
You can see, in the logs, execution thread is always Thread1, count down by 1, every 1 second. Execute in parallel
As this code snippet runs asynchronously, in Unity in this method execution will not affect another operation executed in main thread. It also does not prevent multiple execution..
When we called twice in a row, we'll see the two tasks transformed themselves into slices, and weaved in the execution of the main thread.
Execution in linear
If two or more Coroutines require convergence (including other process controls, such as if / switch / loop), an additional parent Coroutine is required to be scheduled in Unity. We can create the following code:
\n
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n StartCoroutine(CoroutineCountDownSeq(3, \"BasicCoCallA\", \"BasicCoCallB\"));\n}\n\npublic IEnumerator CoroutineCountDownSeq(int countDown, params string[] flags)\n{\n foreach (var flag in flags)\n {\n yield return StartCoroutine(CoroutineCountDown(3, flag));\n }\n}\n
\n
\n
\n
\n
\n
You can see that parent method enumerates a IEnumerator waiting YieldInstructions (this time UnityEngine.Coroutine class) , so dispatcher can schedule YieldInstructions sequences as one, back to top Scheduler.
Results:
Combining code snippet above, we can also implement complex patterns, such as Timer, Event Recognizer, Fork-Join etc.. We are not unfold all of them here.
public async Task TaskAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000);\n }\n}
\n
\n
\n
\n
\n
This version of the code is very similar to the Coroutine version: same CPS transformation, only using await instead of yield return, and using Task instead if Coroutine. Another way to achieve same is \"async void function\".
\n
\n
\n
\n
\n
public async void VoidAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000);\n }\n}\n
\n
\n
\n
\n
\n
In community articles and multiple versions of the documents we mentioned, In addition to using the void function as an event handler, \"async void functions\" are strongly not recommended . Because the functions dose not return anything Task scheduler can access. This code snippet is presented as a negative example here, for your reference.
When we do not need to do anything for this asynchronous task and just start it, the Task object async method returns is relatively meaningless, we can call an async function the in the Start function directly. Although this will be in the Visual Studio with a green wavy line warning, but this is actually a legitimate usage.
In order to avoid the occurrence of such noise, returned could be received by a temporary variable without any operation on it. Like what:
\n
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var _ = TaskAsyncCountDown(3, \"BasicAsyncCall\");\n}
\n
\n
\n
\n
\n
Result just like Coroutine
As you can see, await in the async functions use the default Task choreographer, completed Task will be executed each time the County asked after conversion back to the Unity of the main thread.
If we want to change this behavior, we can modify the TaskAsyncCountDown Function, modify the following code
\n
\n
\n
\n
\n
public async Task TaskAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000).ConfigureAwait(false);\n }\n}
\n
\n
\n
\n
\n
\n
Await Scheduler uses the thread pool, and each step of await is no longer be forced to return to game's main thread, which might improve execution speed. In this case operations to some objects that need be operate in main thread (such as Texture Read-write) will fail.CPU intensive computation are recommended to be scheduled in the thread pool, in order to unblock render updates, which can make same effect as reduce workload in Update() method.
Execute in parallel from main thread
Using the Task, multiple operations can start and return to the main thread.
\n
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var a = TaskAsyncCountDown(3, \"BasicAsyncCallA\");\n var b = TaskAsyncCountDown(3, \"BasicAsyncCallB\");\n}
\n
\n
\n
\n
\n
Execute in linear from main thread
Like the Coroutine, async methods can be linked one after another:
\n
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var t = TaskAsyncCountDownSeq(3, \"BasicAsyncCallA\", \"BasicAsyncCallB\");\n}\n\npublic async Task TaskAsyncCountDownSeq(int countDown, params string[] flags)\n{\n foreach (var flag in flags)\n {\n await TaskAsyncCountDown(3, flag);\n }\n}\n
\n
\n
\n
\n
\n
>Execution results
Execute in thread pooling
If you are careful enough, you will find out that in ConfigureAwait(false) code execution result, thread id value in first line was 1 .
Before the first await keyword, operations will execute on the caller's thread in typical async executions. In extreme cases, if an asynchronous function executes CPU-intensive or long-running synchronous IO operations at the entrance, main thread of Unity will still be blocked. This can be optimized in the following way:
\n
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var _ = Task.Run(() => TaskAsyncCountDown(3, \"BasicAsyncCall\"));\n}
\n
\n
\n
\n
\n
At this point the function entry is called by the thread pool scheduler. Since the thread in the thread pool does not synchronize the context, all subsequent calls will randomly use the available threads in the thread pool. Even if you forced it by setting parameter of .ConfigureAwait () to true, it would not help. Please pay attention to the potential impact of such calls: you will lose the ability to go return to the main thread contexts.
Is there another way to have synchronization context and run steps in thread pool?
Execute with Mixed Scheduler
In order to address the questions raised by the end of the previous section, I have designed this use case:
Assume that following steps are demanded in a business logic:
\n
a. computing n! (n=150)
\n
\n
b. 1 seconds waiting
\n
\n
c. output
\n
So we get the following code (in order to expand the execution load, I added sleep time in loops):
\n
\n
\n
\n
\n
public void CPUBigHead(int n)\n{\n double result = 1;\n LogToTUnityConsole(result, $\"n!(n={n}) start\");\n for (int i = 1; i <= n; i++)\n {\n result = result * i;\n Thread.Sleep(10);\n }\n LogToTUnityConsole(result, $\"n!(n={n}) stop\");\n Thread.Sleep(1000);\n\n //Texture change logic puts here \n\n LogToTUnityConsole(result, $\"n!(n={n}) output\");\n}
\n
\n
\n
\n
\n
n! calculation is a CPU-intensive operation. We want it executing in other threads, and output the results in the UI layer called texture changes, you need to manipulate the thread Id is 1. On this basis, I modified synchronized code into async to achieve.
\n
\n
\n
\n
\n
\n
public async Task CPUBigHeadAsync(int n)\n{\n double result = 1;\n await Task.Run(() =>\n {\n LogToTUnityConsole(result, $\"n!(n={n}) start\");\n for (int i = 1; i <= n; i++)\n {\n result = result * i;\n Thread.Sleep(10);\n }\n LogToTUnityConsole(result, $\"n!(n={n}) stop\");\n }); //Scheduler will contiue execution in main thread here \n\n await Task.Delay(1000);\n //Texture change logic puts here \n LogToTUnityConsole(result, $\"n!(n={n}) output\");\n}
\n
\n
\n
\n
\n
> Get the following results:
Can see that we make sure that CPU-intensive operations are not running in the main thread. This modification ensures a relatively smooth rendering update.
Comparison summary From the above examples, we can see that the new Task API / async syntax brings new optimization possibilities for Unity. Old Coroutine mechanisms can be logically split into small sections, but it have less power to control each part running in thread freely. With new Task API you can easily do operations in a thread pool, and make calculations easier.
In addition, Task/await also has some other advantages
\n
· Highly integrated with the UWP API, you can use the simple await/AsTask () extension method to convert.
\n
\n
· To maintain async job's lifetime at the Application level.。
\n
\n
· Control timer/manual interruption of the execution tree by CancellationToke
\n
\n
· Fast package of Event/thread/IAsyncResult, provides a simple unified calling pattern.
As I mentioned at the beginning of this article, new member, Task/async will exist with Coroutine side by side, and the ecosystem will need them interactive with each other. So how to interactive one to another ?
>interactive with each other,means that we are able to Coroutine call the Async method, as well as the calling Coroutine in the Async method. Examples of concurrent execution and no different from basic calls, here we show you how to call one another and calling the next one after the implementation of process implementation.
If you want to call a Coroutine and in the async methods, we need to wrap the Coroutine implementation to a simple Task.
There are no callbacks or wait handle in YeildInstruction class of Unity. So we need a parent's Coroutine method to monitor completion of the target Coroutine.
public IEnumerator CoroutineAwaitATask()\n{\n yield return CoroutineCountDown(2, \"pretask\");\n\n var task = TaskAsyncCountDown(3, \"task\");\n yield return new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);\n //Check task's return; \n if (task.IsCompleted)\n {\n LogToTUnityConsole(\"TDone\", \"task\");\n }\n yield return CoroutineCountDown(2, \"posttask\");\n}
\n
\n
\n
\n
Execution:
\n
\n
\n
\n
void Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n StartCoroutine(CoroutineAwaitATask());\n}
\n
\n
\n
\n
You can see, after the executions of the TaskAsyncCountDown \"task\" Async method, Unity dispatcher continued to execute the CoroutineCountDown \"posttask\"
Code snippets above shows us how to make Task and Coroutine call each other. So do we have a way of simplifying this process, makes operations more productive?
Because we were using the. NET 4.6 subset already , wrapping these operations into extension methods is very easy. So I created CoTaskHelper class. to simplify calling.
\n
\n
\n
using System.Collections;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing UnityEngine;\n\npublic static class CoTaskHelper\n{\n\n\n public static async Task ExecuteCoroutineAsync(this MonoBehaviour monoBehavior, IEnumerator coroutine)\n {\n var tcs = new System.Threading.Tasks.TaskCompletionSource<object>();\n\n monoBehavior.StartCoroutine(\n tempCoroutine(\n coroutine,\n () => tcs.TrySetResult(null)));\n\n await tcs.Task;\n }\n\n\n\n static IEnumerator tempCoroutine(IEnumerator coro, System.Action afterExecutionCallback)\n {\n yield return coro;\n afterExecutionCallback();\n }\n\n public static IEnumerator WaitAsCoroutine(this Task task)\n {\n yield return new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);\n }\n\n}\n
In this article, we briefly introduce and compare the Unity native Coroutine programming approach and the .NET 4.6 subset + TAP programming approach introduced in the Unity 2017.1, also release and provide examples of code that two methods interact with each other. Hopefully these examples can inspire readers and become the help of using Unity to increase productivity.
\n
\n
P.S.
After practice with projects, I have written a better version, and added YeildInstruction support. Please feel free give me feedback in comments 🙂
\n
\n
\n
/// <summary> \n/// Coroutine and Task Async Interactive Helper \n/// Based on artical https://blogs.msdn.microsoft.com/appconsult/2017/09/01/unity-coroutine-tap-en-us/ \n/// </summary> \npublic static class CoroutineTaskHelper\n{\n /// <summary> \n /// Translate a coroutine to Task and run. It needs a Mono Behavior to locate Unity thread context. \n /// </summary> \n /// <param name=\"monoBehavior\">The Mono Behavior that managing coroutines</param> \n /// <param name=\"coroutine\">the coroutine that needs to run </param> \n /// <returns>Task that can be await</returns> \n public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, IEnumerator coroutine)\n {\n var tcs = new TaskCompletionSource<object>();\n monoBehavior\n .StartCoroutine(\n emptyCoroutine(\n coroutine,\n tcs));\n await tcs.Task;\n }\n\n /// <summary> \n /// Translate a YieldInstruction to Task and run. It needs a Mono Behavior to locate Unity thread context. \n /// </summary> \n /// <param name=\"monoBehavior\">The Mono Behavior that managing coroutines</param> \n /// <param name=\"yieldInstruction\"></param> \n /// <returns>Task that can be await</returns> \n public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, YieldInstruction yieldInstruction)\n {\n var tcs = new TaskCompletionSource<object>();\n monoBehavior\n .StartCoroutine(\n emptyCoroutine(\n yieldInstruction,\n tcs));\n await tcs.Task;\n }\n\n /// <summary> \n /// Wrap a Task as a Coroutine. \n /// </summary> \n /// <param name=\"task\">The target task.</param> \n /// <returns>Wrapped Coroutine</returns> \n public static CoroutineWithTask<System.Object> AsCoroutine(this Task task)\n {\n var coroutine = new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);\n return new CoroutineWithTask<object>(task);\n }\n\n /// <summary> \n /// Wrap a Task as a Coroutine. \n /// </summary> \n /// <param name=\"task\">The target task.</param> \n /// <returns>Wrapped Coroutine</returns> \n public static CoroutineWithTask<T> AsCoroutine<T>(this Task<T> task)\n {\n\n return new CoroutineWithTask<T>(task);\n }\n\n private static IEnumerator emptyCoroutine(YieldInstruction coro, TaskCompletionSource<object> completion)\n {\n yield return coro;\n completion.TrySetResult(null);\n }\n\n private static IEnumerator emptyCoroutine(IEnumerator coro, TaskCompletionSource<object> completion)\n {\n yield return coro;\n completion.TrySetResult(null);\n }\n\n /// <summary> \n /// Wrapped Task, behaves like a coroutine \n /// </summary> \n public struct CoroutineWithTask<T> : IEnumerator\n {\n\n private IEnumerator _coreCoroutine;\n\n /// <summary> \n /// Constructor for Task with a return value; \n /// </summary> \n /// <param name=\"coreTask\">Task that need wrap</param> \n public CoroutineWithTask(Task<T> coreTask)\n {\n WrappedTask = coreTask;\n _coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);\n }\n\n /// <summary> \n /// Constructor for Task without a return value; \n /// </summary> \n /// <param name=\"coreTask\">Task that need wrap</param> \n public CoroutineWithTask(Task coreTask)\n {\n WrappedTask = Task.Run(async () =>\n {\n await coreTask;\n return default(T);\n });\n _coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);\n }\n\n /// <summary> \n /// The task have wrapped in this coroutine. \n /// </summary> \n public Task<T> WrappedTask { get; private set; }\n\n\n /// <summary> \n /// Task result, if it have. Calling this property will wait execution synchronously. \n /// </summary> \n public T Result { get { return WrappedTask.Result; } }\n\n\n /// <summary> \n /// Gets the current element in the collection. \n /// </summary> \n public object Current => _coreCoroutine.Current;\n\n /// <summary> \n /// Advances the enumerator to the next element of the collection. \n /// </summary> \n /// <returns> \n /// true if the enumerator was successfully advanced to the next element; false if \n /// the enumerator has passed the end of the collection. \n /// </returns> \n public bool MoveNext()\n {\n return _coreCoroutine.MoveNext();\n }\n\n /// <summary> \n /// Sets the enumerator to its initial position, which is before the first element \n /// in the collection. \n /// </summary> \n public void Reset()\n {\n _coreCoroutine.Reset();\n }\n }\n}\n
A couple of weeks ago, Unity has released a new version, 2017.1. In this version, the most anticipated feature, TAP and Async-await support, finally came out as a beta feature, with .NET 4.6 Experimental Equivalent. This is not a coincidence. With the Microsoft HoloLens and Windows MR platform strategic layout gradually being mature, many of Unity developers began to study how to interact with the UWP API to obtain the necessary support from windows platform.
As a 3D scripting engine, Unity 5.X and earlier provide only limited. NET 2.0-4. x, c # 4 support. To access a comprehensive asynchronous API still requires a lot of adaptive work. If you are unfamiliar with UWP and TAP the underlying implementations, the developer is hard to port TAP into Unity existing Update Check/Coroutine model development process. In the other hand, experienced UWP developers are also eager to XR world,, but are suffering from lacking async-await/TAP , misunderstanding Coroutine asynchronous model. (I was one of the struggled member.)
Now, with the constant maturity of .net standard libs, which is trying to smooth all platform differences. With efforts from Unity, Microsoft and geeks in community , Unity developers and UWP developers are finally able to develop using the Coroutine and TAP at the same time. That is the kind of news makes me laugh out loud in my dream.
While celebrating, we still should realize that this brings new challenges. We update the function is not to all overturn everything to start again, whetheryou are a Unity master developer, you may have projects that need porting to the UWP platform, or you are a novice of unity but a UWP developer, you may want to upgrade your 2D XAML application to Windows MR platform. Or, if you are completely new to both,just want a lot of Unity and UWP code examples find your App technical feasibility. No matter who you are, , you will eventually encounter this problem: how to interact with Unity Coroutine and. Net TAP correctly.
This article aims to provide you with a clear reference, or to be inspired by the tools provided in this article, to provide better productivity for later work and study.
As most of the code snippets only dependents on Unity Editor Console printout, you can have use Unity 2017.1 to proceed.
Project Setting Up The sample project needs to configure your Unity project to start .NET 4.6 and async support. If you are not familiar with this, it is recommended that you follow the steps below to set up your new project.
\n
1. Start Unity
\n
\n
2. Click on the \"New\" icon, enter the project name \"AsyncExample\"
\n
\n
3. Click the \"Create Project\" button
\n
\n
4. Click on the menu \"File-> Build Settings\"
\n
\n
5. Click \"Player Settings\" on the bottom.
\n
Look at your \"Inspector\" window, there will be some property tabs. Unfold \"Other Settings\" tab.
\n
6. Find the \"Configuration\" property group. Change the value of \"Scripting Runtime Version *\" \"Stable (.NET 3.5 Equivalent)\" to \"Experinmental (.NET 4.6 Equivalent) \"
\n
\n
7. Unity Editor needs a complete reboot after your modification, you will see following message.
\n
Select \"Restart\" to restart the Unity. After restart, at the same location, properties should be
At this point, Unity Editor obtained the ability to execute c# 6.0, some previously unrecognized class library and syntax will be able to be tested and debugged at the Editor Player, without the need for conditional compilation delay to other platforms to run.
\n
8. In the \"Project\" window, create a new child folder \"Scripts\" as child folder of \"Assets\". Create a new C# script \"AsyncExample.cs\" in \"Scripts\"
\n
\n
9. In the \"Hierarchy\" window, create a new, empty object named \"ConsoleScripts\"
\n
\n
10. Drag the script you have created into \"ConsoleScripts\" Game Object
\n
\n
\n
Basic codes Next, we need to prepare for some infrastructure, allows us to create some simple behaviors for our tests.
Logging
Log output code is very simple, it will help us to Unity Console output format information. First of all, we add the following code in the script:
Stopwatch object can help us trace calling time. When the Unity scene enters the running state, the stopwatch will start, we can clearly see a thread at a certain time, in which function to do what.
Next, In order to study how multiple asynchronous tasks directly link and call, we often need to pre-design some tasks , we often need to design a typical template. which can be easy to control and the output sequence. My choice was Count Down Task.
\npublic IEnumerator CoroutineCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n yield return new WaitForSeconds(1);\n }\n}\n
\n
\n
\n
\n
If you are a beginner of Unity, you can see this is a yield function returns a enumerator, by your c# experience. Unity can use IEnumerator returned this by method, which can populate sequence of YieldInstruction objects (WaitForSeconds). This sequence is consumed by dispatcher in the base class, MonoBehavior. In each of the YieldInstruction consumption, when the asynchronous operation is complete, the dispatcher will join execution back to the main thread of Unity and calls the IEnumerator MoveNext() method to get the next YieldInstruction. Execution: CoroutineCountDown
Execute separately
Put the following code in the Start method as below, we can run game in Editor and get console output
You can see, in the logs, execution thread is always Thread1, count down by 1, every 1 second. Execute in parallel
As this code snippet runs asynchronously, in Unity in this method execution will not affect another operation executed in main thread. It also does not prevent multiple execution..
When we called twice in a row, we'll see the two tasks transformed themselves into slices, and weaved in the execution of the main thread.
Execution in linear
If two or more Coroutines require convergence (including other process controls, such as if / switch / loop), an additional parent Coroutine is required to be scheduled in Unity. We can create the following code:
\n
\n
\n
\n
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n StartCoroutine(CoroutineCountDownSeq(3, \"BasicCoCallA\", \"BasicCoCallB\"));\n}\n\npublic IEnumerator CoroutineCountDownSeq(int countDown, params string[] flags)\n{\n foreach (var flag in flags)\n {\n yield return StartCoroutine(CoroutineCountDown(3, flag));\n }\n}\n\n
\n
\n
\n
\n
You can see that parent method enumerates a IEnumerator waiting YieldInstructions (this time UnityEngine.Coroutine class) , so dispatcher can schedule YieldInstructions sequences as one, back to top Scheduler.
Results:
Combining code snippet above, we can also implement complex patterns, such as Timer, Event Recognizer, Fork-Join etc.. We are not unfold all of them here.
\npublic async Task TaskAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000);\n }\n}\n
\n
\n
\n
\n
This version of the code is very similar to the Coroutine version: same CPS transformation, only using await instead of yield return, and using Task instead if Coroutine. Another way to achieve same is \"async void function\".
\n
\n
\n
\n
\npublic async void VoidAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000);\n }\n}\n\n
\n
\n
\n
\n
In community articles and multiple versions of the documents we mentioned, In addition to using the void function as an event handler, \"async void functions\" are strongly not recommended . Because the functions dose not return anything Task scheduler can access. This code snippet is presented as a negative example here, for your reference.
When we do not need to do anything for this asynchronous task and just start it, the Task object async method returns is relatively meaningless, we can call an async function the in the Start function directly. Although this will be in the Visual Studio with a green wavy line warning, but this is actually a legitimate usage.
In order to avoid the occurrence of such noise, returned could be received by a temporary variable without any operation on it. Like what:
\n
\n
\n
\n
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var _ = TaskAsyncCountDown(3, \"BasicAsyncCall\");\n}\n
\n
\n
\n
\n
Result just like Coroutine
As you can see, await in the async functions use the default Task choreographer, completed Task will be executed each time the County asked after conversion back to the Unity of the main thread.
If we want to change this behavior, we can modify the TaskAsyncCountDown Function, modify the following code
\n
\n
\n
\n
\npublic async Task TaskAsyncCountDown(int count, string flag = \"\")\n{\n for (int i = count; i >= 0; i--)\n {\n LogToTUnityConsole(i, flag);\n await Task.Delay(1000).ConfigureAwait(false);\n }\n}\n
\n
\n
\n
\n
\n
Await Scheduler uses the thread pool, and each step of await is no longer be forced to return to game's main thread, which might improve execution speed. In this case operations to some objects that need be operate in main thread (such as Texture Read-write) will fail.CPU intensive computation are recommended to be scheduled in the thread pool, in order to unblock render updates, which can make same effect as reduce workload in Update() method.
Execute in parallel from main thread
Using the Task, multiple operations can start and return to the main thread.
\n
\n
\n
\n
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var a = TaskAsyncCountDown(3, \"BasicAsyncCallA\");\n var b = TaskAsyncCountDown(3, \"BasicAsyncCallB\");\n}\n
\n
\n
\n
\n
Execute in linear from main thread
Like the Coroutine, async methods can be linked one after another:
\n
\n
\n
\n
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var t = TaskAsyncCountDownSeq(3, \"BasicAsyncCallA\", \"BasicAsyncCallB\");\n}\n\npublic async Task TaskAsyncCountDownSeq(int countDown, params string[] flags)\n{\n foreach (var flag in flags)\n {\n await TaskAsyncCountDown(3, flag);\n }\n}\n\n
\n
\n
\n
\n
>Execution results
Execute in thread pooling
If you are careful enough, you will find out that in ConfigureAwait(false) code execution result, thread id value in first line was 1 .
Before the first await keyword, operations will execute on the caller's thread in typical async executions. In extreme cases, if an asynchronous function executes CPU-intensive or long-running synchronous IO operations at the entrance, main thread of Unity will still be blocked. This can be optimized in the following way:
\n
\n
\n
\n
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n var _ = Task.Run(() => TaskAsyncCountDown(3, \"BasicAsyncCall\"));\n}\n
\n
\n
\n
\n
At this point the function entry is called by the thread pool scheduler. Since the thread in the thread pool does not synchronize the context, all subsequent calls will randomly use the available threads in the thread pool. Even if you forced it by setting parameter of .ConfigureAwait () to true, it would not help. Please pay attention to the potential impact of such calls: you will lose the ability to go return to the main thread contexts.
Is there another way to have synchronization context and run steps in thread pool?
Execute with Mixed Scheduler
In order to address the questions raised by the end of the previous section, I have designed this use case:
Assume that following steps are demanded in a business logic:
\n
a. computing n! (n=150)
\n
\n
b. 1 seconds waiting
\n
\n
c. output
\n
So we get the following code (in order to expand the execution load, I added sleep time in loops):
\n
\n
\n
\n
\npublic void CPUBigHead(int n)\n{\n double result = 1;\n LogToTUnityConsole(result, $\"n!(n={n}) start\");\n for (int i = 1; i <= n; i++)\n {\n result = result * i;\n Thread.Sleep(10);\n }\n LogToTUnityConsole(result, $\"n!(n={n}) stop\");\n Thread.Sleep(1000);\n\n //Texture change logic puts here \n\n LogToTUnityConsole(result, $\"n!(n={n}) output\");\n}\n
\n
\n
\n
\n
n! calculation is a CPU-intensive operation. We want it executing in other threads, and output the results in the UI layer called texture changes, you need to manipulate the thread Id is 1. On this basis, I modified synchronized code into async to achieve.
\n
\n
\n
\n
\n
\npublic async Task CPUBigHeadAsync(int n)\n{\n double result = 1;\n await Task.Run(() =>\n {\n LogToTUnityConsole(result, $\"n!(n={n}) start\");\n for (int i = 1; i <= n; i++)\n {\n result = result * i;\n Thread.Sleep(10);\n }\n LogToTUnityConsole(result, $\"n!(n={n}) stop\");\n }); //Scheduler will contiue execution in main thread here \n\n await Task.Delay(1000);\n //Texture change logic puts here \n LogToTUnityConsole(result, $\"n!(n={n}) output\");\n}\n
\n
\n
\n
\n
> Get the following results:
Can see that we make sure that CPU-intensive operations are not running in the main thread. This modification ensures a relatively smooth rendering update.
Comparison summary From the above examples, we can see that the new Task API / async syntax brings new optimization possibilities for Unity. Old Coroutine mechanisms can be logically split into small sections, but it have less power to control each part running in thread freely. With new Task API you can easily do operations in a thread pool, and make calculations easier.
In addition, Task/await also has some other advantages
\n
· Highly integrated with the UWP API, you can use the simple await/AsTask () extension method to convert.
\n
\n
· To maintain async job's lifetime at the Application level.。
\n
\n
· Control timer/manual interruption of the execution tree by CancellationToke
\n
\n
· Fast package of Event/thread/IAsyncResult, provides a simple unified calling pattern.
As I mentioned at the beginning of this article, new member, Task/async will exist with Coroutine side by side, and the ecosystem will need them interactive with each other. So how to interactive one to another ?
>interactive with each other,means that we are able to Coroutine call the Async method, as well as the calling Coroutine in the Async method. Examples of concurrent execution and no different from basic calls, here we show you how to call one another and calling the next one after the implementation of process implementation.
If you want to call a Coroutine and in the async methods, we need to wrap the Coroutine implementation to a simple Task.
There are no callbacks or wait handle in YeildInstruction class of Unity. So we need a parent's Coroutine method to monitor completion of the target Coroutine.
\nvoid Start()\n{\n stopwatch = new System.Diagnostics.Stopwatch();\n stopwatch.Start();\n StartCoroutine(CoroutineAwaitATask());\n}\n
\n
\n
\n
You can see, after the executions of the TaskAsyncCountDown \"task\" Async method, Unity dispatcher continued to execute the CoroutineCountDown \"posttask\"
Code snippets above shows us how to make Task and Coroutine call each other. So do we have a way of simplifying this process, makes operations more productive?
Because we were using the. NET 4.6 subset already , wrapping these operations into extension methods is very easy. So I created CoTaskHelper class. to simplify calling.
In this article, we briefly introduce and compare the Unity native Coroutine programming approach and the .NET 4.6 subset + TAP programming approach introduced in the Unity 2017.1, also release and provide examples of code that two methods interact with each other. Hopefully these examples can inspire readers and become the help of using Unity to increase productivity.
\n
\n
P.S.
After practice with projects, I have written a better version, and added YeildInstruction support. Please feel free give me feedback in comments 🙂
\n
\n
\n/// <summary> \n/// Coroutine and Task Async Interactive Helper \n/// Based on artical https://blogs.msdn.microsoft.com/appconsult/2017/09/01/unity-coroutine-tap-en-us/ \n/// </summary> \npublic static class CoroutineTaskHelper\n{\n /// <summary> \n /// Translate a coroutine to Task and run. It needs a Mono Behavior to locate Unity thread context. \n /// </summary> \n /// <param name=\"monoBehavior\">The Mono Behavior that managing coroutines</param> \n /// <param name=\"coroutine\">the coroutine that needs to run </param> \n /// <returns>Task that can be await</returns> \n public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, IEnumerator coroutine)\n {\n var tcs = new TaskCompletionSource<object>();\n monoBehavior\n .StartCoroutine(\n emptyCoroutine(\n coroutine,\n tcs));\n await tcs.Task;\n }\n\n /// <summary> \n /// Translate a YieldInstruction to Task and run. It needs a Mono Behavior to locate Unity thread context. \n /// </summary> \n /// <param name=\"monoBehavior\">The Mono Behavior that managing coroutines</param> \n /// <param name=\"yieldInstruction\"></param> \n /// <returns>Task that can be await</returns> \n public static async Task StartCoroutineAsync(this MonoBehaviour monoBehavior, YieldInstruction yieldInstruction)\n {\n var tcs = new TaskCompletionSource<object>();\n monoBehavior\n .StartCoroutine(\n emptyCoroutine(\n yieldInstruction,\n tcs));\n await tcs.Task;\n }\n\n /// <summary> \n /// Wrap a Task as a Coroutine. \n /// </summary> \n /// <param name=\"task\">The target task.</param> \n /// <returns>Wrapped Coroutine</returns> \n public static CoroutineWithTask<System.Object> AsCoroutine(this Task task)\n {\n var coroutine = new WaitUntil(() => task.IsCompleted || task.IsFaulted || task.IsCanceled);\n return new CoroutineWithTask<object>(task);\n }\n\n /// <summary> \n /// Wrap a Task as a Coroutine. \n /// </summary> \n /// <param name=\"task\">The target task.</param> \n /// <returns>Wrapped Coroutine</returns> \n public static CoroutineWithTask<T> AsCoroutine<T>(this Task<T> task)\n {\n\n return new CoroutineWithTask<T>(task);\n }\n\n private static IEnumerator emptyCoroutine(YieldInstruction coro, TaskCompletionSource<object> completion)\n {\n yield return coro;\n completion.TrySetResult(null);\n }\n\n private static IEnumerator emptyCoroutine(IEnumerator coro, TaskCompletionSource<object> completion)\n {\n yield return coro;\n completion.TrySetResult(null);\n }\n\n /// <summary> \n /// Wrapped Task, behaves like a coroutine \n /// </summary> \n public struct CoroutineWithTask<T> : IEnumerator\n {\n\n private IEnumerator _coreCoroutine;\n\n /// <summary> \n /// Constructor for Task with a return value; \n /// </summary> \n /// <param name=\"coreTask\">Task that need wrap</param> \n public CoroutineWithTask(Task<T> coreTask)\n {\n WrappedTask = coreTask;\n _coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);\n }\n\n /// <summary> \n /// Constructor for Task without a return value; \n /// </summary> \n /// <param name=\"coreTask\">Task that need wrap</param> \n public CoroutineWithTask(Task coreTask)\n {\n WrappedTask = Task.Run(async () =>\n {\n await coreTask;\n return default(T);\n });\n _coreCoroutine = new WaitUntil(() => coreTask.IsCompleted || coreTask.IsFaulted || coreTask.IsCanceled);\n }\n\n /// <summary> \n /// The task have wrapped in this coroutine. \n /// </summary> \n public Task<T> WrappedTask { get; private set; }\n\n\n /// <summary> \n /// Task result, if it have. Calling this property will wait execution synchronously. \n /// </summary> \n public T Result { get { return WrappedTask.Result; } }\n\n\n /// <summary> \n /// Gets the current element in the collection. \n /// </summary> \n public object Current => _coreCoroutine.Current;\n\n /// <summary> \n /// Advances the enumerator to the next element of the collection. \n /// </summary> \n /// <returns> \n /// true if the enumerator was successfully advanced to the next element; false if \n /// the enumerator has passed the end of the collection. \n /// </returns> \n public bool MoveNext()\n {\n return _coreCoroutine.MoveNext();\n }\n\n /// <summary> \n /// Sets the enumerator to its initial position, which is before the first element \n /// in the collection. \n /// </summary> \n public void Reset()\n {\n _coreCoroutine.Reset();\n }\n }\n}\n\n
","introduction":"","coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""},"currentRevision":{"__ref":"Revision:revision:316851_8"},"latestVersion":{"__typename":"FriendlyVersion","major":"8","minor":"0"},"metrics":{"__typename":"MessageMetrics","views":8510},"visibilityScope":"PUBLIC","canonicalUrl":null,"seoTitle":"Asynchronous programming in Unity, Using Coroutine and TAP","seoDescription":"Asynchronous programming in Unity, Using Coroutine and TAP","placeholder":false,"originalMessageForPlaceholder":null,"contributors":{"__typename":"UserConnection","edges":[]},"nonCoAuthorContributors":{"__typename":"UserConnection","edges":[]},"coAuthors":{"__typename":"UserConnection","edges":[]},"blogMessagePolicies":{"__typename":"BlogMessagePolicies","canDoAuthoringActionsOnBlog":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.blog.action_can_do_authoring_action.accessDenied","key":"error.lithium.policies.blog.action_can_do_authoring_action.accessDenied","args":[]}}},"archivalData":null,"replies":{"__typename":"MessageConnection","edges":[{"__typename":"MessageEdge","cursor":"MjUuMXwyLjF8aXwxMHwxMzI6MHxpbnQsNDE0MjM1OSw0MTQyMzU5","node":{"__ref":"BlogReplyMessage:message:4142359"}}],"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"customFields":[],"revisions({\"constraints\":{\"isPublished\":{\"eq\":true}},\"first\":1})":{"__typename":"RevisionConnection","totalCount":8}},"Conversation:conversation:316851":{"__typename":"Conversation","id":"conversation:316851","solved":false,"topic":{"__ref":"BlogTopicMessage:message:316851"},"lastPostingActivityTime":"2024-05-16T01:46:40.930-07:00","lastPostTime":"2024-05-16T01:46:40.930-07:00","unreadReplyCount":1,"isSubscribed":false},"ModerationData:moderation_data:316851":{"__typename":"ModerationData","id":"moderation_data:316851","status":"APPROVED","rejectReason":null,"isReportedAbuse":false,"rejectUser":null,"rejectTime":null,"rejectActorType":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjVpRTlGQjVFNzdGRjBEQzRENw?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjVpRTlGQjVFNzdGRjBEQzRENw?revision=8","title":"","associationType":"BODY","width":480,"height":279,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjdpMDE0NjZGREUzMzk2QkEyRA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjdpMDE0NjZGREUzMzk2QkEyRA?revision=8","title":"","associationType":"BODY","width":480,"height":372,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjhpNzM4RUQ5OEIwRUQxQTBDNQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MjhpNzM4RUQ5OEIwRUQxQTBDNQ?revision=8","title":"","associationType":"BODY","width":321,"height":624,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzFpNjc5Qzk0MDdGQzE5NUVGRg?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzFpNjc5Qzk0MDdGQzE5NUVGRg?revision=8","title":"","associationType":"BODY","width":459,"height":170,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzJpOTI1RDc2MDgyNTM3RDhGMg?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzJpOTI1RDc2MDgyNTM3RDhGMg?revision=8","title":"","associationType":"BODY","width":398,"height":183,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzRpRDJGMTM2MkUwRTQyOTJFMg?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzRpRDJGMTM2MkUwRTQyOTJFMg?revision=8","title":"","associationType":"BODY","width":430,"height":128,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzZpNkUxMTYyRjkzMjYyODE1QQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzZpNkUxMTYyRjkzMjYyODE1QQ?revision=8","title":"","associationType":"BODY","width":480,"height":141,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzhpQTNDRjU5QUZCQTQ4MjJEQQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5MzhpQTNDRjU5QUZCQTQ4MjJEQQ?revision=8","title":"","associationType":"BODY","width":236,"height":94,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDBpNzgyRkU1MTc2RThBMzlEOA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDBpNzgyRkU1MTc2RThBMzlEOA?revision=8","title":"","associationType":"BODY","width":488,"height":229,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDFpMEYwRUYzNDVCMkJBNkE1RQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDFpMEYwRUYzNDVCMkJBNkE1RQ?revision=8","title":"","associationType":"BODY","width":480,"height":141,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDJpQTgyMzA3RDJDMjVFNUQ3OA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDJpQTgyMzA3RDJDMjVFNUQ3OA?revision=8","title":"","associationType":"BODY","width":480,"height":284,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDRpMjA4RTMyM0RFMzRBRDVDRQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDRpMjA4RTMyM0RFMzRBRDVDRQ?revision=8","title":"","associationType":"BODY","width":551,"height":272,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDZpNzQwQTgxMjkxOEQ4QjUzRA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDZpNzQwQTgxMjkxOEQ4QjUzRA?revision=8","title":"","associationType":"BODY","width":883,"height":189,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDhpOTdDODRFRDE5OUE1RTFDMw?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDhpOTdDODRFRDE5OUE1RTFDMw?revision=8","title":"","associationType":"BODY","width":480,"height":156,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDlpQjNCOUZBRTJFOTg4QzE3MA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NDlpQjNCOUZBRTJFOTg4QzE3MA?revision=8","title":"","associationType":"BODY","width":480,"height":153,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTFpRkU1NjRCMzFFMzBBNDUwMA?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTFpRkU1NjRCMzFFMzBBNDUwMA?revision=8","title":"","associationType":"BODY","width":480,"height":273,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTNpMEQ2NUEyNTY0MkUyNzQ1Mg?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTNpMEQ2NUEyNTY0MkUyNzQ1Mg?revision=8","title":"","associationType":"BODY","width":480,"height":283,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTRpODdERjFFMTFDMURBN0MzQQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTRpODdERjFFMTFDMURBN0MzQQ?revision=8","title":"","associationType":"BODY","width":480,"height":158,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTZpNUY2OTA5REJFRjcxMUIzNw?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTZpNUY2OTA5REJFRjcxMUIzNw?revision=8","title":"","associationType":"BODY","width":480,"height":127,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NThpMTMyNjFGNDNFNEYyQzFBOQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NThpMTMyNjFGNDNFNEYyQzFBOQ?revision=8","title":"","associationType":"BODY","width":480,"height":130,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTlpNzg3QTZCM0IyRTdGOTcwMg?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NTlpNzg3QTZCM0IyRTdGOTcwMg?revision=8","title":"","associationType":"BODY","width":467,"height":382,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NjBpQTMzMDk3MzE4M0Y1QzUyRQ?revision=8\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS0zMTY4NTEtNjY5NjBpQTMzMDk3MzE4M0Y1QzUyRQ?revision=8","title":"","associationType":"BODY","width":480,"height":372,"altText":null},"Revision:revision:316851_8":{"__typename":"Revision","id":"revision:316851_8","lastEditTime":"2022-11-22T12:25:28.524-08:00"},"CachedAsset:theme:customTheme1-1745486121533":{"__typename":"CachedAsset","id":"theme:customTheme1-1745486121533","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["default"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"favicon-1730836283320.png","imageLastModified":"1730836286415","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"favicon-1730836271365.png","imageLastModified":"1730836274203","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1300px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_BROWSER","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"3px","borderRadius":"3px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"16px","paddingXHero":"60px","fontStyle":"NORMAL","fontWeight":"700","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-200)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-200)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"LIGHT","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.16)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.12)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-link-color)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#4099E2","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#148563","blogColor":"#1CBAA0","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#4C6B90","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#FF8000","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#D13A1F","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#333333","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#717171","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0069D4","secondary":"#333333","bodyText":"#1E1E1E","bodyBg":"#FFFFFF","info":"#409AE2","success":"#41C5AE","warning":"#FCC844","danger":"#BC341B","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#D3F5A4","#243A5E"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Segoe UI","fontStyle":"NORMAL","fontWeight":"400","h1FontSize":"34px","h2FontSize":"32px","h3FontSize":"28px","h4FontSize":"24px","h5FontSize":"20px","h6FontSize":"16px","lineHeight":"1.3","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":"","imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"40px","defaultMessageHeaderMarginBottom":"20px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"40px","specialMessageHeaderMarginBottom":"20px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Segoe UI","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.5","fontSizeBase":"16px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"14px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[{"source":"SERVER","name":"Segoe UI","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"},{"style":"NORMAL","weight":"300","__typename":"FontStyleData"},{"style":"NORMAL","weight":"600","__typename":"FontStyleData"},{"style":"NORMAL","weight":"700","__typename":"FontStyleData"},{"style":"ITALIC","weight":"400","__typename":"FontStyleData"}],"assetNames":["SegoeUI-normal-400.woff2","SegoeUI-normal-300.woff2","SegoeUI-normal-600.woff2","SegoeUI-normal-700.woff2","SegoeUI-italic-400.woff2"],"__typename":"CustomFont"},{"source":"SERVER","name":"MWF Fluent Icons","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"}],"assetNames":["MWFFluentIcons-normal-400.woff2"],"__typename":"CustomFont"}],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1745505309750","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1745505309750","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:quilt:o365.prod:pages/blogs/BlogMessagePage:board:ModernWorkAppConsult-1745502712655":{"__typename":"CachedAsset","id":"quilt:o365.prod:pages/blogs/BlogMessagePage:board:ModernWorkAppConsult-1745502712655","value":{"id":"BlogMessagePage","container":{"id":"Common","headerProps":{"backgroundImageProps":null,"backgroundColor":null,"addComponents":null,"removeComponents":["community.widget.bannerWidget"],"componentOrder":null,"__typename":"QuiltContainerSectionProps"},"headerComponentProps":{"community.widget.breadcrumbWidget":{"disableLastCrumbForDesktop":false}},"footerProps":null,"footerComponentProps":null,"items":[{"id":"blog-article","layout":"ONE_COLUMN","bgColor":null,"showTitle":null,"showDescription":null,"textPosition":null,"textColor":null,"sectionEditLevel":"LOCKED","bgImage":null,"disableSpacing":null,"edgeToEdgeDisplay":null,"fullHeight":null,"showBorder":null,"__typename":"OneColumnQuiltSection","columnMap":{"main":[{"id":"blogs.widget.blogArticleWidget","className":"lia-blog-container","props":null,"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"}},{"id":"section-1729184836777","layout":"MAIN_SIDE","bgColor":"transparent","showTitle":false,"showDescription":false,"textPosition":"CENTER","textColor":"var(--lia-bs-body-color)","sectionEditLevel":null,"bgImage":null,"disableSpacing":null,"edgeToEdgeDisplay":null,"fullHeight":null,"showBorder":null,"__typename":"MainSideQuiltSection","columnMap":{"main":[],"side":[],"__typename":"MainSideSectionColumns"}}],"__typename":"QuiltContainer"},"__typename":"Quilt","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-pages/blogs/BlogMessagePage-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-pages/blogs/BlogMessagePage-1745505309750","value":{"title":"{contextMessageSubject} | {communityTitle}","errorMissing":"This blog post cannot be found","name":"Blog Message Page","section.blog-article.title":"Blog Post","archivedMessageTitle":"This Content Has Been Archived","section.section-1729184836777.title":"","section.section-1729184836777.description":"","section.CncIde.title":"Blog Post","section.tifEmD.description":"","section.tifEmD.title":""},"localOverride":false},"CachedAsset:quiltWrapper:o365.prod:Common:1745505310233":{"__typename":"CachedAsset","id":"quiltWrapper:o365.prod:Common:1745505310233","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"community.widget.navbarWidget","props":{"showUserName":true,"showRegisterLink":true,"useIconLanguagePicker":true,"useLabelLanguagePicker":true,"className":"QuiltComponent_lia-component-edit-mode__0nCcm","links":{"sideLinks":[],"mainLinks":[{"children":[],"linkType":"INTERNAL","id":"gxcuf89792","params":{},"routeName":"CommunityPage"},{"children":[],"linkType":"EXTERNAL","id":"external-link","url":"/Directory","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft365","params":{"categoryId":"microsoft365"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows","params":{"categoryId":"Windows"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"Common-microsoft365-copilot-link","params":{"categoryId":"Microsoft365Copilot"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-teams","params":{"categoryId":"MicrosoftTeams"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-securityand-compliance","params":{"categoryId":"microsoft-security"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"azure","params":{"categoryId":"Azure"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"Common-content_management-link","params":{"categoryId":"Content_Management"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"exchange","params":{"categoryId":"Exchange"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows-server","params":{"categoryId":"Windows-Server"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"outlook","params":{"categoryId":"Outlook"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-endpoint-manager","params":{"categoryId":"microsoftintune"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-2","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities","url":"/","target":"BLANK"},{"children":[{"linkType":"INTERNAL","id":"a-i","params":{"categoryId":"AI"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"education-sector","params":{"categoryId":"EducationSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"partner-community","params":{"categoryId":"PartnerCommunity"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"i-t-ops-talk","params":{"categoryId":"ITOpsTalk"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"healthcare-and-life-sciences","params":{"categoryId":"HealthcareAndLifeSciences"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-mechanics","params":{"categoryId":"MicrosoftMechanics"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"public-sector","params":{"categoryId":"PublicSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-m-b","params":{"categoryId":"MicrosoftforNonprofits"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"io-t","params":{"categoryId":"IoT"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"startupsat-microsoft","params":{"categoryId":"StartupsatMicrosoft"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"driving-adoption","params":{"categoryId":"DrivingAdoption"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-1","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities-1","url":"/","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external","url":"/Blogs","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external-1","url":"/Events","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft-learn-1","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-learn-blog","params":{"boardId":"MicrosoftLearnBlog","categoryId":"MicrosoftLearn"},"routeName":"BlogBoardPage"},{"linkType":"EXTERNAL","id":"external-10","url":"https://learningroomdirectory.microsoft.com/","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-3","url":"https://docs.microsoft.com/learn/dynamics365/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-4","url":"https://docs.microsoft.com/learn/m365/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-5","url":"https://docs.microsoft.com/learn/topics/sci/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-6","url":"https://docs.microsoft.com/learn/powerplatform/?wt.mc_id=techcom_header-webpage-powerplatform","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-7","url":"https://docs.microsoft.com/learn/github/?wt.mc_id=techcom_header-webpage-github","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-8","url":"https://docs.microsoft.com/learn/teams/?wt.mc_id=techcom_header-webpage-teams","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-9","url":"https://docs.microsoft.com/learn/dotnet/?wt.mc_id=techcom_header-webpage-dotnet","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-2","url":"https://docs.microsoft.com/learn/azure/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"}],"linkType":"INTERNAL","id":"microsoft-learn","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"community-info-center","params":{"categoryId":"Community-Info-Center"},"routeName":"CategoryPage"}]},"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","controllerHighlightColor":"hsla(30, 100%, 50%)","linkFontWeight":"400","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkBoxShadowHover":"none","linkFontSize":"14px","backgroundOpacity":0.8,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","hamburgerColor":"var(--lia-nav-controller-icon-color)","linkTextBorderBottom":"none","brandLogoHeight":"30px","linkBgHoverColor":"transparent","linkLetterSpacing":"normal","collapseMenuDividerOpacity":0.16,"dropdownPaddingBottom":"15px","paddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"1px solid var(--lia-bs-border-color)","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","collapseMenuDividerBg":"var(--lia-nav-link-color)","linkColor":"var(--lia-bs-body-color)","linkJustifyContent":"flex-start","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","controllerTextColor":"var(--lia-nav-controller-icon-color)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-body-color)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid var(--lia-bs-body-color)","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","linkPaddingX":"10px","linkPaddingY":"5px","paddingTop":"15px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkBgColor":"transparent","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkDropdownPaddingY":"9px","controllerIconColor":"var(--lia-bs-body-color)","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"var(--lia-bs-body-color)"},"showSearchIcon":false,"languagePickerStyle":"iconAndLabel"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"transparent","linkHighlightColor":"var(--lia-bs-primary)","visualEffects":{"showBottomBorder":true},"linkTextColor":"var(--lia-bs-gray-700)"},"__typename":"QuiltComponent"},{"id":"custom.widget.community_banner","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"usePageWidth":false,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.HeroBanner","props":{"widgetVisibility":"signedInOrAnonymous","usePageWidth":false,"useTitle":true,"cMax_items":3,"useBackground":false,"title":"","lazyLoad":false,"widgetChooser":"custom.widget.HeroBanner"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.MicrosoftFooter","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1745505309750","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.community_banner-en-1745486158577":{"__typename":"CachedAsset","id":"component:custom.widget.community_banner-en-1745486158577","value":{"component":{"id":"custom.widget.community_banner","template":{"id":"community_banner","markupLanguage":"HANDLEBARS","style":".community-banner {\n a.top-bar.btn {\n top: 0px;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0px;\n background: #0068b8;\n color: white;\n padding: 10px 0px;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0px !important;\n font-size: 14px;\n }\n}\n","texts":null,"defaults":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.community_banner","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_community_banner_community-banner_1x9u2_1 {\n a.custom_widget_community_banner_top-bar_1x9u2_2.custom_widget_community_banner_btn_1x9u2_2 {\n top: 0;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0;\n background: #0068b8;\n color: white;\n padding: 0.625rem 0;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0 !important;\n font-size: 0.875rem;\n }\n}\n","tokens":{"community-banner":"custom_widget_community_banner_community-banner_1x9u2_1","top-bar":"custom_widget_community_banner_top-bar_1x9u2_2","btn":"custom_widget_community_banner_btn_1x9u2_2"}},"form":null},"localOverride":false},"CachedAsset:component:custom.widget.HeroBanner-en-1745486158577":{"__typename":"CachedAsset","id":"component:custom.widget.HeroBanner-en-1745486158577","value":{"component":{"id":"custom.widget.HeroBanner","template":{"id":"HeroBanner","markupLanguage":"REACT","style":null,"texts":{"searchPlaceholderText":"Search this community","followActionText":"Follow","unfollowActionText":"Following","searchOnHoverText":"Please enter your search term(s) and then press return key to complete a search.","blogs.sidebar.pagetitle":"Latest Blogs | Microsoft Tech Community","followThisNode":"Follow this node","unfollowThisNode":"Unfollow this node"},"defaults":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.HeroBanner","form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"__typename":"Component","localOverride":false},"globalCss":null,"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"}},"localOverride":false},"CachedAsset:component:custom.widget.MicrosoftFooter-en-1745486158577":{"__typename":"CachedAsset","id":"component:custom.widget.MicrosoftFooter-en-1745486158577","value":{"component":{"id":"custom.widget.MicrosoftFooter","template":{"id":"MicrosoftFooter","markupLanguage":"HANDLEBARS","style":".context-uhf {\n min-width: 280px;\n font-size: 15px;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.c-uhff-link {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.c-uhff {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.c-uhff-nav {\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n .c-heading-4 {\n color: #616161;\n word-break: break-word;\n font-size: 15px;\n line-height: 20px;\n padding: 36px 0 4px;\n font-weight: 600;\n }\n .c-uhff-nav-row {\n .c-uhff-nav-group {\n display: block;\n float: left;\n min-height: 1px;\n vertical-align: text-top;\n padding: 0 12px;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.c-list.f-bare {\n font-size: 11px;\n line-height: 16px;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 8px 0;\n margin: 0;\n }\n }\n }\n }\n}\n.c-uhff-base {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 30px 5% 16px;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.c-uhff-ccpa {\n font-size: 11px;\n line-height: 16px;\n float: left;\n margin: 3px 0;\n }\n a.c-uhff-ccpa:hover {\n text-decoration: underline;\n }\n ul.c-list {\n font-size: 11px;\n line-height: 16px;\n float: right;\n margin: 3px 0;\n color: #616161;\n li {\n padding: 0 24px 4px 0;\n display: inline-block;\n }\n }\n .c-list.f-bare {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 30px 24px 16px;\n }\n}\n\n.social-share {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n\n.sharing-options {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 43px;\n border-radius: 0px 7px 7px 0px;\n}\n.linkedin-icon {\n border-top-right-radius: 7px;\n}\n.linkedin-icon:hover {\n border-radius: 0;\n}\n.social-share-rss-image {\n border-bottom-right-radius: 7px;\n}\n.social-share-rss-image:hover {\n border-radius: 0;\n}\n\n.social-link-footer {\n position: relative;\n display: block;\n margin: -2px 0;\n transition: all 0.2s ease;\n}\n.social-link-footer:hover .linkedin-icon {\n border-radius: 0;\n}\n.social-link-footer:hover .social-share-rss-image {\n border-radius: 0;\n}\n\n.social-link-footer img {\n width: 40px;\n height: auto;\n transition: filter 0.3s ease;\n}\n\n.social-share-list {\n width: 40px;\n}\n.social-share-rss-image {\n width: 40px;\n}\n\n.share-icon {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n\n.share-icon:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n\n.share-icon:hover .label {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n\n.label {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 10px;\n top: 50%;\n transform: translateY(-50%);\n height: 40px;\n border-radius: 0 6px 6px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px 5px 20px 8px;\n margin-left: -1px;\n}\n.linkedin {\n background-color: #0474b4;\n}\n.facebook {\n background-color: #3c5c9c;\n}\n.twitter {\n background-color: white;\n color: black;\n}\n.reddit {\n background-color: #fc4404;\n}\n.mail {\n background-color: #848484;\n}\n.bluesky {\n background-color: white;\n color: black;\n}\n.rss {\n background-color: #ec7b1c;\n}\n#RSS {\n width: 40px;\n height: 40px;\n}\n\n@media (max-width: 991px) {\n .social-share {\n display: none;\n }\n}\n","texts":{"New tab":"What's New","New 1":"Surface Laptop Studio 2","New 2":"Surface Laptop Go 3","New 3":"Surface Pro 9","New 4":"Surface Laptop 5","New 5":"Surface Studio 2+","New 6":"Copilot in Windows","New 7":"Microsoft 365","New 8":"Windows 11 apps","Store tab":"Microsoft Store","Store 1":"Account Profile","Store 2":"Download Center","Store 3":"Microsoft Store Support","Store 4":"Returns","Store 5":"Order tracking","Store 6":"Certified Refurbished","Store 7":"Microsoft Store Promise","Store 8":"Flexible Payments","Education tab":"Education","Edu 1":"Microsoft in education","Edu 2":"Devices for education","Edu 3":"Microsoft Teams for Education","Edu 4":"Microsoft 365 Education","Edu 5":"How to buy for your school","Edu 6":"Educator Training and development","Edu 7":"Deals for students and parents","Edu 8":"Azure for students","Business tab":"Business","Bus 1":"Microsoft Cloud","Bus 2":"Microsoft Security","Bus 3":"Dynamics 365","Bus 4":"Microsoft 365","Bus 5":"Microsoft Power Platform","Bus 6":"Microsoft Teams","Bus 7":"Microsoft Industry","Bus 8":"Small Business","Developer tab":"Developer & IT","Dev 1":"Azure","Dev 2":"Developer Center","Dev 3":"Documentation","Dev 4":"Microsoft Learn","Dev 5":"Microsoft Tech Community","Dev 6":"Azure Marketplace","Dev 7":"AppSource","Dev 8":"Visual Studio","Company tab":"Company","Com 1":"Careers","Com 2":"About Microsoft","Com 3":"Company News","Com 4":"Privacy at Microsoft","Com 5":"Investors","Com 6":"Diversity and inclusion","Com 7":"Accessiblity","Com 8":"Sustainibility"},"defaults":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.MicrosoftFooter","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_MicrosoftFooter_context-uhf_105bp_1 {\n min-width: 17.5rem;\n font-size: 0.9375rem;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-link_105bp_12 {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff_105bp_12 {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35 {\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n .custom_widget_MicrosoftFooter_c-heading-4_105bp_49 {\n color: #616161;\n word-break: break-word;\n font-size: 0.9375rem;\n line-height: 1.25rem;\n padding: 2.25rem 0 0.25rem;\n font-weight: 600;\n }\n .custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57 {\n .custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58 {\n display: block;\n float: left;\n min-height: 0.0625rem;\n vertical-align: text-top;\n padding: 0 0.75rem;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 0.5rem 0;\n margin: 0;\n }\n }\n }\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff-base_105bp_94 {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 1.875rem 5% 1rem;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: left;\n margin: 0.1875rem 0;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107:hover {\n text-decoration: underline;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: right;\n margin: 0.1875rem 0;\n color: #616161;\n li {\n padding: 0 1.5rem 0.25rem 0;\n display: inline-block;\n }\n }\n .custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 1.875rem 1.5rem 1rem;\n }\n}\n.custom_widget_MicrosoftFooter_social-share_105bp_138 {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n.custom_widget_MicrosoftFooter_sharing-options_105bp_146 {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 2.6875rem;\n border-radius: 0 0.4375rem 0.4375rem 0;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-top-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-bottom-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 {\n position: relative;\n display: block;\n margin: -0.125rem 0;\n transition: all 0.2s ease;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 img {\n width: 2.5rem;\n height: auto;\n transition: filter 0.3s ease;\n}\n.custom_widget_MicrosoftFooter_social-share-list_105bp_188 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195 {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover .custom_widget_MicrosoftFooter_label_105bp_207 {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n.custom_widget_MicrosoftFooter_label_105bp_207 {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n height: 2.5rem;\n border-radius: 0 0.375rem 0.375rem 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.25rem 0.3125rem 1.25rem 0.5rem;\n margin-left: -0.0625rem;\n}\n.custom_widget_MicrosoftFooter_linkedin_105bp_156 {\n background-color: #0474b4;\n}\n.custom_widget_MicrosoftFooter_facebook_105bp_237 {\n background-color: #3c5c9c;\n}\n.custom_widget_MicrosoftFooter_twitter_105bp_240 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_reddit_105bp_244 {\n background-color: #fc4404;\n}\n.custom_widget_MicrosoftFooter_mail_105bp_247 {\n background-color: #848484;\n}\n.custom_widget_MicrosoftFooter_bluesky_105bp_250 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_rss_105bp_254 {\n background-color: #ec7b1c;\n}\n#custom_widget_MicrosoftFooter_RSS_105bp_1 {\n width: 2.5rem;\n height: 2.5rem;\n}\n@media (max-width: 991px) {\n .custom_widget_MicrosoftFooter_social-share_105bp_138 {\n display: none;\n }\n}\n","tokens":{"context-uhf":"custom_widget_MicrosoftFooter_context-uhf_105bp_1","c-uhff-link":"custom_widget_MicrosoftFooter_c-uhff-link_105bp_12","c-uhff":"custom_widget_MicrosoftFooter_c-uhff_105bp_12","c-uhff-nav":"custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35","c-heading-4":"custom_widget_MicrosoftFooter_c-heading-4_105bp_49","c-uhff-nav-row":"custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57","c-uhff-nav-group":"custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58","c-list":"custom_widget_MicrosoftFooter_c-list_105bp_78","f-bare":"custom_widget_MicrosoftFooter_f-bare_105bp_78","c-uhff-base":"custom_widget_MicrosoftFooter_c-uhff-base_105bp_94","c-uhff-ccpa":"custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107","social-share":"custom_widget_MicrosoftFooter_social-share_105bp_138","sharing-options":"custom_widget_MicrosoftFooter_sharing-options_105bp_146","linkedin-icon":"custom_widget_MicrosoftFooter_linkedin-icon_105bp_156","social-share-rss-image":"custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162","social-link-footer":"custom_widget_MicrosoftFooter_social-link-footer_105bp_169","social-share-list":"custom_widget_MicrosoftFooter_social-share-list_105bp_188","share-icon":"custom_widget_MicrosoftFooter_share-icon_105bp_195","label":"custom_widget_MicrosoftFooter_label_105bp_207","linkedin":"custom_widget_MicrosoftFooter_linkedin_105bp_156","facebook":"custom_widget_MicrosoftFooter_facebook_105bp_237","twitter":"custom_widget_MicrosoftFooter_twitter_105bp_240","reddit":"custom_widget_MicrosoftFooter_reddit_105bp_244","mail":"custom_widget_MicrosoftFooter_mail_105bp_247","bluesky":"custom_widget_MicrosoftFooter_bluesky_105bp_250","rss":"custom_widget_MicrosoftFooter_rss_105bp_254","RSS":"custom_widget_MicrosoftFooter_RSS_105bp_1"}},"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1745505309750","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBanner-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBanner-1745505309750","value":{"messageMarkedAsSpam":"This post has been marked as spam","messageMarkedAsSpam@board:TKB":"This article has been marked as spam","messageMarkedAsSpam@board:BLOG":"This post has been marked as spam","messageMarkedAsSpam@board:FORUM":"This discussion has been marked as spam","messageMarkedAsSpam@board:OCCASION":"This event has been marked as spam","messageMarkedAsSpam@board:IDEA":"This idea has been marked as spam","manageSpam":"Manage Spam","messageMarkedAsAbuse":"This post has been marked as abuse","messageMarkedAsAbuse@board:TKB":"This article has been marked as abuse","messageMarkedAsAbuse@board:BLOG":"This post has been marked as abuse","messageMarkedAsAbuse@board:FORUM":"This discussion has been marked as abuse","messageMarkedAsAbuse@board:OCCASION":"This event has been marked as abuse","messageMarkedAsAbuse@board:IDEA":"This idea has been marked as abuse","preModCommentAuthorText":"This comment will be published as soon as it is approved","preModCommentModeratorText":"This comment is awaiting moderation","messageMarkedAsOther":"This post has been rejected due to other reasons","messageMarkedAsOther@board:TKB":"This article has been rejected due to other reasons","messageMarkedAsOther@board:BLOG":"This post has been rejected due to other reasons","messageMarkedAsOther@board:FORUM":"This discussion has been rejected due to other reasons","messageMarkedAsOther@board:OCCASION":"This event has been rejected due to other reasons","messageMarkedAsOther@board:IDEA":"This idea has been rejected due to other reasons","messageArchived":"This post was archived on {date}","relatedUrl":"View Related Content","relatedContentText":"Showing related content","archivedContentLink":"View Archived Content"},"localOverride":false},"Category:category:Exchange":{"__typename":"Category","id":"category:Exchange","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Outlook":{"__typename":"Category","id":"category:Outlook","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Community-Info-Center":{"__typename":"Category","id":"category:Community-Info-Center","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:EducationSector":{"__typename":"Category","id":"category:EducationSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:DrivingAdoption":{"__typename":"Category","id":"category:DrivingAdoption","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Azure":{"__typename":"Category","id":"category:Azure","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows-Server":{"__typename":"Category","id":"category:Windows-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftTeams":{"__typename":"Category","id":"category:MicrosoftTeams","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PublicSector":{"__typename":"Category","id":"category:PublicSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:IoT":{"__typename":"Category","id":"category:IoT","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:HealthcareAndLifeSciences":{"__typename":"Category","id":"category:HealthcareAndLifeSciences","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:ITOpsTalk":{"__typename":"Category","id":"category:ITOpsTalk","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftLearn":{"__typename":"Category","id":"category:MicrosoftLearn","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Blog:board:MicrosoftLearnBlog":{"__typename":"Blog","id":"board:MicrosoftLearnBlog","blogPolicies":{"__typename":"BlogPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:AI":{"__typename":"Category","id":"category:AI","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftMechanics":{"__typename":"Category","id":"category:MicrosoftMechanics","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftforNonprofits":{"__typename":"Category","id":"category:MicrosoftforNonprofits","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:StartupsatMicrosoft":{"__typename":"Category","id":"category:StartupsatMicrosoft","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PartnerCommunity":{"__typename":"Category","id":"category:PartnerCommunity","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Microsoft365Copilot":{"__typename":"Category","id":"category:Microsoft365Copilot","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows":{"__typename":"Category","id":"category:Windows","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Content_Management":{"__typename":"Category","id":"category:Content_Management","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-security":{"__typename":"Category","id":"category:microsoft-security","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoftintune":{"__typename":"Category","id":"category:microsoftintune","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"QueryVariables:TopicReplyList:message:316851:8":{"__typename":"QueryVariables","id":"TopicReplyList:message:316851:8","value":{"id":"message:316851","first":10,"sorts":{"postTime":{"direction":"DESC"}},"repliesFirst":3,"repliesFirstDepthThree":1,"repliesSorts":{"postTime":{"direction":"DESC"}},"useAvatar":true,"useAuthorLogin":true,"useAuthorRank":true,"useBody":true,"useKudosCount":true,"useTimeToRead":false,"useMedia":false,"useReadOnlyIcon":false,"useRepliesCount":true,"useSearchSnippet":false,"useAcceptedSolutionButton":false,"useSolvedBadge":false,"useAttachments":false,"attachmentsFirst":5,"useTags":true,"useNodeAncestors":false,"useUserHoverCard":false,"useNodeHoverCard":false,"useModerationStatus":true,"usePreviewSubjectModal":false,"useMessageStatus":true}},"ROOT_MUTATION":{"__typename":"Mutation"},"CachedAsset:text:en_US-components/community/Navbar-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1745505309750","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","gxcuf89792":"Tech Community","external-1":"Events","s-m-b":"Nonprofit Community","windows-server":"Windows Server","education-sector":"Education Sector","driving-adoption":"Driving Adoption","Common-content_management-link":"Content Management","microsoft-learn":"Microsoft Learn","s-q-l-server":"Content Management","partner-community":"Microsoft Partner Community","microsoft365":"Microsoft 365","external-9":".NET","external-8":"Teams","external-7":"Github","products-services":"Products","external-6":"Power Platform","communities-1":"Topics","external-5":"Microsoft Security","planner":"Outlook","external-4":"Microsoft 365","external-3":"Dynamics 365","azure":"Azure","healthcare-and-life-sciences":"Healthcare and Life Sciences","external-2":"Azure","microsoft-mechanics":"Microsoft Mechanics","microsoft-learn-1":"Community","external-10":"Learning Room Directory","microsoft-learn-blog":"Blog","windows":"Windows","i-t-ops-talk":"ITOps Talk","external-link-1":"View All","microsoft-securityand-compliance":"Microsoft Security","public-sector":"Public Sector","community-info-center":"Lounge","external-link-2":"View All","microsoft-teams":"Microsoft Teams","external":"Blogs","microsoft-endpoint-manager":"Microsoft Intune","startupsat-microsoft":"Startups at Microsoft","exchange":"Exchange","a-i":"AI and Machine Learning","io-t":"Internet of Things (IoT)","Common-microsoft365-copilot-link":"Microsoft 365 Copilot","outlook":"Microsoft 365 Copilot","external-link":"Community Hubs","communities":"Products"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1745505309750","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1745505309750","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1745505309750","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1745505309750","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1745505309750","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewStandard-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewStandard-1745505309750","value":{"anonymous":"Anonymous","author":"{messageAuthorLogin}","authorBy":"{messageAuthorLogin}","board":"{messageBoardTitle}","replyToUser":" to {parentAuthor}","showMoreReplies":"Show More","replyText":"Reply","repliesText":"Replies","markedAsSolved":"Marked as Solved","movedMessagePlaceholder.BLOG":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.TKB":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.FORUM":"{count, plural, =0 {This reply has been} other {These replies have been} }","movedMessagePlaceholder.IDEA":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.OCCASION":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholderUrlText":"moved.","messageStatus":"Status: ","statusChanged":"Status changed: {previousStatus} to {currentStatus}","statusAdded":"Status added: {status}","statusRemoved":"Status removed: {status}","labelExpand":"expand replies","labelCollapse":"collapse replies","unhelpfulReason.reason1":"Content is outdated","unhelpfulReason.reason2":"Article is missing information","unhelpfulReason.reason3":"Content is for a different Product","unhelpfulReason.reason4":"Doesn't match what I was searching for"},"localOverride":false},"CachedAsset:text:en_US-components/messages/ThreadedReplyList-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/ThreadedReplyList-1745505309750","value":{"title":"{count, plural, one{# Reply} other{# Replies}}","title@board:BLOG":"{count, plural, one{# Comment} other{# Comments}}","title@board:TKB":"{count, plural, one{# Comment} other{# Comments}}","title@board:IDEA":"{count, plural, one{# Comment} other{# Comments}}","title@board:OCCASION":"{count, plural, one{# Comment} other{# Comments}}","noRepliesTitle":"No Replies","noRepliesTitle@board:BLOG":"No Comments","noRepliesTitle@board:TKB":"No Comments","noRepliesTitle@board:IDEA":"No Comments","noRepliesTitle@board:OCCASION":"No Comments","noRepliesDescription":"Be the first to reply","noRepliesDescription@board:BLOG":"Be the first to comment","noRepliesDescription@board:TKB":"Be the first to comment","noRepliesDescription@board:IDEA":"Be the first to comment","noRepliesDescription@board:OCCASION":"Be the first to comment","messageReadOnlyAlert:BLOG":"Comments have been turned off for this post","messageReadOnlyAlert:TKB":"Comments have been turned off for this article","messageReadOnlyAlert:IDEA":"Comments have been turned off for this idea","messageReadOnlyAlert:FORUM":"Replies have been turned off for this discussion","messageReadOnlyAlert:OCCASION":"Comments have been turned off for this event"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyCallToAction-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyCallToAction-1745505309750","value":{"leaveReply":"Leave a reply...","leaveReply@board:BLOG@message:root":"Leave a comment...","leaveReply@board:TKB@message:root":"Leave a comment...","leaveReply@board:IDEA@message:root":"Leave a comment...","leaveReply@board:OCCASION@message:root":"Leave a comment...","repliesTurnedOff.FORUM":"Replies are turned off for this topic","repliesTurnedOff.BLOG":"Comments are turned off for this topic","repliesTurnedOff.TKB":"Comments are turned off for this topic","repliesTurnedOff.IDEA":"Comments are turned off for this topic","repliesTurnedOff.OCCASION":"Comments are turned off for this topic","infoText":"Stop poking me!"},"localOverride":false},"Rank:rank:37":{"__typename":"Rank","id":"rank:37","position":18,"name":"Copper Contributor","color":"333333","icon":null,"rankStyle":"TEXT"},"User:user:2475440":{"__typename":"User","id":"user:2475440","uid":2475440,"login":"TheEpicCoder","biography":null,"registrationData":{"__typename":"RegistrationData","status":null,"registrationTime":"2024-05-16T01:44:46.825-07:00"},"deleted":false,"email":"","avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/m_assets/avatars/default/avatar-9.svg?time=0"},"rank":{"__ref":"Rank:rank:37"},"entityType":"USER","eventPath":"community:gxcuf89792/user:2475440"},"ModerationData:moderation_data:4142359":{"__typename":"ModerationData","id":"moderation_data:4142359","status":"APPROVED","rejectReason":null,"isReportedAbuse":false,"rejectUser":null,"rejectTime":null,"rejectActorType":null},"BlogReplyMessage:message:4142359":{"__typename":"BlogReplyMessage","author":{"__ref":"User:user:2475440"},"id":"message:4142359","revisionNum":1,"uid":4142359,"depth":1,"hasGivenKudo":false,"subscribed":false,"board":{"__ref":"Blog:board:ModernWorkAppConsult"},"parent":{"__ref":"BlogTopicMessage:message:316851"},"conversation":{"__ref":"Conversation:conversation:316851"},"subject":"Re: Asynchronous programming in Unity, Using Coroutine and TAP","moderationData":{"__ref":"ModerationData:moderation_data:4142359"},"body":"
Thank you very much for such a detailed and meaningful article. I learned a lot and got a cool experience)
","body@stripHtml({\"removeProcessingText\":false,\"removeSpoilerMarkup\":false,\"removeTocMarkup\":false,\"truncateLength\":200})@stringLength":"108","kudosSumWeight":0,"repliesCount":0,"postTime":"2024-05-16T01:46:40.930-07:00","lastPublishTime":"2024-05-16T01:46:40.930-07:00","metrics":{"__typename":"MessageMetrics","views":221},"visibilityScope":"PUBLIC","placeholder":false,"originalMessageForPlaceholder":null,"entityType":"BLOG_REPLY","eventPath":"category:microsoft365/category:products-services/category:communities/community:gxcuf89792board:ModernWorkAppConsult/message:316851/message:4142359","replies":{"__typename":"MessageConnection","pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null},"edges":[]},"customFields":[],"attachments":{"__typename":"AttachmentConnection","edges":[],"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1745505309750","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1745505309750","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageCoverImage-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageCoverImage-1745505309750","value":{"coverImageTitle":"Cover Image"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeTitle-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeTitle-1745505309750","value":{"nodeTitle":"{nodeTitle, select, community {Community} other {{nodeTitle}}} "},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTimeToRead-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTimeToRead-1745505309750","value":{"minReadText":"{min} MIN READ"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1745505309750","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1745505309750","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserRank-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserRank-1745505309750","value":{"rankName":"{rankName}","userRank":"Author rank {rankName}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1745505309750","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1745505309750","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageCustomFields-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageCustomFields-1745505309750","value":{"CustomField.default.label":"Value of {name}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRevision-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRevision-1745505309750","value":{"lastUpdatedDatePublished":"{publishCount, plural, one{Published} other{Updated}} {date}","lastUpdatedDateDraft":"Created {date}","version":"Version {major}.{minor}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyButton-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyButton-1745505309750","value":{"repliesCount":"{count}","title":"Reply","title@board:BLOG@message:root":"Comment","title@board:TKB@message:root":"Comment","title@board:IDEA@message:root":"Comment","title@board:OCCASION@message:root":"Comment"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageAuthorBio-1745505309750","value":{"sendMessage":"Send Message","actionMessage":"Follow this blog board to get notified when there's new activity","coAuthor":"CO-PUBLISHER","contributor":"CONTRIBUTOR","userProfile":"View Profile","iconlink":"Go to {name} {type}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1745505309750","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/ranks/UserRankLabel-1745505309750","value":{"altTitle":"Icon for {rankName} rank"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserRegistrationDate-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserRegistrationDate-1745505309750","value":{"noPrefix":"{date}","withPrefix":"Joined {date}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeAvatar-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeAvatar-1745505309750","value":{"altTitle":"Node avatar for {nodeTitle}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeDescription-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeDescription-1745505309750","value":{"description":"{description}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagView/TagViewChip-1745505309750","value":{"tagLabelName":"Tag name {tagName}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745505309750":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1745505309750","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false}}}},"page":"/blogs/BlogMessagePage/BlogMessagePage","query":{"boardId":"modernworkappconsult","messageSubject":"asynchronous-programming-in-unity-using-coroutine-and-tap","messageId":"316851"},"buildId":"HEhyUrv5OXNBIbfCLaOrw","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"o365","openTelemetryServiceVersion":"25.1.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/customComponent/CustomComponent/CustomComponent.tsx","./components/blogs/BlogArticleWidget/BlogArticleWidget.tsx","./components/external/components/ExternalComponent.tsx","./components/messages/MessageView/MessageViewStandard/MessageViewStandard.tsx","./components/messages/ThreadedReplyList/ThreadedReplyList.tsx","../shared/client/components/common/List/UnstyledList/UnstyledList.tsx","./components/messages/MessageView/MessageView.tsx","../shared/client/components/common/List/UnwrappedList/UnwrappedList.tsx","./components/tags/TagView/TagView.tsx","./components/tags/TagView/TagViewChip/TagViewChip.tsx"],"appGip":true,"scriptLoader":[{"id":"analytics","src":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/pagescripts/1730819800000/analytics.js?page.id=BlogMessagePage&entity.id=board%3Amodernworkappconsult&entity.id=message%3A316851","strategy":"afterInteractive"}]}