adding source code as checkpoint for further editing/refinement.
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -0,0 +1,261 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
|
@ -0,0 +1,31 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App1"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<Image Source="ms-appx:///Assets/beer.png" Stretch="Uniform" Height="160" HorizontalAlignment="Center"/>
|
||||
<TextBlock x:Name="KegTitle" x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" Margin="0,1,0,0" >
|
||||
<StackPanel Orientation="Vertical" Margin="19,6,-19,-6" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="AdminScan1" x:Uid="AdminScan1" Text="{Binding [AdminScan1]}" Style="{StaticResource AppBodyTextBlockStyle}" Margin="60,0,60,0" HorizontalTextAlignment="Center"/>
|
||||
<TextBlock x:Name="AdminScan2" x:Uid="AdminScan2" Text="{Binding [AdminScan2]}" Style="{StaticResource AppBodyTextBlockStyle}" Margin="60,0,60,0" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using System.Diagnostics;
|
||||
using Windows.Devices.Gpio;
|
||||
using Windows.UI.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime;
|
||||
using Keg.DAL.Models;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using System.Text;
|
||||
using Keg.DAL;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App1 : Page
|
||||
{
|
||||
public Admin_App1()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
Window.Current.CoreWindow.KeyDown += OnKeyDown;
|
||||
}
|
||||
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
|
||||
public async void OnKeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs e)
|
||||
{
|
||||
if (e.VirtualKey == Windows.System.VirtualKey.Enter)
|
||||
{
|
||||
var k = await User.GetUserByHashcode(Hasher.GetSmartCardHash(sb.ToString()));
|
||||
Dictionary<string, string> admin = new Dictionary<string, string>();
|
||||
admin.Add($"Admin id: {sb.ToString()} ", $"Hash: {Hasher.GetSmartCardHash(sb.ToString())} ");
|
||||
if (k != null && k.IsApprover)
|
||||
{
|
||||
KegLogger.KegLogTrace("Admin Login successful", "App1:OnKeyDown", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, admin);
|
||||
Window.Current.CoreWindow.KeyDown -= OnKeyDown;
|
||||
this.Frame.Navigate(typeof(Admin_App2));
|
||||
}
|
||||
else
|
||||
{
|
||||
KegLogger.KegLogTrace("Admin Login unsuccessful", "App1:OnKeyDown", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, admin);
|
||||
}
|
||||
sb.Clear();
|
||||
return;
|
||||
}
|
||||
sb.Append((int)e.VirtualKey - 48);
|
||||
}
|
||||
|
||||
private async void AddAdminUser(string hashcode)
|
||||
{
|
||||
User u = new User();
|
||||
{
|
||||
u.HashCode = hashcode;
|
||||
u.IsApprover = true;
|
||||
}
|
||||
User.AddUserAsync(u);
|
||||
}
|
||||
|
||||
public enum NotifyType
|
||||
{
|
||||
StatusMessage,
|
||||
ErrorMessage
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App2"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Image Source="ms-appx:///Assets/beer.png" Stretch="Uniform" Height="160" HorizontalAlignment="Center"/>
|
||||
<TextBlock x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" Margin="0,1,0,0" >
|
||||
<StackPanel Orientation="Vertical" Height="639" VerticalAlignment="Center" >
|
||||
<TextBlock x:Uid="Welcome" Text="{Binding [Welcome]}" Style="{StaticResource AppBodyTextBlockStyle}" Margin="60,0,60,0"/>
|
||||
<Button x:Uid="AdminAction1" Content="{Binding [AdminAction1]}" Style="{StaticResource AppButtonStyle}" Click="Button_Click" Margin="0,10,0,0"/>
|
||||
<HyperlinkButton x:Uid="AdminAction2" Content="{Binding [AdminAction2]}" Style="{StaticResource AppHyperlinkStyle}" Click="HyperlinkButton_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using System.Diagnostics;
|
||||
using Windows.Devices.Gpio;
|
||||
using Windows.UI.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime;
|
||||
using Keg.DAL;
|
||||
using Keg.DAL.Models;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using System.Text;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App2 : Page
|
||||
{
|
||||
public Admin_App2()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Frame.Navigate(typeof(Admin_App3));
|
||||
}
|
||||
|
||||
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Frame.Navigate(typeof(Admin_App6));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App3"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<Button Grid.Column="0" x:Name="BackButton" Content="{StaticResource IconBack}" Background="Transparent" BorderThickness="0" BorderBrush="Transparent"
|
||||
FontFamily="{StaticResource IconFontFamily}" FontSize="24"
|
||||
Margin="24,0,0,0" Height="48" Width="48" VerticalAlignment="Top" FontWeight="ExtraBold" FontStretch="ExtraExpanded" Click="BackButton_Click"/>
|
||||
<Image Source="ms-appx:///Assets/beer.png" Stretch="Uniform" Height="160" HorizontalAlignment="Center"/>
|
||||
<TextBlock x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" Margin="0,1,0,0" >
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<TextBlock x:Uid="ScanBadge" Text="{Binding [ScanBadge]}" Style="{StaticResource AppBodyTextBlockStyle}"/>
|
||||
<Image Source="Assets/id.png" HorizontalAlignment="Center" Height="423" Width="343"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Keg.DAL.Models;
|
||||
using Keg.DAL;
|
||||
using System.Text;
|
||||
|
||||
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App3 : Page
|
||||
{
|
||||
public Admin_App3()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
Window.Current.CoreWindow.KeyDown += OnKeyDown;
|
||||
}
|
||||
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
|
||||
public void OnKeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs e)
|
||||
{
|
||||
if (e.VirtualKey == Windows.System.VirtualKey.Enter)
|
||||
{
|
||||
Dictionary<string, string> user = new Dictionary<string, string>();
|
||||
user.Add($"User id: {sb.ToString()} ", $"Hash: {Hasher.GetSmartCardHash(sb.ToString())} ");
|
||||
if (sb.Length != 0)
|
||||
{
|
||||
User u = new User();
|
||||
{
|
||||
u.HashCode = Hasher.GetSmartCardHash(sb.ToString());
|
||||
u.IsApprover = false;
|
||||
}
|
||||
KegLogger.KegLogTrace($"Adding user User id: { sb.ToString()} Hash: { Hasher.GetSmartCardHash(sb.ToString())}", "App3:OnKeyDown", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, null);
|
||||
User.AddUserAsync(u);
|
||||
Window.Current.CoreWindow.KeyDown -= OnKeyDown;
|
||||
this.Frame.Navigate(typeof(Admin_App4));
|
||||
}
|
||||
sb.Clear();
|
||||
return;
|
||||
}
|
||||
sb.Append((int)e.VirtualKey - 48);
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Frame.Navigate(typeof(Admin_App2));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App4"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<TextBlock x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" Margin="0,1,0,0" >
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<TextBlock x:Uid="AddUser1" Text="{Binding [AddUser1]}" Style="{StaticResource AppTitleTextBlockStyle}" />
|
||||
<Image Source="Assets/beer.gif" HorizontalAlignment="Center" Height="405" Margin="509,0,495,0" Width="496" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App4 : Page
|
||||
{
|
||||
public Admin_App4()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
NavigateNext();
|
||||
}
|
||||
|
||||
private async void NavigateNext()
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
this.Frame.Navigate(typeof(Admin_App5));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App5"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<Button Grid.Column="0" x:Name="BackButton" Content="{StaticResource IconBack}" Background="Transparent" BorderThickness="0" BorderBrush="Transparent"
|
||||
FontFamily="{StaticResource IconFontFamily}" FontSize="24"
|
||||
Margin="24,0,0,0" Height="48" Width="48" VerticalAlignment="Top" FontWeight="ExtraBold" FontStretch="ExtraExpanded" Click="BackButton_Click"/>
|
||||
<TextBlock x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" Margin="0,1,0,0" >
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<TextBlock x:Uid="AddUser2" Text="{Binding [AddUser2]}" Style="{StaticResource AppBodyTextBlockStyle}"/>
|
||||
<Image Source="Assets/checkmark.png" HorizontalAlignment="Center" Height="405" Margin="509,0,495,0" Width="496" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App5 : Page
|
||||
{
|
||||
public Admin_App5()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Frame.Navigate(typeof(Admin_App2));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<Page
|
||||
x:Class="Admin.UWP.Admin_App6"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="0.5*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Grid.Row="0" x:Name="HeaderRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<Button Grid.Column="0" x:Name="BackButton" Content="{StaticResource IconBack}" Background="Transparent" BorderThickness="0" BorderBrush="Transparent"
|
||||
FontFamily="{StaticResource IconFontFamily}" FontSize="24"
|
||||
Margin="24,0,0,0" Height="48" Width="48" VerticalAlignment="Top" FontWeight="ExtraBold" FontStretch="ExtraExpanded" Click="BackButton_Click"/>
|
||||
<TextBlock x:Uid="KegTitle" Text="{Binding [KegTitle]}" Style="{StaticResource AppTitleTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" x:Name="DataRow" >
|
||||
<StackPanel Orientation="Vertical" >
|
||||
<TextBlock x:Uid="OfficeHours" Text="{Binding [OfficeHours]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center">
|
||||
<ComboBox x:Name="cBox1" Style="{StaticResource AppComboBoxStyle}" />
|
||||
<ComboBox x:Name="cBox2" Style="{StaticResource AppComboBoxStyle}" />
|
||||
<TextBlock x:Uid="To" Text="{Binding [To]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
<ComboBox x:Name="cBox3" Style="{StaticResource AppComboBoxStyle}" />
|
||||
<ComboBox x:Name="cBox4" Style="{StaticResource AppComboBoxStyle}" />
|
||||
</StackPanel>
|
||||
<TextBlock x:Uid="EventDuration" Text="{Binding [EventDuration]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
|
||||
<ComboBox x:Name="cBox5" Style="{StaticResource AppComboBoxStyle}" />
|
||||
<TextBlock x:Uid="Minutes" Text="{Binding [Minutes]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<TextBlock x:Uid="ConsumptionLimit" Text="{Binding [ConsumptionLimit]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
|
||||
<ComboBox x:Name="cBox6" Style="{StaticResource AppComboBoxStyle}" />
|
||||
<TextBlock x:Uid="Pints" Text="{Binding [Pints]}" Style="{StaticResource AppBodyTextBlockStyle}" HorizontalTextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<Button Content="Save Settings" Style="{StaticResource AppButtonStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" Click="SaveSettings" Margin="0,200,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,115 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using Keg.DAL;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class Admin_App6 : Page
|
||||
{
|
||||
private class KegConfig
|
||||
{
|
||||
[JsonProperty("maxeventdurationminutes")]
|
||||
public int MaxEventDurationMinutes { get; set; }
|
||||
|
||||
[JsonProperty("maxuserouncesperhour")]
|
||||
public int MaxUserOuncesPerHour { get; set; }
|
||||
|
||||
[JsonProperty("corehours")]
|
||||
public string CoreHours { get; set; }
|
||||
|
||||
[JsonProperty("coredays")]
|
||||
public string CoreDays { get { return "Mon, Tue, Wed, Thu, Fri"; } }
|
||||
}
|
||||
private void PopulateComboBox()
|
||||
{
|
||||
List<string> timeIntervals = new List<string>();
|
||||
TimeSpan startTime = new TimeSpan(1, 0, 0);
|
||||
DateTime startDate = new DateTime(DateTime.MinValue.Ticks); // Date to be used to get shortTime format.
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
int minutesToBeAdded = 60 * i; // Increasing minutes by 30 minutes interval
|
||||
TimeSpan timeToBeAdded = new TimeSpan(0, minutesToBeAdded, 0);
|
||||
TimeSpan t = startTime.Add(timeToBeAdded);
|
||||
DateTime result = startDate + t;
|
||||
timeIntervals.Add(result.ToString("HH:mm")); // Use Date.ToShortTimeString() method to get the desired format
|
||||
}
|
||||
cBox1.ItemsSource = timeIntervals;
|
||||
cBox1.SelectedIndex = timeIntervals.Count() / 2;
|
||||
cBox2.ItemsSource = new List<string> { "AM", "PM" };
|
||||
cBox2.SelectedIndex = 0;
|
||||
cBox3.ItemsSource = timeIntervals;
|
||||
cBox3.SelectedIndex = (timeIntervals.Count() / 2) + 4;
|
||||
cBox4.ItemsSource = new List<string> { "AM", "PM" };
|
||||
cBox4.SelectedIndex = 1;
|
||||
List<int> minutes = new List<int>();
|
||||
for(int i = 1; i < 24; i++ )
|
||||
{
|
||||
minutes.Add(i * 60);
|
||||
}
|
||||
cBox5.ItemsSource = minutes;
|
||||
cBox5.SelectedIndex = 1;
|
||||
cBox6.ItemsSource = new List<int> { 1, 2, 3, 4, 5, 6 };
|
||||
cBox6.SelectedIndex = 3;
|
||||
}
|
||||
public Admin_App6()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
PopulateComboBox();
|
||||
}
|
||||
|
||||
private static async void SaveKegConfigAsync(KegConfig config)
|
||||
{
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
string url = $"https://kegocnizerdemofunctions.azurewebsites.net/api/kegconfig";
|
||||
var data = JsonConvert.SerializeObject(config);
|
||||
StringContent content = new StringContent(data, System.Text.Encoding.UTF8, "application/json");
|
||||
KegLogger.KegLogTrace($"Save Keg Config MaxEventDuration : {config.MaxEventDurationMinutes} MaxUserOuncesPerHour: {config.MaxUserOuncesPerHour} CoreHours: {config.CoreHours}",
|
||||
"App6:SaveSettings", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, null);
|
||||
var result = await client.PostAsync(url, content);
|
||||
}
|
||||
|
||||
private void SaveSettings(object sender, RoutedEventArgs e)
|
||||
{
|
||||
KegConfig config = new KegConfig();
|
||||
config.MaxEventDurationMinutes = (int)cBox5.SelectedItem;
|
||||
config.MaxUserOuncesPerHour = (int)cBox6.SelectedItem;
|
||||
config.CoreHours = GetCoreHours(cBox1.SelectedItem.ToString() + cBox2.SelectedItem.ToString() + ";" + cBox3.SelectedItem.ToString() + cBox4.SelectedItem.ToString());
|
||||
SaveKegConfigAsync(config);
|
||||
}
|
||||
|
||||
private string GetCoreHours(String timeString)
|
||||
{
|
||||
string EventDuration = null;
|
||||
String[] timeStrings = timeString.Split(';');
|
||||
DateTime dt1 = DateTime.ParseExact(timeStrings[0], "hh:mmtt", System.Globalization.CultureInfo.CurrentCulture);
|
||||
DateTime dt2 = DateTime.ParseExact(timeStrings[1], "hh:mmtt", System.Globalization.CultureInfo.CurrentCulture);
|
||||
EventDuration = dt1.Hour + "T" + dt2.Hour;
|
||||
return EventDuration;
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Frame.Navigate(typeof(Admin_App2));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.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)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{B048E94D-9407-422D-A213-1D79061D7A63}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Admin.UWP</RootNamespace>
|
||||
<AssemblyName>Admin.UWP</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<PackageCertificateKeyFile>TestSmartCardApp_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Admin-App2.xaml.cs">
|
||||
<DependentUpon>Admin-App2.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Admin-App3.xaml.cs">
|
||||
<DependentUpon>Admin-App3.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Admin-App4.xaml.cs">
|
||||
<DependentUpon>Admin-App4.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Admin-App5.xaml.cs">
|
||||
<DependentUpon>Admin-App5.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Admin-App6.xaml.cs">
|
||||
<DependentUpon>Admin-App6.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Admin-App1.xaml.cs">
|
||||
<DependentUpon>Admin-App1.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
<None Include="Admin.UWP_TemporaryKey.pfx" />
|
||||
<PRIResource Include="Strings\en-US\Resources.resw" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\beer.gif" />
|
||||
<Content Include="Assets\beer.png" />
|
||||
<Content Include="Assets\checkmark.png" />
|
||||
<Content Include="Assets\id.png" />
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="Admin-App2.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Admin-App3.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Admin-App4.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Admin-App5.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Admin-App6.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Admin-App1.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Styles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<SDKReference Include="WindowsDesktop, Version=10.0.16299.0">
|
||||
<Name>Windows Desktop Extensions for the UWP</Name>
|
||||
</SDKReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights">
|
||||
<Version>2.6.4</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.0.8</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq">
|
||||
<Version>4.8.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>11.0.2</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WCFMetadata Include="Connected Services\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Keg.DAL, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Keg.DAL\bin\x64\Release\Keg.DAL.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.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>
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2027
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.UWP", "Admin.UWP.csproj", "{B048E94D-9407-422D-A213-1D79061D7A63}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x64.Build.0 = Debug|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x86.Build.0 = Debug|x86
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|ARM.Build.0 = Release|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x64.ActiveCfg = Release|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x64.Build.0 = Release|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x64.Deploy.0 = Release|x64
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x86.ActiveCfg = Release|x86
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x86.Build.0 = Release|x86
|
||||
{B048E94D-9407-422D-A213-1D79061D7A63}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4ADA610B-7B5E-4394-AA10-49C67B0F5129}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,12 @@
|
|||
<Application
|
||||
x:Class="Admin.UWP.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP"
|
||||
RequestedTheme="Light">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary Source="Styles.xaml" />
|
||||
</Application.Resources>
|
||||
|
||||
</Application>
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Text;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.ApplicationModel.Resources.Core;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Globalization;
|
||||
using Windows.System.UserProfile;
|
||||
using Keg.DAL;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Windows.Security.ExchangeActiveSyncProvisioning;
|
||||
using Moq;
|
||||
|
||||
namespace Admin.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(Admin_App1), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
EasClientDeviceInformation deviceInfo;
|
||||
string _productName = null;
|
||||
|
||||
deviceInfo = new EasClientDeviceInformation();
|
||||
_productName = deviceInfo.SystemProductName;
|
||||
KegLogger.KegLogTrace("Admin App Loaded", "App:Initialize", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
KegLogger.KegLogException(e.Exception, "App:NavigationFailed", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 4.3 KiB |
После Ширина: | Высота: | Размер: 5.4 KiB |
После Ширина: | Высота: | Размер: 6.8 KiB |
После Ширина: | Высота: | Размер: 9.5 KiB |
После Ширина: | Высота: | Размер: 24 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 1.9 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
После Ширина: | Высота: | Размер: 5.4 KiB |
После Ширина: | Высота: | Размер: 7.5 KiB |
После Ширина: | Высота: | Размер: 2.0 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
После Ширина: | Высота: | Размер: 3.0 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 9.2 KiB |
Двоичные данные
Demos/Kegocnizer/CS/Admin.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-16.png
Normal file
После Ширина: | Высота: | Размер: 518 B |
Двоичные данные
Demos/Kegocnizer/CS/Admin.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-256.png
Normal file
После Ширина: | Высота: | Размер: 8.6 KiB |
Двоичные данные
Demos/Kegocnizer/CS/Admin.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-32.png
Normal file
После Ширина: | Высота: | Размер: 976 B |
Двоичные данные
Demos/Kegocnizer/CS/Admin.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-48.png
Normal file
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 4.4 KiB |
После Ширина: | Высота: | Размер: 413 B |
После Ширина: | Высота: | Размер: 595 B |
Двоичные данные
Demos/Kegocnizer/CS/Admin.UWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
Normal file
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 6.8 KiB |
После Ширина: | Высота: | Размер: 764 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 1.9 KiB |
После Ширина: | Высота: | Размер: 2.3 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
После Ширина: | Высота: | Размер: 6.4 KiB |
После Ширина: | Высота: | Размер: 2.2 KiB |
После Ширина: | Высота: | Размер: 2.7 KiB |
После Ширина: | Высота: | Размер: 3.3 KiB |
После Ширина: | Высота: | Размер: 4.7 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 40 KiB |
После Ширина: | Высота: | Размер: 5.8 KiB |
После Ширина: | Высота: | Размер: 4.7 KiB |
После Ширина: | Высота: | Размер: 6.0 KiB |
После Ширина: | Высота: | Размер: 7.6 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 29 KiB |
После Ширина: | Высота: | Размер: 4.4 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
|
||||
<Identity Name="e5517a7a-ad96-447e-b78d-209f930900da" Publisher="CN=iotkeg" Version="1.0.0.0" />
|
||||
<mp:PhoneIdentity PhoneProductId="e5517a7a-ad96-447e-b78d-209f930900da" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
<Properties>
|
||||
<DisplayName>KegAdmin</DisplayName>
|
||||
<PublisherDisplayName>iotkeg</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="Admin.UWP.App">
|
||||
<uap:VisualElements DisplayName="KegAdmin" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="Admin app for Kegocnizer" BackgroundColor="transparent">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" ShortName="Kegocnizer" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png">
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Assets\beer.png" />
|
||||
<uap:InitialRotationPreference>
|
||||
<uap:Rotation Preference="portrait" />
|
||||
<uap:Rotation Preference="landscape" />
|
||||
<uap:Rotation Preference="portraitFlipped" />
|
||||
<uap:Rotation Preference="landscapeFlipped" />
|
||||
</uap:InitialRotationPreference>
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<uap:Capability Name="sharedUserCertificates" />
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -0,0 +1,29 @@
|
|||
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("KegAdmin")]
|
||||
[assembly: AssemblyDescription("Admin app for Kegocnizer")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("Kegocnizer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 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")]
|
||||
[assembly: ComVisible(false)]
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||
optimizer.
|
||||
|
||||
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||
|
||||
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||
|
||||
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||
|
||||
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||
-->
|
||||
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<!--
|
||||
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
|
||||
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
|
||||
|
||||
</Application>
|
||||
</Directives>
|
|
@ -0,0 +1,168 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AddUser1.Text" xml:space="preserve">
|
||||
<value>Adding user to the system...</value>
|
||||
</data>
|
||||
<data name="AddUser2.Text" xml:space="preserve">
|
||||
<value>User has been added!</value>
|
||||
</data>
|
||||
<data name="AdminAction1.Content" xml:space="preserve">
|
||||
<value>Add new user</value>
|
||||
</data>
|
||||
<data name="AdminAction2.Content" xml:space="preserve">
|
||||
<value>Manage settings</value>
|
||||
</data>
|
||||
<data name="AdminScan1.Text" xml:space="preserve">
|
||||
<value>Please scan your badge</value>
|
||||
</data>
|
||||
<data name="AdminScan2.Text" xml:space="preserve">
|
||||
<value>to confirm administrative permissions.</value>
|
||||
</data>
|
||||
<data name="ConsumptionLimit.Text" xml:space="preserve">
|
||||
<value>Consumption limit per user:</value>
|
||||
</data>
|
||||
<data name="EventDuration.Text" xml:space="preserve">
|
||||
<value>Change event duration:</value>
|
||||
</data>
|
||||
<data name="KegTitle.Text" xml:space="preserve">
|
||||
<value>Kegocnizer</value>
|
||||
</data>
|
||||
<data name="KegTitleImage" xml:space="preserve">
|
||||
<value>ms-appx:///Assets/beer.png</value>
|
||||
</data>
|
||||
<data name="Minutes.Text" xml:space="preserve">
|
||||
<value>minutes</value>
|
||||
</data>
|
||||
<data name="OfficeHours.Text" xml:space="preserve">
|
||||
<value>Change office hours:</value>
|
||||
</data>
|
||||
<data name="Pints.Text" xml:space="preserve">
|
||||
<value>pints</value>
|
||||
</data>
|
||||
<data name="ScanBadge.Text" xml:space="preserve">
|
||||
<value>Scan new user's badge</value>
|
||||
</data>
|
||||
<data name="To.Text" xml:space="preserve">
|
||||
<value>to</value>
|
||||
</data>
|
||||
<data name="Welcome.Text" xml:space="preserve">
|
||||
<value>Welcome!</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,57 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Admin.UWP">
|
||||
|
||||
<!--Theme-->
|
||||
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush" Color="#F1C744"/>
|
||||
|
||||
<!--Fonts-->
|
||||
<Style x:Key="AppTitleTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="70" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AppBodyTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="45"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="0,10,0,0" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AppButtonStyle" TargetType="Button">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="Background" Value="Black"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="FontSize" Value="50"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AppHyperlinkStyle" TargetType="HyperlinkButton">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="50"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="0,10,0,0" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AppComboBoxStyle" TargetType="ComboBox">
|
||||
<Setter Property="FontSize" Value="30"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Margin" Value="10,20,20,0" />
|
||||
<Setter Property="BorderBrush" Value="Black" />
|
||||
<Setter Property="BorderThickness" Value="5" />
|
||||
<Setter Property="Width" Value="150" />
|
||||
</Style>
|
||||
|
||||
<!--Icons-->
|
||||
<FontFamily x:Key="IconFontFamily">Segoe MDL2 Assets</FontFamily>
|
||||
<FontFamily x:Key="IoTIconFontFamily">ms-appx:///Assets/Fonts/IOTMDL2.1.35.ttf#IOT MDL2 Assets</FontFamily>
|
||||
|
||||
<x:String x:Key="IconBlock"></x:String>
|
||||
<x:String x:Key="IconBack"></x:String>
|
||||
|
||||
</ResourceDictionary>
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
/*
|
||||
* Demo Keys
|
||||
*/
|
||||
|
||||
///// <summary>
|
||||
///// Update this with Azure Functions Url
|
||||
///// </summary>
|
||||
//public const string COSMOSAzureFunctionsURL = "https://kegocnizerdemofunctions.azurewebsites.net/api/";
|
||||
|
||||
///// <summary>
|
||||
///// KegConfig Guid Entiry enables to retrieve Configurations from Cloud
|
||||
///// </summary>
|
||||
//public static readonly string KEGSETTINGSGUID = "6fd83ffd-601a-48b0-bff9-566250928e8d";
|
||||
|
||||
////Change this Key as required.
|
||||
//public static readonly string INSTRUMENTKEY = "e86b04e5-ecd0-4b44-a595-d416f0611a8b";
|
||||
|
||||
/*
|
||||
* Deployed Keys
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Update this with Azure Functions Url
|
||||
/// </summary>
|
||||
public const string COSMOSAzureFunctionsURL = "https://wsdkegfunctions.azurewebsites.net/api/";
|
||||
|
||||
/// <summary>
|
||||
/// KegConfig Guid Entiry enables to retrieve Configurations from Cloud. Typically Keg Admin tool will help getting this Guid
|
||||
/// </summary>
|
||||
public static readonly string KEGSETTINGSGUID = "2a9d4c3a-75d7-4222-9827-5704efb24b54";
|
||||
|
||||
//Change this Key as required.
|
||||
public static readonly string INSTRUMENTKEY = "6d8fbbea-ecf0-4827-b6ff-c79199ba869e";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class FixedSizedQueue<T> : IReadOnlyCollection<T>
|
||||
{
|
||||
private object LOCK = new object();
|
||||
ConcurrentQueue<T> queue;
|
||||
private int _count;
|
||||
|
||||
public int MaxSize { get; set; }
|
||||
|
||||
public int Count { get { return _count; } }
|
||||
|
||||
public FixedSizedQueue(int maxSize, IEnumerable<T> items = null)
|
||||
{
|
||||
this.MaxSize = maxSize;
|
||||
if (items == null)
|
||||
{
|
||||
queue = new ConcurrentQueue<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
queue = new ConcurrentQueue<T>(items);
|
||||
EnsureLimitConstraint();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T obj)
|
||||
{
|
||||
queue.Enqueue(obj);
|
||||
_count++;
|
||||
EnsureLimitConstraint();
|
||||
}
|
||||
|
||||
private void EnsureLimitConstraint()
|
||||
{
|
||||
if (queue.Count > MaxSize)
|
||||
{
|
||||
lock (LOCK)
|
||||
{
|
||||
T overflow;
|
||||
while (queue.Count > MaxSize)
|
||||
{
|
||||
queue.TryDequeue(out overflow);
|
||||
_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
return queue.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return queue.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return queue.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
using Keg.DAL.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Devices.Gpio;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class Flow
|
||||
{
|
||||
public IDictionary<string, object> CalibrationSettings { get; set; }
|
||||
public const string FlowGPIOPinNumberSetting = @"FlowGPIOPinNumber"; // a string, valued e.g., SPI0 or SPI1 to indicate which SPI bus is being used
|
||||
public const string FlowCalibrationFactorSetting = @"FlowCalibrationFactor"; // a float (as string), such as "0.05" for 'factor' in (reading * factor) + offset
|
||||
public const string FlowCalibrationOffsetSetting = @"FlowCalibrationOffset"; // a float (as string), such as "14.0" for 'offset' in (reading * factor) + offset
|
||||
private Measurement lastMeasurement; // this value accumulates over time. Consumers should note the starting measurement and then compare that to a future measurement.
|
||||
|
||||
//RPI
|
||||
private static readonly Int32 FLOWGPIOPIN = 3; //PIN5
|
||||
|
||||
public Models.Measurement GetFlow()
|
||||
{
|
||||
return lastMeasurement;
|
||||
}
|
||||
|
||||
public event EventHandler<MeasurementChangedEventArgs> FlowChanged;
|
||||
protected virtual void OnFlowChanged(MeasurementChangedEventArgs e)
|
||||
{
|
||||
FlowChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public Flow()
|
||||
{
|
||||
CalibrationSettings = new Dictionary<string, object>(GetDefaultCalibrationSettings());
|
||||
lastMeasurement = new Measurement(0.0f, Measurement.UnitsOfMeasure.Ounces);
|
||||
}
|
||||
|
||||
public Flow(IDictionary<string, object> calibrationSettings)
|
||||
: this()
|
||||
{
|
||||
foreach (string key in calibrationSettings.Keys)
|
||||
{
|
||||
if (key.Equals(FlowGPIOPinNumberSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(FlowCalibrationFactorSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(FlowCalibrationOffsetSetting, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
CalibrationSettings[key] = calibrationSettings[key].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the purpose of this object is to allow someone an easy way to generate the proper
|
||||
// default calibration settings that this sensor interface object supports.
|
||||
// in this case, it supports a Measurement that indicates how many degrees to add
|
||||
// to readings to account for variations in the tolerance of the actual circuitry.
|
||||
public static IDictionary<string, object> GetDefaultCalibrationSettings()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{ FlowGPIOPinNumberSetting, FLOWGPIOPIN.ToString() },
|
||||
{ FlowCalibrationFactorSetting, ".0045" },
|
||||
{ FlowCalibrationOffsetSetting, "0" }
|
||||
};
|
||||
}
|
||||
|
||||
private GpioPin _pin;
|
||||
|
||||
private bool IsInitialized { get; set; }
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized)
|
||||
return;
|
||||
//IsInitialized = true;
|
||||
|
||||
int pinNumber = Int32.Parse(CalibrationSettings[FlowGPIOPinNumberSetting].ToString());
|
||||
|
||||
var c = GpioController.GetDefault();
|
||||
if (c != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_pin = c.OpenPin(pinNumber);
|
||||
if (_pin != null)
|
||||
{
|
||||
if (_pin.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
|
||||
_pin.SetDriveMode(GpioPinDriveMode.InputPullUp);
|
||||
|
||||
_pin.ValueChanged += _pin_ValueChanged;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Exception:{ex.Message}");
|
||||
KegLogger.KegLogException(ex, "Flow:Initialize", SeverityLevel.Critical);
|
||||
|
||||
KegLogger.KegLogTrace(ex.Message, "Flow:Initialize", SeverityLevel.Error,
|
||||
new Dictionary<string, string>() {
|
||||
{"PinNumber", CalibrationSettings[FlowGPIOPinNumberSetting].ToString() }
|
||||
});
|
||||
//Pin used exception
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
private int _second = -1;
|
||||
private float _persecond = 0.0f;
|
||||
|
||||
private void _pin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
|
||||
{
|
||||
Debug.WriteLine($"Flow Pinchanged:{args.Edge}");
|
||||
|
||||
var task = Task.Run(() => {
|
||||
if (args.Edge == GpioPinEdge.RisingEdge)
|
||||
{
|
||||
int second = DateTime.Now.Second;
|
||||
if (second != _second)
|
||||
{
|
||||
Debug.WriteLine($"{_persecond} per-second");
|
||||
_second = second;
|
||||
int offset = Int32.Parse(CalibrationSettings[FlowCalibrationOffsetSetting].ToString());
|
||||
float factor = float.Parse(CalibrationSettings[FlowCalibrationFactorSetting].ToString());
|
||||
lastMeasurement.Amount += _persecond * factor + offset;
|
||||
|
||||
_persecond = 0.0f;
|
||||
|
||||
OnFlowChanged(new MeasurementChangedEventArgs(lastMeasurement));
|
||||
//_second = second;
|
||||
//_persecond = 0.0f;
|
||||
}
|
||||
_persecond++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Timer _timer;
|
||||
public void Initialize(int initialDelay, int period)
|
||||
{
|
||||
Initialize();
|
||||
_timer = new Timer(OnTimer, null, initialDelay, period);
|
||||
}
|
||||
|
||||
public void ResetFlow()
|
||||
{
|
||||
lastMeasurement.Amount = 0.0f;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
var timer = _timer;
|
||||
_timer = null;
|
||||
timer?.Dispose();
|
||||
}
|
||||
|
||||
private void OnTimer(object state)
|
||||
{
|
||||
OnFlowChanged(new MeasurementChangedEventArgs(lastMeasurement));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Devices.Gpio;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class FlowControl
|
||||
{
|
||||
public IDictionary<string, object> CalibrationSettings { get; set; }
|
||||
public const string FlowControlGpioPinNumberSetting = @"FlowControlGPIOPinNumber"; // an integer, like 18
|
||||
private GpioPin _pin;
|
||||
private GpioPinValue _isActive;
|
||||
|
||||
//RPI
|
||||
private static readonly Int32 FLOWCONTROLGPIOPIN = 18; //PIN 12
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive == GpioPinValue.High; }
|
||||
set
|
||||
{
|
||||
if ((_isActive == GpioPinValue.High) != value || _pin == null)
|
||||
{
|
||||
_isActive = value ? GpioPinValue.High : GpioPinValue.Low;
|
||||
|
||||
try
|
||||
{
|
||||
if (_pin == null)
|
||||
{
|
||||
int pinNumber = FLOWCONTROLGPIOPIN; // default
|
||||
if (CalibrationSettings.ContainsKey(FlowControlGpioPinNumberSetting))
|
||||
pinNumber = Int32.Parse(CalibrationSettings[FlowControlGpioPinNumberSetting].ToString());
|
||||
Debug.WriteLine($"Flow Control:Initializing pin {pinNumber}.");
|
||||
var c = GpioController.GetDefault();
|
||||
if (c != null)
|
||||
{
|
||||
_pin = c.OpenPin(pinNumber);
|
||||
_pin.SetDriveMode(GpioPinDriveMode.Output);
|
||||
}
|
||||
}
|
||||
if (_pin != null)
|
||||
{
|
||||
Debug.WriteLine($"Setting flow control to {_isActive}.");
|
||||
_pin.Write(_isActive);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Flow Control:Error setting flow control value, " + ex.Message);
|
||||
KegLogger.KegLogException(ex, "FlowControl:IsActive", SeverityLevel.Critical);
|
||||
|
||||
KegLogger.KegLogTrace(ex.Message, "FlowControl:IsActive", SeverityLevel.Error,
|
||||
new Dictionary<string, string>() {
|
||||
{"PinNumber", CalibrationSettings[FlowControlGpioPinNumberSetting].ToString() }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<FlowControlChangedEventArgs> FlowControlChanged;
|
||||
protected virtual void OnFlowControlChanged(FlowControlChangedEventArgs e)
|
||||
{
|
||||
FlowControlChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
// the purpose of this object is to allow someone an easy way to generate the proper
|
||||
// default calibration settings that this sensor interface object supports.
|
||||
// in this case, it supports a Measurement that indicates how many degrees to add
|
||||
// to readings to account for variations in the tolerance of the actual circuitry.
|
||||
public static IDictionary<string, object> GetDefaultCalibrationSettings()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{ FlowControlGpioPinNumberSetting, FLOWCONTROLGPIOPIN.ToString() },
|
||||
};
|
||||
}
|
||||
|
||||
public FlowControl()
|
||||
{
|
||||
CalibrationSettings = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public FlowControl(IDictionary<string, object> calibrationSettings)
|
||||
: this()
|
||||
{
|
||||
CalibrationSettings.Add(FlowControlGpioPinNumberSetting, (calibrationSettings.ContainsKey(FlowControlGpioPinNumberSetting)) ? calibrationSettings[FlowControlGpioPinNumberSetting] as string : "");
|
||||
}
|
||||
|
||||
private Timer _timer;
|
||||
public void Initialize(int initialDelay, int period)
|
||||
{
|
||||
Initialize();
|
||||
_timer = new Timer(OnTimer, null, initialDelay, period);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var gpio = GpioController.GetDefault();
|
||||
if (gpio == null)
|
||||
{
|
||||
_pin = null;
|
||||
Debug.WriteLine("Flow Control:Unable to initialize, no GPIO controller.");
|
||||
KegLogger.KegLogTrace("Custom: Flow Control:Unable to initialize, no GPIO controller.",
|
||||
"FlowControl:Initialize", SeverityLevel.Error,
|
||||
new Dictionary<string, string>() {
|
||||
{"PinNumber", CalibrationSettings[FlowControlGpioPinNumberSetting].ToString() },
|
||||
{"IsActive", _isActive.ToString() }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if(_pin == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_pin = gpio.OpenPin(Int32.Parse(CalibrationSettings[FlowControlGpioPinNumberSetting].ToString()), GpioSharingMode.Exclusive);
|
||||
_pin.Write(_isActive);
|
||||
_pin.SetDriveMode(GpioPinDriveMode.Output);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Flow Control:Unable to initialize, PIN Null.{ex.Message}");
|
||||
KegLogger.KegLogException(ex, "FlowControl:Initialize", SeverityLevel.Critical);
|
||||
|
||||
KegLogger.KegLogTrace(ex.Message, "FlowControl:Initialize", SeverityLevel.Critical,
|
||||
new Dictionary<string, string>() {
|
||||
{"PinNumber", CalibrationSettings[FlowControlGpioPinNumberSetting].ToString() },
|
||||
{"IsActive", _isActive.ToString() }
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var timer = _timer;
|
||||
_timer = null;
|
||||
timer?.Dispose();
|
||||
}
|
||||
|
||||
private void OnTimer(object state)
|
||||
{
|
||||
OnFlowControlChanged(new FlowControlChangedEventArgs(IsActive));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class FlowControlChangedEventArgs : EventArgs
|
||||
{
|
||||
public Boolean Flowing { get; set; }
|
||||
public FlowControlChangedEventArgs(Boolean flowing)
|
||||
{
|
||||
Flowing = flowing;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class Hasher
|
||||
{
|
||||
public static string GetSmartCardHash(string SmartCardId)
|
||||
{
|
||||
if (SmartCardId == null)
|
||||
return SmartCardId;
|
||||
SHA256 crypt = SHA256.Create();
|
||||
var hash = new System.Text.StringBuilder();
|
||||
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(SmartCardId));
|
||||
foreach (byte b in crypto)
|
||||
{
|
||||
hash.Append(b.ToString("x2"));
|
||||
}
|
||||
return hash.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Keg.DAL.Helpers
|
||||
{
|
||||
public class Hasher
|
||||
{
|
||||
public static string GetSmartCardHash(string SmartCardId)
|
||||
{
|
||||
if (SmartCardId == null)
|
||||
return SmartCardId;
|
||||
SHA256 crypt = SHA256.Create();
|
||||
var hash = new System.Text.StringBuilder();
|
||||
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(SmartCardId));
|
||||
foreach (byte b in crypto)
|
||||
{
|
||||
hash.Append(b.ToString("x2"));
|
||||
}
|
||||
return hash.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.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>{9FD08840-1057-4AF7-92AB-21C710121B5F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Keg.DAL</RootNamespace>
|
||||
<AssemblyName>Keg.DAL</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</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;NETFX_CORE;WINDOWS_UWP</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;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="FixedSizedQueue.cs" />
|
||||
<Compile Include="Flow.cs" />
|
||||
<Compile Include="FlowControl.cs" />
|
||||
<Compile Include="FlowControlChangedEventArgs.cs" />
|
||||
<Compile Include="Hasher.cs" />
|
||||
<Compile Include="KegLogger.cs" />
|
||||
<Compile Include="MeasurementChangedEventArgs.cs" />
|
||||
<Compile Include="Models\KegSettings.cs" />
|
||||
<Compile Include="Models\Measurement.cs" />
|
||||
<Compile Include="Models\User.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Temperature.cs" />
|
||||
<Compile Include="Weight.cs" />
|
||||
<EmbeddedResource Include="Properties\Keg.DAL.rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights">
|
||||
<Version>2.5.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.0.8</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>11.0.2</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Sensors.Temperature\Sensors.Temperature.vcxproj">
|
||||
<Project>{2cd70a4f-9eed-4cda-9e07-1a2bd33b4976}</Project>
|
||||
<Name>Sensors.Temperature</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Sensors.Weight\Sensors.Weight.csproj">
|
||||
<Project>{76fb0145-f64b-4d6a-a94f-365e5dc3231f}</Project>
|
||||
<Name>Sensors.Weight</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.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>
|
|
@ -0,0 +1,212 @@
|
|||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Security.ExchangeActiveSyncProvisioning;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public static class KegLogger
|
||||
{
|
||||
private static readonly TelemetryClient telemetryClient = null;
|
||||
|
||||
public enum DeviceTypes { RPI2, RPI3, MBM, DB410, GenericBoard, Unknown };
|
||||
static DeviceTypes _type = DeviceTypes.Unknown;
|
||||
static string _productName = null;
|
||||
static EasClientDeviceInformation deviceInfo;
|
||||
|
||||
static KegLogger()
|
||||
{
|
||||
Init();
|
||||
|
||||
//KegConfig kegConfig = GlobalSettings.GetKegSetting("fdaeadba-4027-407d-bd9a-dd679c223f65").Result;
|
||||
|
||||
//Telemetry
|
||||
TelemetryConfiguration teleConfig = new TelemetryConfiguration
|
||||
{
|
||||
InstrumentationKey = Constants.INSTRUMENTKEY
|
||||
};
|
||||
teleConfig.TelemetryChannel.DeveloperMode = false;
|
||||
if(Constants.INSTRUMENTKEY.Trim().Length == 0 )
|
||||
{
|
||||
teleConfig.DisableTelemetry = true;
|
||||
}
|
||||
//override as needed
|
||||
// true: disable telemetry, false: enables telemetry
|
||||
teleConfig.DisableTelemetry = false;
|
||||
|
||||
telemetryClient = new TelemetryClient(teleConfig);
|
||||
|
||||
telemetryClient.Context.User.Id = deviceInfo.FriendlyName;
|
||||
telemetryClient.Context.Device.Type = _type.ToString();
|
||||
telemetryClient.Context.Device.Model = _productName;
|
||||
telemetryClient.Context.Device.Id = deviceInfo.Id.ToString();
|
||||
telemetryClient.Context.Device.OemName = deviceInfo.SystemManufacturer;
|
||||
|
||||
//Each reboot starts a new session
|
||||
telemetryClient.Context.Session.Id = Guid.NewGuid().ToString();
|
||||
|
||||
if (!ulong.TryParse(Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamilyVersion, out ulong version))
|
||||
{
|
||||
//var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
|
||||
//OSVersion.Text = loader.GetString("OSVersionNotAvailable");
|
||||
telemetryClient.Context.Device.OperatingSystem = deviceInfo.OperatingSystem;
|
||||
}
|
||||
else
|
||||
{
|
||||
telemetryClient.Context.Device.OperatingSystem = String.Format(CultureInfo.InvariantCulture, "{4}-IoTCore v{0}.{1}.{2}.{3}",
|
||||
(version & 0xFFFF000000000000) >> 48,
|
||||
(version & 0x0000FFFF00000000) >> 32,
|
||||
(version & 0x00000000FFFF0000) >> 16,
|
||||
version & 0x000000000000FFFF,
|
||||
deviceInfo.OperatingSystem);
|
||||
|
||||
}
|
||||
|
||||
KegLogTrace("App Started", "KegLogger", SeverityLevel.Information, null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void Init()
|
||||
{
|
||||
if (_type == DeviceTypes.Unknown)
|
||||
{
|
||||
deviceInfo = new EasClientDeviceInformation();
|
||||
_productName = deviceInfo.FriendlyName;
|
||||
|
||||
if (deviceInfo.SystemProductName.IndexOf("MinnowBoard", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
_type = DeviceTypes.MBM;
|
||||
}
|
||||
else if (deviceInfo.SystemProductName.IndexOf("Raspberry", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
if (deviceInfo.SystemProductName.IndexOf("Pi 3", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
_type = DeviceTypes.RPI3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = DeviceTypes.RPI2;
|
||||
}
|
||||
}
|
||||
else if (deviceInfo.SystemProductName == "SBC")
|
||||
{
|
||||
_type = DeviceTypes.DB410;
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = DeviceTypes.GenericBoard;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static bool IsRaspberryPi
|
||||
{
|
||||
get
|
||||
{
|
||||
return Type == DeviceTypes.RPI2 || Type == DeviceTypes.RPI3;
|
||||
}
|
||||
}
|
||||
|
||||
public static DeviceTypes Type
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _type;
|
||||
}
|
||||
}
|
||||
|
||||
// this might return null
|
||||
public static string ProductName
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _productName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async void KegLogTrace(string message, string method, SeverityLevel severityLevel = SeverityLevel.Information, IDictionary<string, string> properties = null)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
telemetryClient.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.TrackTrace(message, severityLevel, properties);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void KegLogEvent(string message, string method, IDictionary<string, string> properties)
|
||||
{
|
||||
telemetryClient.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.TrackEvent(message, properties, null);
|
||||
|
||||
}
|
||||
|
||||
public static void KegLogMetrics(string message, string method, string metricName, double metricValue)
|
||||
{
|
||||
var sample = new MetricTelemetry
|
||||
{
|
||||
Name = metricName,
|
||||
Sum = metricValue
|
||||
};
|
||||
|
||||
sample.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.TrackMetric(sample);
|
||||
|
||||
}
|
||||
|
||||
public static void KegLogMetrics(string message, string method, MetricTelemetry metric)
|
||||
{
|
||||
metric.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.Context.Operation.Name = method;
|
||||
|
||||
telemetryClient.TrackMetric(metric);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void KegLogException(Exception exception, string method, IDictionary<string, string> properties)
|
||||
{
|
||||
telemetryClient.Context.Operation.Name = method;
|
||||
//exception.StackTrace = Environment.StackTrace;
|
||||
|
||||
//ExceptionTelemetry exceptionTelemetry = new ExceptionTelemetry();
|
||||
//exceptionTelemetry.Context.Operation.Name = method;
|
||||
//exceptionTelemetry.Exception = exception;
|
||||
|
||||
telemetryClient.TrackException(exception, properties, null);
|
||||
|
||||
}
|
||||
|
||||
public static void KegLogException(Exception exception, string method, SeverityLevel? severityLevel)
|
||||
{
|
||||
//telemetryClient.Context.Operation.Name = method;
|
||||
//exception.StackTrace = Environment.StackTrace;
|
||||
|
||||
ExceptionTelemetry exceptionTelemetry = new ExceptionTelemetry();
|
||||
exceptionTelemetry.Context.Operation.Name = method;
|
||||
exceptionTelemetry.Exception = exception;
|
||||
exceptionTelemetry.SeverityLevel = severityLevel;
|
||||
|
||||
telemetryClient.TrackException(exceptionTelemetry);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class MeasurementChangedEventArgs : EventArgs
|
||||
{
|
||||
public Models.Measurement Measurement { get; set; }
|
||||
public MeasurementChangedEventArgs(Models.Measurement measurement)
|
||||
{
|
||||
this.Measurement = measurement;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
using Keg.DAL;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL.Models
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Class Designed to hold the values from CosmosDB related to KegConfig Only
|
||||
/// </summary>
|
||||
public class KegConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Hardcoded class for KegConfig Type
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
public string Type { get { return "KegConfig"; } }
|
||||
|
||||
/// <summary>
|
||||
/// Identifier
|
||||
/// </summary>
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum Event Duration In Minutes
|
||||
/// </summary>
|
||||
[JsonProperty("maxeventdurationminutes")]
|
||||
public int MaxEventDurationMinutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum Ounces to be consumed in UserConsumptionReset Minutes
|
||||
/// </summary>
|
||||
[JsonProperty("maxuserouncesperhour")]
|
||||
public int MaxUserOuncesPerHour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Core Business Hours ( Not allowed)
|
||||
/// </summary>
|
||||
[JsonProperty("corehours")]
|
||||
public string CoreHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Core Days allowed
|
||||
/// </summary>
|
||||
[JsonProperty("coredays")]
|
||||
public string CoreDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance Mode Flag
|
||||
/// </summary>
|
||||
[JsonProperty("maintenance")]
|
||||
public bool MaintenanceMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Weight Callibration Factor
|
||||
/// </summary>
|
||||
[JsonProperty("weightcalibrationfactor")]
|
||||
public float WeightCalibrationFactor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Weight Callibration Offset
|
||||
/// </summary>
|
||||
[JsonProperty("weightcalibrationoffset")]
|
||||
public float WeightCalibrationOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maxiumum volume in the Keg
|
||||
/// </summary>
|
||||
[JsonProperty("maxkegvolumeinpints")]
|
||||
public float MaxKegVolumeInPints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum Weight Of Keg allowed
|
||||
/// </summary>
|
||||
[JsonProperty("maxkegweight")]
|
||||
public float MaxKegWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Weight of Empty Keg
|
||||
/// </summary>
|
||||
[JsonProperty("emptykegweight")]
|
||||
public float EmptyKegWeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum visitors allowed per Event
|
||||
/// </summary>
|
||||
[JsonProperty("maxvisitorsperevent")]
|
||||
public Int32 MaxPersonsPerEvent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Consumption Limit Reset
|
||||
/// </summary>
|
||||
[JsonProperty("userconsumptionresetminutes")]
|
||||
public Int32 UserConsumptionReset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flow Callibration Number
|
||||
/// </summary>
|
||||
[JsonProperty("flowcalibrationfactor")]
|
||||
public float FlowCalibrationFactor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flow Callibration Offset
|
||||
/// </summary>
|
||||
[JsonProperty("flowcalibrationoffset")]
|
||||
public float FlowCalibrationOffset { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class GlobalSettings
|
||||
{
|
||||
public static string UrlCombine(params string[] urls)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
foreach (var url in urls)
|
||||
{
|
||||
if (result.Length > 0 && url.Length > 0)
|
||||
result += '/';
|
||||
|
||||
result += url.Trim('/');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool CheckValidUrl()
|
||||
{
|
||||
try
|
||||
{
|
||||
//TODO: Add Validation
|
||||
//Constants.COSMOSAzureFunctionsURL
|
||||
return true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
KegLogger.KegLogException(ex, "GlobalSettings:GetKegSetting", SeverityLevel.Critical);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<KegConfig>> GetKegSettings()
|
||||
{
|
||||
if(!CheckValidUrl())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
string url = UrlCombine(Constants.COSMOSAzureFunctionsURL,"kegconfig");
|
||||
var response = await client.GetAsync(url);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
List<KegConfig> list = JsonConvert.DeserializeObject<List<KegConfig>>(body);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<KegConfig> GetKegSetting(string id)
|
||||
{
|
||||
if (!CheckValidUrl())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var myClientHandler = new HttpClientHandler
|
||||
{
|
||||
Credentials = System.Net.CredentialCache.DefaultCredentials
|
||||
};
|
||||
|
||||
var client = new HttpClient(myClientHandler)
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(60)
|
||||
};
|
||||
|
||||
//var client = new Windows.Web.Http.HttpClient();
|
||||
string url = UrlCombine(Constants.COSMOSAzureFunctionsURL, "kegconfig", id);
|
||||
|
||||
try
|
||||
{
|
||||
var response = await client.GetAsync(new Uri(url));
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
List<KegConfig> list = JsonConvert.DeserializeObject<List<KegConfig>>(body);
|
||||
return list.FirstOrDefault();
|
||||
}
|
||||
catch(TaskCanceledException tEx)
|
||||
{
|
||||
KegLogger.KegLogException(tEx, "GlobalSettings:GetKegSetting", SeverityLevel.Critical);
|
||||
throw tEx;
|
||||
}
|
||||
catch(HttpRequestException hEx)
|
||||
{
|
||||
KegLogger.KegLogException(hEx, "GlobalSettings:GetKegSetting", SeverityLevel.Critical);
|
||||
throw hEx;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Method and not to be used.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static async void SetKegSettings(this KegConfig item)
|
||||
{
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
string url = UrlCombine(Constants.COSMOSAzureFunctionsURL, "kegconfig");
|
||||
StringContent content = new StringContent(JsonConvert.SerializeObject(item));
|
||||
var response = await client.PostAsync(url, content);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Keg.DAL.Models
|
||||
{
|
||||
public class Measurement
|
||||
{
|
||||
public enum UnitsOfMeasure { Pounds, Ounces, Kilograms, Milliliters, Celsius, Fahrenheit }
|
||||
|
||||
[JsonProperty("amount")]
|
||||
public float Amount { get; set; }
|
||||
|
||||
[JsonProperty("units")]
|
||||
public UnitsOfMeasure Units { get; set; }
|
||||
|
||||
[JsonProperty("timestamp")]
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
public Measurement() { }
|
||||
|
||||
public Measurement(float amount, UnitsOfMeasure units)
|
||||
{
|
||||
Amount = amount;
|
||||
Units = units;
|
||||
Timestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
public Measurement(float amount, UnitsOfMeasure units, DateTime timestamp)
|
||||
: this(amount, units)
|
||||
{
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
|
||||
public override String ToString()
|
||||
{
|
||||
return $"{Amount} {Units}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using Keg.DAL;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL.Models
|
||||
{
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public string Type { get { return "KegUser"; } }
|
||||
|
||||
[JsonProperty("hashcode")]
|
||||
public string HashCode { get; set; }
|
||||
|
||||
[JsonProperty("isapprover")]
|
||||
public bool IsApprover { get; set; }
|
||||
|
||||
public static async Task<User> GetUserByHashcode(string hashcode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
string url = $"{GlobalSettings.UrlCombine(Constants.COSMOSAzureFunctionsURL, "keguser", hashcode)}";
|
||||
//string url = $"https://kegocnizerfunctions.azurewebsites.net/api/keguser/{hashcode}";
|
||||
var response = await client.GetAsync(url);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
List<User> list = JsonConvert.DeserializeObject<List<User>>(body);
|
||||
return list.FirstOrDefault();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
KegLogger.KegLogException(ex, "User:GetUserByHashcode", SeverityLevel.Critical);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async void AddUserAsync(User item)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
string url = $"{GlobalSettings.UrlCombine(Constants.COSMOSAzureFunctionsURL, "keguser")}";
|
||||
//string url = $"https://kegocnizerfunctions.azurewebsites.net/api/keguser";
|
||||
StringContent content = new StringContent(JsonConvert.SerializeObject(item));
|
||||
var response = await client.PostAsync(url, content);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
KegLogger.KegLogException(ex, "User:AddUserAsync", SeverityLevel.Critical);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
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("Keg.DAL")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Keg.DAL")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 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")]
|
||||
[assembly: ComVisible(false)]
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This file contains Runtime Directives, specifications about types your application accesses
|
||||
through reflection and other dynamic code patterns. Runtime Directives are used to control the
|
||||
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
|
||||
library does not do any reflection, then you generally do not need to edit this file. However,
|
||||
if your library reflects over types, especially types passed to it or derived from its types,
|
||||
then you should write Runtime Directives.
|
||||
|
||||
The most common use of reflection in libraries is to discover information about types passed
|
||||
to the library. Runtime Directives have three ways to express requirements on types passed to
|
||||
your library.
|
||||
|
||||
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
|
||||
Use these directives to reflect over types passed as a parameter.
|
||||
|
||||
2. SubTypes
|
||||
Use a SubTypes directive to reflect over types derived from another type.
|
||||
|
||||
3. AttributeImplies
|
||||
Use an AttributeImplies directive to indicate that your library needs to reflect over
|
||||
types or methods decorated with an attribute.
|
||||
|
||||
For more information on writing Runtime Directives for libraries, please visit
|
||||
https://go.microsoft.com/fwlink/?LinkID=391919
|
||||
-->
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Library Name="Keg.DAL">
|
||||
|
||||
<!-- add directives for your library here -->
|
||||
|
||||
</Library>
|
||||
</Directives>
|
|
@ -0,0 +1,186 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Keg.DAL.Models;
|
||||
using Windows.Devices.Gpio;
|
||||
using Sensors.Temperature;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class Temperature : IDisposable
|
||||
{
|
||||
//RPI
|
||||
private static readonly Int32 TEMPERATUREDATAPIN = 4; //PIN 7
|
||||
//MBM
|
||||
//const Int32 TEMPERATUREDATAPIN = 9;
|
||||
|
||||
public IDictionary<string, object> CalibrationSettings { get; set; }
|
||||
public const string AdjustTemperatureSetting = @"AdjustTemperature"; // a Measurement object, such as {-2, Fahrenheit}
|
||||
public const string TempGpioPinNumberSetting = @"TempGPIOPinNumber"; // an integer, such as 5 or 9 or 17
|
||||
public const string PreferredTemperatureUnits = @"TemperatureUnits"; // a Measurement.Units enum value, such as "Celsius" or "Fahrenheit"
|
||||
|
||||
private GpioPin _pin;
|
||||
private Dht11 _dht11;
|
||||
private Measurement _lastMeasurement;
|
||||
|
||||
// takes an instant reading or returns the average accumulated value, and returns
|
||||
// the interpreted value adjusted by calibration settings.
|
||||
public async Task<Models.Measurement> GetTemperature()
|
||||
{
|
||||
Measurement result = _lastMeasurement;
|
||||
|
||||
try
|
||||
{
|
||||
if (_pin == null || _dht11 == null)
|
||||
{
|
||||
int pinNumber = TEMPERATUREDATAPIN; // default
|
||||
if (CalibrationSettings.ContainsKey(TempGpioPinNumberSetting))
|
||||
pinNumber = Int32.Parse(CalibrationSettings[TempGpioPinNumberSetting].ToString());
|
||||
var c = GpioController.GetDefault();
|
||||
if (c != null)
|
||||
{
|
||||
_pin = c.OpenPin(pinNumber, GpioSharingMode.Exclusive);
|
||||
if (_pin != null)
|
||||
_dht11 = new Dht11(_pin, GpioPinDriveMode.Input);
|
||||
}
|
||||
}
|
||||
if(_dht11 == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DhtReading reading = await _dht11.GetReadingAsync().AsTask();
|
||||
for (int retries = 0; retries < 10; retries++)
|
||||
{
|
||||
if (reading.TimedOut)
|
||||
Debug.Write(".");
|
||||
else if (!reading.IsValid)
|
||||
Debug.Write("x");
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (reading.IsValid)
|
||||
{
|
||||
//Debug.WriteLine($"Temp reading = {reading.Temperature}");
|
||||
Measurement.UnitsOfMeasure units = Measurement.UnitsOfMeasure.Fahrenheit;
|
||||
if (CalibrationSettings.ContainsKey(PreferredTemperatureUnits))
|
||||
units = (Measurement.UnitsOfMeasure)Enum.Parse(typeof(Measurement.UnitsOfMeasure), CalibrationSettings[PreferredTemperatureUnits].ToString());
|
||||
Measurement adjust = new Measurement(0.0f, Measurement.UnitsOfMeasure.Fahrenheit);
|
||||
if (CalibrationSettings.ContainsKey(AdjustTemperatureSetting))
|
||||
adjust = CalibrationSettings[AdjustTemperatureSetting] as Measurement;
|
||||
|
||||
float temperature = (float)reading.Temperature;
|
||||
temperature = Convert(Measurement.UnitsOfMeasure.Celsius, units, temperature);
|
||||
adjust.Amount = Convert(adjust.Units, units, adjust.Amount);
|
||||
adjust.Units = units;
|
||||
temperature += adjust.Amount; // now that we know they are in the same (preferred) units
|
||||
|
||||
result = new Measurement(temperature, units);
|
||||
_lastMeasurement = result;
|
||||
OnTemperatureChanged(new MeasurementChangedEventArgs(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
KegLogger.KegLogException(new TemperatureException("Custom: Unable to Read temperature."), "GetTemperature", SeverityLevel.Warning);
|
||||
Debug.WriteLine($"Unable to read temperature.");
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error, " + ex.Message);
|
||||
KegLogger.KegLogException(ex, "GetTemperature", SeverityLevel.Critical);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private float Convert(Measurement.UnitsOfMeasure from, Measurement.UnitsOfMeasure to, float value)
|
||||
{
|
||||
float result = 0.0f;
|
||||
if (from == to)
|
||||
result = value;
|
||||
else if (from == Measurement.UnitsOfMeasure.Celsius)
|
||||
result = value * 9 / 5 + 32;
|
||||
else
|
||||
result = (value - 32) * 5 / 9;
|
||||
return result;
|
||||
}
|
||||
|
||||
public event EventHandler<MeasurementChangedEventArgs> TemperatureChanged;
|
||||
protected virtual void OnTemperatureChanged(MeasurementChangedEventArgs e)
|
||||
{
|
||||
TemperatureChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
// the purpose of this object is to allow someone an easy way to generate the proper
|
||||
// default calibration settings that this sensor interface object supports.
|
||||
// in this case, it supports a Measurement that indicates how many degrees to add
|
||||
// to readings to account for variations in the tolerance of the actual circuitry.
|
||||
public static IDictionary<string,object> GetDefaultCalibrationSettings()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{ AdjustTemperatureSetting, new Measurement(0, Measurement.UnitsOfMeasure.Fahrenheit) },
|
||||
{ TempGpioPinNumberSetting, TEMPERATUREDATAPIN.ToString() },
|
||||
{ PreferredTemperatureUnits, "Fahrenheit" }
|
||||
};
|
||||
}
|
||||
|
||||
// default constructor
|
||||
public Temperature()
|
||||
{
|
||||
CalibrationSettings = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public Temperature(IDictionary<string,object> calibrationSettings)
|
||||
: this()
|
||||
{
|
||||
//AdjustTemperatureSetting
|
||||
CalibrationSettings.Add(AdjustTemperatureSetting, (calibrationSettings.ContainsKey(AdjustTemperatureSetting)) ? calibrationSettings[AdjustTemperatureSetting] as Measurement : new Measurement(0.0f, Measurement.UnitsOfMeasure.Celsius));
|
||||
//TempGpioPinNumberSetting
|
||||
CalibrationSettings.Add(TempGpioPinNumberSetting, (calibrationSettings.ContainsKey(TempGpioPinNumberSetting)) ? calibrationSettings[TempGpioPinNumberSetting] : TEMPERATUREDATAPIN);
|
||||
//PreferredTemperatureUnits
|
||||
CalibrationSettings.Add(PreferredTemperatureUnits, (calibrationSettings.ContainsKey(PreferredTemperatureUnits)) ? calibrationSettings[PreferredTemperatureUnits] : Measurement.UnitsOfMeasure.Celsius.ToString());
|
||||
|
||||
}
|
||||
|
||||
private Timer _timer;
|
||||
public void Initialize(int initialDelay, int period)
|
||||
{
|
||||
_timer = new Timer(OnTimer, null, initialDelay, period);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var timer = _timer;
|
||||
_timer = null;
|
||||
timer?.Dispose();
|
||||
}
|
||||
|
||||
private async void OnTimer(object state)
|
||||
{
|
||||
OnTemperatureChanged(new MeasurementChangedEventArgs(await GetTemperature()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serializable()]
|
||||
public class TemperatureException : System.Exception
|
||||
{
|
||||
public TemperatureException() : base() { }
|
||||
public TemperatureException(string message) : base(message) { }
|
||||
public TemperatureException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
protected TemperatureException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
using Keg.DAL.Models;
|
||||
using Sensors.Weight;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Windows.Devices.Gpio;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.DAL
|
||||
{
|
||||
public class Weight
|
||||
{
|
||||
public IDictionary<string, object> CalibrationSettings { get; set; }
|
||||
public const string WeightClockGpioPinNumberSetting = @"WeightClockGPIOPinNumber"; // an integer, such as 5 or 9 or 17
|
||||
public const string WeightDataGpioPinNumberSetting = @"WeightDataGPIOPinNumber"; // an integer, such as 5 or 9 or 17
|
||||
public const string AdjustWeightFactorSetting = @"AdjustWeightFactor"; // in integer
|
||||
public const string AdjustWeightOffsetSetting = @"AdjustWeightOffset"; // an integer
|
||||
public const string PreferredWeightUnits = @"PreferredWeightUnits"; // a supported Measurement.UnitsOfMeasure value, like "Pounds"
|
||||
|
||||
//RPI
|
||||
const string WEIGHTCLOCKGPIOPINNUMBER = "21"; //PIN 40
|
||||
const string WEIGHTDATAGPIOPINNUMBER = "12"; //PIN 32
|
||||
|
||||
|
||||
//private double calibrationConstant; use AdjustWeightSetting instead
|
||||
private HX711 device;
|
||||
private GpioPin dataPin;
|
||||
private GpioPin clockPin;
|
||||
public FixedSizedQueue<Measurement> PriorMeasurements { get; set; }
|
||||
|
||||
public Measurement GetWeight(bool single =false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (clockPin == null || dataPin == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: sample sensors and report weight -- mocked for now
|
||||
//return new Measurement(165.0f, Measurement.UnitsOfMeasure.Pounds);
|
||||
device = new HX711(clockPin, dataPin);
|
||||
|
||||
var w = _GetOutputData();
|
||||
Debug.WriteLine($"Single:{w}");
|
||||
var c = Calibrated(w);
|
||||
|
||||
if(!CheckAnomaly(c))
|
||||
{
|
||||
PriorMeasurements.Enqueue(new Measurement(c, Measurement.UnitsOfMeasure.Ounces));
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Current Avg:{PriorMeasurements.Average(i => i.Amount)}");
|
||||
#if DEBUG
|
||||
foreach (var item in PriorMeasurements)
|
||||
{
|
||||
Debug.WriteLine($" {item.Amount}");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (single)
|
||||
return new Measurement(w, Measurement.UnitsOfMeasure.Ounces);
|
||||
else
|
||||
return new Measurement(PriorMeasurements.Average(i => i.Amount), Measurement.UnitsOfMeasure.Ounces);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error,{ex.Message}");
|
||||
KegLogger.KegLogException(ex, "Weight:GetWeight", SeverityLevel.Critical);
|
||||
|
||||
KegLogger.KegLogTrace(ex.Message, "Weight:GetWeight", SeverityLevel.Warning,
|
||||
new Dictionary<string, string>() {
|
||||
{"ClockPin", CalibrationSettings[WeightClockGpioPinNumberSetting].ToString() },
|
||||
{"DataPin", CalibrationSettings[WeightDataGpioPinNumberSetting].ToString() }
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool CheckAnomaly(float newValue)
|
||||
{
|
||||
if(PriorMeasurements.Count > 2 && newValue > PriorMeasurements.Average(i => i.Amount) * 2)
|
||||
{
|
||||
Debug.WriteLine($" Anomaly: {newValue}");
|
||||
KegLogger.KegLogTrace("Anomaly Detected!", "Weight:GetWeight", SeverityLevel.Error,
|
||||
new Dictionary<string, string>() {
|
||||
{"Weight", newValue.ToString() }
|
||||
});
|
||||
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private float Calibrated(float w)
|
||||
{
|
||||
//Debug.WriteLine($"Weight:{w}");
|
||||
Debug.WriteLine($"Weight Factor:{CalibrationSettings[AdjustWeightFactorSetting]}, Weight Offset:{CalibrationSettings[AdjustWeightOffsetSetting]}");
|
||||
var a = float.Parse(CalibrationSettings[AdjustWeightFactorSetting].ToString());
|
||||
var b = float.Parse(CalibrationSettings[AdjustWeightOffsetSetting].ToString()); b = b == 0 ? 1 : b;
|
||||
//Debug.WriteLine($"Calibrated:{ (a - (w / b))*100 })");
|
||||
//return (a - (w / b))*100;
|
||||
Debug.WriteLine($"Calibrated:{ ((w * a) + b) }");
|
||||
return (w * a) + b;
|
||||
|
||||
}
|
||||
|
||||
// the purpose of this object is to allow someone an easy way to generate the proper
|
||||
// default calibration settings that this sensor interface object supports.
|
||||
// in this case, it supports a Measurement that indicates how many degrees to add
|
||||
// to readings to account for variations in the tolerance of the actual circuitry.
|
||||
public static IDictionary<string, object> GetDefaultCalibrationSettings()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{ AdjustWeightFactorSetting, "1" },
|
||||
{ AdjustWeightOffsetSetting, "0" },
|
||||
{ WeightClockGpioPinNumberSetting, WEIGHTCLOCKGPIOPINNUMBER },
|
||||
{ WeightDataGpioPinNumberSetting, WEIGHTDATAGPIOPINNUMBER },
|
||||
{ PreferredWeightUnits, "Ounces" }
|
||||
};
|
||||
}
|
||||
|
||||
public event EventHandler<MeasurementChangedEventArgs> WeightChanged;
|
||||
protected virtual void OnWeightChanged(MeasurementChangedEventArgs e)
|
||||
{
|
||||
WeightChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public Weight()
|
||||
{
|
||||
CalibrationSettings = new Dictionary<string, object>(GetDefaultCalibrationSettings());
|
||||
PriorMeasurements = new FixedSizedQueue<Measurement>(10);
|
||||
}
|
||||
|
||||
public Weight(IDictionary<string, object> calibrationSettings)
|
||||
: this()
|
||||
{
|
||||
foreach(string key in calibrationSettings.Keys)
|
||||
{
|
||||
if (key.Equals(WeightClockGpioPinNumberSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(WeightDataGpioPinNumberSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(AdjustWeightFactorSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(AdjustWeightOffsetSetting, StringComparison.OrdinalIgnoreCase)
|
||||
|| key.Equals(PreferredWeightUnits, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
CalibrationSettings[key] = calibrationSettings[key].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (device == null)
|
||||
{
|
||||
GpioController controller = GpioController.GetDefault();
|
||||
GpioOpenStatus status;
|
||||
|
||||
if (controller != null
|
||||
&& controller.TryOpenPin(Int32.Parse(CalibrationSettings[WeightClockGpioPinNumberSetting].ToString()), GpioSharingMode.Exclusive, out clockPin, out status)
|
||||
&& controller.TryOpenPin(Int32.Parse(CalibrationSettings[WeightDataGpioPinNumberSetting].ToString()), GpioSharingMode.Exclusive, out dataPin, out status))
|
||||
{
|
||||
device = new HX711(clockPin, dataPin);
|
||||
}
|
||||
else
|
||||
device = null;
|
||||
}
|
||||
if (device != null)
|
||||
device.PowerOn();
|
||||
}
|
||||
|
||||
private int _GetOutputData()
|
||||
{
|
||||
Initialize();
|
||||
int result = 0;
|
||||
if (device != null)
|
||||
{
|
||||
result = device.Read();
|
||||
}
|
||||
device.PowerDown();
|
||||
return result;
|
||||
}
|
||||
|
||||
//public string GetReading()
|
||||
//{
|
||||
// string numberFormat = "G" + Precision;
|
||||
// return LeadingUnit + ((_GetOutputData() - Offset) / CalibrationConstant).ToString(numberFormat) + TrailingUnit;
|
||||
//}
|
||||
|
||||
private Timer _timer;
|
||||
public void Initialize(int initialDelay, int period)
|
||||
{
|
||||
if (device != null)
|
||||
{
|
||||
_timer = new Timer(OnTimer, null, initialDelay, period);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var timer = _timer;
|
||||
_timer = null;
|
||||
timer?.Dispose();
|
||||
}
|
||||
|
||||
private void OnTimer(object state)
|
||||
{
|
||||
var measurement = GetWeight();
|
||||
if(measurement != null )
|
||||
{
|
||||
Debug.WriteLine($" OnTimer:{measurement.Amount}");
|
||||
PriorMeasurements.Enqueue(measurement);
|
||||
|
||||
//var result = new Measurement( PriorMeasurements.Average(i => i.Amount), Measurement.UnitsOfMeasure.Ounces);
|
||||
this.OnWeightChanged(new MeasurementChangedEventArgs(measurement));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<Application
|
||||
x:Class="Keg.UWP.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Keg.UWP"
|
||||
RequestedTheme="Light">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary Source="Styles.xaml" />
|
||||
</Application.Resources>
|
||||
|
||||
</Application>
|
|
@ -0,0 +1,218 @@
|
|||
using Keg.DAL;
|
||||
using Keg.DAL.Models;
|
||||
using Keg.UWP.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Resources.Core;
|
||||
using Windows.Globalization;
|
||||
using Windows.System.UserProfile;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
|
||||
namespace Keg.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
//public static ResourceLoader resourceLoader;
|
||||
//public Temperature _temperature { get; set; }
|
||||
|
||||
public static readonly bool IgnoreCoreHours = false;
|
||||
|
||||
internal static Dictionary<string, object> calibration;
|
||||
|
||||
public static Temperature _temperature;
|
||||
public static Weight _weight;
|
||||
public static Flow _flow;
|
||||
public static FlowControl _flowControl;
|
||||
|
||||
//public static TelemetryClient telemetryClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Task.Run(() => Common.GetKegSettings()).Wait();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
//Azure Down
|
||||
//TODO
|
||||
Debug.WriteLine($"Exception:{ex.Message}");
|
||||
|
||||
KegLogger.KegLogException(ex, "App:App", SeverityLevel.Critical);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
InitializeCallibrations();
|
||||
|
||||
}
|
||||
|
||||
internal void InitializeCallibrations()
|
||||
{
|
||||
calibration = new Dictionary<string, object>();
|
||||
try
|
||||
{
|
||||
// to initialize a sensor measurement object, we pass it a calibration object
|
||||
// eventually, these will come from a specific Cosmos document that the app will passthru
|
||||
foreach (var c in Weight.GetDefaultCalibrationSettings()) calibration[c.Key] = c.Value;
|
||||
foreach (var c in FlowControl.GetDefaultCalibrationSettings()) calibration[c.Key] = c.Value;
|
||||
foreach (var c in Temperature.GetDefaultCalibrationSettings()) calibration[c.Key] = c.Value;
|
||||
foreach (var c in Flow.GetDefaultCalibrationSettings()) calibration[c.Key] = c.Value;
|
||||
|
||||
calibration[Weight.AdjustWeightFactorSetting] = Common.KegSettings.WeightCalibrationFactor.ToString();
|
||||
calibration[Weight.AdjustWeightOffsetSetting] = Common.KegSettings.WeightCalibrationOffset.ToString();
|
||||
|
||||
if (calibration.ContainsKey(Temperature.AdjustTemperatureSetting))
|
||||
{
|
||||
calibration[Temperature.AdjustTemperatureSetting] = new Measurement(-2.0f, Measurement.UnitsOfMeasure.Fahrenheit);
|
||||
}
|
||||
else
|
||||
{
|
||||
calibration.Add(Temperature.AdjustTemperatureSetting, new Measurement(-2.0f, Measurement.UnitsOfMeasure.Fahrenheit));
|
||||
}
|
||||
|
||||
//Flow Calibration
|
||||
calibration[Flow.FlowCalibrationFactorSetting] = Common.KegSettings.FlowCalibrationFactor.ToString();
|
||||
calibration[Flow.FlowCalibrationOffsetSetting] = Common.KegSettings.FlowCalibrationOffset.ToString();
|
||||
|
||||
App._flowControl = new FlowControl(App.calibration);
|
||||
App._flowControl.Initialize(1000, 1000);
|
||||
|
||||
App._flow = new Flow(App.calibration);
|
||||
App._flow.Initialize(1000, 1000);
|
||||
|
||||
//Objects Initializations
|
||||
App._temperature = new Temperature(App.calibration);
|
||||
//App._temperature.TemperatureChanged += OnTemperatureChange;
|
||||
App._temperature.Initialize(1000, 10000);
|
||||
|
||||
App._weight = new Weight(App.calibration);
|
||||
//App._weight.WeightChanged += OnWeightChange;
|
||||
App._weight.Initialize();
|
||||
//App._weight.Initialize(1000, 50000);
|
||||
App._weight.Initialize(1000, 10000);
|
||||
|
||||
KegLogger.KegLogTrace("Kegocnizer App Loaded", "AppLoad", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Dictionary<string, string> log = new Dictionary<string, string>();
|
||||
foreach (var item in calibration)
|
||||
{
|
||||
log.Add(item.Key, item.Value.ToString());
|
||||
}
|
||||
KegLogger.KegLogTrace(ex.Message, "App:InitializeCallibrations", SeverityLevel.Critical, log);
|
||||
|
||||
KegLogger.KegLogException(ex, "App:InitializeCallibrations", SeverityLevel.Critical);
|
||||
#if !DEBUG
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
//Set Default Primary Language
|
||||
//Setting this, will be directly reflected in ApplicationLanguages.Languages
|
||||
ApplicationLanguages.PrimaryLanguageOverride = GlobalizationPreferences.Languages[0];
|
||||
// Set the default language
|
||||
rootFrame.Language = "en-US";
|
||||
|
||||
//resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
|
||||
|
||||
// Refresh the resources in new language
|
||||
ResourceContext.GetForCurrentView().Reset();
|
||||
ResourceContext.GetForViewIndependentUse().Reset();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
//Exception ex = new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
KegLogger.KegLogException(e.Exception, "App:OnNavigationFailed", SeverityLevel.Critical);
|
||||
|
||||
KegLogger.KegLogTrace(e.Exception.Message, "App:OnNavigationFailed", SeverityLevel.Critical,
|
||||
new Dictionary<string, string>() {
|
||||
{"SourcePage", e.SourcePageType.FullName }
|
||||
});
|
||||
throw e.Exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
После Ширина: | Высота: | Размер: 5.6 KiB |
После Ширина: | Высота: | Размер: 7.7 KiB |
После Ширина: | Высота: | Размер: 9.7 KiB |
После Ширина: | Высота: | Размер: 14 KiB |