mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Finalizing branching activities
--HG-- branch : 1.x extra : rebase_source : 51c51c157af384782d33300d94ed0690b03d070f
This commit is contained in:
@@ -69,7 +69,7 @@ namespace Orchard.Forms.Services {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<dynamic>(state);
|
||||
return JObject.Parse(state);
|
||||
}
|
||||
|
||||
public static string ToJsonString(FormCollection formCollection) {
|
||||
|
@@ -1,8 +1,17 @@
|
||||
using System.Linq;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Workflows.Models;
|
||||
|
||||
namespace Orchard.Workflows.Activities {
|
||||
public class ExclusiveBranchActivity : BranchActivity {
|
||||
public override string Name {
|
||||
get { return "ExclusiveBranch"; }
|
||||
}
|
||||
|
||||
public override LocalizedString Description {
|
||||
get { return T("Splits the workflow on different branches, activating the first event to occur."); }
|
||||
}
|
||||
|
||||
public override void OnActivityExecuted(WorkflowContext workflowContext, ActivityContext activityContext) {
|
||||
|
||||
// for blocking activities only
|
||||
@@ -16,7 +25,7 @@ namespace Orchard.Workflows.Activities {
|
||||
|
||||
// if a direct target of a Branch Activity is executed, then suppress all other direct waiting activities
|
||||
var parentBranchActivities = inboundActivities
|
||||
.Where(x => x.SourceActivityRecord.Name == typeof(ExclusiveBranchActivity).Name)
|
||||
.Where(x => x.SourceActivityRecord.Name == this.Name)
|
||||
.Select(x => x.SourceActivityRecord)
|
||||
.ToList();
|
||||
|
||||
|
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Workflows.Models;
|
||||
using Orchard.Workflows.Services;
|
||||
|
||||
namespace Orchard.Workflows.Activities {
|
||||
public class MergeActivity : Task {
|
||||
|
||||
public MergeActivity() {
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override bool CanExecute(WorkflowContext workflowContext, ActivityContext activityContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public override IEnumerable<LocalizedString> GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) {
|
||||
yield return T("Done");
|
||||
}
|
||||
|
||||
public override IEnumerable<LocalizedString> Execute(WorkflowContext workflowContext, ActivityContext activityContext) {
|
||||
// wait for all incoming branches to trigger the Execute before returning the result
|
||||
var branchesState = workflowContext.GetStateFor<string>(activityContext.Record, "Branches");
|
||||
|
||||
if (String.IsNullOrWhiteSpace(branchesState)) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var branches = GetBranches(branchesState);
|
||||
var inboundActivities = workflowContext.GetInboundTransitions(activityContext.Record);
|
||||
var done = inboundActivities
|
||||
.All(x => branches.Contains(GetTransitionKey(x)));
|
||||
|
||||
if(done) {
|
||||
yield return T("Done");
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get { return "MergeBranch"; }
|
||||
}
|
||||
|
||||
public override LocalizedString Category {
|
||||
get { return T("Flow"); }
|
||||
}
|
||||
|
||||
public override LocalizedString Description {
|
||||
get { return T("Merges multiple branches."); }
|
||||
}
|
||||
|
||||
public override string Form {
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override void OnActivityExecuted(WorkflowContext workflowContext, ActivityContext activityContext) {
|
||||
|
||||
// activity records pointed by the executed activity
|
||||
var outboundActivities = workflowContext.GetOutboundTransitions(activityContext.Record);
|
||||
|
||||
// if a direct target of a Branch Activity is executed, then suppress all other direct waiting activities
|
||||
var childBranches = outboundActivities
|
||||
.Where(x => x.DestinationActivityRecord.Name == this.Name)
|
||||
.ToList();
|
||||
|
||||
foreach (var childBranch in childBranches) {
|
||||
var branchesState = workflowContext.GetStateFor<string>(childBranch.DestinationActivityRecord, "Branches");
|
||||
var branches = GetBranches(branchesState);
|
||||
branches = branches.Union(new[] { GetTransitionKey(childBranch)}).Distinct();
|
||||
workflowContext.SetStateFor(childBranch.DestinationActivityRecord, "Branches", String.Join(",", branches.ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTransitionKey(TransitionRecord transitionRecord) {
|
||||
return "@" + transitionRecord.SourceActivityRecord.Id + "_" + transitionRecord.SourceEndpoint;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetBranches(string branches) {
|
||||
if (String.IsNullOrEmpty(branches)) {
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
return branches.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -62,7 +62,11 @@ namespace Orchard.Workflows.Activities {
|
||||
// checking if user is in an accepted role
|
||||
var workContext = _workContextAccessor.GetContext();
|
||||
var user = workContext.CurrentUser;
|
||||
var roles = GetRoles(context);
|
||||
var roles = GetRoles(context).ToArray();
|
||||
|
||||
if (!roles.Any()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return UserIsInRole(user, roles);
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using Orchard.Data;
|
||||
using Orchard.Forms.Services;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Security;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Workflows.Activities;
|
||||
using Orchard.Workflows.Models;
|
||||
@@ -47,16 +48,7 @@ namespace Orchard.Workflows.Drivers {
|
||||
var user = workContext.CurrentUser;
|
||||
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var actions = awaiting.Where(x => {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string rolesState = state.Roles ?? "";
|
||||
var roles = rolesState.Split(',').Select(role => role.Trim());
|
||||
return UserTaskActivity.UserIsInRole(user, roles);
|
||||
}).SelectMany(x => {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string actionState = state.Actions ?? "";
|
||||
return actionState.Split(',').Select(action => action.Trim());
|
||||
}).ToList();
|
||||
var actions = awaiting.Where(x => UserIsInRole(x, user)).SelectMany(ListAction).ToList();
|
||||
|
||||
return shapeHelper.UserTask_ActionButton().Actions(actions);
|
||||
})
|
||||
@@ -67,6 +59,26 @@ namespace Orchard.Workflows.Drivers {
|
||||
return Combined(results.ToArray());
|
||||
}
|
||||
|
||||
// returns all the actions associated with a specific state
|
||||
private static IEnumerable<string> ListAction(AwaitingActivityRecord x) {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string actionState = state.Actions ?? "";
|
||||
return actionState.Split(',').Select(action => action.Trim());
|
||||
}
|
||||
|
||||
// whether a user is in an accepted role for this state
|
||||
private static bool UserIsInRole(AwaitingActivityRecord x, IUser user) {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string rolesState = state.Roles ?? "";
|
||||
|
||||
// "Any" if string is empty
|
||||
if (string.IsNullOrWhiteSpace(rolesState)) {
|
||||
return true;
|
||||
}
|
||||
var roles = rolesState.Split(',').Select(role => role.Trim());
|
||||
return UserTaskActivity.UserIsInRole(user, roles);
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(ContentPart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||
var httpContext = _httpContextAccessor.Current();
|
||||
var name = httpContext.Request.Form["submit.Save"];
|
||||
@@ -76,16 +88,7 @@ namespace Orchard.Workflows.Drivers {
|
||||
var user = Services.WorkContext.CurrentUser;
|
||||
|
||||
var awaiting = _awaitingActivityRepository.Table.Where(x => x.ContentItemRecord == part.ContentItem.Record && x.ActivityRecord.Name == "UserTask").ToList();
|
||||
var actions = awaiting.Where(x => {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string rolesState = state.Roles ?? "";
|
||||
var roles = rolesState.Split(',').Select(role => role.Trim());
|
||||
return UserTaskActivity.UserIsInRole(user, roles);
|
||||
}).SelectMany(x => {
|
||||
var state = FormParametersHelper.FromJsonString(x.ActivityRecord.State);
|
||||
string actionState = state.Actions ?? "";
|
||||
return actionState.Split(',').Select(action => action.Trim());
|
||||
}).ToList();
|
||||
var actions = awaiting.Where(x => UserIsInRole(x, user)).SelectMany(ListAction).ToList();
|
||||
|
||||
if (!actions.Contains(name)) {
|
||||
Services.Notifier.Error(T("Not authorized to trigger {0}.", name));
|
||||
|
@@ -117,6 +117,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Activities\ContentActivity.cs" />
|
||||
<Compile Include="Activities\BranchActivity.cs" />
|
||||
<Compile Include="Activities\MergeBranchActivity.cs" />
|
||||
<Compile Include="Activities\DeleteActivity.cs" />
|
||||
<Compile Include="Activities\ExclusiveBranchActivity.cs" />
|
||||
<Compile Include="Activities\IsInRoleActivity.cs" />
|
||||
@@ -212,6 +213,12 @@
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Activity-Timer.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Activity-ExclusiveBranch.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Activity-MergeBranch.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
@@ -115,11 +115,6 @@ namespace Orchard.Workflows.Services {
|
||||
return;
|
||||
}
|
||||
|
||||
// load workflow definitions too for eager loading
|
||||
_workflowDefinitionRepository.Table
|
||||
.Where(x => x.Enabled && x.ActivityRecords.Any(e => e.Name == name))
|
||||
.ToList();
|
||||
|
||||
// resume halted workflows
|
||||
foreach (var awaitingActivityRecord in awaitingActivities) {
|
||||
ResumeWorkflow(awaitingActivityRecord, workflowContext, tokens);
|
||||
@@ -144,7 +139,7 @@ namespace Orchard.Workflows.Services {
|
||||
// workflow halted, create a workflow state
|
||||
var workflow = new WorkflowRecord {
|
||||
WorkflowDefinitionRecord = activityRecord.WorkflowDefinitionRecord,
|
||||
State = FormParametersHelper.ToJsonString("{}")
|
||||
State = "{}"
|
||||
};
|
||||
|
||||
workflowContext.Record = workflow;
|
||||
@@ -196,10 +191,12 @@ namespace Orchard.Workflows.Services {
|
||||
var workflow = awaitingActivityRecord.WorkflowRecord;
|
||||
workflowContext.Record = workflow;
|
||||
|
||||
workflow.AwaitingActivities.Remove(awaitingActivityRecord);
|
||||
|
||||
var blockedOn = ExecuteWorkflow(workflowContext, awaitingActivityRecord.ActivityRecord, tokens).ToList();
|
||||
|
||||
// is the workflow halted on a blocking activity ?
|
||||
if (!blockedOn.Any()) {
|
||||
// is the workflow halted on a blocking activity, and there is no more awaiting activities
|
||||
if (!blockedOn.Any() && !workflow.AwaitingActivities.Any()) {
|
||||
// no, delete the workflow
|
||||
_workflowRepository.Delete(awaitingActivityRecord.WorkflowRecord);
|
||||
}
|
||||
@@ -240,9 +237,20 @@ namespace Orchard.Workflows.Services {
|
||||
firstPass = false;
|
||||
}
|
||||
|
||||
var outcomes = activityContext.Activity.Execute(workflowContext, activityContext);
|
||||
// signal every activity that the activity is about to be executed
|
||||
var cancellationToken = new CancellationToken();
|
||||
InvokeActivities(activity => activity.OnActivityExecuting(workflowContext, activityContext, cancellationToken));
|
||||
|
||||
if (cancellationToken.IsCancelled) {
|
||||
// activity is aborted
|
||||
continue;
|
||||
}
|
||||
|
||||
var outcomes = activityContext.Activity.Execute(workflowContext, activityContext).ToList();
|
||||
|
||||
// signal every activity that the activity is executed
|
||||
InvokeActivities(activity => activity.OnActivityExecuted(workflowContext, activityContext));
|
||||
|
||||
if (outcomes != null) {
|
||||
foreach (var outcome in outcomes) {
|
||||
// look for next activity in the graph
|
||||
var transition = workflowContext.Record.WorkflowDefinitionRecord.TransitionRecords.FirstOrDefault(x => x.SourceActivityRecord == activityRecord && x.SourceEndpoint == outcome.TextHint);
|
||||
@@ -252,7 +260,6 @@ namespace Orchard.Workflows.Services {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply Distinct() as two paths could block on the same activity
|
||||
return blocking.Distinct();
|
||||
|
@@ -5,3 +5,20 @@
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.exclusive-branch {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYCAYAAADpnJ2CAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAoklEQVRIS+2TzQnAIAyF3ckFXMGxnMF9nMBVPHlIa0GQ+Kh/baHg4bvEZ14SjSCiLqy1JKWEGGNOCb7HgUFOjFForaFZQilFIQR4lwODnG24DUtgEPHpWpTkbke6KoHBO/5t6L2Hb7SCc+5MDQxbP3EWPonKsDWqVV1TwPmfYe9CP6W7qkCHiVxdrhZpEiO6mUSCMaTbht2J3jSsGNF9vBaGDk3NF8LuD+uFAAAAAElFTkSuQmCC');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.merge-branch {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAYCAYAAADpnJ2CAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAk0lEQVRIS+2T0QmAIBRF304u4AqO5Qzu4wSu4pcflsGjkmsqSlAYnJ/btWPiI611FEJAjDFxfygxq0dSSvgyoZSKIQTy3k/rLeESHnQJXx8LLvLueLec54z2qoWc7wvR2Y9QFCastXDRCM65/dOn4yZsofVIS8Dwif8KWwe/Bgxzaje4529hmLOES3gFhog5YxFpA8qKN6JZxNXVAAAAAElFTkSuQmCC');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,13 @@
|
||||
@using Orchard.Utility.Extensions
|
||||
|
||||
@{
|
||||
string name = Model.Name;
|
||||
string branches = Model.State.Branches;
|
||||
var outcomes = String.Join(",", branches == null ? new string[0] : branches.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => "'" + x.Trim() + "'").ToArray());
|
||||
}
|
||||
|
||||
<div data-outcomes="@outcomes" title="First of @outcomes">
|
||||
<div class="exclusive-branch" ></div>
|
||||
@*@name.CamelFriendly()*@
|
||||
</div>
|
||||
|
@@ -0,0 +1,13 @@
|
||||
@using Orchard.Utility.Extensions
|
||||
|
||||
@{
|
||||
string name = Model.Name;
|
||||
string branches = Model.State.Branches;
|
||||
var outcomes = String.Join(",", branches == null ? new string[0] : branches.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => "'" + x.Trim() + "'").ToArray());
|
||||
}
|
||||
|
||||
<div title="Merge">
|
||||
<div class="merge-branch" ></div>
|
||||
@*@name.CamelFriendly()*@
|
||||
</div>
|
||||
|
@@ -146,12 +146,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpgradeTo16", "Orchard.Web\
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Workflows", "Orchard.Web\Modules\Orchard.Workflows\Orchard.Workflows.csproj", "{7059493C-8251-4764-9C1E-2368B8B485BC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Caching", "Orchard.Web\Modules\Orchard.Caching\Orchard.Caching.csproj", "{7528BF74-25C7-4ABE-883A-443B4EEC4776}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Memcached", "Orchard.Web\Modules\Memcached\Memcached.csproj", "{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Caching.Memcached", "Orchard.Web\Modules\Orchard.Caching.Memcached\Orchard.Caching.Memcached.csproj", "{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CodeCoverage|Any CPU = CodeCoverage|Any CPU
|
||||
@@ -823,13 +819,6 @@ Global
|
||||
{7059493C-8251-4764-9C1E-2368B8B485BC}.FxCop|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7059493C-8251-4764-9C1E-2368B8B485BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7059493C-8251-4764-9C1E-2368B8B485BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.Coverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.FxCop|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.CodeCoverage|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.Coverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -840,13 +829,6 @@ Global
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.FxCop|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.Coverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.FxCop|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -902,9 +884,7 @@ Global
|
||||
{3BD22132-D538-48C6-8854-F71333C798EB} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{7059493C-8251-4764-9C1E-2368B8B485BC} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{7528BF74-25C7-4ABE-883A-443B4EEC4776} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{4A037ACB-A79A-43A9-9E7D-E8F1BF7AEB91} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{A2C5BAE0-E4A0-4B41-BC44-D4099E471111} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{ABC826D4-2FA1-4F2F-87DE-E6095F653810} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
{F112851D-B023-4746-B6B1-8D2E5AD8F7AA} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
{6CB3EB30-F725-45C0-9742-42599BA8E8D2} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
|
Reference in New Issue
Block a user