diff --git a/Content/icons/web_services/ms-word-icon-64x64.png b/Content/icons/web_services/ms-word-icon-64x64.png
new file mode 100644
index 0000000000..bc2ab64f8f
Binary files /dev/null and b/Content/icons/web_services/ms-word-icon-64x64.png differ
diff --git a/Fr8Infrastructure.NET/Data/Control/Control.cs b/Fr8Infrastructure.NET/Data/Control/Control.cs
index e1857d70e2..61f00db5cf 100644
--- a/Fr8Infrastructure.NET/Data/Control/Control.cs
+++ b/Fr8Infrastructure.NET/Data/Control/Control.cs
@@ -399,6 +399,9 @@ public TextBlock()
public class FilePicker : ControlDefinitionDTO
{
+ [JsonProperty("fileextensions")]
+ public string FileExtensions { get; set; }
+
public FilePicker()
{
Type = ControlTypes.FilePicker;
diff --git a/Tests/terminalGoogleTests/Integration/Terminal_Discover_v1_Tests.cs b/Tests/terminalGoogleTests/Integration/Terminal_Discover_v1_Tests.cs
index dc3e68f3e5..57760c4223 100644
--- a/Tests/terminalGoogleTests/Integration/Terminal_Discover_v1_Tests.cs
+++ b/Tests/terminalGoogleTests/Integration/Terminal_Discover_v1_Tests.cs
@@ -31,18 +31,20 @@ public async Task Terminal_Google_Discover()
Assert.IsNotNull(googleTerminalDiscoveryResponse, "Terminal Google discovery did not happen.");
Assert.IsNotNull(googleTerminalDiscoveryResponse.Activities, "Google terminal does not have actions.");
- Assert.AreEqual(4, googleTerminalDiscoveryResponse.Activities.Count, "Google terminal expected 4 actions.");
+ Assert.AreEqual(5, googleTerminalDiscoveryResponse.Activities.Count, "Google terminal expected 5 actions.");
Assert.AreEqual("terminalGoogle", googleTerminalDiscoveryResponse.Definition.Name);
Assert.AreEqual("Google", googleTerminalDiscoveryResponse.Definition.Label);
Assert.AreEqual(googleTerminalDiscoveryResponse.Activities.Any(a => a.Name == "Get_Google_Sheet_Data"), true, "Action Get_Google_Sheet_Data was not loaded");
Assert.AreEqual(googleTerminalDiscoveryResponse.Activities.Any(a => a.Name == "Monitor_Form_Responses"), true, "Action Monitor_Form_Responses was not loaded");
Assert.AreEqual(googleTerminalDiscoveryResponse.Activities.Any(a => a.Name == "Save_To_Google_Sheet"), true, "Action Save_To_Google_Sheet was not loaded");
Assert.AreEqual(googleTerminalDiscoveryResponse.Activities.Any(a => a.Name == "Monitor_Gmail_Inbox"), true, "Action Monitor_Gmail_Inbox was not loaded");
+ Assert.AreEqual(googleTerminalDiscoveryResponse.Activities.Any(a => a.Name == "Create_Google_Doc"), true, "Action Create_Google_Doc was not loaded");
//Check Activities Categories
Assert.True(googleTerminalDiscoveryResponse.Activities.Single(a => a.Name == "Get_Google_Sheet_Data").Categories.Any(x => x.Id == ActivityCategories.ReceiveId), "Activity Get_Google_Sheet_Data is not of Category Receivers");
Assert.True(googleTerminalDiscoveryResponse.Activities.Single(a => a.Name == "Monitor_Form_Responses").Categories.Any(x => x.Id == ActivityCategories.MonitorId), "Activity Monitor_Form_Responses is not of Category Monitors");
Assert.True(googleTerminalDiscoveryResponse.Activities.Single(a => a.Name == "Save_To_Google_Sheet").Categories.Any(x => x.Id == ActivityCategories.ForwardId), "Activity Save_To_Google_Sheet is not of Category Forwarders");
Assert.True(googleTerminalDiscoveryResponse.Activities.Single(a => a.Name == "Monitor_Gmail_Inbox").Categories.Any(x => x.Id == ActivityCategories.MonitorId), "Activity Monitor_Gmail_Inbox is not of Category Monitors");
+ Assert.True(googleTerminalDiscoveryResponse.Activities.Single(a => a.Name == "Create_Google_Doc").Categories.Any(x => x.Id == ActivityCategories.ForwardId), "Activity Create_Google_Doc is not of Category Forwarders");
}
}
}
diff --git a/Views/AngularTemplate/FilePicker.cshtml b/Views/AngularTemplate/FilePicker.cshtml
index 191172ad97..a023a8b1c5 100644
--- a/Views/AngularTemplate/FilePicker.cshtml
+++ b/Views/AngularTemplate/FilePicker.cshtml
@@ -1,5 +1,5 @@
Select File
+ accept="{{field.fileextensions}}" ngf-max-size='20MB' ngf-min-height='100'>Select File
{{field.value == null ? 'No file selected' : field.value|formatInput}}
diff --git a/terminalExcel/Activities/Load_Excel_File_v1.cs b/terminalExcel/Activities/Load_Excel_File_v1.cs
index 975f2c37bf..5898ef1ef6 100644
--- a/terminalExcel/Activities/Load_Excel_File_v1.cs
+++ b/terminalExcel/Activities/Load_Excel_File_v1.cs
@@ -33,6 +33,7 @@ public ActivityUi()
{
FilePicker = new FilePicker
{
+ FileExtensions = ".xls,.xlsx",
Label = "Select an Excel file",
Name = nameof(FilePicker),
Required = true,
diff --git a/terminalGoogle/Activities/Create_Google_Doc_v1.cs b/terminalGoogle/Activities/Create_Google_Doc_v1.cs
new file mode 100644
index 0000000000..f2614c2dda
--- /dev/null
+++ b/terminalGoogle/Activities/Create_Google_Doc_v1.cs
@@ -0,0 +1,254 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Fr8.Infrastructure.Data.Control;
+using Fr8.Infrastructure.Data.Crates;
+using Fr8.Infrastructure.Data.DataTransferObjects;
+using Fr8.Infrastructure.Data.Managers;
+using Fr8.Infrastructure.Data.Manifests;
+using Fr8.Infrastructure.Data.Manifests.Helpers;
+using Fr8.Infrastructure.Data.States;
+using Fr8.TerminalBase.Errors;
+using Fr8.TerminalBase.Infrastructure;
+using Google.GData.Client;
+using Newtonsoft.Json;
+using terminalGoogle.Actions;
+using terminalGoogle.DataTransferObjects;
+using terminalGoogle.Interfaces;
+using Fr8.TerminalBase.Services;
+using System.Globalization;
+using System.Text;
+using Fr8.Infrastructure.Data.Constants;
+using System.IO;
+
+namespace terminalGoogle.Activities
+{
+ public class Create_Google_Doc_v1 : BaseGoogleTerminalActivity
+ {
+ public static ActivityTemplateDTO ActivityTemplateDTO = new ActivityTemplateDTO
+ {
+ Id = new Guid("DAFD6823-CF54-4DD4-A618-D89A967EB885"),
+ Name = "Create_Google_Doc",
+ Label = "Create Google Doc",
+ Version = "1",
+ Terminal = TerminalData.TerminalDTO,
+ NeedsAuthentication = true,
+ MinPaneWidth = 300,
+ Categories = new[]
+ {
+ ActivityCategories.Forward,
+ TerminalData.GooogleActivityCategoryDTO
+ }
+ };
+ protected override ActivityTemplateDTO MyTemplate => ActivityTemplateDTO;
+
+ public class ActivityUi : StandardConfigurationControlsCM
+ {
+ public CrateChooser UpstreamCrateChooser { get; set; }
+
+ public DropDownList ExistingFilesList { get; set; }
+
+ public RadioButtonOption UseIncomingDataOption { get; set; }
+
+ public RadioButtonOption UseStoredFileOption { get; set; }
+
+ public RadioButtonGroup ContentSelectionGroup { get; set; }
+
+ public TextSource NewFileName { get; set; }
+
+ public ActivityUi(UiBuilder uiBuilder)
+ {
+ NewFileName = uiBuilder.CreateSpecificOrUpstreamValueChooser("Title", nameof(NewFileName), addRequestConfigEvent: true, requestUpstream: true, availability: AvailabilityType.RunTime);
+ NewFileName.IsCollapsed = false;
+ Controls.Add(NewFileName);
+
+ UpstreamCrateChooser = new CrateChooser
+ {
+ Label = "Crate to store",
+ Name = nameof(UpstreamCrateChooser),
+ Required = true,
+ RequestUpstream = true,
+ SingleManifestOnly = true,
+ };
+
+ ExistingFilesList = new DropDownList
+ {
+ Name = nameof(ExistingFilesList),
+ Events = new List { ControlEvent.RequestConfig }
+ };
+
+ UseIncomingDataOption = new RadioButtonOption
+ {
+ Selected = true,
+ Name = nameof(UseIncomingDataOption),
+ Value = "Use Incoming Data",
+ Controls = new List { UpstreamCrateChooser }
+ };
+
+ UseStoredFileOption = new RadioButtonOption()
+ {
+ Selected = false,
+ Name = nameof(UseStoredFileOption),
+ Value = "Use Excisting File",
+ Controls = new List { ExistingFilesList }
+ };
+
+ ContentSelectionGroup = new RadioButtonGroup
+ {
+ GroupName = nameof(ContentSelectionGroup),
+ Name = nameof(ContentSelectionGroup),
+ Events = new List { ControlEvent.RequestConfig },
+ Radios = new List
+ {
+ UseIncomingDataOption,
+ UseStoredFileOption
+ }
+ };
+
+ Controls.Add(ContentSelectionGroup);
+ }
+ }
+
+ private const string SelectedDocCrateLabel = "Selected Doc";
+
+ private readonly IGoogleDrive _googleDrive;
+
+ public Create_Google_Doc_v1(ICrateManager crateManager, IGoogleIntegration googleIntegration, IGoogleDrive googleDrive)
+ : base(crateManager, googleIntegration)
+ {
+ _googleDrive = googleDrive;
+ }
+
+ private GoogleAuthDTO GetGoogleAuthToken()
+ {
+ return JsonConvert.DeserializeObject(AuthorizationToken.Token);
+ }
+
+ public override async Task Initialize()
+ {
+ ActivityUI.ExistingFilesList.ListItems = await GetCurrentUsersFiles(".doc",".docx");
+ }
+
+ public override async Task FollowUp()
+ {
+ }
+
+ protected override Task Validate()
+ {
+ ValidationManager.ValidateTextSourceNotEmpty(ActivityUI.NewFileName, "Title for Document must be specified");
+
+ if(ActivityUI.UseIncomingDataOption.Selected == true)
+ {
+ ValidationManager.ValidateCrateChooserNotEmpty(ActivityUI.UpstreamCrateChooser, "File must be specified");
+ }
+
+ if(ActivityUI.UseStoredFileOption.Selected == true)
+ {
+ ValidationManager.ValidateDropDownListNotEmpty(ActivityUI.ExistingFilesList, "File must be specified");
+ }
+
+ return Task.FromResult(0);
+ }
+
+ public override async Task Run()
+ {
+ byte[] body = null;
+ string fileName = null;
+
+ if(ActivityUI.UseIncomingDataOption.Selected == true)
+ {
+ var crateToProcess = FindCrateToProcess();
+ if (crateToProcess == null)
+ {
+ throw new ActivityExecutionException($"Failed to run {ActivityPayload.Name} because specified upstream crate was not found in payload");
+ }
+
+ var content = crateToProcess.Get();
+ body = Convert.FromBase64String(content.TextRepresentation);
+ fileName = content.Filename;
+ }
+ else if(ActivityUI.UseStoredFileOption.Selected == true)
+ {
+ var fileSelector = ActivityUI.ExistingFilesList;
+ if (string.IsNullOrEmpty(fileSelector.Value))
+ {
+ RaiseError("No File was selected on design time", ActivityErrorCode.DESIGN_TIME_DATA_MISSING);
+ return;
+ }
+ //let's download this file
+ var file = await HubCommunicator.DownloadFile(int.Parse(fileSelector.Value));
+ if (file == null || file.Length < 1)
+ {
+ RaiseError("Unable to download file from Hub");
+ return;
+ }
+ fileName = fileSelector.selectedKey;
+
+ using (var reader = new MemoryStream())
+ {
+ file.CopyTo(reader);
+ body = reader.ToArray();
+ }
+ }
+
+ try
+ {
+ var file = await _googleDrive.CreateFile(ActivityUI.NewFileName.TextValue,
+ body, GetMimeType(fileName), GetGoogleAuthToken());
+
+ }
+ catch (GDataRequestException ex)
+ {
+ if (ex.InnerException.Message.IndexOf("(401) Unauthorized") > -1)
+ {
+ throw new AuthorizationTokenExpiredOrInvalidException();
+ }
+
+ throw;
+ }
+ }
+
+ private static string GetMimeType(string fileName)
+ {
+ string mimeType = "application/unknown";
+ string ext = System.IO.Path.GetExtension(fileName).ToLower();
+ Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
+ if (regKey != null && regKey.GetValue("Content Type") != null)
+ mimeType = regKey.GetValue("Content Type").ToString();
+ return mimeType;
+ }
+
+ private async Task> GetCurrentUsersFiles(params string[] extensions)
+ {
+ var curAccountFileList = await HubCommunicator.GetFiles();
+ if(extensions != null)
+ {
+ curAccountFileList = curAccountFileList.Where(f =>
+ {
+ bool result = true;
+ foreach (var ext in extensions)
+ {
+ if (f.OriginalFileName.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ }
+ return result;
+ });
+ }
+
+ return curAccountFileList.Select(c => new ListItem() { Key = c.OriginalFileName, Value = c.Id.ToString(CultureInfo.InvariantCulture) }).ToList();
+ }
+
+ private Crate FindCrateToProcess()
+ {
+ var desiredCrateDescription = ActivityUI.UpstreamCrateChooser.CrateDescriptions.Single(x => x.Selected);
+ return Payload.FirstOrDefault(x => x.Label == desiredCrateDescription.Label && x.ManifestType.Type == desiredCrateDescription.ManifestType);
+ }
+ }
+}
\ No newline at end of file
diff --git a/terminalGoogle/Interfaces/IGoogleDrive.cs b/terminalGoogle/Interfaces/IGoogleDrive.cs
index 7c67dcea57..f83248e5a0 100644
--- a/terminalGoogle/Interfaces/IGoogleDrive.cs
+++ b/terminalGoogle/Interfaces/IGoogleDrive.cs
@@ -10,5 +10,7 @@ public interface IGoogleDrive
Task CreateDriveService(GoogleAuthDTO authDTO);
bool FileExist(DriveService driveService, string filename, out string link);
Task> GetGoogleForms(GoogleAuthDTO authDTO);
- }
+ Task CreateFile(string title, byte[] body, string mimeType, GoogleAuthDTO authDTO);
+
+ }
}
\ No newline at end of file
diff --git a/terminalGoogle/Services/GoogleDrive.cs b/terminalGoogle/Services/GoogleDrive.cs
index 945e8ca88a..92df274426 100644
--- a/terminalGoogle/Services/GoogleDrive.cs
+++ b/terminalGoogle/Services/GoogleDrive.cs
@@ -77,6 +77,20 @@ public async Task DownloadFile(string fileId, GoogleAuthDTO authDTO)
return fileContent;
}
+ public async Task CreateFile(string title, byte[] body, string mimeType, GoogleAuthDTO authDTO)
+ {
+ var driveService = await CreateDriveService(authDTO);
+ var doc = new Google.Apis.Drive.v2.Data.File();
+ doc.Title = title;
+ doc.MimeType = mimeType;
+ var stream = new System.IO.MemoryStream(body);
+
+ var request = driveService.Files.Insert(doc, stream, mimeType);
+ await request.UploadAsync();
+ return request.ResponseBody;
+ }
+
+
public async Task> GetGoogleForms(GoogleAuthDTO authDTO)
{
var driveService = await CreateDriveService(authDTO);
diff --git a/terminalGoogle/Startup.cs b/terminalGoogle/Startup.cs
index ad7036469d..129e3c8ead 100644
--- a/terminalGoogle/Startup.cs
+++ b/terminalGoogle/Startup.cs
@@ -56,6 +56,7 @@ protected override void RegisterActivities()
ActivityStore.RegisterActivity(Monitor_Form_Responses_v1.ActivityTemplateDTO);
ActivityStore.RegisterActivity(Save_To_Google_Sheet_v1.ActivityTemplateDTO);
ActivityStore.RegisterActivity(Monitor_Gmail_Inbox_v1.ActivityTemplateDTO);
+ ActivityStore.RegisterActivity(Create_Google_Doc_v1.ActivityTemplateDTO);
}
}
}
diff --git a/terminalGoogle/terminalGoogle.csproj b/terminalGoogle/terminalGoogle.csproj
index 29df308c03..cfadc36ffc 100644
--- a/terminalGoogle/terminalGoogle.csproj
+++ b/terminalGoogle/terminalGoogle.csproj
@@ -304,6 +304,7 @@
+
diff --git a/terminalUtilities/Excel/ExcelUtils.cs b/terminalUtilities/Excel/ExcelUtils.cs
index 6e911c7a39..85e5a47515 100644
--- a/terminalUtilities/Excel/ExcelUtils.cs
+++ b/terminalUtilities/Excel/ExcelUtils.cs
@@ -15,6 +15,7 @@
using OfficeOpenXml;
using StructureMap;
using RestSharp.Extensions;
+using terminalUtilities.Files;
namespace terminalUtilities.Excel
{
@@ -22,11 +23,13 @@ public class ExcelUtils
{
private readonly IRestfulServiceClient _restfulServiceClient;
private readonly ICrateManager _crateManager;
+ private readonly FileUtils _fileUtils;
- public ExcelUtils(IRestfulServiceClient restfulServiceClient, ICrateManager crateManager)
+ public ExcelUtils(IRestfulServiceClient restfulServiceClient, ICrateManager crateManager, FileUtils fileUtils)
{
_restfulServiceClient = restfulServiceClient;
_crateManager = crateManager;
+ _fileUtils = fileUtils;
}
public static void ConvertToCsv(string pathToExcel, string pathToCsv)
@@ -263,9 +266,7 @@ public static Dictionary>> GetTabularData(byt
public async Task GetExcelFileAsByteArray(string selectedFilePath)
{
- var fileAsByteArray = await RetrieveFile(selectedFilePath);
- fileAsByteArray.Position = 0;
- return fileAsByteArray.ReadAsBytes();
+ return await _fileUtils.GetFileAsByteArray(selectedFilePath, ".xls", ".xlsx");
}
public async Task GetExcelFile(string selectedFilePath, bool isFirstRowAsColumnNames = true)
@@ -334,12 +335,7 @@ public StandardTableDataCM GetExcelFile(byte[] fileAsByteArray, string selectedF
private async Task RetrieveFile(string filePath)
{
- var ext = Path.GetExtension(filePath);
- if (ext != ".xls" && ext != ".xlsx")
- {
- throw new ArgumentException("Expected '.xls' or '.xlsx'", "selectedFile");
- }
- return await _restfulServiceClient.DownloadAsync(new Uri(filePath));
+ return await _fileUtils.RetrieveFile(filePath, ".xls", ".xlsx");
}
public static List CreateTableCellPayloadObjects(Dictionary>> rowsDictionary, string[] headersArray = null, bool includeHeadersAsFirstRow = false)
diff --git a/terminalUtilities/Files/FileUtils.cs b/terminalUtilities/Files/FileUtils.cs
new file mode 100644
index 0000000000..6ed4ed3d48
--- /dev/null
+++ b/terminalUtilities/Files/FileUtils.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Excel;
+using Fr8.Infrastructure.Data.Crates;
+using Fr8.Infrastructure.Data.DataTransferObjects;
+using Fr8.Infrastructure.Data.Managers;
+using Fr8.Infrastructure.Data.Manifests;
+using Fr8.Infrastructure.Data.States;
+using Fr8.Infrastructure.Interfaces;
+using OfficeOpenXml;
+using StructureMap;
+using RestSharp.Extensions;
+
+namespace terminalUtilities.Files
+{
+ public class FileUtils
+ {
+ private readonly IRestfulServiceClient _restfulServiceClient;
+
+ public FileUtils(IRestfulServiceClient restfulServiceClient, ICrateManager crateManager)
+ {
+ _restfulServiceClient = restfulServiceClient;
+ }
+
+
+ public async Task GetFileAsByteArray(string selectedFilePath, params string[] extensions)
+ {
+ var fileAsByteArray = await RetrieveFile(selectedFilePath, extensions);
+ fileAsByteArray.Position = 0;
+ return fileAsByteArray.ReadAsBytes();
+ }
+ public async Task RetrieveFile(string filePath, params string[] extensions)
+ {
+ var ext = System.IO.Path.GetExtension(filePath);
+ string exception = "Expected ";
+ bool hasException = false;
+ foreach (var extension in extensions)
+ {
+ if(ext == extension)
+ {
+ hasException = false;
+ break;
+ }
+ if (ext != extension)
+ {
+ hasException = true;
+ if (extensions.First() == extension)
+ {
+ exception += extension;
+ }
+ else
+ {
+ exception += " or " + extension;
+ }
+ }
+ }
+ if (hasException == true)
+ {
+ throw new ArgumentException(exception, "selectedFile");
+ }
+
+ return await _restfulServiceClient.DownloadAsync(new Uri(filePath));
+ }
+ }
+}
+
diff --git a/terminalUtilities/terminalUtilities.csproj b/terminalUtilities/terminalUtilities.csproj
index f9d222c36e..5a57909666 100644
--- a/terminalUtilities/terminalUtilities.csproj
+++ b/terminalUtilities/terminalUtilities.csproj
@@ -155,6 +155,7 @@
+
diff --git a/terminalWord/Activities/Load_Word_File_v1.cs b/terminalWord/Activities/Load_Word_File_v1.cs
new file mode 100644
index 0000000000..da4c38a8f1
--- /dev/null
+++ b/terminalWord/Activities/Load_Word_File_v1.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Fr8.Infrastructure.Data.Constants;
+using Fr8.Infrastructure.Data.Control;
+using Fr8.Infrastructure.Data.Crates;
+using Fr8.Infrastructure.Data.DataTransferObjects;
+using Fr8.Infrastructure.Data.Managers;
+using Fr8.Infrastructure.Data.Manifests;
+using Fr8.Infrastructure.Data.States;
+using Fr8.TerminalBase.BaseClasses;
+using Fr8.TerminalBase.Errors;
+using RestSharp.Extensions;
+using terminalUtilities.Files;
+
+namespace terminalWord.Activities
+{
+ public class Load_Word_File_v1 : TerminalActivity
+ {
+ public static ActivityTemplateDTO ActivityTemplateDTO = new ActivityTemplateDTO
+ {
+ Id = new Guid("8BBB1FE4-58F0-4342-B0E2-65CECB21F5DC"),
+ Name = "Load_Word_File",
+ Label = "Load Word File",
+ Version = "1",
+ MinPaneWidth = 300,
+ Terminal = TerminalData.TerminalDTO,
+ Categories = new[]
+ {
+ ActivityCategories.Receive,
+ TerminalData.ActivityCategoryDTO
+ }
+ };
+ protected override ActivityTemplateDTO MyTemplate => ActivityTemplateDTO;
+
+ private const string FileCrateLabel = "File uploaded by Load Word";
+
+ private const string ConfigurationCrateLabel = "Selected File";
+
+ private const string ExternalObjectHandlesLabel = "External Object Handles";
+
+ public class ActivityUi : StandardConfigurationControlsCM
+ {
+ public FilePicker FilePicker { get; set; }
+
+ public TextBlock UploadedFileDescription { get; set; }
+
+ public TextBlock ActivityDescription { get; set; }
+
+ public ActivityUi()
+ {
+ FilePicker = new FilePicker
+ {
+ FileExtensions= ".doc,.docx",
+ Label = "Select a Word file",
+ Name = nameof(FilePicker),
+ Required = true,
+ Events = new List { ControlEvent.RequestConfig },
+ };
+ Controls.Add(FilePicker);
+ UploadedFileDescription = new TextBlock
+ {
+ Name = nameof(UploadedFileDescription),
+ IsHidden = true
+ };
+ Controls.Add(UploadedFileDescription);
+ }
+ public void MarkFileAsUploaded(string fileName, string filePath)
+ {
+ FilePicker.Value = filePath;
+ UploadedFileDescription.Value = $"Uploaded file: {fileName}";
+ UploadedFileDescription.IsHidden = false;
+ }
+
+ public void ClearFileDescription()
+ {
+ UploadedFileDescription.Value = string.Empty;
+ UploadedFileDescription.IsHidden = true;
+ }
+ }
+
+ private readonly FileUtils _fileUtils;
+ public Load_Word_File_v1(ICrateManager crateManager, FileUtils fileUtils)
+ : base(crateManager)
+ {
+ _fileUtils = fileUtils;
+ }
+
+ public override async Task Initialize()
+ {
+ CrateSignaller.MarkAvailableAtRuntime(FileCrateLabel);
+ }
+
+ public override Task FollowUp()
+ {
+ return Task.FromResult(0);
+ }
+
+ protected override Task Validate()
+ {
+ if(string.IsNullOrEmpty(ActivityUI.FilePicker.Value))
+ {
+ ValidationManager.SetError("File must be specified", ActivityUI.FilePicker);
+ }
+ return Task.FromResult(0);
+ }
+
+ public override async Task Run()
+ {
+ var byteArray = await _fileUtils.GetFileAsByteArray(ActivityUI.FilePicker.Value, ".doc", ".docx");
+
+ var fileDescription = new StandardFileDescriptionCM
+ {
+
+ TextRepresentation = Convert.ToBase64String(byteArray),
+ Filetype = System.IO.Path.GetExtension(ActivityUI.FilePicker.Value),
+ Filename = System.IO.Path.GetFileName(ActivityUI.FilePicker.Value)
+ };
+
+ Payload.Add(Crate.FromContent(FileCrateLabel, fileDescription));
+ }
+ }
+}
\ No newline at end of file
diff --git a/terminalWord/App_Start/RouteConfig.cs b/terminalWord/App_Start/RouteConfig.cs
new file mode 100644
index 0000000000..564cf9e5c9
--- /dev/null
+++ b/terminalWord/App_Start/RouteConfig.cs
@@ -0,0 +1,13 @@
+using System.Web.Http;
+using Fr8.TerminalBase.BaseClasses;
+
+namespace terminalWord
+{
+ public static class RoutesConfig
+ {
+ public static void Register(HttpConfiguration config)
+ {
+ BaseTerminalWebApiConfig.Register("terminalWord", config);
+ }
+ }
+}
\ No newline at end of file
diff --git a/terminalWord/App_Start/SwaggerConfig.cs b/terminalWord/App_Start/SwaggerConfig.cs
new file mode 100644
index 0000000000..7d4576f45c
--- /dev/null
+++ b/terminalWord/App_Start/SwaggerConfig.cs
@@ -0,0 +1,246 @@
+using System.Web.Http;
+using WebActivatorEx;
+using terminalWord;
+using Swashbuckle.Application;
+
+//[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
+
+namespace terminalWord
+{
+ public class SwaggerConfig
+ {
+ public static void Register(HttpConfiguration configuration)
+ {
+ var thisAssembly = typeof(SwaggerConfig).Assembly;
+
+ GlobalConfiguration.Configuration
+ .EnableSwagger(c =>
+ {
+ // By default, the service root url is inferred from the request used to access the docs.
+ // However, there may be situations (e.g. proxy and load-balanced environments) where this does not
+ // resolve correctly. You can workaround this by providing your own code to determine the root URL.
+ //
+ //c.RootUrl(req => GetRootUrlFromAppConfig());
+
+ // If schemes are not explicitly provided in a Swagger 2.0 document, then the scheme used to access
+ // the docs is taken as the default. If your API supports multiple schemes and you want to be explicit
+ // about them, you can use the "Schemes" option as shown below.
+ //
+ //c.Schemes(new[] { "http", "https" });
+
+ // Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to
+ // hold additional metadata for an API. Version and title are required but you can also provide
+ // additional fields by chaining methods off SingleApiVersion.
+ //
+ c.SingleApiVersion("v1", "terminalWord");
+
+ // If your API has multiple versions, use "MultipleApiVersions" instead of "SingleApiVersion".
+ // In this case, you must provide a lambda that tells Swashbuckle which actions should be
+ // included in the docs for a given API version. Like "SingleApiVersion", each call to "Version"
+ // returns an "Info" builder so you can provide additional metadata per API version.
+ //
+ //c.MultipleApiVersions(
+ // (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion),
+ // (vc) =>
+ // {
+ // vc.Version("v2", "Swashbuckle Dummy API V2");
+ // vc.Version("v1", "Swashbuckle Dummy API V1");
+ // });
+
+ // You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API.
+ // See https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md for more details.
+ // NOTE: These only define the schemes and need to be coupled with a corresponding "security" property
+ // at the document or operation level to indicate which schemes are required for an operation. To do this,
+ // you'll need to implement a custom IDocumentFilter and/or IOperationFilter to set these properties
+ // according to your specific authorization implementation
+ //
+ //c.BasicAuth("basic")
+ // .Description("Basic HTTP Authentication");
+ //
+ // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section
+ //c.ApiKey("apiKey")
+ // .Description("API Key Authentication")
+ // .Name("apiKey")
+ // .In("header");
+ //
+ //c.OAuth2("oauth2")
+ // .Description("OAuth2 Implicit Grant")
+ // .Flow("implicit")
+ // .AuthorizationUrl("http://petstore.swagger.wordnik.com/api/oauth/dialog")
+ // //.TokenUrl("https://tempuri.org/token")
+ // .Scopes(scopes =>
+ // {
+ // scopes.Add("read", "Read access to protected resources");
+ // scopes.Add("write", "Write access to protected resources");
+ // });
+
+ // Set this flag to omit descriptions for any actions decorated with the Obsolete attribute
+ //c.IgnoreObsoleteActions();
+
+ // Each operation be assigned one or more tags which are then used by consumers for various reasons.
+ // For example, the swagger-ui groups operations according to the first tag of each operation.
+ // By default, this will be controller name but you can use the "GroupActionsBy" option to
+ // override with any value.
+ //
+ //c.GroupActionsBy(apiDesc => apiDesc.HttpMethod.ToString());
+
+ // You can also specify a custom sort order for groups (as defined by "GroupActionsBy") to dictate
+ // the order in which operations are listed. For example, if the default grouping is in place
+ // (controller name) and you specify a descending alphabetic sort order, then actions from a
+ // ProductsController will be listed before those from a CustomersController. This is typically
+ // used to customize the order of groupings in the swagger-ui.
+ //
+ //c.OrderActionGroupsBy(new DescendingAlphabeticComparer());
+
+ // If you annotate Controllers and API Types with
+ // Xml comments (http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx), you can incorporate
+ // those comments into the generated docs and UI. You can enable this by providing the path to one or
+ // more Xml comment files.
+ //
+ //c.IncludeXmlComments(GetXmlCommentsPath());
+
+ // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types
+ // exposed in your API. However, there may be occasions when more control of the output is needed.
+ // This is supported through the "MapType" and "SchemaFilter" options:
+ //
+ // Use the "MapType" option to override the Schema generation for a specific type.
+ // It should be noted that the resulting Schema will be placed "inline" for any applicable Operations.
+ // While Swagger 2.0 supports inline definitions for "all" Schema types, the swagger-ui tool does not.
+ // It expects "complex" Schemas to be defined separately and referenced. For this reason, you should only
+ // use the "MapType" option when the resulting Schema is a primitive or array type. If you need to alter a
+ // complex Schema, use a Schema filter.
+ //
+ //c.MapType(() => new Schema { type = "integer", format = "int32" });
+
+ // If you want to post-modify "complex" Schemas once they've been generated, across the board or for a
+ // specific type, you can wire up one or more Schema filters.
+ //
+ //c.SchemaFilter();
+
+ // In a Swagger 2.0 document, complex types are typically declared globally and referenced by unique
+ // Schema Id. By default, Swashbuckle does NOT use the full type name in Schema Ids. In most cases, this
+ // works well because it prevents the "implementation detail" of type namespaces from leaking into your
+ // Swagger docs and UI. However, if you have multiple types in your API with the same class name, you'll
+ // need to opt out of this behavior to avoid Schema Id conflicts.
+ //
+ //c.UseFullTypeNameInSchemaIds();
+
+ // Alternatively, you can provide your own custom strategy for inferring SchemaId's for
+ // describing "complex" types in your API.
+ //
+ //c.SchemaId(t => t.FullName.Contains('`') ? t.FullName.Substring(0, t.FullName.IndexOf('`')) : t.FullName);
+
+ // Set this flag to omit schema property descriptions for any type properties decorated with the
+ // Obsolete attribute
+ //c.IgnoreObsoleteProperties();
+
+ // In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers.
+ // You can change the serializer behavior by configuring the StringToEnumConverter globally or for a given
+ // enum type. Swashbuckle will honor this change out-of-the-box. However, if you use a different
+ // approach to serialize enums as strings, you can also force Swashbuckle to describe them as strings.
+ //
+ //c.DescribeAllEnumsAsStrings();
+
+ // Similar to Schema filters, Swashbuckle also supports Operation and Document filters:
+ //
+ // Post-modify Operation descriptions once they've been generated by wiring up one or more
+ // Operation filters.
+ //
+ //c.OperationFilter();
+ //
+ // If you've defined an OAuth2 flow as described above, you could use a custom filter
+ // to inspect some attribute on each action and infer which (if any) OAuth2 scopes are required
+ // to execute the operation
+ //
+ //c.OperationFilter();
+
+ // Post-modify the entire Swagger document by wiring up one or more Document filters.
+ // This gives full control to modify the final SwaggerDocument. You should have a good understanding of
+ // the Swagger 2.0 spec. - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
+ // before using this option.
+ //
+ //c.DocumentFilter();
+
+ // In contrast to WebApi, Swagger 2.0 does not include the query string component when mapping a URL
+ // to an action. As a result, Swashbuckle will raise an exception if it encounters multiple actions
+ // with the same path (sans query string) and HTTP method. You can workaround this by providing a
+ // custom strategy to pick a winner or merge the descriptions for the purposes of the Swagger docs
+ //
+ //c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
+
+ // Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an
+ // alternative implementation for ISwaggerProvider with the CustomProvider option.
+ //
+ //c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));
+ })
+ .EnableSwaggerUi(c =>
+ {
+ // Use the "InjectStylesheet" option to enrich the UI with one or more additional CSS stylesheets.
+ // The file must be included in your project as an "Embedded Resource", and then the resource's
+ // "Logical Name" is passed to the method as shown below.
+ //
+ //c.InjectStylesheet(containingAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testStyles1.css");
+
+ // Use the "InjectJavaScript" option to invoke one or more custom JavaScripts after the swagger-ui
+ // has loaded. The file must be included in your project as an "Embedded Resource", and then the resource's
+ // "Logical Name" is passed to the method as shown above.
+ //
+ //c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js");
+
+ // The swagger-ui renders boolean data types as a dropdown. By default, it provides "true" and "false"
+ // strings as the possible choices. You can use this option to change these to something else,
+ // for example 0 and 1.
+ //
+ //c.BooleanValues(new[] { "0", "1" });
+
+ // By default, swagger-ui will validate specs against swagger.io's online validator and display the result
+ // in a badge at the bottom of the page. Use these options to set a different validator URL or to disable the
+ // feature entirely.
+ //c.SetValidatorUrl("http://localhost/validator");
+ //c.DisableValidator();
+
+ // Use this option to control how the Operation listing is displayed.
+ // It can be set to "None" (default), "List" (shows operations for each resource),
+ // or "Full" (fully expanded: shows operations and their details).
+ //
+ //c.DocExpansion(DocExpansion.List);
+
+ // Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables
+ // it for all operations.
+ //
+ //c.SupportedSubmitMethods("GET", "HEAD");
+
+ // Use the CustomAsset option to provide your own version of assets used in the swagger-ui.
+ // It's typically used to instruct Swashbuckle to return your version instead of the default
+ // when a request is made for "index.html". As with all custom content, the file must be included
+ // in your project as an "Embedded Resource", and then the resource's "Logical Name" is passed to
+ // the method as shown below.
+ //
+ //c.CustomAsset("index", containingAssembly, "YourWebApiProject.SwaggerExtensions.index.html");
+
+ // If your API has multiple versions and you've applied the MultipleApiVersions setting
+ // as described above, you can also enable a select box in the swagger-ui, that displays
+ // a discovery URL for each version. This provides a convenient way for users to browse documentation
+ // for different API versions.
+ //
+ //c.EnableDiscoveryUrlSelector();
+
+ // If your API supports the OAuth2 Implicit flow, and you've described it correctly, according to
+ // the Swagger 2.0 specification, you can enable UI support as shown below.
+ //
+ //c.EnableOAuth2Support(
+ // clientId: "test-client-id",
+ // clientSecret: null,
+ // realm: "test-realm",
+ // appName: "Swagger UI"
+ // //additionalQueryStringParams: new Dictionary() { { "foo", "bar" } }
+ //);
+
+ // If your API supports ApiKey, you can override the default values.
+ // "apiKeyIn" can either be "query" or "header"
+ //
+ //c.EnableApiKeySupport("apiKey", "header");
+ });
+ }
+ }
+}
diff --git a/terminalWord/Controllers/ActivityController.cs b/terminalWord/Controllers/ActivityController.cs
new file mode 100644
index 0000000000..28b64796ae
--- /dev/null
+++ b/terminalWord/Controllers/ActivityController.cs
@@ -0,0 +1,13 @@
+using Fr8.TerminalBase.BaseClasses;
+using Fr8.TerminalBase.Services;
+
+namespace terminalWord.Controllers
+{
+ public class ActivityController : DefaultActivityController
+ {
+ public ActivityController(IActivityExecutor activityExecutor)
+ : base(activityExecutor)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/terminalWord/Controllers/TerminalController.cs b/terminalWord/Controllers/TerminalController.cs
new file mode 100644
index 0000000000..beed4b4b67
--- /dev/null
+++ b/terminalWord/Controllers/TerminalController.cs
@@ -0,0 +1,13 @@
+using Fr8.TerminalBase.BaseClasses;
+using Fr8.TerminalBase.Services;
+
+namespace terminalWord.Controllers
+{
+ public class TerminalController : DefaultTerminalController
+ {
+ public TerminalController(IActivityStore activityStore, IHubDiscoveryService hubDiscovery)
+ : base(activityStore, hubDiscovery)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/terminalWord/Global.asax b/terminalWord/Global.asax
new file mode 100644
index 0000000000..2ae86aee55
--- /dev/null
+++ b/terminalWord/Global.asax
@@ -0,0 +1 @@
+<%@ Application Codebehind="Global.asax.cs" Inherits="terminalWord.WebApiApplication" Language="C#" %>
diff --git a/terminalWord/Global.asax.cs b/terminalWord/Global.asax.cs
new file mode 100644
index 0000000000..b8b830c341
--- /dev/null
+++ b/terminalWord/Global.asax.cs
@@ -0,0 +1,7 @@
+namespace terminalWord
+{
+ public class WebApiApplication : System.Web.HttpApplication
+ {
+
+ }
+}
diff --git a/terminalWord/Properties/AssemblyInfo.cs b/terminalWord/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..855bddfe47
--- /dev/null
+++ b/terminalWord/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("$projectsafename$")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("$projectsafename")]
+[assembly: AssemblyCopyright("Copyright © terminalWord 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3b6ebeb4-7cd4-4008-aaab-a3c4cdc77655")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/terminalWord/Startup.cs b/terminalWord/Startup.cs
new file mode 100644
index 0000000000..c6ec36b2ef
--- /dev/null
+++ b/terminalWord/Startup.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Web.Http.Dispatcher;
+using Fr8.TerminalBase.BaseClasses;
+using Microsoft.Owin;
+using Owin;
+using terminalWord.Controllers;
+using terminalWord;
+
+[assembly: OwinStartup(typeof(Startup))]
+
+namespace terminalWord
+{
+ public class Startup : BaseConfiguration
+ {
+ public Startup()
+ : base(TerminalData.TerminalDTO)
+ {
+ }
+
+ public void Configuration(IAppBuilder app)
+ {
+ Configuration(app, false);
+ }
+
+ public void Configuration(IAppBuilder app, bool selfHost)
+ {
+ ConfigureProject(selfHost, null);
+ SwaggerConfig.Register(_configuration);
+ RoutesConfig.Register(_configuration);
+ ConfigureFormatters();
+ app.UseWebApi(_configuration);
+ if (!selfHost)
+ {
+ StartHosting();
+ }
+ }
+
+ protected override void RegisterActivities()
+ {
+ ActivityStore.RegisterActivity(Activities.Load_Word_File_v1.ActivityTemplateDTO);
+ }
+
+ public override ICollection GetControllerTypes(IAssembliesResolver assembliesResolver)
+ {
+ return new Type[] {
+ typeof(ActivityController),
+ typeof(TerminalController),
+ };
+ }
+ }
+}
diff --git a/terminalWord/TerminalData.cs b/terminalWord/TerminalData.cs
new file mode 100644
index 0000000000..e35c8eeabd
--- /dev/null
+++ b/terminalWord/TerminalData.cs
@@ -0,0 +1,25 @@
+using Fr8.Infrastructure.Data.DataTransferObjects;
+using Fr8.Infrastructure.Data.States;
+using Fr8.Infrastructure.Utilities.Configuration;
+
+namespace terminalWord
+{
+ public static class TerminalData
+ {
+ public static ActivityCategoryDTO ActivityCategoryDTO = new ActivityCategoryDTO
+ {
+ Name = "Word",
+ IconPath = "/Content/icons/web_services/ms-word-icon-64x64.png",
+ Type = "WebService"
+ };
+
+ public static TerminalDTO TerminalDTO = new TerminalDTO
+ {
+ Endpoint = CloudConfigurationManager.GetSetting("terminalWord.TerminalEndpoint"),
+ TerminalStatus = TerminalStatus.Active,
+ Name = "terminalWord",
+ Label = "Word",
+ Version = "1"
+ };
+ }
+}
\ No newline at end of file
diff --git a/terminalWord/Web.Debug.config b/terminalWord/Web.Debug.config
new file mode 100644
index 0000000000..680849f611
--- /dev/null
+++ b/terminalWord/Web.Debug.config
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/terminalWord/Web.Release.config b/terminalWord/Web.Release.config
new file mode 100644
index 0000000000..943c9c0de7
--- /dev/null
+++ b/terminalWord/Web.Release.config
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/terminalWord/Web.config b/terminalWord/Web.config
new file mode 100644
index 0000000000..0600d234ee
--- /dev/null
+++ b/terminalWord/Web.config
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/terminalWord/favicon.ico b/terminalWord/favicon.ico
new file mode 100644
index 0000000000..a3a799985c
Binary files /dev/null and b/terminalWord/favicon.ico differ
diff --git a/terminalWord/index.html b/terminalWord/index.html
new file mode 100644
index 0000000000..dd07692281
--- /dev/null
+++ b/terminalWord/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ This is the home page of the Fr8Demo Terminal Service, one of the many terminals being developed.
+
+
+
+
diff --git a/terminalWord/packages.config b/terminalWord/packages.config
new file mode 100644
index 0000000000..f5502e330d
--- /dev/null
+++ b/terminalWord/packages.config
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/terminalWord/terminalWord.csproj b/terminalWord/terminalWord.csproj
new file mode 100644
index 0000000000..52b60a66f6
--- /dev/null
+++ b/terminalWord/terminalWord.csproj
@@ -0,0 +1,242 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+
+
+ 2.0
+ {C808A1BB-26EC-4EF9-8592-10176BF1E558}
+ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ Properties
+ terminalWord
+ terminalWord
+ v4.5
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+ full
+ false
+ bin\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\AutoMapper.4.0.4\lib\net45\AutoMapper.dll
+ True
+
+
+ ..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll
+ True
+
+
+ ..\packages\log4net.2.0.5\lib\net45-full\log4net.dll
+ True
+
+
+ ..\packages\Microsoft.ApplicationInsights.2.0.0\lib\net45\Microsoft.ApplicationInsights.dll
+ True
+
+
+
+ ..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll
+ True
+
+
+ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+ ..\packages\libphonenumber-csharp.7.2.5\lib\PhoneNumbers.dll
+ True
+
+
+ ..\packages\PusherServer.3.0.0\lib\net35\PusherServer.dll
+ True
+
+
+ ..\packages\RestSharp.105.0.1\lib\net4\RestSharp.dll
+ True
+
+
+ ..\packages\structuremap.3.1.6.186\lib\net40\StructureMap.dll
+ True
+
+
+ ..\packages\structuremap.3.1.6.186\lib\net40\StructureMap.Net4.dll
+ True
+
+
+ ..\packages\Swashbuckle.Core.5.4.0\lib\net40\Swashbuckle.Core.dll
+ True
+
+
+
+
+
+ ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll
+ True
+
+
+ ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
+
+
+
+
+ ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
+
+
+
+
+ ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
+
+
+ ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll
+
+
+
+ ..\packages\WebActivatorEx.2.0\lib\net40\WebActivatorEx.dll
+ True
+
+
+ ..\packages\YamlDotNet.3.8.0\lib\net35\YamlDotNet.dll
+ True
+
+
+
+
+ ..\packages\Owin.1.0\lib\net40\Owin.dll
+
+
+ ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
+
+
+ ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
+
+
+ ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll
+
+
+
+
+
+
+
+
+
+ Global.asax
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+ Web.config
+
+
+ Web.config
+
+
+
+
+
+
+
+
+
+
+ {bba91af2-7636-41b6-87c4-c1575ae8b04b}
+ Fr8Infrastructure.NET
+
+
+ {bf96675e-6baf-4ac9-b247-1551d62e8c44}
+ Fr8TerminalBase.NET
+
+
+ {E46B602A-287B-450F-B455-5EED20C93EB7}
+ terminalUtilities
+
+
+
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file