Revised for new Azure Code Samples page and repo
|
@ -1,22 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console_RateCard", "ConsoleProj\Console_RateCard.csproj", "{54A35A7A-4B54-4429-A68B-93294C8FC678}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="ADALServiceURL" value="https://login.microsoftonline.com"/> <!-- Service root URL for ADAL authentication service WITH NO TRAILING SLASH! -->
|
||||
<add key="ADALRedirectURL" value="https://localhost/"/> <!-- Redirect URL for ADAL authentication service MUST MATCH YOUR AAD APP CONFIGURATION! -->
|
||||
<add key="ARMBillingServiceURL" value="https://management.azure.com"/> <!-- Service root URL for ARM/Billing service WITH NO TRAILING SLASH! -->
|
||||
<add key="TenantDomain" value="ENTER.AZURE.AD.DNS.NAME"/> <!-- DNS name for your Azure AD tenant -->
|
||||
<add key="SubscriptionID" value="00000000-0000-0000-0000-000000000000"/> <!-- GUID of Azure Subscription that is trusting AAD tenant specified above -->
|
||||
<add key="ClientId" value="00000000-0000-0000-0000-000000000000"/> <!-- GUID for AAD application configured as Native Client App in AAD tenant specified above -->
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -1,77 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{54A35A7A-4B54-4429-A68B-93294C8FC678}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ARMAPI_Test</RootNamespace>
|
||||
<AssemblyName>ARMAPI_Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Azure.Documents.Client">
|
||||
<HintPath>..\packages\Microsoft.Azure.Documents.Client.0.9.0-preview\lib\net40\Microsoft.Azure.Documents.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp">
|
||||
<HintPath>..\packages\RestSharp.105.0.1\lib\net4\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RateCardPayload.cs" />
|
||||
<Compile Include="Resource.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,103 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
using Microsoft.Azure.Documents.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Configuration; //BL
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
#error Please update the appSettings section in app.config, then remove this statement
|
||||
|
||||
class Program
|
||||
{
|
||||
//This is a sample console application that shows you how to grab a User token from AAD for the current user of the app
|
||||
//The same caveat remains, that the current user of the app needs to be part of either the Owner, Reader or Contributor role for the requested AzureSubID.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//Get the AAD User token to get authorized to make the call to the Usage API
|
||||
string token = GetOAuthTokenFromAAD();
|
||||
|
||||
/*Setup API call to RateCard API
|
||||
Callouts:
|
||||
* See the App.config file for all AppSettings key/value pairs
|
||||
* You can get a list of offer numbers from this URL: http://azure.microsoft.com/en-us/support/legal/offer-details/
|
||||
* You can configure an OfferID for this API by updating 'MS-AZR-{Offer Number}'
|
||||
* The RateCard Service/API is currently in preview; please use 2016-06-01-preview for api-version
|
||||
*/
|
||||
|
||||
// Build up the HttpWebRequest
|
||||
string requestURL = String.Format("{0}/{1}/{2}/{3}",
|
||||
ConfigurationManager.AppSettings["ARMBillingServiceURL"],
|
||||
"subscriptions",
|
||||
ConfigurationManager.AppSettings["SubscriptionID"],
|
||||
"providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview&$filter=OfferDurableId eq 'MS-AZR-0121p' and Currency eq 'USD' and Locale eq 'en-US' and RegionInfo eq 'US'");
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
|
||||
|
||||
// Add the OAuth Authorization header, and Content Type header
|
||||
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
|
||||
request.ContentType = "application/json";
|
||||
|
||||
// Call the RateCard API, dump the output to the console window
|
||||
try
|
||||
{
|
||||
// Call the REST endpoint
|
||||
Console.WriteLine("Calling RateCard service...");
|
||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||
Console.WriteLine(String.Format("RateCard service response status: {0}", response.StatusDescription));
|
||||
Stream receiveStream = response.GetResponseStream();
|
||||
|
||||
// Pipes the stream to a higher level stream reader with the required encoding format.
|
||||
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
|
||||
var rateCardResponse = readStream.ReadToEnd();
|
||||
Console.WriteLine("RateCard stream received. Press ENTER to continue with raw output.");
|
||||
Console.ReadLine();
|
||||
Console.WriteLine(rateCardResponse);
|
||||
Console.WriteLine("Raw output complete. Press ENTER to continue with JSON output.");
|
||||
Console.ReadLine();
|
||||
|
||||
// Convert the Stream to a strongly typed RateCardPayload object.
|
||||
// You can also walk through this object to manipulate the individuals member objects.
|
||||
RateCardPayload payload = JsonConvert.DeserializeObject<RateCardPayload>(rateCardResponse);
|
||||
Console.WriteLine(rateCardResponse.ToString());
|
||||
response.Close();
|
||||
readStream.Close();
|
||||
Console.WriteLine("JSON output complete. Press ENTER to close.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine(String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : ""));
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string GetOAuthTokenFromAAD()
|
||||
{
|
||||
var authenticationContext = new AuthenticationContext( String.Format("{0}/{1}",
|
||||
ConfigurationManager.AppSettings["ADALServiceURL"],
|
||||
ConfigurationManager.AppSettings["TenantDomain"]));
|
||||
|
||||
//Ask the logged in user to authenticate, so that this client app can get a token on his behalf
|
||||
var result = authenticationContext.AcquireToken(String.Format("{0}/",ConfigurationManager.AppSettings["ARMBillingServiceURL"]),
|
||||
ConfigurationManager.AppSettings["ClientID"],
|
||||
new Uri(ConfigurationManager.AppSettings["ADALRedirectURL"]));
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
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("ConsoleApplication2")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ConsoleApplication2")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[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("605fab13-fb23-4e23-8038-fae885423c55")]
|
||||
|
||||
// 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 Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,19 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class RateCardPayload
|
||||
{
|
||||
public List<object> OfferTerms { get; set; }
|
||||
public List<Resource> Meters { get; set; }
|
||||
public string Currency { get; set; }
|
||||
public string Locale { get; set; }
|
||||
public string RatingDate { get; set; }
|
||||
public bool IsTaxIncluded { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
public string MeterId { get; set; }
|
||||
public string MeterName { get; set; }
|
||||
public string MeterCategory { get; set; }
|
||||
public string MeterSubCategory { get; set; }
|
||||
public string Unit { get; set; }
|
||||
public Dictionary<double, double> MeterRates { get; set; }
|
||||
public string EffectiveDate { get; set; }
|
||||
public List<string> MeterTags { get; set; }
|
||||
public string MeterRegion { get; set; }
|
||||
public double IncludedQuantity { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Azure.Documents.Client" version="0.9.0-preview" targetFramework="net45" />
|
||||
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.14.201151115" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
|
||||
<package id="RestSharp" version="105.0.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,64 +0,0 @@
|
|||
# ConsoleApp-Billing-RateCard
|
||||
---------------------------
|
||||
This is a simple console app that calls the Azure Billing RateCard REST API to retrieve the list of resources per Azure offer in a given subscription, along with the pricing details for each resource. The app first fetches an access token using credentials of the signed-in user, then gets the RateCard response and deserializes it and prints it to the console.
|
||||
|
||||
Please note, the Usage APIs were in Preview at the time of this writing. Please refer to MSDN article [Azure Billing REST API Reference (Preview)] (https://msdn.microsoft.com/library/azure/1ea5b323-54bb-423d-916f-190de96c6a3c) for details on the Billing RateCard API.
|
||||
|
||||
## How To Run This Sample
|
||||
|
||||
To run this sample you will need:
|
||||
|
||||
- Visual Studio 2013 or higher
|
||||
- An Internet connection
|
||||
- An Azure subscription (a free trial is sufficient)
|
||||
|
||||
You will also need to be comfortable with the following tasks:
|
||||
|
||||
- Using the Azure Management Portal (or working with your administrator) to do configuration work
|
||||
- Using Git and Github to bring the sample down to your location machine
|
||||
- Using Visual Studio to edit configuration files, build, and run the sample
|
||||
|
||||
Every Azure subscription has an associated Azure Active Directory (AAD) tenant. If you don't already have an Azure subscription, you can get a free subscription by signing up at [http://wwww.windowsazure.com](http://www.windowsazure.com).
|
||||
|
||||
### Step 1: Configure a Native Client application in your AAD tenant
|
||||
Before you can run the sample application, you will need to allow it to access your AAD tenant for authentication and authorization to access the Billing APIs. If you already have a Native Client Application configured that you would like to use (and it is configured according to the steps below), you can jump to Step 2.
|
||||
|
||||
To configure a new AAD application:
|
||||
|
||||
1. Log in to the [Azure Management Portal](http://manage.windowsazure.com), using credentials that have been granted service co-administrator access on the subscription which is trusting your AAD tenant, and granted Global Administrator access in the AAD tenant.
|
||||
2. Select the AAD tenant you wish to use, and go to the "Applications" page.
|
||||
3. From there, you can use the "Add" feature to "Add a new application my organization is developing".
|
||||
4. Provide a name (ie: ConsoleApp-Billing-RateCard or similar) for the new application.
|
||||
5. Be sure to select the "Native Client Application" type, then specify a valid URL for "Redirect URI" (which can be http://localhost/ for the purposes of this sample), and click the check mark to save.
|
||||
6. After you've added the new application, select it again within the list of applications and click "Configure" so you can make sure the sample app will have permissions to access the Windows Azure Service Management APIs, which is the permission used to secure the Billing APIs.
|
||||
7. Scroll down to the to the "Permissions to other applications" section of your newly created application's configuration page. Then click the "Add Application" button, select the "Windows Azure Service Management" row, and click the check mark to save. After saving, hover the "Delegated Permissions" area on the right side of the "Windows Azure Service Management" row, click the "Delegated Permissions" drop down list, select the "Access Azure Service Management (preview)" option, and click "Save" again.
|
||||
|
||||
**NOTE**: the "Windows Azure Active Directory" permission "Enable sign-on and read users' profiles" is enabled by default. It allows users to sign in to the application with their organizational accounts, enabling the application to read the profiles of signed-in users, such as their email address and contact information. This is a delegation permission, and gives the user the ability to consent before proceeding. Please refer to [Adding, Updating, and Removing an Application](https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx) for more depth on configuring an Azure AD tenant to enable an application to access your tenant.
|
||||
|
||||
8. While you are on this page, also note/copy the "Client ID" GUID and "Redirect URI", as you will use these in Step #3 below. You will also need your Azure Subscription ID and AAD tenant domain name, both of which you can copy from the "Settings" page in the management portal.
|
||||
|
||||
### Step 2: Clone or download the BillingCodeSamples repository
|
||||
|
||||
From your shell (ie: Git Bash, etc.) or command line, run the following command :
|
||||
|
||||
git clone https://github.com/Azure/BillingCodeSamples.git
|
||||
|
||||
### Step 3: Edit and Build the sample in Visual Studio
|
||||
After you've configured your tenant and downloaded the sample app, you will need to go into the local sub directory in which the Visual Studio solution is stored (typically in <your-git-root-directory>\BillingCodeSamples), and open the ConsoleApp-Billing-RateCard.sln Visual Studio solution. Upon opening, navigate to the app.config file and update the following key/value pairs, using your subscription and AAD specific configuration information from earlier. NOTE: It's very important that all values match your configuration!
|
||||
|
||||
<add key="ADALRedirectURL" value="https://localhost/"/>
|
||||
<add key="TenantDomain" value="ENTER.AZURE.AD.DNS.NAME"/>
|
||||
<add key="SubscriptionID" value="00000000-0000-0000-0000-000000000000"/>
|
||||
<add key="ClientId" value="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
When you build the solution, it will also restore the missing Nuget packages which contain libraries upon which the sample depends. Program.cs contains the RateCard query string, so if you would like to query for different data, you can also change the OfferDurableId, Currency, Locale, and/or RegionInfo parameter values.
|
||||
|
||||
### Step 4: Run the application against your AAD tenant
|
||||
|
||||
When finished with Step 3, you should be able to successfully run the application, which will prompt you for your Azure AD credentials. Upon successful authentication, the API will be called and the results will be displayed in the console window.
|
||||
|
||||
**Note**: The Azure Billing REST APIs are implemented as a Resource Provider as part of the Azure Resource Manager, and therefore share its dependencies. Access control for Azure Resource Manager uses the built-in Owner, Contributor, and Reader roles, via the Role Based Access Control (RBAC) feature in the [Azure Preview Portal](https://portal.azure.com/). Therefore, you must make sure that the logged-in user is a member of either the ‘Reader’, ‘Owner’ or ‘Contributor’ roles for the specified subscription. By default, all service administrators are members of the Owner role. For details, see [Role-based access control in the Microsoft Azure portal](https://azure.microsoft.com/en-us/documentation/articles/role-based-access-control-configure/).
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console_UsageAPI", "ConsoleProj\Console_UsageAPI.csproj", "{54A35A7A-4B54-4429-A68B-93294C8FC678}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{54A35A7A-4B54-4429-A68B-93294C8FC678}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="ADALServiceURL" value="https://login.microsoftonline.com"/> <!-- Service root URL for ADAL authentication service WITH NO TRAILING SLASH! -->
|
||||
<add key="ADALRedirectURL" value="https://localhost/"/> <!-- Redirect URL for ADAL authentication service MUST MATCH YOUR AAD APP CONFIGURATION! -->
|
||||
<add key="ARMBillingServiceURL" value="https://management.azure.com"/> <!-- Service root URL for ARM/Billing service WITH NO TRAILING SLASH! -->
|
||||
<add key="TenantDomain" value="ENTER.AZURE.AD.DNS.NAME"/> <!-- DNS name for your Azure AD tenant -->
|
||||
<add key="SubscriptionID" value="00000000-0000-0000-0000-000000000000"/> <!-- GUID of Azure Subscription that is trusting AAD tenant specified above -->
|
||||
<add key="ClientId" value="00000000-0000-0000-0000-000000000000"/> <!-- GUID for AAD application configured as Native Client App in AAD tenant specified above -->
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
|
@ -1,79 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{54A35A7A-4B54-4429-A68B-93294C8FC678}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ARMAPI_Test</RootNamespace>
|
||||
<AssemblyName>ARMAPI_Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Azure.Documents.Client">
|
||||
<HintPath>..\packages\Microsoft.Azure.Documents.Client.0.9.0-preview\lib\net40\Microsoft.Azure.Documents.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp">
|
||||
<HintPath>..\packages\RestSharp.105.0.1\lib\net4\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="InfoFields.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UsageAggregate.cs" />
|
||||
<Compile Include="UsagePayload.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class InfoFields
|
||||
{
|
||||
public string meteredRegion { get; set; }
|
||||
public string meteredService { get; set; }
|
||||
public string project { get; set; }
|
||||
public string meteredServiceType { get; set; }
|
||||
public string serviceInfo1 { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.Azure.Documents;
|
||||
using Microsoft.Azure.Documents.Client;
|
||||
using Microsoft.Azure.Documents.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Configuration;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
#error Please update the appSettings section in app.config, then remove this statement
|
||||
|
||||
class Program
|
||||
{
|
||||
//This is a sample console application that shows you how to grab a token from AAD for the current user of the app, and then get usage data for the customer with that token.
|
||||
//The same caveat remains, that the current user of the app needs to be part of either the Owner, Reader or Contributor role for the requested AzureSubID.
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//Get the AAD token to get authorized to make the call to the Usage API
|
||||
string token = GetOAuthTokenFromAAD();
|
||||
|
||||
/*Setup API call to Usage API
|
||||
Callouts:
|
||||
* See the App.config file for all AppSettings key/value pairs
|
||||
* You can get a list of offer numbers from this URL: http://azure.microsoft.com/en-us/support/legal/offer-details/
|
||||
* See the Azure Usage API specification for more details on the query parameters for this API.
|
||||
* The Usage Service/API is currently in preview; please use 2016-06-01-preview for api-version
|
||||
|
||||
*/
|
||||
// Build up the HttpWebRequest
|
||||
string requestURL = String.Format("{0}/{1}/{2}/{3}",
|
||||
ConfigurationManager.AppSettings["ARMBillingServiceURL"],
|
||||
"subscriptions",
|
||||
ConfigurationManager.AppSettings["SubscriptionID"],
|
||||
"providers/Microsoft.Commerce/UsageAggregates?api-version=2015-06-01-preview&reportedstartTime=2015-03-01+00%3a00%3a00Z&reportedEndTime=2015-05-18+00%3a00%3a00Z");
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
|
||||
|
||||
// Add the OAuth Authorization header, and Content Type header
|
||||
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
|
||||
request.ContentType = "application/json";
|
||||
|
||||
// Call the Usage API, dump the output to the console window
|
||||
try
|
||||
{
|
||||
// Call the REST endpoint
|
||||
Console.WriteLine("Calling Usage service...");
|
||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||
Console.WriteLine(String.Format("Usage service response status: {0}", response.StatusDescription));
|
||||
Stream receiveStream = response.GetResponseStream();
|
||||
|
||||
// Pipes the stream to a higher level stream reader with the required encoding format.
|
||||
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
|
||||
var usageResponse = readStream.ReadToEnd();
|
||||
Console.WriteLine("Usage stream received. Press ENTER to continue with raw output.");
|
||||
Console.ReadLine();
|
||||
Console.WriteLine(usageResponse);
|
||||
Console.WriteLine("Raw output complete. Press ENTER to continue with JSON output.");
|
||||
Console.ReadLine();
|
||||
|
||||
// Convert the Stream to a strongly typed RateCardPayload object.
|
||||
// You can also walk through this object to manipulate the individuals member objects.
|
||||
UsagePayload payload = JsonConvert.DeserializeObject<UsagePayload>(usageResponse);
|
||||
Console.WriteLine(usageResponse.ToString());
|
||||
response.Close();
|
||||
readStream.Close();
|
||||
Console.WriteLine("JSON output complete. Press ENTER to close.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : ""));
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
public static string GetOAuthTokenFromAAD()
|
||||
{
|
||||
var authenticationContext = new AuthenticationContext(String.Format("{0}/{1}",
|
||||
ConfigurationManager.AppSettings["ADALServiceURL"],
|
||||
ConfigurationManager.AppSettings["TenantDomain"]));
|
||||
|
||||
//Ask the logged in user to authenticate, so that this client app can get a token on his behalf
|
||||
var result = authenticationContext.AcquireToken(String.Format("{0}/", ConfigurationManager.AppSettings["ARMBillingServiceURL"]),
|
||||
ConfigurationManager.AppSettings["ClientID"],
|
||||
new Uri(ConfigurationManager.AppSettings["ADALRedirectURL"]));
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to obtain the JWT token");
|
||||
}
|
||||
|
||||
return result.AccessToken;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class Properties
|
||||
{
|
||||
public string subscriptionId { get; set; }
|
||||
public string usageStartTime { get; set; }
|
||||
public string usageEndTime { get; set; }
|
||||
public string meterId { get; set; }
|
||||
public InfoFields infoFields { get; set; }
|
||||
|
||||
[JsonProperty("instanceData")]
|
||||
public string instanceDataRaw { get; set; }
|
||||
|
||||
public InstanceDataType InstanceData
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonConvert.DeserializeObject<InstanceDataType>(instanceDataRaw.Replace("\\\"", ""));
|
||||
}
|
||||
}
|
||||
public double quantity { get; set; }
|
||||
public string unit { get; set; }
|
||||
public string meterName { get; set; }
|
||||
public string meterCategory { get; set; }
|
||||
public string meterSubCategory { get; set; }
|
||||
public string meterRegion { get; set; }
|
||||
}
|
||||
|
||||
public class InstanceDataType
|
||||
{
|
||||
[JsonProperty("Microsoft.Resources")]
|
||||
public MicrosoftResourcesDataType MicrosoftResources { get; set; }
|
||||
}
|
||||
|
||||
public class MicrosoftResourcesDataType
|
||||
{
|
||||
public string resourceUri { get; set; }
|
||||
|
||||
public IDictionary<string, string> tags { get; set; }
|
||||
|
||||
public IDictionary<string, string> additionalInfo { get; set; }
|
||||
|
||||
public string location { get; set; }
|
||||
|
||||
public string partNumber { get; set; }
|
||||
|
||||
public string orderNumber { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
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("ConsoleApplication2")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ConsoleApplication2")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[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("605fab13-fb23-4e23-8038-fae885423c55")]
|
||||
|
||||
// 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 Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class UsageAggregate
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string name { get; set; }
|
||||
public string type { get; set; }
|
||||
public Properties properties { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ARMAPI_Test
|
||||
{
|
||||
public class UsagePayload
|
||||
{
|
||||
public List<UsageAggregate> value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Azure.Documents.Client" version="0.9.0-preview" targetFramework="net45" />
|
||||
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.14.201151115" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
|
||||
<package id="RestSharp" version="105.0.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,64 +0,0 @@
|
|||
# ConsoleApp-Billing-Usage
|
||||
---------------------------
|
||||
This is a simple console app that calls the Azure Billing Usage REST API to retrieve resource usage data for a subscription. The app first fetches an access token using credentials of the signed-in user, then calls the Usage API and gets usage data for the requested time range, deserializes it into a payload object (which has a list of the usage aggregates), then prints it to the console.
|
||||
|
||||
Please note, the Usage APIs were in Preview at the time of this writing. Please refer to MSDN article [Azure Billing REST API Reference (Preview)] (https://msdn.microsoft.com/library/azure/1ea5b323-54bb-423d-916f-190de96c6a3c) for details on the Billing Usage API.
|
||||
|
||||
## How To Run This Sample
|
||||
|
||||
To run this sample you will need:
|
||||
|
||||
- Visual Studio 2013 or higher
|
||||
- An Internet connection
|
||||
- An Azure subscription (a free trial is sufficient)
|
||||
|
||||
You will also need to be comfortable with the following tasks:
|
||||
|
||||
- Using the Azure Management Portal (or working with your administrator) to do configuration work
|
||||
- Using Git and Github to bring the sample down to your location machine
|
||||
- Using Visual Studio to edit configuration files, build, and run the sample
|
||||
|
||||
Every Azure subscription has an associated Azure Active Directory (AAD) tenant. If you don't already have an Azure subscription, you can get a free subscription by signing up at [http://wwww.windowsazure.com](http://www.windowsazure.com).
|
||||
|
||||
### Step 1: Configure a Native Client application in your AAD tenant
|
||||
Before you can run the sample application, you will need to allow it to access your AAD tenant for authentication and authorization to access the Billing APIs. If you already have a Native Client Application configured that you would like to use (and it is configured according to the steps below), you can jump to Step 2.
|
||||
|
||||
To configure a new AAD application:
|
||||
|
||||
1. Log in to the [Azure Management Portal](http://manage.windowsazure.com), using credentials that have been granted service co-administrator access on the subscription which is trusting your AAD tenant, and granted Global Administrator access in the AAD tenant.
|
||||
2. Select the AAD tenant you wish to use, and go to the "Applications" page.
|
||||
3. From there, you can use the "Add" feature to "Add a new application my organization is developing".
|
||||
4. Provide a name (ie: ConsoleApp-Billing-Usage or similar) for the new application.
|
||||
5. Be sure to select the "Native Client Application" type, then specify a valid URL for "Redirect URI" (which can be http://localhost/ for the purposes of this sample), and click the check mark to save.
|
||||
6. After you've added the new application, select it again within the list of applications and click "Configure" so you can make sure the sample app will have permissions to access the Windows Azure Service Management APIs, which is the permission used to secure the Billing APIs.
|
||||
7. Scroll down to the to the "Permissions to other applications" section of your newly created application's configuration page. Then click the "Add Application" button, select the "Windows Azure Service Management" row, and click the check mark to save. After saving, hover the "Delegated Permissions" area on the right side of the "Windows Azure Service Management" row, click the "Delegated Permissions" drop down list, select the "Access Azure Service Management (preview)" option, and click "Save" again.
|
||||
|
||||
**NOTE**: the "Windows Azure Active Directory" permission "Enable sign-on and read users' profiles" is enabled by default. It allows users to sign in to the application with their organizational accounts, enabling the application to read the profiles of signed-in users, such as their email address and contact information. This is a delegation permission, and gives the user the ability to consent before proceeding. Please refer to [Adding, Updating, and Removing an Application](https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx) for more depth on configuring an Azure AD tenant to enable an application to access your tenant.
|
||||
|
||||
8. While you are on this page, also note/copy the "Client ID" GUID and "Redirect URI", as you will use these in Step #3 below. You will also need your Azure Subscription ID and AAD tenant domain name, both of which you can copy from the "Settings" page in the management portal.
|
||||
|
||||
### Step 2: Clone or download the BillingCodeSamples repository
|
||||
|
||||
From your shell (ie: Git Bash, etc.) or command line, run the following command :
|
||||
|
||||
git clone https://github.com/Azure/BillingCodeSamples.git
|
||||
|
||||
### Step 3: Edit and Build the sample in Visual Studio
|
||||
After you've configured your tenant and downloaded the sample app, you will need to go into the local sub directory in which the Visual Studio solution is stored (typically in <your-git-root-directory>\BillingCodeSamples), and open the ConsoleApp-Billing-Usage.sln Visual Studio solution. Upon opening, navigate to the app.config file and update the following key/value pairs, using your subscription and AAD specific configuration information from earlier. NOTE: It's very important that all values match your configuration!
|
||||
|
||||
<add key="ADALRedirectURL" value="https://localhost/"/>
|
||||
<add key="TenantDomain" value="ENTER.AZURE.AD.DNS.NAME"/>
|
||||
<add key="SubscriptionID" value="00000000-0000-0000-0000-000000000000"/>
|
||||
<add key="ClientId" value="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
When you build the solution, it will also restore the missing Nuget packages which contain libraries upon which the sample depends. Program.cs contains the Usage query string, so if you would like to query for a different time range, you can change the reportedStartTime and reportedEndTime parameter values.
|
||||
|
||||
### Step 4: Run the application against your AAD tenant
|
||||
|
||||
When finished with Step 3, you should be able to successfully run the application, which will prompt you for your Azure AD credentials. Upon successful authentication, the API will be called and the results will be displayed in the console window.
|
||||
|
||||
**Note**: The Azure Billing REST APIs are implemented as a Resource Provider as part of the Azure Resource Manager, and therefore share its dependencies. Access control for Azure Resource Manager uses the built-in Owner, Contributor, and Reader roles, via the Role Based Access Control (RBAC) feature in the [Azure Preview Portal](https://portal.azure.com/). Therefore, you must make sure that the logged-in user is a member of either the ‘Reader’, ‘Owner’ or ‘Contributor’ roles for the specified subscription. By default, all service administrators are members of the Owner role. For details, see [Role-based access control in the Microsoft Azure portal](https://azure.microsoft.com/en-us/documentation/articles/role-based-access-control-configure/).
|
||||
|
||||
|
||||
|
||||
|
21
License.TXT
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1,114 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using ISVDemoUsage.Models;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class ADALTokenCache : TokenCache
|
||||
{
|
||||
private DataAccess db = new DataAccess();
|
||||
string User;
|
||||
PerUserTokenCache Cache;
|
||||
|
||||
// constructor
|
||||
public ADALTokenCache(string user)
|
||||
{
|
||||
// associate the cache to the current user of the web app
|
||||
User = user;
|
||||
|
||||
this.AfterAccess = AfterAccessNotification;
|
||||
this.BeforeAccess = BeforeAccessNotification;
|
||||
this.BeforeWrite = BeforeWriteNotification;
|
||||
|
||||
// look up the entry in the DB
|
||||
Cache = db.PerUserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User);
|
||||
// place the entry in memory
|
||||
this.Deserialize((Cache == null) ? null : Cache.cacheBits);
|
||||
}
|
||||
|
||||
// clean up the DB
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
foreach (var cacheEntry in db.PerUserTokenCacheList)
|
||||
db.PerUserTokenCacheList.Remove(cacheEntry);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
// Notification raised before ADAL accesses the cache.
|
||||
// This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
|
||||
void BeforeAccessNotification(TokenCacheNotificationArgs args)
|
||||
{
|
||||
if (Cache == null)
|
||||
{
|
||||
// first time access
|
||||
Cache = db.PerUserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User);
|
||||
}
|
||||
else
|
||||
{ // retrieve last write from the DB
|
||||
var status = from e in db.PerUserTokenCacheList
|
||||
where (e.webUserUniqueId == User)
|
||||
select new
|
||||
{
|
||||
LastWrite = e.LastWrite
|
||||
};
|
||||
// if the in-memory copy is older than the persistent copy
|
||||
if (status.First().LastWrite > Cache.LastWrite)
|
||||
//// read from from storage, update in-memory copy
|
||||
{
|
||||
Cache = db.PerUserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User);
|
||||
}
|
||||
}
|
||||
this.Deserialize((Cache == null) ? null : Cache.cacheBits);
|
||||
}
|
||||
// Notification raised after ADAL accessed the cache.
|
||||
// If the HasStateChanged flag is set, ADAL changed the content of the cache
|
||||
void AfterAccessNotification(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// if state changed
|
||||
if (this.HasStateChanged)
|
||||
{
|
||||
// check for an existing entry
|
||||
Cache = db.PerUserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == User);
|
||||
if (Cache == null)
|
||||
{
|
||||
// if no existing entry for that user, create a new one
|
||||
Cache = new PerUserTokenCache
|
||||
{
|
||||
webUserUniqueId = User,
|
||||
};
|
||||
}
|
||||
|
||||
// update the cache contents and the last write timestamp
|
||||
Cache.cacheBits = this.Serialize();
|
||||
Cache.LastWrite = DateTime.Now;
|
||||
|
||||
// update the DB with modification or new entry
|
||||
db.Entry(Cache).State = Cache.Id == 0 ? EntityState.Added : EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
this.HasStateChanged = false;
|
||||
}
|
||||
}
|
||||
void BeforeWriteNotification(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Web;
|
||||
using System.Web.Optimization;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class BundleConfig
|
||||
{
|
||||
// For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
|
||||
public static void RegisterBundles(BundleCollection bundles)
|
||||
{
|
||||
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
|
||||
"~/Scripts/jquery-{version}.js"));
|
||||
|
||||
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
|
||||
"~/Scripts/jquery.validate*"));
|
||||
|
||||
// Use the development version of Modernizr to develop with and learn from. Then, when you're
|
||||
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
|
||||
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
|
||||
"~/Scripts/modernizr-*"));
|
||||
|
||||
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
|
||||
"~/Scripts/bootstrap.js",
|
||||
"~/Scripts/respond.js"));
|
||||
|
||||
bundles.Add(new StyleBundle("~/Content/css").Include(
|
||||
"~/Content/bootstrap.css",
|
||||
"~/Content/site.css"));
|
||||
|
||||
// Set EnableOptimizations to false for debugging. For more information,
|
||||
// visit http://go.microsoft.com/fwlink/?LinkId=301862
|
||||
BundleTable.EnableOptimizations = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class FilterConfig
|
||||
{
|
||||
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
|
||||
{
|
||||
filters.Add(new HandleErrorAttribute());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class RouteConfig
|
||||
{
|
||||
public static void RegisterRoutes(RouteCollection routes)
|
||||
{
|
||||
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
|
||||
|
||||
routes.MapRoute(
|
||||
name: "Default",
|
||||
url: "{controller}/{action}/{id}",
|
||||
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using Microsoft.Owin.Security;
|
||||
using Microsoft.Owin.Security.Cookies;
|
||||
using Microsoft.Owin.Security.OpenIdConnect;
|
||||
using Owin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Security.Claims;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace ISVDemoUsage {
|
||||
public partial class Startup
|
||||
{
|
||||
private DataAccess db = new DataAccess();
|
||||
public void ConfigureAuth(IAppBuilder app)
|
||||
{
|
||||
string ClientId = ConfigurationManager.AppSettings["ida:ClientID"];
|
||||
string Password = ConfigurationManager.AppSettings["ida:Password"];
|
||||
string Authority = string.Format(ConfigurationManager.AppSettings["ida:Authority"], "common");
|
||||
string GraphAPIIdentifier = ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"];
|
||||
string AzureResourceManagerIdentifier = ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"];
|
||||
|
||||
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
|
||||
app.UseCookieAuthentication(new CookieAuthenticationOptions { });
|
||||
app.UseOpenIdConnectAuthentication(
|
||||
new OpenIdConnectAuthenticationOptions
|
||||
{
|
||||
ClientId = ClientId,
|
||||
Authority = Authority,
|
||||
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
|
||||
{
|
||||
// we inject our own multitenant validation logic
|
||||
ValidateIssuer = false,
|
||||
},
|
||||
Notifications = new OpenIdConnectAuthenticationNotifications()
|
||||
{
|
||||
RedirectToIdentityProvider = (context) =>
|
||||
{
|
||||
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
|
||||
// this allows you to deploy your app (to Azure Web Sites, for example) without having to change settings
|
||||
// Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
|
||||
//string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
|
||||
|
||||
object obj = null;
|
||||
if (context.OwinContext.Environment.TryGetValue("Authority", out obj))
|
||||
{
|
||||
string authority = obj as string;
|
||||
if (authority != null)
|
||||
{
|
||||
context.ProtocolMessage.IssuerAddress = authority;
|
||||
}
|
||||
}
|
||||
if (context.OwinContext.Environment.TryGetValue("DomainHint", out obj))
|
||||
{
|
||||
string domainHint = obj as string;
|
||||
if (domainHint != null)
|
||||
{
|
||||
context.ProtocolMessage.SetParameter("domain_hint", domainHint);
|
||||
}
|
||||
}
|
||||
context.ProtocolMessage.RedirectUri = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path);
|
||||
context.ProtocolMessage.PostLogoutRedirectUri = new UrlHelper(HttpContext.Current.Request.RequestContext).Action
|
||||
("Index", "Home", null, HttpContext.Current.Request.Url.Scheme);
|
||||
context.ProtocolMessage.Resource = GraphAPIIdentifier;
|
||||
return Task.FromResult(0);
|
||||
},
|
||||
AuthorizationCodeReceived = (context) =>
|
||||
{
|
||||
ClientCredential credential = new ClientCredential(ClientId, Password);
|
||||
string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
|
||||
string signedInUserUniqueName = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value.Split('#')[context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
ADALTokenCache cache = new ADALTokenCache(signedInUserUniqueName);
|
||||
|
||||
|
||||
cache.Clear();
|
||||
|
||||
|
||||
AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.microsoftonline.com/{0}", tenantID),
|
||||
new ADALTokenCache(signedInUserUniqueName));
|
||||
|
||||
var items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
AuthenticationResult result1 = authContext.AcquireTokenByAuthorizationCode(
|
||||
context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential);
|
||||
|
||||
items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
AuthenticationResult result2 = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
return Task.FromResult(0);
|
||||
},
|
||||
// we use this notification for injecting our custom logic
|
||||
SecurityTokenValidated = (context) =>
|
||||
{
|
||||
// retriever caller data from the incoming principal
|
||||
string issuer = context.AuthenticationTicket.Identity.FindFirst("iss").Value;
|
||||
if (!issuer.StartsWith("https://sts.windows.net/"))
|
||||
// the caller is not from a trusted issuer - throw to block the authentication flow
|
||||
throw new System.IdentityModel.Tokens.SecurityTokenValidationException();
|
||||
|
||||
return Task.FromResult(0);
|
||||
},
|
||||
//AuthenticationFailed = (context) =>
|
||||
//{
|
||||
// context.OwinContext.Response.Redirect(new UrlHelper(HttpContext.Current.Request.RequestContext).
|
||||
// Action("Index", "Home", null, HttpContext.Current.Request.Url.Scheme));
|
||||
// context.HandleResponse(); // Suppress the exception
|
||||
// return Task.FromResult(0);
|
||||
//}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
using ISVDemoUsage.Models;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public static class AzureADGraphAPIUtil
|
||||
{
|
||||
public static string GetOrganizationDisplayName(string organizationId)
|
||||
{
|
||||
string displayName = null;
|
||||
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure AD Graph API
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
// Get a list of Organizations of which the user is a member
|
||||
string requestUrl = string.Format("{0}{1}/tenantDetails?api-version={2}", ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"],
|
||||
organizationId, ConfigurationManager.AppSettings["ida:GraphAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of Tenant Objects
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var organizationPropertiesResult = (Json.Decode(responseContent)).value;
|
||||
if (organizationPropertiesResult != null && organizationPropertiesResult.Length > 0)
|
||||
{
|
||||
displayName = organizationPropertiesResult[0].displayName;
|
||||
if (organizationPropertiesResult[0].verifiedDomains != null)
|
||||
foreach (var verifiedDomain in organizationPropertiesResult[0].verifiedDomains)
|
||||
if (verifiedDomain["default"])
|
||||
displayName += " (" + verifiedDomain.name + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return displayName;
|
||||
}
|
||||
public static string GetObjectIdOfServicePrincipalInOrganization(string organizationId, string applicationId )
|
||||
{
|
||||
string objectId = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire App Only Access Token to call Azure Resource Manager - Client Credential OAuth Flow
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId));
|
||||
AuthenticationResult result = authContext.AcquireToken(ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"], credential);
|
||||
|
||||
// Get a list of Organizations of which the user is a member
|
||||
string requestUrl = string.Format("{0}{1}/servicePrincipals?api-version={2}&$filter=appId eq '{3}'",
|
||||
ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"], organizationId,
|
||||
ConfigurationManager.AppSettings["ida:GraphAPIVersion"], applicationId);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint should return JSON with one or none serviePrincipal object
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var servicePrincipalResult = (Json.Decode(responseContent)).value;
|
||||
if (servicePrincipalResult != null && servicePrincipalResult.Length > 0)
|
||||
objectId = servicePrincipalResult[0].objectId;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return objectId;
|
||||
}
|
||||
public static string LookupDisplayNameOfAADObject(string organizationId, string objectId)
|
||||
{
|
||||
string objectDisplayName = null;
|
||||
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
// Aquire Access Token to call Azure AD Graph API
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
|
||||
string doQueryUrl = string.Format("{0}{1}/directoryObjects/{2}?api-version={3}",
|
||||
ConfigurationManager.AppSettings["ida:GraphAPIIdentifier"], organizationId,
|
||||
objectId, ConfigurationManager.AppSettings["ida:GraphAPIVersion"]);
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, doQueryUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var responseContent = response.Content;
|
||||
string responseString = responseContent.ReadAsStringAsync().Result;
|
||||
var directoryObject = System.Web.Helpers.Json.Decode(responseString);
|
||||
if (directoryObject != null) objectDisplayName = string.Format("{0} ({1})", directoryObject.displayName, directoryObject.objectType);
|
||||
}
|
||||
|
||||
return objectDisplayName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,537 +0,0 @@
|
|||
using ISVDemoUsage.Models;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public static class AzureResourceManagerUtil
|
||||
{
|
||||
public static List<Organization> GetUserOrganizations()
|
||||
{
|
||||
List<Organization> organizations = new List<Organization>();
|
||||
|
||||
string tenantId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], tenantId), new ADALTokenCache(signedInUserUniqueName));
|
||||
|
||||
var items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
|
||||
// Get a list of Organizations of which the user is a member
|
||||
string requestUrl = string.Format("{0}/tenants?api-version={1}", ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"],
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of Tenant Objects
|
||||
// id tenantId
|
||||
// -- --------
|
||||
// /tenants/7fe877e6-a150-4992-bbfe-f517e304dfa0 7fe877e6-a150-4992-bbfe-f517e304dfa0
|
||||
// /tenants/62e173e9-301e-423e-bcd4-29121ec1aa24 62e173e9-301e-423e-bcd4-29121ec1aa24
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var organizationsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var organization in organizationsResult)
|
||||
organizations.Add(new Organization()
|
||||
{
|
||||
Id = organization.tenantId,
|
||||
//DisplayName = AzureADGraphAPIUtil.GetOrganizationDisplayName(organization.tenantId),
|
||||
objectIdOfISVDemoUsageServicePrincipal =
|
||||
AzureADGraphAPIUtil.GetObjectIdOfServicePrincipalInOrganization(organization.tenantId, ConfigurationManager.AppSettings["ida:ClientID"])
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], tenantId), new ADALTokenCache(signedInUserUniqueName));
|
||||
|
||||
var items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
|
||||
AuthenticationResult result =authContext.AcquireToken(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential);
|
||||
|
||||
|
||||
//(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
//new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
items = authContext.TokenCache.ReadItems().ToList();
|
||||
|
||||
|
||||
// Get a list of Organizations of which the user is a member
|
||||
string requestUrl = string.Format("{0}/tenants?api-version={1}", ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"],
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of Tenant Objects
|
||||
// id tenantId
|
||||
// -- --------
|
||||
// /tenants/7fe877e6-a150-4992-bbfe-f517e304dfa0 7fe877e6-a150-4992-bbfe-f517e304dfa0
|
||||
// /tenants/62e173e9-301e-423e-bcd4-29121ec1aa24 62e173e9-301e-423e-bcd4-29121ec1aa24
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var organizationsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var organization in organizationsResult)
|
||||
organizations.Add(new Organization()
|
||||
{
|
||||
Id = organization.tenantId,
|
||||
//DisplayName = AzureADGraphAPIUtil.GetOrganizationDisplayName(organization.tenantId),
|
||||
objectIdOfISVDemoUsageServicePrincipal =
|
||||
AzureADGraphAPIUtil.GetObjectIdOfServicePrincipalInOrganization(organization.tenantId, ConfigurationManager.AppSettings["ida:ClientID"])
|
||||
});
|
||||
}
|
||||
}
|
||||
return organizations;
|
||||
}
|
||||
public static List<Subscription> GetUserSubscriptions(string organizationId)
|
||||
{
|
||||
List<Subscription> subscriptions = null;
|
||||
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId),
|
||||
new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result =
|
||||
authContext.AcquireTokenSilent(
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
subscriptions = new List<Subscription>();
|
||||
|
||||
// Get subscriptions to which the user has some kind of access
|
||||
string requestUrl = string.Format("{0}/subscriptions?api-version={1}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"],
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var subscriptionsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var subscription in subscriptionsResult)
|
||||
subscriptions.Add(new Subscription()
|
||||
{
|
||||
Id = subscription.subscriptionId,
|
||||
DisplayName = subscription.displayName,
|
||||
OrganizationId = organizationId
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
//ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
// ConfigurationManager.AppSettings["ida:Password"]);
|
||||
//// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
//AuthenticationContext authContext = new AuthenticationContext(
|
||||
// string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
//string resource = ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"];
|
||||
|
||||
|
||||
//AuthenticationResult result = authContext.AcquireToken(resource, credential.ClientId,
|
||||
// new UserCredential(signedInUserUniqueName));
|
||||
|
||||
////authContext.AcquireToken(resource,userAssertion:)
|
||||
|
||||
// //new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId)));
|
||||
|
||||
// //AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
// //new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
//subscriptions = new List<Subscription>();
|
||||
|
||||
//// Get subscriptions to which the user has some kind of access
|
||||
//string requestUrl = string.Format("{0}/subscriptions?api-version={1}", ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"],
|
||||
// ConfigurationManager.AppSettings["ida:AzureResourceManagerAPIVersion"]);
|
||||
|
||||
//// Make the GET request
|
||||
//HttpClient client = new HttpClient();
|
||||
//HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
//request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
//HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
//if (response.IsSuccessStatusCode)
|
||||
//{
|
||||
// string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
// var subscriptionsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
// foreach (var subscription in subscriptionsResult)
|
||||
// subscriptions.Add(new Subscription()
|
||||
// {
|
||||
// Id = subscription.subscriptionId,
|
||||
// DisplayName = subscription.displayName,
|
||||
// OrganizationId = organizationId
|
||||
// });
|
||||
//}
|
||||
}
|
||||
|
||||
return subscriptions;
|
||||
}
|
||||
public static string GetUsage(string subscriptionId, string organizationId)
|
||||
{
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
string UsageResponse = "";
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
//Making a call to the Azure Usage API for a set time frame with the input AzureSubID
|
||||
string requesturl = String.Format("https://management.azure.com/subscriptions/{0}/providers/Microsoft.Commerce/UsageAggregates?api-version=2015-06-01-preview&reportedstartTime=2015-05-15+00%3a00%3a00Z&reportedEndTime=2015-05-16+00%3a00%3a00Z", subscriptionId);
|
||||
|
||||
//Crafting the HTTP call
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requesturl);
|
||||
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + result.AccessToken);
|
||||
request.ContentType = "application/json";
|
||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||
Console.WriteLine(response.StatusDescription);
|
||||
Stream receiveStream = response.GetResponseStream();
|
||||
|
||||
// Pipes the stream to a higher level stream reader with the required encoding format.
|
||||
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
|
||||
UsageResponse = readStream.ReadToEnd();
|
||||
}
|
||||
catch { }
|
||||
|
||||
return UsageResponse;
|
||||
}
|
||||
public static bool UserCanManageAccessForSubscription(string subscriptionId, string organizationId)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
|
||||
// Get permissions of the user on the subscription
|
||||
string requestUrl = string.Format("{0}/subscriptions/{1}/providers/microsoft.authorization/permissions?api-version={2}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], subscriptionId, ConfigurationManager.AppSettings["ida:ARMAuthorizationPermissionsAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of Actions and NotActions
|
||||
// actions notActions
|
||||
// ------- ----------
|
||||
// {*} {Microsoft.Authorization/*/Write, Microsoft.Authorization/*/Delete}
|
||||
// {*/read} {}
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var permissionsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var permissions in permissionsResult)
|
||||
{
|
||||
bool permissionMatch = false;
|
||||
foreach (string action in permissions.actions)
|
||||
{
|
||||
var actionPattern = "^" + Regex.Escape(action.ToLower()).Replace("\\*", ".*") + "$";
|
||||
permissionMatch = Regex.IsMatch("microsoft.authorization/roleassignments/write", actionPattern);
|
||||
if (permissionMatch) break;
|
||||
}
|
||||
// if one of the actions match, check that the NotActions don't
|
||||
if (permissionMatch)
|
||||
{
|
||||
foreach (string notAction in permissions.notActions)
|
||||
{
|
||||
var notActionPattern = "^" + Regex.Escape(notAction.ToLower()).Replace("\\*", ".*") + "$";
|
||||
if (Regex.IsMatch("microsoft.authorization/roleassignments/write", notActionPattern))
|
||||
permissionMatch = false;
|
||||
if (!permissionMatch) break;
|
||||
}
|
||||
}
|
||||
if (permissionMatch)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return ret;
|
||||
}
|
||||
public static bool ServicePrincipalHasReadAccessToSubscription(string subscriptionId, string organizationId)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire App Only Access Token to call Azure Resource Manager - Client Credential OAuth Flow
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId));
|
||||
AuthenticationResult result = authContext.AcquireToken(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential);
|
||||
|
||||
|
||||
// Get permissions of the app on the subscription
|
||||
string requestUrl = string.Format("{0}/subscriptions/{1}/providers/microsoft.authorization/permissions?api-version={2}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], subscriptionId, ConfigurationManager.AppSettings["ida:ARMAuthorizationPermissionsAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of Actions and NotActions
|
||||
// actions notActions
|
||||
// ------- ----------
|
||||
// {*} {Microsoft.Authorization/*/Write, Microsoft.Authorization/*/Delete}
|
||||
// {*/read} {}
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var permissionsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var permissions in permissionsResult)
|
||||
{
|
||||
bool permissionMatch = false;
|
||||
foreach (string action in permissions.actions)
|
||||
if (action.Equals("*/read", StringComparison.CurrentCultureIgnoreCase) || action.Equals("*", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
permissionMatch = true;
|
||||
break;
|
||||
}
|
||||
// if one of the actions match, check that the NotActions don't
|
||||
if (permissionMatch)
|
||||
{
|
||||
foreach (string notAction in permissions.notActions)
|
||||
if (notAction.Equals("*", StringComparison.CurrentCultureIgnoreCase) || notAction.EndsWith("/read", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
permissionMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (permissionMatch)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return ret;
|
||||
}
|
||||
public static void GrantRoleToServicePrincipalOnSubscription(string objectId, string subscriptionId, string organizationId)
|
||||
{
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
|
||||
// Create role assignment for application on the subscription
|
||||
string roleAssignmentId = Guid.NewGuid().ToString();
|
||||
string roleDefinitionId = GetRoleId(ConfigurationManager.AppSettings["ida:RequiredARMRoleOnSubscription"], subscriptionId, organizationId);
|
||||
|
||||
string requestUrl = string.Format("{0}/subscriptions/{1}/providers/microsoft.authorization/roleassignments/{2}?api-version={3}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], subscriptionId, roleAssignmentId,
|
||||
ConfigurationManager.AppSettings["ida:ARMAuthorizationRoleAssignmentsAPIVersion"]);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
StringContent content = new StringContent("{\"properties\": {\"roleDefinitionId\":\"" + roleDefinitionId + "\",\"principalId\":\"" + objectId + "\"}}");
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
request.Content = content;
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
public static void RevokeRoleFromServicePrincipalOnSubscription(string objectId, string subscriptionId, string organizationId)
|
||||
{
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
|
||||
// Get rolesAssignments to application on the subscription
|
||||
string requestUrl = string.Format("{0}/subscriptions/{1}/providers/microsoft.authorization/roleassignments?api-version={2}&$filter=principalId eq '{3}'",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], subscriptionId,
|
||||
ConfigurationManager.AppSettings["ida:ARMAuthorizationRoleAssignmentsAPIVersion"], objectId);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of role assignments
|
||||
// properties id type name
|
||||
// ---------- -- ---- ----
|
||||
// @{roleDefinitionId=/subscriptions/e91d47... /subscriptions/e91d47c4-76f3-4271-a796-2... Microsoft.Authorization/roleAssignments 9db2cdc1-2971-42fe-bd21-c7c4ead4b1b8
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var roleAssignmentsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
//remove all role assignments
|
||||
foreach (var roleAssignment in roleAssignmentsResult)
|
||||
{
|
||||
requestUrl = string.Format("{0}{1}?api-version={2}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], roleAssignment.id,
|
||||
ConfigurationManager.AppSettings["ida:ARMAuthorizationRoleAssignmentsAPIVersion"]);
|
||||
request = new HttpRequestMessage(HttpMethod.Delete, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
response = client.SendAsync(request).Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
public static string GetRoleId(string roleName, string subscriptionId, string organizationId)
|
||||
{
|
||||
string roleId = null;
|
||||
|
||||
string signedInUserUniqueName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#')[ClaimsPrincipal.Current.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
|
||||
|
||||
try
|
||||
{
|
||||
// Aquire Access Token to call Azure Resource Manager
|
||||
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
|
||||
ConfigurationManager.AppSettings["ida:Password"]);
|
||||
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB
|
||||
AuthenticationContext authContext = new AuthenticationContext(
|
||||
string.Format(ConfigurationManager.AppSettings["ida:Authority"], organizationId), new ADALTokenCache(signedInUserUniqueName));
|
||||
AuthenticationResult result = authContext.AcquireTokenSilent(ConfigurationManager.AppSettings["ida:AzureResourceManagerIdentifier"], credential,
|
||||
new UserIdentifier(signedInUserUniqueName, UserIdentifierType.RequiredDisplayableId));
|
||||
|
||||
// Get subscriptions to which the user has some kind of access
|
||||
string requestUrl = string.Format("{0}/subscriptions/{1}/providers/Microsoft.Authorization/roleDefinitions?api-version={2}",
|
||||
ConfigurationManager.AppSettings["ida:AzureResourceManagerUrl"], subscriptionId,
|
||||
ConfigurationManager.AppSettings["ida:ARMAuthorizationRoleDefinitionsAPIVersion"]);
|
||||
|
||||
// Make the GET request
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
|
||||
// Endpoint returns JSON with an array of roleDefinition Objects
|
||||
// properties id type name
|
||||
// ---------- -- ---- ----
|
||||
// @{roleName=Contributor; type=BuiltInRole... /subscriptions/e91d47c4-76f3-4271-a796-2... Microsoft.Authorization/roleDefinitions b24988ac-6180-42a0-ab88-20f7382dd24c
|
||||
// @{roleName=Owner; type=BuiltInRole; desc... /subscriptions/e91d47c4-76f3-4271-a796-2... Microsoft.Authorization/roleDefinitions 8e3af657-a8ff-443c-a75c-2fe8c4bcb635
|
||||
// @{roleName=Reader; type=BuiltInRole; des... /subscriptions/e91d47c4-76f3-4271-a796-2... Microsoft.Authorization/roleDefinitions acdd72a7-3385-48ef-bd42-f606fba81ae7
|
||||
// ...
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var roleDefinitionsResult = (Json.Decode(responseContent)).value;
|
||||
|
||||
foreach (var roleDefinition in roleDefinitionsResult)
|
||||
if ((roleDefinition.properties.roleName as string).Equals(roleName, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
roleId = roleDefinition.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return roleId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
body {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Set padding to keep content from hitting the edges */
|
||||
.body-content {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/* Override the default bootstrap behavior where horizontal description lists
|
||||
will truncate terms that are too long to fit in the left column
|
||||
*/
|
||||
.dl-horizontal dt {
|
||||
white-space: normal;
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using Microsoft.Owin.Security;
|
||||
using Microsoft.Owin.Security.Cookies;
|
||||
using Microsoft.Owin.Security.OpenIdConnect;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace ISVDemoUsage.Controllers
|
||||
{
|
||||
public class AccountController : Controller
|
||||
{
|
||||
// sign in triggered from the Sign In gesture in the UI
|
||||
// configured to return to the home page upon successful authentication
|
||||
public void SignIn(string directoryName = "common", bool isMSA = false)
|
||||
{
|
||||
if (!Request.IsAuthenticated)
|
||||
{
|
||||
// note configuration (keys, etc…) will not necessarily understand this authority.
|
||||
HttpContext.GetOwinContext().Environment.Add("Authority", string.Format(ConfigurationManager.AppSettings["ida:Authority"] + "OAuth2/Authorize", directoryName));
|
||||
if (isMSA) HttpContext.GetOwinContext().Environment.Add("DomainHint", "live.com");
|
||||
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = this.Url.Action("Index", "Home") }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
|
||||
}
|
||||
}
|
||||
// sign out triggered from the Sign Out gesture in the UI
|
||||
// after sign out, it redirects to Post_Logout_Redirect_Uri (as set in Startup.Auth.cs)
|
||||
public void SignOut()
|
||||
{
|
||||
HttpContext.GetOwinContext().Authentication.SignOut(
|
||||
OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
using ISVDemoUsage.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ISVDemoUsage.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private DataAccess db = new DataAccess();
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
HomeIndexViewModel model = null;
|
||||
|
||||
if (ClaimsPrincipal.Current.Identity.IsAuthenticated)
|
||||
{
|
||||
model = new HomeIndexViewModel();
|
||||
model.UserOrganizations = new Dictionary<string,Organization>();
|
||||
model.UserSubscriptions = new Dictionary<string,Subscription>();
|
||||
model.UserCanManageAccessForSubscriptions = new List<string>();
|
||||
model.DisconnectedUserOrganizations = new List<string>();
|
||||
|
||||
var orgnaizations = AzureResourceManagerUtil.GetUserOrganizations();
|
||||
foreach (Organization org in orgnaizations)
|
||||
{
|
||||
model.UserOrganizations.Add(org.Id, org);
|
||||
var subscriptions = AzureResourceManagerUtil.GetUserSubscriptions(org.Id);
|
||||
|
||||
if (subscriptions != null)
|
||||
{
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
|
||||
Subscription s = db.Subscriptions.Find(subscription.Id);
|
||||
if (s != null)
|
||||
{
|
||||
subscription.IsConnected = true;
|
||||
subscription.ConnectedOn = s.ConnectedOn;
|
||||
subscription.ConnectedBy = s.ConnectedBy;
|
||||
subscription.AzureAccessNeedsToBeRepaired = AzureResourceManagerUtil.ServicePrincipalHasReadAccessToSubscription(subscription.Id, org.Id);
|
||||
subscription.UsageString = AzureResourceManagerUtil.GetUsage(s.Id, org.Id);
|
||||
//Deserialize the usage response into the usagePayload object
|
||||
subscription.usagePayload = JsonConvert.DeserializeObject<UsagePayload>(subscription.UsageString);
|
||||
List<UsageAggregate> UsageAggregateList = subscription.usagePayload.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
subscription.IsConnected = false;
|
||||
}
|
||||
model.UserSubscriptions.Add(subscription.Id, subscription);
|
||||
|
||||
if (AzureResourceManagerUtil.UserCanManageAccessForSubscription(subscription.Id, org.Id))
|
||||
model.UserCanManageAccessForSubscriptions.Add(subscription.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
model.DisconnectedUserOrganizations.Add(org.Id);
|
||||
}
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public ActionResult Contact()
|
||||
{
|
||||
ViewBag.Message = "Your contact page.";
|
||||
|
||||
return View();
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
db.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
using ISVDemoUsage.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Claims;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace ISVDemoUsage.Controllers
|
||||
{
|
||||
public class SubscriptionController : Controller
|
||||
{
|
||||
private DataAccess db = new DataAccess();
|
||||
|
||||
public ActionResult Connect([Bind(Include = "Id, OrganizationId")] Subscription subscription, string servicePrincipalObjectId)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
AzureResourceManagerUtil.GrantRoleToServicePrincipalOnSubscription(servicePrincipalObjectId, subscription.Id, subscription.OrganizationId);
|
||||
if (AzureResourceManagerUtil.ServicePrincipalHasReadAccessToSubscription(subscription.Id, subscription.OrganizationId))
|
||||
{
|
||||
subscription.ConnectedBy = (System.Security.Claims.ClaimsPrincipal.Current).FindFirst(ClaimTypes.Name).Value;
|
||||
subscription.ConnectedOn = DateTime.Now;
|
||||
|
||||
db.Subscriptions.Add(subscription);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
public ActionResult Disconnect([Bind(Include = "Id, OrganizationId")] Subscription subscription, string servicePrincipalObjectId)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
AzureResourceManagerUtil.RevokeRoleFromServicePrincipalOnSubscription(servicePrincipalObjectId, subscription.Id, subscription.OrganizationId);
|
||||
|
||||
Subscription s = db.Subscriptions.Find(subscription.Id);
|
||||
if (s != null)
|
||||
{
|
||||
db.Subscriptions.Remove(s);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
public ActionResult RepairAccess([Bind(Include = "Id, OrganizationId")] Subscription subscription, string servicePrincipalObjectId)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
AzureResourceManagerUtil.RevokeRoleFromServicePrincipalOnSubscription(servicePrincipalObjectId, subscription.Id, subscription.OrganizationId);
|
||||
AzureResourceManagerUtil.GrantRoleToServicePrincipalOnSubscription(servicePrincipalObjectId, subscription.Id, subscription.OrganizationId);
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
db.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using ISVDemoUsage.Models;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class DataAccess : DbContext
|
||||
{
|
||||
public DataAccess() : base("DataAccess") { }
|
||||
public DbSet<Subscription> Subscriptions { get; set; }
|
||||
public DbSet<PerUserTokenCache> PerUserTokenCacheList { get; set; }
|
||||
}
|
||||
// public class DataAccessInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<DataAccess>
|
||||
public class DataAccessInitializer : System.Data.Entity.CreateDatabaseIfNotExists<DataAccess>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<%@ Application Codebehind="Global.asax.cs" Inherits="ISVDemoUsage.MvcApplication" Language="C#" %>
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Optimization;
|
||||
using System.Web.Routing;
|
||||
using System.Data.Entity;
|
||||
using System.Web.Helpers;
|
||||
using System.IdentityModel.Claims;
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public class MvcApplication : System.Web.HttpApplication
|
||||
{
|
||||
protected void Application_Start()
|
||||
{
|
||||
AreaRegistration.RegisterAllAreas();
|
||||
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
|
||||
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||
// Database.SetInitializer<DataAccess>(new DataAccessInitializer());
|
||||
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ISVDemoUsage</RootNamespace>
|
||||
<AssemblyName>ISVDemoUsage</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
|
||||
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
|
||||
<IISExpressUseClassicPipelineMode>false</IISExpressUseClassicPipelineMode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="EntityFramework">
|
||||
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework.SqlServer">
|
||||
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.13.112191810\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.13.112191810\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IdentityModel.Protocol.Extensions">
|
||||
<HintPath>..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.1\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.Cookies">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security.OpenIdConnect">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.OpenIdConnect.3.0.0\lib\net45\Microsoft.Owin.Security.OpenIdConnect.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IdentityModel" />
|
||||
<Reference Include="System.IdentityModel.Tokens.Jwt">
|
||||
<HintPath>..\packages\System.IdentityModel.Tokens.Jwt.4.0.1\lib\net45\System.IdentityModel.Tokens.Jwt.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http">
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest">
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.0\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.0\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Optimization">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.0\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.0\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.0\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.0\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="WebGrease">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\WebGrease.1.5.2\lib\WebGrease.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Antlr3.Runtime">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ADALTokenCache.cs" />
|
||||
<Compile Include="App_Start\BundleConfig.cs" />
|
||||
<Compile Include="App_Start\FilterConfig.cs" />
|
||||
<Compile Include="App_Start\RouteConfig.cs" />
|
||||
<Compile Include="App_Start\Startup.Auth.cs" />
|
||||
<Compile Include="AzureADGraphAPIUtil.cs" />
|
||||
<Compile Include="AzureResourceManagerUtil.cs" />
|
||||
<Compile Include="Controllers\AccountController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\SubscriptionController.cs" />
|
||||
<Compile Include="DataAccess.cs" />
|
||||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\InfoFields.cs" />
|
||||
<Compile Include="Models\InstanceData.cs" />
|
||||
<Compile Include="Models\Organization.cs" />
|
||||
<Compile Include="Models\PerUserTokenCache.cs" />
|
||||
<Compile Include="Models\Properties.cs" />
|
||||
<Compile Include="Models\Subscription.cs" />
|
||||
<Compile Include="Models\UsageAggregate.cs" />
|
||||
<Compile Include="Models\UsagePayload.cs" />
|
||||
<Compile Include="Models\ViewModels.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Startup.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="App_Data\DataAccess.mdf" />
|
||||
<Content Include="App_Data\DataAccess_log.ldf">
|
||||
<DependentUpon>DataAccess.mdf</DependentUpon>
|
||||
</Content>
|
||||
<Content Include="Content\bootstrap.css" />
|
||||
<Content Include="Content\bootstrap.min.css" />
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.svg" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Content\Site.css" />
|
||||
<Content Include="Images\azure.png" />
|
||||
<Content Include="Images\directory.png" />
|
||||
<Content Include="Images\msa.png" />
|
||||
<Content Include="Images\org.png" />
|
||||
<Content Include="Scripts\bootstrap.js" />
|
||||
<Content Include="Scripts\bootstrap.min.js" />
|
||||
<None Include="Scripts\jquery-1.10.2.intellisense.js" />
|
||||
<Content Include="Scripts\jquery-1.10.2.js" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.js" />
|
||||
<None Include="Scripts\jquery.validate-vsdoc.js" />
|
||||
<Content Include="Scripts\jquery.validate.js" />
|
||||
<Content Include="Scripts\jquery.validate.min.js" />
|
||||
<Content Include="Scripts\jquery.validate.unobtrusive.js" />
|
||||
<Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
|
||||
<Content Include="Scripts\modernizr-2.6.2.js" />
|
||||
<Content Include="Scripts\respond.js" />
|
||||
<Content Include="Scripts\respond.min.js" />
|
||||
<Content Include="Scripts\_references.js" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Web.Debug.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</Content>
|
||||
<Content Include="Web.Release.config">
|
||||
<DependentUpon>Web.config</DependentUpon>
|
||||
</Content>
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Views\_ViewStart.cshtml" />
|
||||
<Content Include="Views\Shared\Error.cshtml" />
|
||||
<Content Include="Views\Shared\_Layout.cshtml" />
|
||||
<Content Include="Views\Home\Contact.cshtml" />
|
||||
<Content Include="Views\Home\Index.cshtml" />
|
||||
<Content Include="Scripts\jquery-1.10.2.min.map" />
|
||||
<Content Include="Views\Shared\_LoginPartial.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="fonts\glyphicons-halflings-regular.woff" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.ttf" />
|
||||
<Content Include="fonts\glyphicons-halflings-regular.eot" />
|
||||
<Content Include="packages.config" />
|
||||
<None Include="Project_Readme.html" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\PublishProfiles\" />
|
||||
<Folder Include="Views\Subscription\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>62080</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:62080/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target> -->
|
||||
</Project>
|
|
@ -1,38 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<NameOfLastUsedPublishProfile>vipswapper</NameOfLastUsedPublishProfile>
|
||||
<WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
|
||||
<WebStackScaffolding_IsLayoutPageSelected>True</WebStackScaffolding_IsLayoutPageSelected>
|
||||
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
|
||||
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>True</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
|
||||
<WebStackScaffolding_LayoutPageFile />
|
||||
<WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
|
||||
<ProjectView>ShowAllFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>True</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>True</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>True</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/Images/azure.png
До Ширина: | Высота: | Размер: 759 B |
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/Images/directory.png
До Ширина: | Высота: | Размер: 177 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/Images/msa.png
До Ширина: | Высота: | Размер: 3.4 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/Images/org.png
До Ширина: | Высота: | Размер: 9.0 KiB |
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class InfoFields
|
||||
{
|
||||
public string meteredRegion { get; set; }
|
||||
public string meteredService { get; set; }
|
||||
public string project { get; set; }
|
||||
public string meteredServiceType { get; set; }
|
||||
public string serviceInfo1 { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class InstanceData
|
||||
{
|
||||
public string resourceUri { get; set; }
|
||||
|
||||
public IDictionary<string, string> tags { get; set; }
|
||||
|
||||
public IDictionary<string, string> additionalInfo { get; set; }
|
||||
|
||||
public string location { get; set; }
|
||||
|
||||
public string partNumber { get; set; }
|
||||
|
||||
public string orderNumber { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class Organization
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string objectIdOfISVDemoUsageServicePrincipal { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class PerUserTokenCache
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string webUserUniqueId { get; set; }
|
||||
public byte[] cacheBits { get; set; }
|
||||
public DateTime LastWrite { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class Properties
|
||||
{
|
||||
public string subscriptionId { get; set; }
|
||||
public string usageStartTime { get; set; }
|
||||
public string usageEndTime { get; set; }
|
||||
public string meterId { get; set; }
|
||||
public InfoFields infoFields { get; set; }
|
||||
|
||||
[JsonProperty("instanceData")]
|
||||
public string instanceDataRaw { get; set; }
|
||||
|
||||
public InstanceDataType InstanceData
|
||||
{
|
||||
get
|
||||
{
|
||||
return JsonConvert.DeserializeObject<InstanceDataType>(instanceDataRaw.Replace("\\\"", ""));
|
||||
}
|
||||
}
|
||||
public double quantity { get; set; }
|
||||
public string unit { get; set; }
|
||||
public string meterName { get; set; }
|
||||
public string meterCategory { get; set; }
|
||||
public string meterSubCategory { get; set; }
|
||||
public string meterRegion { get; set; }
|
||||
}
|
||||
|
||||
public class InstanceDataType
|
||||
{
|
||||
[JsonProperty("Microsoft.Resources")]
|
||||
public MicrosoftResourcesDataType MicrosoftResources { get; set; }
|
||||
}
|
||||
|
||||
public class MicrosoftResourcesDataType
|
||||
{
|
||||
public string resourceUri { get; set; }
|
||||
|
||||
public IDictionary<string, string> tags { get; set; }
|
||||
|
||||
public IDictionary<string, string> additionalInfo { get; set; }
|
||||
|
||||
public string location { get; set; }
|
||||
|
||||
public string partNumber { get; set; }
|
||||
|
||||
public string orderNumber { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class Subscription
|
||||
{
|
||||
public string Id { get; set; }
|
||||
[NotMapped]
|
||||
public string DisplayName { get; set; }
|
||||
[NotMapped]
|
||||
public string OrganizationId { get; set; }
|
||||
[NotMapped]
|
||||
public bool IsConnected { get; set; }
|
||||
public DateTime ConnectedOn { get; set; }
|
||||
public string ConnectedBy { get; set; }
|
||||
[NotMapped]
|
||||
public UsagePayload usagePayload { get; set; }
|
||||
public string UsageString { get; set; }
|
||||
public bool AzureAccessNeedsToBeRepaired { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class UsageAggregate
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string name { get; set; }
|
||||
public string type { get; set; }
|
||||
public Properties properties { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class UsagePayload
|
||||
{
|
||||
public List<UsageAggregate> value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace ISVDemoUsage.Models
|
||||
{
|
||||
public class HomeIndexViewModel
|
||||
{
|
||||
public Dictionary<string, Organization> UserOrganizations { get; set; }
|
||||
public Dictionary<string, Subscription> UserSubscriptions { get; set; }
|
||||
public List<string> UserCanManageAccessForSubscriptions { get; set; }
|
||||
public List<string> DisconnectedUserOrganizations { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ISV Demo for Usage API</title>
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
color: #505050;
|
||||
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
|
||||
margin: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #efefef;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 48px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0 30px;
|
||||
line-height: 150px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
background: #969696;
|
||||
padding: 0 30px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
#main {
|
||||
padding: 5px 30px;
|
||||
}
|
||||
|
||||
.section {
|
||||
width: 21.7%;
|
||||
float: left;
|
||||
margin: 0 0 0 4%;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid silver;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section.first {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.section.first h2 {
|
||||
font-size: 24px;
|
||||
text-transform: none;
|
||||
margin-bottom: 25px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.section.first li {
|
||||
border-top: 1px solid silver;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.section.last {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #267cb2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="header">
|
||||
<h1>ISV Demo for Usage</h1>
|
||||
<p>Congratulations! You've created a project</p>
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<div class="section first">
|
||||
<h2>This application consists of:</h2>
|
||||
<ul>
|
||||
<li>Sample pages showing basic nav between Home, About, and Contact</li>
|
||||
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=320754">Bootstrap</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320755">Authentication</a>, if selected, shows how to register and sign in</li>
|
||||
<li>ASP.NET features managed using <a href="http://go.microsoft.com/fwlink/?LinkID=320756">NuGet</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Customize app</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320757">Get started with ASP.NET MVC</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320758">Change the site's theme</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320759">Add more libraries using NuGet</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320760">Configure authentication</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320761">Customize information about the website users</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320762">Get information from social providers</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320763">Add HTTP services using ASP.NET Web API</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320764">Secure your web API</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320765">Add real-time web with ASP.NET SignalR</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320766">Add components using Scaffolding</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320767">Test your app with Browser Link</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320768">Share your project</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Deploy</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320769">Ensure your app is ready for production</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320770">Windows Azure</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320771">Hosting providers</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section last">
|
||||
<h2>Get help</h2>
|
||||
<ul>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320772">Get help</a></li>
|
||||
<li><a href="http://go.microsoft.com/fwlink/?LinkID=320773">Get more templates</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
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("ISVDemoUsage")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ISVDemoUsage")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[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("91b64be9-8d73-4706-be16-49978074dcdc")]
|
||||
|
||||
// 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")]
|
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/Scripts/_references.js
|
@ -1,410 +0,0 @@
|
|||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*!
|
||||
** Unobtrusive validation support library for jQuery and jQuery Validate
|
||||
** Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
*/
|
||||
|
||||
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
|
||||
/*global document: false, jQuery: false */
|
||||
|
||||
(function ($) {
|
||||
var $jQval = $.validator,
|
||||
adapters,
|
||||
data_validation = "unobtrusiveValidation";
|
||||
|
||||
function setValidationValues(options, ruleName, value) {
|
||||
options.rules[ruleName] = value;
|
||||
if (options.message) {
|
||||
options.messages[ruleName] = options.message;
|
||||
}
|
||||
}
|
||||
|
||||
function splitAndTrim(value) {
|
||||
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
|
||||
}
|
||||
|
||||
function escapeAttributeValue(value) {
|
||||
// As mentioned on http://api.jquery.com/category/selectors/
|
||||
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
|
||||
}
|
||||
|
||||
function getModelPrefix(fieldName) {
|
||||
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
function appendModelPrefix(value, prefix) {
|
||||
if (value.indexOf("*.") === 0) {
|
||||
value = value.replace("*.", prefix);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function onError(error, inputElement) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
|
||||
|
||||
container.removeClass("field-validation-valid").addClass("field-validation-error");
|
||||
error.data("unobtrusiveContainer", container);
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
error.removeClass("input-validation-error").appendTo(container);
|
||||
}
|
||||
else {
|
||||
error.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onErrors(event, validator) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-summary=true]"),
|
||||
list = container.find("ul");
|
||||
|
||||
if (list && list.length && validator.errorList.length) {
|
||||
list.empty();
|
||||
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
|
||||
|
||||
$.each(validator.errorList, function () {
|
||||
$("<li />").html(this.message).appendTo(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onSuccess(error) { // 'this' is the form element
|
||||
var container = error.data("unobtrusiveContainer"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
|
||||
|
||||
if (container) {
|
||||
container.addClass("field-validation-valid").removeClass("field-validation-error");
|
||||
error.removeData("unobtrusiveContainer");
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onReset(event) { // 'this' is the form element
|
||||
var $form = $(this);
|
||||
$form.data("validator").resetForm();
|
||||
$form.find(".validation-summary-errors")
|
||||
.addClass("validation-summary-valid")
|
||||
.removeClass("validation-summary-errors");
|
||||
$form.find(".field-validation-error")
|
||||
.addClass("field-validation-valid")
|
||||
.removeClass("field-validation-error")
|
||||
.removeData("unobtrusiveContainer")
|
||||
.find(">*") // If we were using valmsg-replace, get the underlying error
|
||||
.removeData("unobtrusiveContainer");
|
||||
}
|
||||
|
||||
function validationInfo(form) {
|
||||
var $form = $(form),
|
||||
result = $form.data(data_validation),
|
||||
onResetProxy = $.proxy(onReset, form),
|
||||
defaultOptions = $jQval.unobtrusive.options || {},
|
||||
execInContext = function (name, args) {
|
||||
var func = defaultOptions[name];
|
||||
func && $.isFunction(func) && func.apply(form, args);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = {
|
||||
options: { // options structure passed to jQuery Validate's validate() method
|
||||
errorClass: defaultOptions.errorClass || "input-validation-error",
|
||||
errorElement: defaultOptions.errorElement || "span",
|
||||
errorPlacement: function () {
|
||||
onError.apply(form, arguments);
|
||||
execInContext("errorPlacement", arguments);
|
||||
},
|
||||
invalidHandler: function () {
|
||||
onErrors.apply(form, arguments);
|
||||
execInContext("invalidHandler", arguments);
|
||||
},
|
||||
messages: {},
|
||||
rules: {},
|
||||
success: function () {
|
||||
onSuccess.apply(form, arguments);
|
||||
execInContext("success", arguments);
|
||||
}
|
||||
},
|
||||
attachValidation: function () {
|
||||
$form
|
||||
.off("reset." + data_validation, onResetProxy)
|
||||
.on("reset." + data_validation, onResetProxy)
|
||||
.validate(this.options);
|
||||
},
|
||||
validate: function () { // a validation function that is called by unobtrusive Ajax
|
||||
$form.validate();
|
||||
return $form.valid();
|
||||
}
|
||||
};
|
||||
$form.data(data_validation, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$jQval.unobtrusive = {
|
||||
adapters: [],
|
||||
|
||||
parseElement: function (element, skipAttach) {
|
||||
/// <summary>
|
||||
/// Parses a single HTML element for unobtrusive validation attributes.
|
||||
/// </summary>
|
||||
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
|
||||
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
|
||||
/// validation to the form. If parsing just this single element, you should specify true.
|
||||
/// If parsing several elements, you should specify false, and manually attach the validation
|
||||
/// to the form when you are finished. The default is false.</param>
|
||||
var $element = $(element),
|
||||
form = $element.parents("form")[0],
|
||||
valInfo, rules, messages;
|
||||
|
||||
if (!form) { // Cannot do client-side validation without a form
|
||||
return;
|
||||
}
|
||||
|
||||
valInfo = validationInfo(form);
|
||||
valInfo.options.rules[element.name] = rules = {};
|
||||
valInfo.options.messages[element.name] = messages = {};
|
||||
|
||||
$.each(this.adapters, function () {
|
||||
var prefix = "data-val-" + this.name,
|
||||
message = $element.attr(prefix),
|
||||
paramValues = {};
|
||||
|
||||
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
|
||||
prefix += "-";
|
||||
|
||||
$.each(this.params, function () {
|
||||
paramValues[this] = $element.attr(prefix + this);
|
||||
});
|
||||
|
||||
this.adapt({
|
||||
element: element,
|
||||
form: form,
|
||||
message: message,
|
||||
params: paramValues,
|
||||
rules: rules,
|
||||
messages: messages
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(rules, { "__dummy__": true });
|
||||
|
||||
if (!skipAttach) {
|
||||
valInfo.attachValidation();
|
||||
}
|
||||
},
|
||||
|
||||
parse: function (selector) {
|
||||
/// <summary>
|
||||
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
|
||||
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
|
||||
/// attribute values.
|
||||
/// </summary>
|
||||
/// <param name="selector" type="String">Any valid jQuery selector.</param>
|
||||
|
||||
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
|
||||
// element with data-val=true
|
||||
var $selector = $(selector),
|
||||
$forms = $selector.parents()
|
||||
.addBack()
|
||||
.filter("form")
|
||||
.add($selector.find("form"))
|
||||
.has("[data-val=true]");
|
||||
|
||||
$selector.find("[data-val=true]").each(function () {
|
||||
$jQval.unobtrusive.parseElement(this, true);
|
||||
});
|
||||
|
||||
$forms.each(function () {
|
||||
var info = validationInfo(this);
|
||||
if (info) {
|
||||
info.attachValidation();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
adapters = $jQval.unobtrusive.adapters;
|
||||
|
||||
adapters.add = function (adapterName, params, fn) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
|
||||
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
|
||||
/// mmmm is the parameter name).</param>
|
||||
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
|
||||
/// attributes into jQuery Validate rules and/or messages.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
if (!fn) { // Called with no params, just a function
|
||||
fn = params;
|
||||
params = [];
|
||||
}
|
||||
this.push({ name: adapterName, params: params, adapt: fn });
|
||||
return this;
|
||||
};
|
||||
|
||||
adapters.addBool = function (adapterName, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has no parameter values.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, true);
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
|
||||
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a minimum value.</param>
|
||||
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a maximum value.</param>
|
||||
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
|
||||
/// have both a minimum and maximum value.</param>
|
||||
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the minimum value. The default is "min".</param>
|
||||
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the maximum value. The default is "max".</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
|
||||
var min = options.params.min,
|
||||
max = options.params.max;
|
||||
|
||||
if (min && max) {
|
||||
setValidationValues(options, minMaxRuleName, [min, max]);
|
||||
}
|
||||
else if (min) {
|
||||
setValidationValues(options, minRuleName, min);
|
||||
}
|
||||
else if (max) {
|
||||
setValidationValues(options, maxRuleName, max);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has a single value.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
|
||||
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
|
||||
/// The default is "val".</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [attribute || "val"], function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
|
||||
});
|
||||
};
|
||||
|
||||
$jQval.addMethod("__dummy__", function (value, element, params) {
|
||||
return true;
|
||||
});
|
||||
|
||||
$jQval.addMethod("regex", function (value, element, params) {
|
||||
var match;
|
||||
if (this.optional(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match = new RegExp(params).exec(value);
|
||||
return (match && (match.index === 0) && (match[0].length === value.length));
|
||||
});
|
||||
|
||||
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
|
||||
var match;
|
||||
if (nonalphamin) {
|
||||
match = value.match(/\W/g);
|
||||
match = match && match.length >= nonalphamin;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
if ($jQval.methods.extension) {
|
||||
adapters.addSingleVal("accept", "mimtype");
|
||||
adapters.addSingleVal("extension", "extension");
|
||||
} else {
|
||||
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
|
||||
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
|
||||
// validating the extension, and ignore mime-type validations as they are not supported.
|
||||
adapters.addSingleVal("extension", "extension", "accept");
|
||||
}
|
||||
|
||||
adapters.addSingleVal("regex", "pattern");
|
||||
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
|
||||
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
|
||||
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
|
||||
adapters.add("equalto", ["other"], function (options) {
|
||||
var prefix = getModelPrefix(options.element.name),
|
||||
other = options.params.other,
|
||||
fullOtherName = appendModelPrefix(other, prefix),
|
||||
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
|
||||
|
||||
setValidationValues(options, "equalTo", element);
|
||||
});
|
||||
adapters.add("required", function (options) {
|
||||
// jQuery Validate equates "required" with "mandatory" for checkbox elements
|
||||
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
|
||||
setValidationValues(options, "required", true);
|
||||
}
|
||||
});
|
||||
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
|
||||
var value = {
|
||||
url: options.params.url,
|
||||
type: options.params.type || "GET",
|
||||
data: {}
|
||||
},
|
||||
prefix = getModelPrefix(options.element.name);
|
||||
|
||||
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
|
||||
var paramName = appendModelPrefix(fieldName, prefix);
|
||||
value.data[paramName] = function () {
|
||||
return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val();
|
||||
};
|
||||
});
|
||||
|
||||
setValidationValues(options, "remote", value);
|
||||
});
|
||||
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
|
||||
if (options.params.min) {
|
||||
setValidationValues(options, "minlength", options.params.min);
|
||||
}
|
||||
if (options.params.nonalphamin) {
|
||||
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
|
||||
}
|
||||
if (options.params.regex) {
|
||||
setValidationValues(options, "regex", options.params.regex);
|
||||
}
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$jQval.unobtrusive.parse(document);
|
||||
});
|
||||
}(jQuery));
|
|
@ -1,340 +0,0 @@
|
|||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
window.matchMedia = window.matchMedia || (function(doc, undefined){
|
||||
|
||||
var bool,
|
||||
docElem = doc.documentElement,
|
||||
refNode = docElem.firstElementChild || docElem.firstChild,
|
||||
// fakeBody required for <FF4 when executed in <head>
|
||||
fakeBody = doc.createElement('body'),
|
||||
div = doc.createElement('div');
|
||||
|
||||
div.id = 'mq-test-1';
|
||||
div.style.cssText = "position:absolute;top:-100em";
|
||||
fakeBody.style.background = "none";
|
||||
fakeBody.appendChild(div);
|
||||
|
||||
return function(q){
|
||||
|
||||
div.innerHTML = '­<style media="'+q+'"> #mq-test-1 { width: 42px; }</style>';
|
||||
|
||||
docElem.insertBefore(fakeBody, refNode);
|
||||
bool = div.offsetWidth == 42;
|
||||
docElem.removeChild(fakeBody);
|
||||
|
||||
return { matches: bool, media: q };
|
||||
};
|
||||
|
||||
})(document);
|
||||
|
||||
|
||||
|
||||
|
||||
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
|
||||
(function( win ){
|
||||
//exposed namespace
|
||||
win.respond = {};
|
||||
|
||||
//define update even in native-mq-supporting browsers, to avoid errors
|
||||
respond.update = function(){};
|
||||
|
||||
//expose media query support flag for external use
|
||||
respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
|
||||
|
||||
//if media queries are supported, exit here
|
||||
if( respond.mediaQueriesSupported ){ return; }
|
||||
|
||||
//define vars
|
||||
var doc = win.document,
|
||||
docElem = doc.documentElement,
|
||||
mediastyles = [],
|
||||
rules = [],
|
||||
appendedEls = [],
|
||||
parsedSheets = {},
|
||||
resizeThrottle = 30,
|
||||
head = doc.getElementsByTagName( "head" )[0] || docElem,
|
||||
base = doc.getElementsByTagName( "base" )[0],
|
||||
links = head.getElementsByTagName( "link" ),
|
||||
requestQueue = [],
|
||||
|
||||
//loop stylesheets, send text content to translate
|
||||
ripCSS = function(){
|
||||
var sheets = links,
|
||||
sl = sheets.length,
|
||||
i = 0,
|
||||
//vars for loop:
|
||||
sheet, href, media, isCSS;
|
||||
|
||||
for( ; i < sl; i++ ){
|
||||
sheet = sheets[ i ],
|
||||
href = sheet.href,
|
||||
media = sheet.media,
|
||||
isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
|
||||
|
||||
//only links plz and prevent re-parsing
|
||||
if( !!href && isCSS && !parsedSheets[ href ] ){
|
||||
// selectivizr exposes css through the rawCssText expando
|
||||
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
|
||||
translate( sheet.styleSheet.rawCssText, href, media );
|
||||
parsedSheets[ href ] = true;
|
||||
} else {
|
||||
if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
|
||||
|| href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
|
||||
requestQueue.push( {
|
||||
href: href,
|
||||
media: media
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeRequests();
|
||||
},
|
||||
|
||||
//recurse through request queue, get css text
|
||||
makeRequests = function(){
|
||||
if( requestQueue.length ){
|
||||
var thisRequest = requestQueue.shift();
|
||||
|
||||
ajax( thisRequest.href, function( styles ){
|
||||
translate( styles, thisRequest.href, thisRequest.media );
|
||||
parsedSheets[ thisRequest.href ] = true;
|
||||
makeRequests();
|
||||
} );
|
||||
}
|
||||
},
|
||||
|
||||
//find media blocks in css text, convert to style blocks
|
||||
translate = function( styles, href, media ){
|
||||
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
|
||||
ql = qs && qs.length || 0,
|
||||
//try to get CSS path
|
||||
href = href.substring( 0, href.lastIndexOf( "/" )),
|
||||
repUrls = function( css ){
|
||||
return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
|
||||
},
|
||||
useMedia = !ql && media,
|
||||
//vars used in loop
|
||||
i = 0,
|
||||
j, fullq, thisq, eachq, eql;
|
||||
|
||||
//if path exists, tack on trailing slash
|
||||
if( href.length ){ href += "/"; }
|
||||
|
||||
//if no internal queries exist, but media attr does, use that
|
||||
//note: this currently lacks support for situations where a media attr is specified on a link AND
|
||||
//its associated stylesheet has internal CSS media queries.
|
||||
//In those cases, the media attribute will currently be ignored.
|
||||
if( useMedia ){
|
||||
ql = 1;
|
||||
}
|
||||
|
||||
|
||||
for( ; i < ql; i++ ){
|
||||
j = 0;
|
||||
|
||||
//media attr
|
||||
if( useMedia ){
|
||||
fullq = media;
|
||||
rules.push( repUrls( styles ) );
|
||||
}
|
||||
//parse for styles
|
||||
else{
|
||||
fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
|
||||
rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
|
||||
}
|
||||
|
||||
eachq = fullq.split( "," );
|
||||
eql = eachq.length;
|
||||
|
||||
for( ; j < eql; j++ ){
|
||||
thisq = eachq[ j ];
|
||||
mediastyles.push( {
|
||||
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
|
||||
rules : rules.length - 1,
|
||||
hasquery: thisq.indexOf("(") > -1,
|
||||
minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
|
||||
maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
applyMedia();
|
||||
},
|
||||
|
||||
lastCall,
|
||||
|
||||
resizeDefer,
|
||||
|
||||
// returns the value of 1em in pixels
|
||||
getEmValue = function() {
|
||||
var ret,
|
||||
div = doc.createElement('div'),
|
||||
body = doc.body,
|
||||
fakeUsed = false;
|
||||
|
||||
div.style.cssText = "position:absolute;font-size:1em;width:1em";
|
||||
|
||||
if( !body ){
|
||||
body = fakeUsed = doc.createElement( "body" );
|
||||
body.style.background = "none";
|
||||
}
|
||||
|
||||
body.appendChild( div );
|
||||
|
||||
docElem.insertBefore( body, docElem.firstChild );
|
||||
|
||||
ret = div.offsetWidth;
|
||||
|
||||
if( fakeUsed ){
|
||||
docElem.removeChild( body );
|
||||
}
|
||||
else {
|
||||
body.removeChild( div );
|
||||
}
|
||||
|
||||
//also update eminpx before returning
|
||||
ret = eminpx = parseFloat(ret);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
//cached container for 1em value, populated the first time it's needed
|
||||
eminpx,
|
||||
|
||||
//enable/disable styles
|
||||
applyMedia = function( fromResize ){
|
||||
var name = "clientWidth",
|
||||
docElemProp = docElem[ name ],
|
||||
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
|
||||
styleBlocks = {},
|
||||
lastLink = links[ links.length-1 ],
|
||||
now = (new Date()).getTime();
|
||||
|
||||
//throttle resize calls
|
||||
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
|
||||
clearTimeout( resizeDefer );
|
||||
resizeDefer = setTimeout( applyMedia, resizeThrottle );
|
||||
return;
|
||||
}
|
||||
else {
|
||||
lastCall = now;
|
||||
}
|
||||
|
||||
for( var i in mediastyles ){
|
||||
var thisstyle = mediastyles[ i ],
|
||||
min = thisstyle.minw,
|
||||
max = thisstyle.maxw,
|
||||
minnull = min === null,
|
||||
maxnull = max === null,
|
||||
em = "em";
|
||||
|
||||
if( !!min ){
|
||||
min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
|
||||
}
|
||||
if( !!max ){
|
||||
max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
|
||||
}
|
||||
|
||||
// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
|
||||
if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
|
||||
if( !styleBlocks[ thisstyle.media ] ){
|
||||
styleBlocks[ thisstyle.media ] = [];
|
||||
}
|
||||
styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
|
||||
}
|
||||
}
|
||||
|
||||
//remove any existing respond style element(s)
|
||||
for( var i in appendedEls ){
|
||||
if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
|
||||
head.removeChild( appendedEls[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
//inject active styles, grouped by media type
|
||||
for( var i in styleBlocks ){
|
||||
var ss = doc.createElement( "style" ),
|
||||
css = styleBlocks[ i ].join( "\n" );
|
||||
|
||||
ss.type = "text/css";
|
||||
ss.media = i;
|
||||
|
||||
//originally, ss was appended to a documentFragment and sheets were appended in bulk.
|
||||
//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
|
||||
head.insertBefore( ss, lastLink.nextSibling );
|
||||
|
||||
if ( ss.styleSheet ){
|
||||
ss.styleSheet.cssText = css;
|
||||
}
|
||||
else {
|
||||
ss.appendChild( doc.createTextNode( css ) );
|
||||
}
|
||||
|
||||
//push to appendedEls to track for later removal
|
||||
appendedEls.push( ss );
|
||||
}
|
||||
},
|
||||
//tweaked Ajax functions from Quirksmode
|
||||
ajax = function( url, callback ) {
|
||||
var req = xmlHttp();
|
||||
if (!req){
|
||||
return;
|
||||
}
|
||||
req.open( "GET", url, true );
|
||||
req.onreadystatechange = function () {
|
||||
if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
|
||||
return;
|
||||
}
|
||||
callback( req.responseText );
|
||||
}
|
||||
if ( req.readyState == 4 ){
|
||||
return;
|
||||
}
|
||||
req.send( null );
|
||||
},
|
||||
//define ajax obj
|
||||
xmlHttp = (function() {
|
||||
var xmlhttpmethod = false;
|
||||
try {
|
||||
xmlhttpmethod = new XMLHttpRequest();
|
||||
}
|
||||
catch( e ){
|
||||
xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
|
||||
}
|
||||
return function(){
|
||||
return xmlhttpmethod;
|
||||
};
|
||||
})();
|
||||
|
||||
//translate CSS
|
||||
ripCSS();
|
||||
|
||||
//expose update for re-running respond later on
|
||||
respond.update = ripCSS;
|
||||
|
||||
//adjust on resize
|
||||
function callMedia(){
|
||||
applyMedia( true );
|
||||
}
|
||||
if( win.addEventListener ){
|
||||
win.addEventListener( "resize", callMedia, false );
|
||||
}
|
||||
else if( win.attachEvent ){
|
||||
win.attachEvent( "onresize", callMedia );
|
||||
}
|
||||
})(this);
|
|
@ -1,20 +0,0 @@
|
|||
/* NUGET: BEGIN LICENSE TEXT
|
||||
*
|
||||
* Microsoft grants you the right to use these script files for the sole
|
||||
* purpose of either: (i) interacting through your browser with the Microsoft
|
||||
* website or online service, subject to the applicable licensing or use
|
||||
* terms; or (ii) using the files as included with a Microsoft product subject
|
||||
* to that product's license terms. Microsoft reserves all other rights to the
|
||||
* files not expressly granted by Microsoft, whether by implication, estoppel
|
||||
* or otherwise. Insofar as a script file is dual licensed under GPL,
|
||||
* Microsoft neither took the code under GPL nor distributes it thereunder but
|
||||
* under the terms set out in this paragraph. All notices and licenses
|
||||
* below are for informational purposes only.
|
||||
*
|
||||
* NUGET: END LICENSE TEXT */
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­<style media="'+h+'"> #mq-test-1 { width: 42px; }</style>';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
|
||||
|
||||
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
|
||||
(function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B<y;B++){A=D[B],z=A.href,C=A.media,x=A.rel&&A.rel.toLowerCase()==="stylesheet";if(!!z&&x&&!o[z]){if(A.styleSheet&&A.styleSheet.rawCssText){m(A.styleSheet.rawCssText,z,C);o[z]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(z)&&!g)||z.replace(RegExp.$1,"").split("/")[0]===e.location.host){d.push({href:z,media:C})}}}}u()},u=function(){if(d.length){var x=d.shift();n(x.href,function(y){m(y,x.href,x.media);o[x.href]=true;u()})}},m=function(I,x,z){var G=I.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),J=G&&G.length||0,x=x.substring(0,x.lastIndexOf("/")),y=function(K){return K.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+x+"$2$3")},A=!J&&z,D=0,C,E,F,B,H;if(x.length){x+="/"}if(A){J=1}for(;D<J;D++){C=0;if(A){E=z;k.push(y(I))}else{E=G[D].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;k.push(RegExp.$2&&y(RegExp.$2))}B=E.split(",");H=B.length;for(;C<H;C++){F=B[C];i.push({media:F.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:k.length-1,hasquery:F.indexOf("(")>-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l<h){clearTimeout(r);r=setTimeout(j,h);return}else{l=z}for(var E in i){var K=i[E],C=K.minw,J=K.maxw,A=C===null,L=J===null,y="em";if(!!C){C=parseFloat(C)*(C.indexOf(y)>-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this);
|
|
@ -1,32 +0,0 @@
|
|||
//----------------------------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
using Microsoft.Owin;
|
||||
using Owin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
[assembly: OwinStartup(typeof(ISVDemoUsage.Startup))]
|
||||
|
||||
namespace ISVDemoUsage
|
||||
{
|
||||
public partial class Startup
|
||||
{
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
ConfigureAuth(app);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
@{
|
||||
ViewBag.Title = "Contact Us";
|
||||
}
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<h3>@ViewBag.Message</h3>
|
||||
|
||||
<address>
|
||||
<strong>Azure PM Team:</strong> <a href="mailto:AzureITFM@microsoft.com">AzureITFM@microsoft.com</a><br />
|
||||
</address>
|
|
@ -1,146 +0,0 @@
|
|||
@model ISVDemoUsage.Models.HomeIndexViewModel
|
||||
@{
|
||||
ViewBag.Title = "ISV Demo for Usage API";
|
||||
}
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>ISV Demo for Usage</h1>
|
||||
<p class="lead">If you have any questions, please email AzureITFM@microsoft.com</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@if (!Request.IsAuthenticated)
|
||||
{
|
||||
<div class="col-lg-4 thumbnail">
|
||||
<div class="caption">
|
||||
<h3>Sign-in to connect your Azure Subscription</h3>
|
||||
<div id="org"><a href='@Url.Action("SignIn", "Account")'><img src="~/Images/org.png" style="height:65px;width:350px;margin:0px" class="img-thumbnail" /></a></div>
|
||||
<span id="back" style="display:none; cursor:pointer" class="glyphicon glyphicon-arrow-left"></span>
|
||||
<div id="msa" style="cursor:pointer"><img src="~/Images/msa.png" style="height:64px;width:350px" class="img-thumbnail" /></div>
|
||||
|
||||
@using (Html.BeginForm("SignIn", "Account", new { isMSA = true }, FormMethod.Get))
|
||||
{
|
||||
<div id="msadir" style="display: none">
|
||||
<div class="input-group" style="width:350px">
|
||||
<input name="directoryName" type="text" class="form-control" placeholder="Directory Name e.g. contoso.com" aria-describedby="basic-addon2">
|
||||
<input name="isMSA" type="hidden" value="true" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit">Go</button>
|
||||
</span>
|
||||
</div>
|
||||
<a style="font-size:smaller; cursor:pointer" data-toggle="modal" data-target=".bs-example-modal-lg">Help me find my directory name</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
|
||||
<div class=" modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<img src="~/Images/directory.png" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (Model != null)
|
||||
{
|
||||
<table class="table table-striped table-condensed table-hover">
|
||||
<tr>
|
||||
<td>
|
||||
<h4>Azure Subscription</h4>
|
||||
</td>
|
||||
<td>
|
||||
<h4>Monitored by ISV?</h4>
|
||||
</td>
|
||||
</tr>
|
||||
@foreach (KeyValuePair<string, ISVDemoUsage.Models.Subscription> entry in Model.UserSubscriptions)
|
||||
{
|
||||
var subscription = entry.Value as ISVDemoUsage.Models.Subscription;
|
||||
<tr>
|
||||
<td>
|
||||
@subscription.DisplayName
|
||||
<br />
|
||||
<small>Subscription Id: @subscription.Id</small>
|
||||
<br />
|
||||
<small>Organization Id: @subscription.OrganizationId</small>
|
||||
</td>
|
||||
<td>
|
||||
@if (subscription.IsConnected)
|
||||
{
|
||||
<text>Yes. </text>
|
||||
<br />
|
||||
<small> Connected By: @subscription.ConnectedBy </small>
|
||||
<small> Connected On: @subscription.ConnectedOn.ToShortDateString() </small>
|
||||
if (Model.UserCanManageAccessForSubscriptions.Contains(@subscription.Id))
|
||||
{
|
||||
<small> Here's your usage @subscription.UsageString </small>
|
||||
@Html.ActionLink("Disconnect", "Disconnect", "Subscription", new
|
||||
{
|
||||
Id = @subscription.Id,
|
||||
OrganizationId = @subscription.OrganizationId,
|
||||
ServicePrincipalObjectId = Model.UserOrganizations[@subscription.OrganizationId].objectIdOfISVDemoUsageServicePrincipal
|
||||
},
|
||||
new { @class = "btn btn-danger btn-xs" })
|
||||
}
|
||||
if (@subscription.AzureAccessNeedsToBeRepaired)
|
||||
{
|
||||
<br />
|
||||
<small> Access in Azure needs to be repaired: </small>
|
||||
@Html.ActionLink("Repair", "RepairAccess", "Subscription", new
|
||||
{
|
||||
Id = @subscription.Id,
|
||||
OrganizationId = @subscription.OrganizationId,
|
||||
ServicePrincipalObjectId = Model.UserOrganizations[@subscription.OrganizationId].objectIdOfISVDemoUsageServicePrincipal
|
||||
},
|
||||
new { @class = "btn btn-info btn-xs" })
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>No. </text>
|
||||
if (Model.UserCanManageAccessForSubscriptions.Contains(@subscription.Id))
|
||||
{
|
||||
@Html.ActionLink("Connect", "Connect", "Subscription", new
|
||||
{
|
||||
Id = @subscription.Id,
|
||||
OrganizationId = @subscription.OrganizationId,
|
||||
ServicePrincipalObjectId = Model.UserOrganizations[@subscription.OrganizationId].objectIdOfISVDemoUsageServicePrincipal
|
||||
},
|
||||
new { @class = "btn btn-success btn-xs" })
|
||||
}
|
||||
}
|
||||
@if (!Model.UserCanManageAccessForSubscriptions.Contains(@subscription.Id))
|
||||
{
|
||||
<text>(You can't manage access for this subscription.)</text>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
if (Model.DisconnectedUserOrganizations.Count > 0)
|
||||
{
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h4> Didn't find the Azure subscription that you want to connect? </h4>
|
||||
<h5>
|
||||
It could be in the @Model.DisconnectedUserOrganizations.Count other Organization(s) of which you're a member.
|
||||
Click here to connect to all your Organizations (you will need to provide consent for each).
|
||||
</h5>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(
|
||||
function () {
|
||||
$("#msa").click(function () {
|
||||
$("#org").hide();
|
||||
$("#back").show();
|
||||
$("#msadir").show("slow");
|
||||
});
|
||||
$("#back").click(function () {
|
||||
$("#back").hide();
|
||||
$("#msadir").hide();
|
||||
$("#org").show("slow");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,17 +0,0 @@
|
|||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<hgroup>
|
||||
<h1>Error.</h1>
|
||||
<h2>An error occurred while processing your request: @ViewBag.Message</h2>
|
||||
</hgroup>
|
||||
</body>
|
||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@ViewBag.Title - ISV Demo for Usage API</title>
|
||||
@Styles.Render("~/Content/css")
|
||||
@Scripts.Render("~/bundles/modernizr")
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
@Html.ActionLink("ISV Demo for Usage", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
|
||||
</ul>
|
||||
@Html.Partial("_LoginPartial")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container body-content">
|
||||
@RenderBody()
|
||||
<hr />
|
||||
<footer>
|
||||
<p>© @DateTime.Now.Year -Usage</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@Scripts.Render("~/bundles/jquery")
|
||||
@Scripts.Render("~/bundles/bootstrap")
|
||||
@RenderSection("scripts", required: false)
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
@if (Request.IsAuthenticated)
|
||||
{
|
||||
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
@Html.ActionLink("Hello " + User.Identity.Name + "!", "Index", "Home", null, null)
|
||||
</li>
|
||||
<li>@Html.ActionLink("Sign out", "SignOut", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
|
||||
</ul>
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
|
||||
<pages pageBaseType="System.Web.Mvc.WebViewPage">
|
||||
<namespaces>
|
||||
<add namespace="System.Web.Mvc" />
|
||||
<add namespace="System.Web.Mvc.Ajax" />
|
||||
<add namespace="System.Web.Mvc.Html" />
|
||||
<add namespace="System.Web.Optimization"/>
|
||||
<add namespace="System.Web.Routing" />
|
||||
<add namespace="ISVDemoUsage" />
|
||||
</namespaces>
|
||||
</pages>
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<remove name="BlockViewHandler"/>
|
||||
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
|
@ -1,3 +0,0 @@
|
|||
@{
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- For more information on using Web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=301874 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your Web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- For more information on using Web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=301874 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<compilation xdt:Transform="RemoveAttributes(debug)" />
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your Web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
For more information on how to configure your ASP.NET application, please visit
|
||||
http://go.microsoft.com/fwlink/?LinkId=301880
|
||||
-->
|
||||
<configuration>
|
||||
<configSections>
|
||||
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
|
||||
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||
</configSections>
|
||||
<appSettings>
|
||||
<add key="webpages:Version" value="3.0.0.0" />
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
<add key="ClientValidationEnabled" value="true" />
|
||||
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
|
||||
<add key="ida:Authority" value="https://login.microsoftonline.com/{0}/" />
|
||||
<add key="ida:Issuer" value="https://sts.windows.net/{0}/" />
|
||||
<add key="ida:GraphAPIIdentifier" value="https://graph.windows.net/" />
|
||||
<add key="ida:GraphAPIVersion" value="1.5" />
|
||||
<add key="ida:AzureResourceManagerIdentifier" value="https://management.core.windows.net/" />
|
||||
<add key="ida:AzureResourceManagerUrl" value="https://management.azure.com" />
|
||||
<add key="ida:AzureResourceManagerAPIVersion" value="2014-04-01-preview" />
|
||||
<add key="ida:ARMAuthorizationPermissionsAPIVersion" value="2014-07-01-preview" />
|
||||
<add key="ida:ARMAuthorizationRoleDefinitionsAPIVersion" value="2014-07-01-preview" />
|
||||
<add key="ida:ARMAuthorizationRoleAssignmentsAPIVersion" value="2014-10-01-preview" />
|
||||
<add key="ida:ARMAuthorizationPermissionsAPIVersion" value="2014-07-01-preview" />
|
||||
<!-- Please note: The user/service principal will require either an Owner, Contributor or Reader role on the subscription to be able to be authorized to get usage for that AzureSubID-->
|
||||
<add key="ida:RequiredARMRoleOnSubscription" value="Reader" />
|
||||
|
||||
<!--Please note: Please register your application in AAD and copy the clientID and client secret/password from the Azure Management Portal (manage.windowsazure.com). Read more about adding applications in Active Directory here: https://msdn.microsoft.com/en-us/library/azure/dn151122.aspx-->
|
||||
<add key="ida:ClientID" value="ENTER-CLIENT-ID-GUID" />
|
||||
<add key="ida:Password" value="ENTER-CLIENT-KEY" />
|
||||
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<customErrors mode="Off"/>
|
||||
<compilation debug="true" targetFramework="4.5" />
|
||||
<httpRuntime targetFramework="4.5" />
|
||||
</system.web>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="1.0.0.0-5.2.0.0" newVersion="5.2.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<entityFramework>
|
||||
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
|
||||
<parameters>
|
||||
<parameter value="v11.0" />
|
||||
</parameters>
|
||||
</defaultConnectionFactory>
|
||||
<providers>
|
||||
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
|
||||
</providers>
|
||||
</entityFramework>
|
||||
</configuration>
|
Двоичные данные
WebApp-Billing-MultiTenant/ISVDemoUsage/favicon.ico
До Ширина: | Высота: | Размер: 31 KiB |
|
@ -1,228 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M1100 500h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200z" />
|
||||
<glyph unicode="+" d="M1100 400h-400v-400h-300v400h-400v300h400v400h300v-400h400v-300z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M800 500h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257 q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406z" />
|
||||
<glyph unicode="−" d="M1100 700h-900v-300h900v300z" />
|
||||
<glyph unicode="☁" d="M178 300h750q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5q0 -80 56.5 -137t135.5 -57z" />
|
||||
<glyph unicode="✉" d="M1200 1100h-1200l600 -603zM300 600l-300 -300v600zM1200 900v-600l-300 300zM800 500l400 -400h-1200l400 400l200 -200z" />
|
||||
<glyph unicode="✏" d="M1101 889l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13l-94 -97zM401 189l614 614l-214 214l-614 -614zM-13 -13l333 112l-223 223z" />
|
||||
<glyph unicode="" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="" d="M700 100h300v-100h-800v100h300v550l-500 550h1200l-500 -550v-550z" />
|
||||
<glyph unicode="" d="M1000 934v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q17 -55 85.5 -75.5t147.5 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7q-79 -25 -122.5 -82t-25.5 -112t86 -75.5t147 5.5 q65 21 109 69t44 90v606z" />
|
||||
<glyph unicode="" d="M913 432l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342t142 342t342 142t342 -142t142 -342q0 -142 -78 -261zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M649 949q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5t-94 124.5t-33.5 117.5q0 64 28 123t73 100.5t104.5 64t119 20.5 t120 -38.5t104.5 -104.5z" />
|
||||
<glyph unicode="" d="M791 522l145 -449l-384 275l-382 -275l146 447l-388 280h479l146 400h2l146 -400h472zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M791 522l145 -449l-384 275l-382 -275l146 447l-388 280h479l146 400h2l146 -400h472zM747 331l-74 229l193 140h-235l-77 211l-78 -211h-239l196 -142l-73 -226l192 140zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M1200 143v-143h-1200v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100z" />
|
||||
<glyph unicode="" d="M1200 1100v-1100h-1200v1100h1200zM200 1000h-100v-100h100v100zM900 1000h-600v-400h600v400zM1100 1000h-100v-100h100v100zM200 800h-100v-100h100v100zM1100 800h-100v-100h100v100zM200 600h-100v-100h100v100zM1100 600h-100v-100h100v100zM900 500h-600v-400h600 v400zM200 400h-100v-100h100v100zM1100 400h-100v-100h100v100zM200 200h-100v-100h100v100zM1100 200h-100v-100h100v100z" />
|
||||
<glyph unicode="" d="M500 1050v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5zM1100 1050v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h400 q21 0 35.5 -14.5t14.5 -35.5zM500 450v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5zM1100 450v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M300 1050v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM700 1050v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5zM1100 1050v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM300 650v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM700 650v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM1100 650v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM300 250v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM700 250v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM1100 250v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5 t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M300 1050v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM1200 1050v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h700 q21 0 35.5 -14.5t14.5 -35.5zM300 450v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-200q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5zM1200 650v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5zM300 250v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5zM1200 250v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M448 34l818 820l-212 212l-607 -607l-206 207l-212 -212z" />
|
||||
<glyph unicode="" d="M882 106l-282 282l-282 -282l-212 212l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282z" />
|
||||
<glyph unicode="" d="M913 432l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342t142 342t342 142t342 -142t142 -342q0 -142 -78 -261zM507 363q137 0 233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5t-234 -97t-97 -233 t97 -233t234 -97zM600 800h100v-200h-100v-100h-200v100h-100v200h100v100h200v-100z" />
|
||||
<glyph unicode="" d="M913 432l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 299q-120 -77 -261 -77q-200 0 -342 142t-142 342t142 342t342 142t342 -142t142 -342q0 -141 -78 -262zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 801v-200h400v200h-400z" />
|
||||
<glyph unicode="" d="M700 750v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5zM800 975v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123 t-123 184t-45.5 224.5q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155z" />
|
||||
<glyph unicode="" d="M1200 1h-200v1200h200v-1200zM900 1h-200v800h200v-800zM600 1h-200v500h200v-500zM300 301h-200v-300h200v300z" />
|
||||
<glyph unicode="" d="M488 183l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5 q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39zM600 815q89 0 152 -63 t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152q0 88 63 151t152 63z" />
|
||||
<glyph unicode="" d="M900 1100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100zM800 1100v100h-300v-100h300zM200 900h900v-800q0 -41 -29.5 -71 t-70.5 -30h-700q-41 0 -70.5 30t-29.5 71v800zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1301 601h-200v-600h-300v400h-300v-400h-300v600h-200l656 644z" />
|
||||
<glyph unicode="" d="M600 700h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18v1150q0 11 7 18t18 7h475v-500zM1000 800h-300v300z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM600 600h200 v-100h-300v400h100v-300z" />
|
||||
<glyph unicode="" d="M721 400h-242l-40 -400h-539l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538zM712 500l-27 300h-170l-27 -300h224z" />
|
||||
<glyph unicode="" d="M1100 400v-400h-1100v400h490l-290 300h200v500h300v-500h200l-290 -300h490zM988 300h-175v-100h175v100z" />
|
||||
<glyph unicode="" d="M600 1199q122 0 233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233t47.5 233t127.5 191t191 127.5t233 47.5zM600 1012q-170 0 -291 -121t-121 -291t121 -291t291 -121t291 121 t121 291t-121 291t-291 121zM700 600h150l-250 -300l-250 300h150v300h200v-300z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM850 600h-150 v-300h-200v300h-150l250 300z" />
|
||||
<glyph unicode="" d="M0 500l200 700h800q199 -700 200 -700v-475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18v475zM903 1000h-606l-97 -500h200l50 -200h300l50 200h200z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5zM797 598 l-297 -201v401z" />
|
||||
<glyph unicode="" d="M1177 600h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123t-123 -184t-45.5 -224.5t45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123 t123 184t45.5 224.5z" />
|
||||
<glyph unicode="" d="M700 800l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400zM500 400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122l-145 -145v400h400z" />
|
||||
<glyph unicode="" d="M100 1200v-1200h1100v1200h-1100zM1100 100h-900v900h900v-900zM400 800h-100v100h100v-100zM1000 800h-500v100h500v-100zM400 600h-100v100h100v-100zM1000 600h-500v100h500v-100zM400 400h-100v100h100v-100zM1000 400h-500v100h500v-100zM400 200h-100v100h100v-100 zM1000 300h-500v-100h500v100z" />
|
||||
<glyph unicode="" d="M200 0h-100v1100h100v-1100zM1100 600v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5z" />
|
||||
<glyph unicode="" d="M1200 275v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5t-49.5 -227v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50 q11 0 18 7t7 18zM400 480v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14zM1000 480v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14z" />
|
||||
<glyph unicode="" d="M0 800v-400h300l300 -200v800l-300 -200h-300zM971 600l141 -141l-71 -71l-141 141l-141 -141l-71 71l141 141l-141 141l71 71l141 -141l141 141l71 -71z" />
|
||||
<glyph unicode="" d="M0 800v-400h300l300 -200v800l-300 -200h-300zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M974 186l6 8q142 178 142 405q0 230 -144 408l-6 8l-83 -64l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8zM300 801l300 200v-800l-300 200h-300v400h300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257z" />
|
||||
<glyph unicode="" d="M100 700h400v100h100v100h-100v300h-500v-600h100v100zM1200 700v500h-600v-200h100v-300h200v-300h300v200h-200v100h200zM100 1100h300v-300h-300v300zM800 800v300h300v-300h-300zM200 900h100v100h-100v-100zM900 1000h100v-100h-100v100zM300 600h-100v-100h-200 v-500h500v500h-200v100zM900 200v-100h-200v100h-100v100h100v200h-200v100h300v-300h200v-100h-100zM400 400v-300h-300v300h300zM300 200h-100v100h100v-100zM1100 300h100v-100h-100v100zM600 100h100v-100h-100v100zM1200 100v-100h-300v100h300z" />
|
||||
<glyph unicode="" d="M100 1200h-100v-1000h100v1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 1200v-1000h-200v1000h200zM400 100v-100h-300v100h300zM500 91h100v-91h-100v91zM700 91h100v-91h-100v91zM1100 91v-91h-200v91h200z " />
|
||||
<glyph unicode="" d="M1200 500l-500 -500l-699 700v475q0 10 7.5 17.5t17.5 7.5h474zM320 882q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71t29 -71q30 -30 71.5 -30t71.5 30z" />
|
||||
<glyph unicode="" d="M1201 500l-500 -500l-699 700v475q0 11 7 18t18 7h474zM1501 500l-500 -500l-50 50l450 450l-700 700h100zM320 882q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71t30 -71q29 -30 71 -30t71 30z" />
|
||||
<glyph unicode="" d="M1200 1200v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900v1025l175 175h925z" />
|
||||
<glyph unicode="" d="M947 829l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18l-94 -346l40 -124h592zM1200 800v-700h-200v200h-800v-200h-200v700h200l100 -200h600l100 200h200zM881 176l38 -152q2 -10 -3.5 -17t-15.5 -7h-600q-10 0 -15.5 7t-3.5 17l38 152q2 10 11.5 17t19.5 7 h500q10 0 19.5 -7t11.5 -17z" />
|
||||
<glyph unicode="" d="M1200 0v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417zM416 521l178 457l46 -140l116 -317 h-340z" />
|
||||
<glyph unicode="" d="M100 1199h471q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111t-162 -38.5h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21 t-29 14t-49 14.5v70zM400 1079v-379h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400z" />
|
||||
<glyph unicode="" d="M877 1200l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425z" />
|
||||
<glyph unicode="" d="M1150 1200h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49v300h150h700zM100 1000v-800h75l-125 -167l-125 167h75v800h-75l125 167 l125 -167h-75z" />
|
||||
<glyph unicode="" d="M950 1201h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50v300h150h700zM200 101h800v75l167 -125l-167 -125v75h-800v-75l-167 125l167 125 v-75z" />
|
||||
<glyph unicode="" d="M700 950v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35zM1100 650v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h1000 q21 0 35.5 15t14.5 35zM900 350v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35zM1200 50v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35 t35.5 -15h1100q21 0 35.5 15t14.5 35z" />
|
||||
<glyph unicode="" d="M1000 950v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35zM1200 650v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h1100 q21 0 35.5 15t14.5 35zM1000 350v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35zM1200 50v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35 t35.5 -15h1100q21 0 35.5 15t14.5 35z" />
|
||||
<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35zM0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M400 1100h-100v-1100h100v1100zM700 950v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35zM1100 650v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15 h500q20 0 35 15t15 35zM100 425v75h-201v100h201v75l166 -125zM900 350v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35zM1200 50v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5 v-100q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35z" />
|
||||
<glyph unicode="" d="M201 950v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35zM801 1100h100v-1100h-100v1100zM601 650v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15 h500q20 0 35 15t15 35zM1101 425v75h200v100h-200v75l-167 -125zM401 350v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35zM701 50v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5 v-100q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35z" />
|
||||
<glyph unicode="" d="M900 925v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53zM1200 300l-300 300l300 300v-600z" />
|
||||
<glyph unicode="" d="M1200 1056v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31zM1100 1000h-1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500zM476 750q0 -56 -39 -95t-95 -39t-95 39t-39 95t39 95t95 39t95 -39 t39 -95z" />
|
||||
<glyph unicode="" d="M600 1213q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262q0 124 60.5 231.5t165 172t226.5 64.5zM599 514q107 0 182.5 75.5t75.5 182.5t-75.5 182 t-182.5 75t-182 -75.5t-75 -181.5q0 -107 75.5 -182.5t181.5 -75.5z" />
|
||||
<glyph unicode="" d="M600 1199q122 0 233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233t47.5 233t127.5 191t191 127.5t233 47.5zM600 173v854q-176 0 -301.5 -125t-125.5 -302t125.5 -302t301.5 -125z " />
|
||||
<glyph unicode="" d="M554 1295q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 138.5t-64 210.5q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5zM455 296q-7 6 -18 17 t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156q14 -82 59.5 -136t136.5 -80z" />
|
||||
<glyph unicode="" d="M1108 902l113 113l-21 85l-92 28l-113 -113zM1100 625v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5 t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125zM436 341l161 50l412 412l-114 113l-405 -405z" />
|
||||
<glyph unicode="" d="M1100 453v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5z M813 431l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209z" />
|
||||
<glyph unicode="" d="M1100 569v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5v300q0 165 117.5 282.5t282.5 117.5h300q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69z M625 348l566 567l-136 137l-430 -431l-147 147l-136 -136z" />
|
||||
<glyph unicode="" d="M900 303v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198l-300 300l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296z" />
|
||||
<glyph unicode="" d="M900 0l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100z" />
|
||||
<glyph unicode="" d="M1200 0l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100z" />
|
||||
<glyph unicode="" d="M1200 0l-500 488v-488l-564 550l564 550v-487l500 487v-1100z" />
|
||||
<glyph unicode="" d="M1100 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M500 150v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5zM900 150v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800q0 -21 14.5 -35.5t35.5 -14.5h200 q21 0 35.5 14.5t14.5 35.5z" />
|
||||
<glyph unicode="" d="M1100 150v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35z" />
|
||||
<glyph unicode="" d="M500 0v488l-500 -488v1100l500 -487v487l564 -550z" />
|
||||
<glyph unicode="" d="M1050 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488l-500 -488v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M650 1064l-550 -564h1100zM1200 350v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M777 7l240 240l-353 353l353 353l-240 240l-592 -594z" />
|
||||
<glyph unicode="" d="M513 -46l-241 240l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM500 900v-200h-200v-200h200v-200h200v200h200v200h-200v200h-200z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM300 700v-200h600v200h-600z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM247 741l141 -141l-142 -141l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141 l-141 142z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM546 623l-102 102l-174 -174l276 -277l411 411l-175 174z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM500 500h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3 q-105 0 -172 -56t-67 -183h144q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5zM500 400v-100h200v100h-200z" />
|
||||
<glyph unicode="" d="M600 1197q162 0 299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5t80 299.5t217.5 217.5t299.5 80zM500 900v-100h200v100h-200zM400 700v-100h100v-200h-100v-100h400v100h-100v300h-300z" />
|
||||
<glyph unicode="" d="M1200 700v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194v200h194q15 60 36 104.5t55.5 86t88 69t126.5 40.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203zM700 500v-206q149 48 201 206h-201v200h200 q-25 74 -76 127.5t-124 76.5v-204h-200v203q-75 -24 -130 -77.5t-79 -125.5h209v-200h-210q24 -73 79.5 -127.5t130.5 -78.5v206h200z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM844 735 l-135 -135l135 -135l-109 -109l-135 135l-135 -135l-109 109l135 135l-135 135l109 109l135 -135l135 135z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM896 654 l-346 -345l-228 228l141 141l87 -87l204 205z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM248 385l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5q0 -115 62 -215zM955 809l-564 -564q97 -59 209 -59q171 0 292.5 121.5 t121.5 292.5q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M1200 400h-600v-301l-600 448l600 453v-300h600v-300z" />
|
||||
<glyph unicode="" d="M600 400h-600v300h600v300l600 -453l-600 -448v301z" />
|
||||
<glyph unicode="" d="M1098 600h-298v-600h-300v600h-296l450 600z" />
|
||||
<glyph unicode="" d="M998 600l-449 -600l-445 600h296v600h300v-600h298z" />
|
||||
<glyph unicode="" d="M600 199v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453z" />
|
||||
<glyph unicode="" d="M1200 1200h-400l129 -129l-294 -294l142 -142l294 294l129 -129v400zM565 423l-294 -294l129 -129h-400v400l129 -129l294 294z" />
|
||||
<glyph unicode="" d="M871 730l129 -130h-400v400l129 -129l295 295l142 -141zM200 600h400v-400l-129 130l-295 -295l-142 141l295 295z" />
|
||||
<glyph unicode="" d="M600 1177q118 0 224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5t45.5 224.5t123 184t184 123t224.5 45.5zM686 549l58 302q4 20 -8 34.5t-33 14.5h-207q-20 0 -32 -14.5t-8 -34.5 l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5zM700 400h-200v-100h200v100z" />
|
||||
<glyph unicode="" d="M1200 900h-111v6t-1 15t-3 18l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6h-111v-100h100v-200h400v300h200v-300h400v200h100v100z M731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269zM481 900h-281q-3 0 14 48t35 96l18 47zM100 0h400v400h-400v-400zM700 400h400v-400h-400v400z" />
|
||||
<glyph unicode="" d="M0 121l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55l-201 -202 v143zM692 611q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5t86.5 76.5q55 66 367 234z" />
|
||||
<glyph unicode="" d="M1261 600l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30l-26 40l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5 t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30zM600 240q64 0 123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212 q0 85 46 158q-102 -87 -226 -258q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5zM484 762l-107 -106q49 -124 154 -191l105 105q-37 24 -75 72t-57 84z" />
|
||||
<glyph unicode="" d="M906 1200l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43l-26 40l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148zM1261 600l-26 -40q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5 t-124 -100t-146.5 -79l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52zM513 264l37 141q-107 18 -178.5 101.5t-71.5 193.5q0 85 46 158q-102 -87 -226 -258q210 -282 393 -336z M484 762l-107 -106q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68z" />
|
||||
<glyph unicode="" d="M-47 0h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 33 -48 36t-48 -29l-642 -1066q-21 -32 -7.5 -66t50.5 -34zM700 200v100h-200v-100h-345l445 723l445 -723h-345zM700 700h-200v-100l100 -300l100 300v100z" />
|
||||
<glyph unicode="" d="M800 711l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -21 -13 -29t-32 1l-94 78h-222l-94 -78q-19 -9 -32 -1t-13 29v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41q0 20 11 44.5t26 38.5 l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339z" />
|
||||
<glyph unicode="" d="M941 800l-600 -600h-341v200h259l600 600h241v198l300 -295l-300 -300v197h-159zM381 678l141 142l-181 180h-341v-200h259zM1100 598l300 -295l-300 -300v197h-241l-181 181l141 142l122 -123h159v198z" />
|
||||
<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
|
||||
<glyph unicode="" d="M400 900h-300v300h300v-300zM1100 900h-300v300h300v-300zM1100 800v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5t-58 109.5t-31.5 116t-15 104t-3 83v200h300v-250q0 -113 6 -145 q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300z" />
|
||||
<glyph unicode="" d="M902 184l226 227l-578 579l-580 -579l227 -227l352 353z" />
|
||||
<glyph unicode="" d="M650 218l578 579l-226 227l-353 -353l-352 353l-227 -227z" />
|
||||
<glyph unicode="" d="M1198 400v600h-796l215 -200h381v-400h-198l299 -283l299 283h-200zM-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196z" />
|
||||
<glyph unicode="" d="M1050 1200h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35 q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43l-100 475q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5z" />
|
||||
<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
|
||||
<glyph unicode="" d="M201 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000zM1501 700l-300 -700h-1200l300 700h1200z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M900 303v197h-600v-197l-300 297l300 298v-198h600v198l300 -298z" />
|
||||
<glyph unicode="" d="M31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM100 300h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM900 200h-100v-100h100v100z M1100 200h-100v-100h100v100z" />
|
||||
<glyph unicode="" d="M1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35zM325 800l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35q-56 337 -56 351v250v5 q0 13 0.5 18.5t2.5 13t8 10.5t15 3h200zM-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5z" />
|
||||
<glyph unicode="" d="M445 1180l-45 -233l-224 78l78 -225l-233 -44l179 -156l-179 -155l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180z" />
|
||||
<glyph unicode="" d="M700 1200h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400q0 -75 100 -75h61q123 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5zM700 925l-50 -225h450 v-125l-250 -375h-214l-136 100h-100v375l150 212l100 213h50v-175zM0 800v-600h200v600h-200z" />
|
||||
<glyph unicode="" d="M700 0h-50q-27 0 -51 20t-38 48l-96 198l-145 196q-20 26 -20 63v400q0 75 100 75h61q123 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5zM200 400h-200v600h200 v-600zM700 275l-50 225h450v125l-250 375h-214l-136 -100h-100v-375l150 -212l100 -213h50v175z" />
|
||||
<glyph unicode="" d="M364 873l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM408 792v-503 l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83zM208 200h-200v600h200v-600z" />
|
||||
<glyph unicode="" d="M475 1104l365 -230q7 -4 16.5 -10.5t26 -26t16.5 -36.5v-526q0 -13 -85.5 -93.5t-93.5 -80.5h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-84 0 -139 39t-55 111t54 110t139 37h302l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6zM370 946 l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100h222q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l106 89v502l-342 237zM1199 201h-200v600h200v-600z" />
|
||||
<glyph unicode="" d="M1100 473v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90zM911 400h-503l-236 339 l83 86l183 -146q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6v7.5v7v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294zM1000 200v-200h-600v200h600z" />
|
||||
<glyph unicode="" d="M305 1104v200h600v-200h-600zM605 310l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15l-230 -362q-15 -31 7 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85l-1 -302q0 -84 38.5 -138t110.5 -54t111 55t39 139v106z M905 804v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146l-83 86l237 339h503z" />
|
||||
<glyph unicode="" d="M603 1195q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5zM598 701h-298v-201h300l-2 -194l402 294l-402 298v-197z" />
|
||||
<glyph unicode="" d="M597 1195q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5zM200 600l400 -294v194h302v201h-300v197z" />
|
||||
<glyph unicode="" d="M603 1195q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M603 1195q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5zM500 900v-300h-200l300 -400l300 400h-200v300h-200z" />
|
||||
<glyph unicode="" d="M603 1195q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5zM627 1101q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6 q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55 t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q102 -2 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7 q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5 t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 41 1 44q31 -13 58.5 -14.5t39.5 3.5l11 4q6 36 -17 53.5t-64 28.5t-56 23q-19 -3 -37 0zM613 994q0 -18 8 -42.5t16.5 -44t9.5 -23.5q-9 2 -31 5t-36 5t-32 8t-30 14q3 12 16 30t16 25q10 -10 18.5 -10 t14 6t14.5 14.5t16 12.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
|
||||
<glyph unicode="" d="M1100 1200v-100h-1000v100h1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M329 729l142 142l-200 200l129 129h-400v-400l129 129zM1200 1200v-400l-129 129l-200 -200l-142 142l200 200l-129 129h400zM271 129l129 -129h-400v400l129 -129l200 200l142 -142zM1071 271l129 129v-400h-400l129 129l-200 200l142 142z" />
|
||||
<glyph unicode="" d="M596 1192q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM596 1010q-171 0 -292.5 -121.5t-121.5 -292.5q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5zM455 905 q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5t16 38.5t39 16.5zM708 821l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5 q0 32 20.5 56.5t51.5 29.5zM855 709q23 0 38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39q0 22 16 38t39 16zM345 709q23 0 39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39t15.5 38.5t38.5 15.5z" />
|
||||
<glyph unicode="" d="M649 54l-16 22q-90 125 -293 323q-71 70 -104.5 105.5t-77 89.5t-61 99t-17.5 91q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-203 -198 -293 -323zM844 524l12 12 q64 62 97.5 97t64.5 79t31 72q0 71 -48 119t-105 48q-74 0 -132 -82l-118 -171l-114 174q-51 79 -123 79q-60 0 -109.5 -49t-49.5 -118q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203z" />
|
||||
<glyph unicode="" d="M476 406l19 -17l105 105l-212 212l389 389l247 -247l-95 -96l18 -18q46 -46 77 -99l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159q0 -93 66 -159zM123 193l141 -141q66 -66 159 -66q95 0 159 66 l283 283q66 66 66 159t-66 159l-141 141q-12 12 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159q0 -94 66 -160z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM900 1000h-600v-700h600v700zM600 46q43 0 73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5t-73.5 -30.5t-30.5 -73.5 t30.5 -73.5t73.5 -30.5z" />
|
||||
<glyph unicode="" d="M700 1029v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5h139q5 -77 48.5 -126.5t117.5 -64.5v335l-27 7q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5 t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5zM600 755v274q-61 -8 -97.5 -37.5t-36.5 -102.5q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3zM700 548 v-311q170 18 170 151q0 64 -44 99.5t-126 60.5z" />
|
||||
<glyph unicode="" d="M866 300l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5t-30 142.5h-221v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5 t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -11 2.5 -24.5t5.5 -24t9.5 -26.5t10.5 -25t14 -27.5t14 -25.5t15.5 -27t13.5 -24h242v-100h-197q8 -50 -2.5 -115t-31.5 -94 q-41 -59 -99 -113q35 11 84 18t70 7q32 1 102 -16t104 -17q76 0 136 30z" />
|
||||
<glyph unicode="" d="M300 0l298 300h-198v900h-200v-900h-198zM900 1200l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M400 300h198l-298 -300l-298 300h198v900h200v-900zM1000 1200v-500h-100v100h-100v-100h-100v500h300zM901 1100h-100v-200h100v200zM700 500h300v-200h-99v-100h-100v100h99v100h-200v100zM800 100h200v-100h-300v200h100v-100z" />
|
||||
<glyph unicode="" d="M400 300h198l-298 -300l-298 300h198v900h200v-900zM1000 1200v-200h-99v-100h-100v100h99v100h-200v100h300zM800 800h200v-100h-300v200h100v-100zM700 500h300v-500h-100v100h-100v-100h-100v500zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M300 0l298 300h-198v900h-200v-900h-198zM900 1100h-100v100h200v-500h-100v400zM1100 500v-500h-100v100h-200v400h300zM1001 400h-100v-200h100v200z" />
|
||||
<glyph unicode="" d="M300 0l298 300h-198v900h-200v-900h-198zM1100 1200v-500h-100v100h-200v400h300zM1001 1100h-100v-200h100v200zM900 400h-100v100h200v-500h-100v400z" />
|
||||
<glyph unicode="" d="M300 0l298 300h-198v900h-200v-900h-198zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
|
||||
<glyph unicode="" d="M300 0l298 300h-198v900h-200v-900h-198zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
|
||||
<glyph unicode="" d="M400 1100h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5v300q0 165 117.5 282.5t282.5 117.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5 t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5z" />
|
||||
<glyph unicode="" d="M700 0h-300q-163 0 -281.5 117.5t-118.5 282.5v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5 t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5zM400 800v-500l333 250z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM900 300v500q0 41 -29.5 70.5t-70.5 29.5h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5 t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5zM800 700h-500l250 -333z" />
|
||||
<glyph unicode="" d="M1100 700v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5zM900 300v500q0 41 -29.5 70.5t-70.5 29.5h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5 t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5zM550 733l-250 -333h500z" />
|
||||
<glyph unicode="" d="M500 1100h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200zM700 550l-400 -350v200h-300v300h300v200z" />
|
||||
<glyph unicode="" d="M403 2l9 -1q13 0 26 16l538 630q15 19 6 36q-8 18 -32 16h-300q1 4 78 219.5t79 227.5q2 17 -6 27l-8 8h-9q-16 0 -25 -15q-4 -5 -98.5 -111.5t-228 -257t-209.5 -238.5q-17 -19 -7 -40q10 -19 32 -19h302q-155 -438 -160 -458q-5 -21 4 -32z" />
|
||||
<glyph unicode="" d="M800 200h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185zM900 200v200h-300v300h300v200l400 -350z" />
|
||||
<glyph unicode="" d="M1200 700l-149 149l-342 -353l-213 213l353 342l-149 149h500v-500zM1022 571l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5v-300 q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM600 794 q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
|
||||
<glyph unicode="" d="M700 800v400h-300v-400h-300l445 -500l450 500h-295zM25 300h1048q11 0 19 -7.5t8 -17.5v-275h-1100v275q0 11 7 18t18 7zM1000 200h-100v-50h100v50z" />
|
||||
<glyph unicode="" d="M400 700v-300h300v300h295l-445 500l-450 -500h300zM25 300h1048q11 0 19 -7.5t8 -17.5v-275h-1100v275q0 11 7 18t18 7zM1000 200h-100v-50h100v50z" />
|
||||
<glyph unicode="" d="M405 400l596 596l-154 155l-442 -442l-150 151l-155 -155zM25 300h1048q11 0 19 -7.5t8 -17.5v-275h-1100v275q0 11 7 18t18 7zM1000 200h-100v-50h100v50z" />
|
||||
<glyph unicode="" d="M409 1103l-97 97l-212 -212l97 -98zM650 861l-149 149l-212 -212l149 -149l-238 -248h700v699zM25 300h1048q11 0 19 -7.5t8 -17.5v-275h-1100v275q0 11 7 18t18 7zM1000 200h-100v-50h100v50z" />
|
||||
<glyph unicode="" d="M539 950l-149 -149l212 -212l149 148l248 -237v700h-699zM297 709l-97 -97l212 -212l98 97zM25 300h1048q11 0 19 -7.5t8 -17.5v-275h-1100v275q0 11 7 18t18 7zM1000 200h-100v-50h100v50z" />
|
||||
<glyph unicode="" d="M1200 1199v-1079l-475 272l-310 -393v416h-392zM1166 1148l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M1100 1000v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1200h-100v-200h100v200z" />
|
||||
<glyph unicode="" d="M578 500h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120zM700 1200h-100v-200h100v200zM1300 538l-475 -476l-244 244l123 123l120 -120l353 352z" />
|
||||
<glyph unicode="" d="M529 500h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170zM700 1200h-100v-200h100v200zM1167 6l-170 170l-170 -170l-127 127l170 170l-170 170l127 127l170 -170l170 170l127 -128 l-170 -169l170 -170z" />
|
||||
<glyph unicode="" d="M700 500h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200zM700 1000h-100v200h100v-200zM1000 600h-200v-300h-200l300 -300l300 300h-200v300z" />
|
||||
<glyph unicode="" d="M602 500h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200zM700 1000h-100v200h100v-200zM1000 300h200l-300 300l-300 -300h200v-300h200v300z" />
|
||||
<glyph unicode="" d="M1200 900v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h1200zM0 800v-550q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200zM100 500h400v-200h-400v200z" />
|
||||
<glyph unicode="" d="M500 1000h400v198l300 -298l-300 -298v198h-400v200zM100 800v200h100v-200h-100zM400 800h-100v200h100v-200zM700 300h-400v-198l-300 298l300 298v-198h400v-200zM800 500h100v-200h-100v200zM1000 500v-200h100v200h-100z" />
|
||||
<glyph unicode="" d="M1200 50v1106q0 31 -18 40.5t-44 -7.5l-276 -117q-25 -16 -43.5 -50.5t-18.5 -65.5v-359q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5zM550 1200l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447l-100 203v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300z" />
|
||||
<glyph unicode="" d="M1100 106v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394 q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5z" />
|
||||
<glyph unicode="" d="M675 1000l-100 100h-375l-100 -100h400l200 -200v-98l295 98h105v200h-425zM500 300v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5zM100 800h300v-200h-300v200zM700 565l400 133 v-163l-400 -133v163zM100 500h300v-200h-300v200zM805 300l295 98v-298h-425l-100 -100h-375l-100 100h400l200 200h105z" />
|
||||
<glyph unicode="" d="M179 1169l-162 -162q-1 -11 -0.5 -32.5t16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q16 17 13 40.5t-22 37.5l-192 136q-19 14 -45 12t-42 -19l-119 -118q-143 103 -267 227q-126 126 -227 268l118 118 q17 17 20 41.5t-11 44.5l-139 194q-14 19 -36.5 22t-40.5 -14z" />
|
||||
<glyph unicode="" d="M1200 712v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40t-53.5 -36.5t-31 -27.5l-9 -10v-200q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38 t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5zM800 650l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -15 -35.5t-35 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5 t30 -27.5t12 -24l1 -10v-50z" />
|
||||
<glyph unicode="" d="M175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250zM1200 100v-100h-1100v100h1100z" />
|
||||
<glyph unicode="" d="M600 1100h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300v1000q0 41 29.5 70.5t70.5 29.5zM1000 800h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300v700q0 41 29.5 70.5t70.5 29.5zM400 0v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400h300z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM200 800v-300h200v-100h-200v-100h300v300h-200v100h200v100h-300zM800 800h-200v-500h200v100h100v300h-100 v100zM800 700v-300h-100v300h100z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM400 600h-100v200h-100v-500h100v200h100v-200h100v500h-100v-200zM800 800h-200v-500h200v100h100v300h-100 v100zM800 700v-300h-100v300h100z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM200 800v-500h300v100h-200v300h200v100h-300zM600 800v-500h300v100h-200v300h200v100h-300z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM500 700l-300 -150l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM900 800v-500h-700v500h700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM800 700h-130 q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM200 800v-300h200v-100h-200v-100h300v300h-200v100h200v100h-300zM800 300h100v500h-200v-100h100v-400z M601 300h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M1200 800v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212zM1000 900h-900v-700h900v700zM300 700v100h-100v-500h300v400h-200zM800 300h100v500h-200v-100h100v-400zM401 400h-100v200h100v-200z M601 300h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM1000 900h-900v-700h900v700zM400 700h-200v100h300v-300h-99v-100h-100v100h99v200zM800 700h-100v100h200v-500h-100v400zM201 400h100v-100 h-100v100zM701 300h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M600 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM600 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM800 700h-300 v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
|
||||
<glyph unicode="" d="M596 1196q162 0 299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299t80 299t217 217t299 80zM596 1014q-171 0 -292.5 -121.5t-121.5 -292.5t121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5zM800 700v-100 h-100v100h-200v-100h200v-100h-200v-100h-100v400h300zM800 400h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M800 300h128q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5q0 -80 56.5 -137t135.5 -57h222v300h400v-300zM700 200h200l-300 -300 l-300 300h200v300h200v-300z" />
|
||||
<glyph unicode="" d="M600 714l403 -403q94 26 154.5 104t60.5 178q0 121 -85 207.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5q0 -80 56.5 -137t135.5 -57h8zM700 -100h-200v300h-200l300 300 l300 -300h-200v-300z" />
|
||||
<glyph unicode="" d="M700 200h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-155l-75 -45h350l-75 45v155z" />
|
||||
<glyph unicode="" d="M700 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -12t1 -11q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5 q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350z" />
|
||||
<glyph unicode="💼" d="M800 1000h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100zM500 1000h200v100h-200v-100zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
|
||||
<glyph unicode="📅" d="M1100 900v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150h1100zM0 800v-750q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100zM100 600h100v-100h-100v100zM300 600h100v-100h-100v100z M500 600h100v-100h-100v100zM700 600h100v-100h-100v100zM900 600h100v-100h-100v100zM100 400h100v-100h-100v100zM300 400h100v-100h-100v100zM500 400h100v-100h-100v100zM700 400h100v-100h-100v100zM900 400h100v-100h-100v100zM100 200h100v-100h-100v100zM300 200 h100v-100h-100v100zM500 200h100v-100h-100v100zM700 200h100v-100h-100v100zM900 200h100v-100h-100v100z" />
|
||||
<glyph unicode="📌" d="M902 1185l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207l-380 -303l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="📎" d="M518 119l69 -60l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163t35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84 t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -79.5 -17t-67.5 -51l-388 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348 q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256z" />
|
||||
<glyph unicode="📷" d="M1200 200v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5z M1000 700h-100v100h100v-100zM844 500q0 -100 -72 -172t-172 -72t-172 72t-72 172t72 172t172 72t172 -72t72 -172zM706 500q0 44 -31 75t-75 31t-75 -31t-31 -75t31 -75t75 -31t75 31t31 75z" />
|
||||
<glyph unicode="🔒" d="M900 800h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="🔔" d="M1062 400h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-22 -9 -63 -23t-167.5 -37t-251.5 -23t-245.5 20.5t-178.5 41.5l-58 20q-18 7 -31 27.5t-13 40.5q0 21 13.5 35.5t33.5 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94 q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327zM600 104q-54 0 -103 6q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6z" />
|
||||
<glyph unicode="🔖" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="🔥" d="M400 755q2 -12 8 -41.5t8 -43t6 -39.5t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85t5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5 q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129 q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5z" />
|
||||
<glyph unicode="🔧" d="M948 778l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138z" />
|
||||
</font>
|
||||
</defs></svg>
|
До Ширина: | Высота: | Размер: 62 KiB |
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Antlr" version="3.4.1.9004" targetFramework="net45" />
|
||||
<package id="bootstrap" version="3.0.0" targetFramework="net45" />
|
||||
<package id="EntityFramework" version="6.1.1" targetFramework="net45" />
|
||||
<package id="jQuery" version="1.10.2" targetFramework="net45" />
|
||||
<package id="jQuery.Validation" version="1.11.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Razor" version="3.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="3.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.13.112191810" targetFramework="net45" />
|
||||
<package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security.Cookies" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security.OpenIdConnect" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
|
||||
<package id="Modernizr" version="2.6.2" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="6.0.3" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="Respond" version="1.2.0" targetFramework="net45" />
|
||||
<package id="System.IdentityModel.Tokens.Jwt" version="4.0.1" targetFramework="net45" />
|
||||
<package id="WebGrease" version="1.5.2" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,129 +0,0 @@
|
|||
# WebApp-Billing-MultiTenant
|
||||
---------------------------
|
||||
This code sample creates a Web App that allows the logged-in user to give consent to the application, to call the Azure Graph API and the Azure Usage API on the user's behalf. It also shows the OAuth flows required to get consent for the ‘Reader’ role, for the list of Microsoft Azure subscriptions that the user wants to allow access to.
|
||||
|
||||
The application first lists all subscriptions that the signed-in user has access to, and then lets the user choose which subscription to use for pulling Usage data. After the subscription is selected, the app retrieves and deserializes the Usage response data, and displays it on the page.
|
||||
|
||||
This sample also demonstrates the MultiTenant functionality in Azure Active Directory (AAD), which is required in partner/ISV scenarios where you are building a Web App that needs consent from owners of multiple AAD tenants, to grant access to their directories.
|
||||
|
||||
Please note, the Usage APIs were in Preview at the time of this writing. Please refer to MSDN article
|
||||
[Azure Billing REST API Reference (Preview)](https://msdn.microsoft.com/library/azure/1ea5b323-54bb-423d-916f-190de96c6a3c) for additional details on the Billing REST APIs.
|
||||
|
||||
## How To Run This Sample
|
||||
|
||||
To run this sample you will need:
|
||||
|
||||
- Visual Studio 2013 or higher (you can get a free version [here](https://www.visualstudio.com/en-us/products/free-developer-offers-vs.aspx))
|
||||
- An Internet connection
|
||||
- An Azure subscription (a free trial is sufficient)
|
||||
|
||||
You will also need to be comfortable with the following tasks:
|
||||
|
||||
- Using the [Azure Management Portal](https://manage.windowsazure.com) (or working with your administrator) to do configuration work
|
||||
- Using Git and Github to bring the [sample code](https://github.com/Azure/BillingCodeSamples) down to your location machine
|
||||
- Using Visual Studio to edit configuration files, build, and run the sample
|
||||
|
||||
Every Azure subscription has an associated AAD tenant. If you don't already have an Azure subscription, you can get a free subscription by signing up at [http://wwww.windowsazure.com](http://www.windowsazure.com).
|
||||
|
||||
### Step 1: Configure a Web App application in your AAD tenant
|
||||
Before you can run the sample application, you will need to allow it to access your AAD tenant for authentication and authorization to access the Graph and Billing APIs.
|
||||
|
||||
To configure a new AAD application:
|
||||
|
||||
1. Log in to the [Azure Management Portal](http://manage.windowsazure.com), using credentials that have been granted service administrator or co-administrator access on the subscription which is trusting your AAD tenant, and granted Global Administrator access in the AAD tenant. See [Manage Accounts, Subscriptions, and Administrative Roles](https://msdn.microsoft.com/library/azure/hh531793.aspx) for details on managing the service administrator and co-administrators.
|
||||
|
||||
2. Select the AAD tenant you wish to use, and go to the "Applications" page.
|
||||
|
||||
3. From there, select the "Add" feature to "Add a new application my organization is developing".
|
||||
|
||||
4. Provide a name (ie: WebApp-Billing-MultiTenant or similar) for the new application.
|
||||
|
||||
5. Be sure to select the "Web Application and/or Web API" type, then click the "next" arrow.
|
||||
|
||||
6. Then specify a valid "Sign-on URL" and "App ID URI". Both must be valid well-formed, and can be changed later.
|
||||
- The "Sign-on URL" (App URL) specifies where users can sign-in and use your application. For the purposes of this sample, you can specify `http://localhost/`.
|
||||
- The "App ID URI" provides a unique/logical identifier which AAD associates with this application. In order to configure this application as Multi-Tenant, the "App ID URI" must be in a verified custom domain for an external user to grant your application access to their AAD data (ie: `xxxx.Test.OnMicrosoft.Com`, if your directory domain is `Test.OnMicrosoft.Com`). It must also be unique within your directory, and therefore not being used as the "App ID URI" for any other applications.
|
||||
- Click the check mark to save.
|
||||
|
||||
7. After you've added the new application, select it again within the list of applications and click "Configure" so you can make the following additional changes:
|
||||
- Under "Application is multi-tenant", select "Yes". Again, this setting indicates that your app can authenticate, and will require consent from, users from multiple AAD tenants.
|
||||
- Under "Keys", click the "Select Duration" dropdown list and pick an appropriate value.
|
||||
|
||||
**NOTE**: This key is used as a password for authentication in conjunction with the Client ID GUID, and is not immediately visible. As the comment indicates, it will become visible after you save all configuration changes later (below), at which point YOU MUST SAVE A COPY, as it will no longer be available for viewing in the Management Portal UI.
|
||||
|
||||
- Under "Reply URL", enter `http://<domain>/Account/SignIn`, where `domain` is the DNS name where the Web App will be hosted. For testing purposes, you will run this application in a locally hosted instance of IIS, so you will need to use `localhost:NNNNN`, where `NNNNN` = the port being used by IIS. When you're finished, the URL should look similar to `http://localhost:62080/Account/SignIn`
|
||||
- Under "Permissions to other applications", click the "Add Application" button, select the "Windows Azure Service Management API" row, and click the check mark to save. After saving, hover the "Delegated Permissions" area on the right side of the "Windows Azure Service Management" row, click the "Delegated Permissions" drop down list, and select the "Access Azure Service Management (preview)" option This will ensure the sample application will have permissions to access the Windows Azure Service Management APIs, which is the permission used to secure the Billing APIs.
|
||||
|
||||
**NOTE**: the "Windows Azure Active Directory" permission "Enable sign-on and read users' profiles" is enabled by default. This allows users to sign in to the application with their organizational accounts, enabling the application to read the profiles of signed-in users, such as their email address and contact information. This is a delegated permission, which gives the user the ability to consent before proceeding. Please refer to [Adding, Updating, and Removing an Application](https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx) for more depth on configuring an Azure AD tenant to enable an application to access your tenant.
|
||||
|
||||
8. Finally, click "Save" at the bottom of the page to save all of the above configuration changes.
|
||||
|
||||
9. While you are on this page, also note/copy the "Client ID" GUID and the client "Key", as you will use these in Step #3 below. As mentioned above, YOU MUST SAVE A COPY of this key, as it will no longer be available for viewing in the Management Portal UI.
|
||||
|
||||
### Step 2: Clone or download the BillingCodeSamples repository
|
||||
|
||||
From your shell (ie: Git Bash, etc.) or command line, run the following command :
|
||||
|
||||
git clone https://github.com/Azure/BillingCodeSamples.git
|
||||
|
||||
### Step 3: Edit and Build the sample in Visual Studio
|
||||
After you've configured your tenant and downloaded the sample app, you will need to go into the local sub directory in which the Visual Studio solution is stored (typically in `<your-git-root-directory>\BillingCodeSamples`), and open the `ConsoleApp-Billing-MultiTenant.sln` Visual Studio solution. Upon opening, navigate to the `web.config` file and update the following key/value pairs, using your "Client ID" GUID and the client "Key" configuration information from earlier. NOTE: It's very important that all values match your configuration!
|
||||
|
||||
<add key="ida:ClientID" value="ENTER-CLIENT-ID-GUID" />
|
||||
<add key="ida:Password" value="ENTER-CLIENT-KEY" />
|
||||
|
||||
The static method `GetUsage()`, which is defined in `AzureResourceManagerUtil.cs`, is responsible for calling the Usage API for the specified subscription, after getting the token for the logged-in user. If you would like to query for a different time range, you can change the `reportedStartTime` and `reportedEndTime` parameter values in this method accordingly :
|
||||
|
||||
string requesturl = String.Format("https://management.azure.com/subscriptions/{0}/providers/Microsoft.Commerce/UsageAggregates?api-version=2015-06-01-preview&reportedstartTime=2015-05-15+00%3a00%3a00Z&reportedEndTime=2015-05-16+00%3a00%3a00Z", subscriptionId);
|
||||
|
||||
When you build the solution, it will also restore the missing Nuget packages which contain libraries upon which the sample depends.
|
||||
|
||||
### Step 4: Run the application against your AAD tenant and the Billing APIs
|
||||
|
||||
When finished with Step 3, you should be able to successfully run the application locally, and will be greeted with the following Sign-In page in your browser where you can select the type of credentials you would like to use for authentication :
|
||||
|
||||
<center>![Sign-In] [1]</center>
|
||||
|
||||
**Note**: The credentials you use for testing the application have 2 requirements :
|
||||
|
||||
- The Azure Billing REST APIs are implemented as a Resource Provider as part of the Azure Resource Manager, and therefore share its dependencies. Access control for Azure Resource Manager uses the built-in Owner, Contributor, and Reader roles, via the Role Based Access Control (RBAC) feature in the [Azure Preview Portal](https://portal.azure.com/). Therefore, you must make sure that the logged-in user is a member of either the ‘Reader’, ‘Owner’ or ‘Contributor’ roles for the specified subscription. By default, all Azure service administrator accounts are members of the Owner role. For details, see [Role-based access control in the Microsoft Azure portal](https://azure.microsoft.com/en-us/documentation/articles/role-based-access-control-configure/).
|
||||
|
||||
- In addition, in order to access the Usage data for the Azure subscription, the credentials you use for sign-in must be granted service administrator or co-administrator access on the subscription.
|
||||
|
||||
If you elect to sign-in with a Microsoft Account, you will first be prompted to specify the DNS name for the AAD tenant (ie: `contoso.com`, `BLTest.OnMicrosoft.Com`, etc.)
|
||||
|
||||
<center>![Sign-In] [2]</center>
|
||||
|
||||
After you select the type of credentials you will use for sign-in, you will be redirected to the appropriate page for entering your credentials. The first example below is the page used for work or school account (aka: Org ID), the second is for Microsoft account :
|
||||
|
||||
<center>![Sign-In] [3]</center>
|
||||
<center>![Sign-In] [4]</center>
|
||||
|
||||
After you successfully sign-in, the first page you see will be similar to the one below, which shows you the subscriptions available to you, given the credentials you used for sign-in. On this page, you will want to pick the subscription you are interested in seeing Usage details for, by clicking the "Connect" button :
|
||||
|
||||
<center>![Sign-In] [5]</center>
|
||||
|
||||
Finally, the last page you will see will show you the Usage consumption details for the subscription you selected, similar to the one below:
|
||||
|
||||
<center>![Sign-In] [6]</center>
|
||||
|
||||
<!--Image references-->
|
||||
[1]: Readme-Sign-In.PNG
|
||||
[2]: Readme-Sign-In-LiveID-TenantDNS.PNG
|
||||
[3]: Readme-Sign-In-OrgID.PNG
|
||||
[4]: Readme-Sign-In-LiveID.PNG
|
||||
[5]: Readme-Subscription.PNG
|
||||
[6]: Readme-Usage.PNG
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Sign-In-LiveID-TenantDNS.PNG
До Ширина: | Высота: | Размер: 71 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Sign-In-LiveID.PNG
До Ширина: | Высота: | Размер: 346 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Sign-In-OrgID.PNG
До Ширина: | Высота: | Размер: 121 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Sign-In.PNG
До Ширина: | Высота: | Размер: 68 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Subscription.PNG
До Ширина: | Высота: | Размер: 105 KiB |
Двоичные данные
WebApp-Billing-MultiTenant/Readme-Usage.PNG
До Ширина: | Высота: | Размер: 216 KiB |
|
@ -1,28 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{06874A2C-7CEF-4191-96B7-5393F3AEC912}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
LICENSE.md = LICENSE.md
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ISVDemoUsage", "ISVDemoUsage\ISVDemoUsage.csproj", "{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D8FBB97-03E4-4870-83E3-6128BB48B7B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
23
readme.md
|
@ -1,23 +1,12 @@
|
|||
# Microsoft Azure Billing API Code Samples
|
||||
|
||||
The Microsoft Azure Billing APIs enable integration of Azure Billing information into your applications, providing new insights into your consumption of Azure resources, allowing you to accurately predict and manage your Azure resource consumption costs.
|
||||
The Microsoft Azure Billing have moved to the new [Azure Code Sample](https://azure.microsoft.com/en-us/documentation/samples/) repositories. You can also navigate directly to the 3 new repositories:
|
||||
|
||||
To learn more about the Billing Usage and RateCard APIs, visit the overview article [Gain insights into your Microsoft Azure resource consumption](https://azure.microsoft.com/documentation/articles/billing-usage-rate-card-overview/). Visit the [Azure Billing REST API Reference](https://msdn.microsoft.com/en-us/library/azure/mt218998.aspx) article for more details on each of the APIs.
|
||||
- [billing-dotnet-usage-api](https://github.com/Azure-Samples/billing-dotnet-usage-api) - This sample will help you get started with the Usage API.
|
||||
- [billing-dotnet-ratecard-api](https://github.com/Azure-Samples/billing-dotnet-ratecard-api/) - This sample help you get started with the RateCard API.
|
||||
- [billing-dotnet-webapp-multitenant](https://github.com/Azure-Samples/billing-dotnet-webapp-multitenant/) - This Multi-Tenant sample creates a WebApp that allows the signed-in user to give it consent, to call the Azure Graph API and the Usage API on the user's behalf. It also shows the OAuth flows required to get consent for the ‘Reader’ role, to access the list of Microsoft Azure subscriptions that the user wants to allow access to.
|
||||
|
||||
## Get started
|
||||
|
||||
To download the source code of our samples via your favorite **git** shell or command line (ie: Git Bash, Git for Windows, etc.) just type:
|
||||
|
||||
git clone https://github.com/Azure/BillingCodeSamples.git
|
||||
cd ./BillingCodeSamples/
|
||||
|
||||
Before you attempt to run the samples, please be sure to follow the instructions in the associated readme.md files for each, as they contain instructions for completing the requisite Azure Active Directory app registration work.
|
||||
|
||||
## Sample Index
|
||||
|
||||
- [ConsoleApp-Billing-Usage](./ConsoleApp-Billing-Usage) - This sample will help you get started with using the Usage API.
|
||||
- [ConsoleApp-Billing-RateCard](./ConsoleApp-Billing-RateCard) - This sample help you get started with using the RateCard API.
|
||||
- [WebApp-Billing-MultiTenant](./WebApp-Billing-MultiTenant) - This MultiTenant sample creates a WebApp that allows the logged-in user to give it consent, to call the Azure Graph API and the Usage API on the user's behalf. It also shows the OAuth flows required to get consent for the ‘Reader’ role, to access the list of Microsoft Azure subscriptions that the user wants to allow access to.
|
||||
To learn more about the Billing Usage and RateCard APIs, visit the overview article [Gain insights into your Microsoft Azure resource consumption](https://azure.microsoft.com/documentation/articles/billing-usage-rate-card-overview/). Please note, the Billing APIs were in Preview at the time of this writing. Please refer to MSDN article [Azure Billing REST API Reference](https://msdn.microsoft.com/library/azure/mt218998.aspx) for current details on the Billing APIs.
|
||||
|
||||
## Need Help?
|
||||
|
||||
|
@ -29,7 +18,5 @@ If you would like to provide feedback on the Billing APIs or ideas on how we can
|
|||
|
||||
If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.com/guidelines.html).
|
||||
|
||||
If you encounter any bugs with the library please file an issue in the [Issues](https://github.com/Azure/BillingCodeSamples/issues) section of the repository.
|
||||
|
||||
## Learn More
|
||||
* [Azure Billing REST API Reference ](https://msdn.microsoft.com/library/azure/1ea5b323-54bb-423d-916f-190de96c6a3c)
|
||||
|
|