finish LastResort

This commit is contained in:
Paddy Xu
2017-04-24 22:17:46 +03:00
parent 431cf1f014
commit 5e70b0052f
16 changed files with 1359 additions and 1031 deletions

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace QuickLook.Plugin.LastResort
{
public static class FileHelper
{
public static void CountFolder(string root, ref bool stop, out long totalDirs, out long totalFiles,
out long totalSize)
{
totalDirs = totalFiles = totalSize = 0L;
var stack = new Stack<DirectoryInfo>();
stack.Push(new DirectoryInfo(root));
totalDirs++; // self
do
{
if (stop)
break;
var pos = stack.Pop();
try
{
// process files in current directory
foreach (var file in pos.EnumerateFiles())
{
totalFiles++;
totalSize += file.Length;
}
// then push all sub-directories
foreach (var dir in pos.EnumerateDirectories())
{
totalDirs++;
stack.Push(dir);
}
}
catch (Exception)
{
totalDirs++;
//pos = stack.Pop();
}
} while (stack.Count != 0);
}
public static string ToPrettySize(this long value, int decimalPlaces = 0)
{
const long OneKb = 1024;
const long OneMb = OneKb * 1024;
const long OneGb = OneMb * 1024;
const long OneTb = OneGb * 1024;
var asTb = Math.Round((double) value / OneTb, decimalPlaces);
var asGb = Math.Round((double) value / OneGb, decimalPlaces);
var asMb = Math.Round((double) value / OneMb, decimalPlaces);
var asKb = Math.Round((double) value / OneKb, decimalPlaces);
var chosenValue = asTb > 1
? $"{asTb} TB"
: asGb > 1
? $"{asGb} GB"
: asMb > 1
? $"{asMb} MB"
: asKb > 1
? $"{asKb} KB"
: $"{Math.Round((double) value, decimalPlaces)} bytes";
return chosenValue;
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace QuickLook.Plugin.LastResort namespace QuickLook.Plugin.LastResort
@@ -211,8 +212,8 @@ namespace QuickLook.Plugin.LastResort
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct POINT public struct POINT
{ {
private int X; private readonly int X;
private int Y; private readonly int Y;
public POINT(int x, int y) public POINT(int x, int y)
{ {

View File

@@ -1,12 +1,35 @@
<UserControl x:Class="QuickLook.Plugin.LastResort.InfoPanel" <UserControl x:Class="QuickLook.Plugin.LastResort.InfoPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:QuickLook.Plugin.LastResort" xmlns:local="clr-namespace:QuickLook.Plugin.LastResort"
mc:Ignorable="d" Width="484.5" Height="172" UseLayoutRounding="True">
mc:Ignorable="d" Width="450" Height="250" UseLayoutRounding="True">
<Grid> <Grid>
<Image x:Name="image" Width="128" Height="128"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="65*" />
</Grid.ColumnDefinitions>
<Image x:Name="image" Grid.Column="0" Height="128" Width="128" Stretch="Fill" />
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="80*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="1" VerticalContentAlignment="Center" Grid.Column="0">Name:</Label>
<Label Grid.Row="2" VerticalContentAlignment="Center" Grid.Column="0">Modified:</Label>
<Label Grid.Row="3" VerticalContentAlignment="Center" Grid.Column="0">Size:</Label>
<Label x:Name="filename" Grid.Row="1" VerticalContentAlignment="Center" Grid.Column="1">Filename.ext</Label>
<Label x:Name="modDate" Grid.Row="2" VerticalContentAlignment="Center" Grid.Column="1">01/01/2017 00:00:00</Label>
<Label x:Name="totalSize" Grid.Row="3" VerticalContentAlignment="Center" Grid.Column="1">Calculating...</Label>
</Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,31 +1,15 @@
using System; using System.Windows.Controls;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace QuickLook.Plugin.LastResort namespace QuickLook.Plugin.LastResort
{ {
/// <summary> /// <summary>
/// Interaction logic for InfoPanel.xaml /// Interaction logic for InfoPanel.xaml
/// </summary> /// </summary>
public partial class InfoPanel : UserControl public partial class InfoPanel : UserControl
{ {
public InfoPanel() public InfoPanel(string path)
{ {
InitializeComponent(); InitializeComponent();
var i = 0;
} }
} }
} }

View File

@@ -1,12 +1,13 @@
using System.Drawing; using System.IO;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using Size = System.Windows.Size;
namespace QuickLook.Plugin.LastResort namespace QuickLook.Plugin.LastResort
{ {
public class Plugin : IViewer public class Plugin : IViewer
{ {
private InfoPanel ip; private InfoPanel ip;
private bool stop;
public int Priority => -9999; public int Priority => -9999;
public bool CanHandle(string sample) public bool CanHandle(string sample)
@@ -16,18 +17,59 @@ namespace QuickLook.Plugin.LastResort
public void View(string path, ViewContentContainer container) public void View(string path, ViewContentContainer container)
{ {
var s = IconHelper.GetBitmapFromPath(path, IconHelper.IconSizeEnum.ExtraLargeIcon).ToBitmapSource(); ip = new InfoPanel(path);
ip = new InfoPanel(); DisplayInfo(path);
ip.image.Source = s;
container.SetContent(ip); container.SetContent(ip);
container.CanResize = false;
container.PreferedSize = new Size {Width = ip.Width, Height = ip.Height}; container.PreferedSize = new Size {Width = ip.Width, Height = ip.Height};
} }
public void Close() public void Close()
{ {
//ip.Dispose(); stop = true;
}
private void DisplayInfo(string path)
{
var icon = IconHelper.GetBitmapFromPath(path, IconHelper.IconSizeEnum.ExtraLargeIcon).ToBitmapSource();
ip.image.Source = icon;
var name = Path.GetFileName(path);
ip.filename.Content = string.IsNullOrEmpty(name) ? path : name;
var last = File.GetLastWriteTime(path);
ip.modDate.Content = $"{last.ToLongDateString()} {last.ToLongTimeString()}";
stop = false;
Task.Run(() =>
{
if (File.Exists(path))
{
var size = new FileInfo(path).Length;
ip.Dispatcher.Invoke(() => { ip.totalSize.Content = size.ToPrettySize(2); });
}
else if (Directory.Exists(path))
{
long totalDirs;
long totalFiles;
long totalSize;
FileHelper.CountFolder(path, ref stop, out totalDirs, out totalFiles, out totalSize);
if (!stop)
ip.Dispatcher.Invoke(() =>
{
ip.totalSize.Content =
$"{totalSize.ToPrettySize(2)} ({totalDirs} folders and {totalFiles} files.)";
});
}
});
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
@@ -33,4 +32,4 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -48,6 +48,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="FileHelper.cs" />
<Compile Include="InfoPanel.xaml.cs"> <Compile Include="InfoPanel.xaml.cs">
<DependentUpon>InfoPanel.xaml</DependentUpon> <DependentUpon>InfoPanel.xaml</DependentUpon>
</Compile> </Compile>

View File

@@ -6,12 +6,24 @@ namespace QuickLook.Plugin.PDFViewer
{ {
internal static class DpiHelper internal static class DpiHelper
{ {
public enum DeviceCap
{
/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90
}
public const float DEFAULT_DPI = 96; public const float DEFAULT_DPI = 96;
public static Dpi GetCurrentDpi() public static Dpi GetCurrentDpi()
{ {
Graphics g = Graphics.FromHwnd(IntPtr.Zero); var g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc(); var desktop = g.GetHdc();
var dpi = new Dpi var dpi = new Dpi
{ {
@@ -24,18 +36,6 @@ namespace QuickLook.Plugin.PDFViewer
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex); public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);
public enum DeviceCap
{
/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90
}
} }
internal class Dpi internal class Dpi

View File

@@ -26,8 +26,8 @@ namespace QuickLook.Plugin.PDFViewer
var height = (int) (pageBound.Height * zoomY); var height = (int) (pageBound.Height * zoomY);
// sets the matrix as a scaling matrix (zoomX,0,0,zoomY,0,0) // sets the matrix as a scaling matrix (zoomX,0,0,zoomY,0,0)
ctm.A = (float)zoomX; ctm.A = (float) zoomX;
ctm.D = (float)zoomY; ctm.D = (float) zoomY;
// creates a pixmap the same size as the width and height of the page // creates a pixmap the same size as the width and height of the page
pix = NativeMethods.NewPixmap(context, NativeMethods.LookupDeviceColorSpace(context, "DeviceRGB"), width, pix = NativeMethods.NewPixmap(context, NativeMethods.LookupDeviceColorSpace(context, "DeviceRGB"), width,

View File

@@ -13,7 +13,7 @@
<ResourceDictionary> <ResourceDictionary>
<local:PageIdToImageConverter x:Key="PageIdToImageConverter" /> <local:PageIdToImageConverter x:Key="PageIdToImageConverter" />
<Style x:Key="ListBoxItemStyleNoFocusedBorder" TargetType="{x:Type ListBoxItem}"> <Style x:Key="ListBoxItemStyleNoFocusedBorder" TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/> <Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
@@ -26,13 +26,13 @@
ScrollViewer.IsDeferredScrollingEnabled="False" ScrollViewer.IsDeferredScrollingEnabled="False"
SelectedIndex="0" SelectedIndex="0"
Focusable="False" Focusable="False"
Background="#9FFFFFFF" Background="#00FFFFFF"
ItemsSource="{Binding PageIds, ElementName=thisPdfViewer}" ItemsSource="{Binding PageIds, ElementName=thisPdfViewer}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0,0,1,0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0,0,1,0"
ItemContainerStyle="{Binding Mode=OneWay, Source={StaticResource ListBoxItemStyleNoFocusedBorder}}"> ItemContainerStyle="{Binding Mode=OneWay, Source={StaticResource ListBoxItemStyleNoFocusedBorder}}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid MaxHeight="150" <Grid MaxHeight="150"
MaxWidth="{Binding ViewportWidth, Mode=Default, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}"> MaxWidth="{Binding ViewportWidth, Mode=Default, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="10" /> <ColumnDefinition Width="10" />
@@ -61,10 +61,10 @@
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
<Grid Grid.Column="1" Background="#DFEFEFEF"> <Grid Grid.Column="1" Background="#00EFEFEF">
<ScrollViewer x:Name="pageViewPanel" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Focusable="False"> <ScrollViewer x:Name="pageViewPanel" HorizontalScrollBarVisibility="Auto"
<Image x:Name="pageViewPanelImage" Stretch="None" RenderOptions.BitmapScalingMode="NearestNeighbor"> VerticalScrollBarVisibility="Auto" Focusable="False">
</Image> <Image x:Name="pageViewPanelImage" Stretch="None" RenderOptions.BitmapScalingMode="NearestNeighbor" />
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -32,19 +32,19 @@ namespace QuickLook
return; return;
} }
var path = String.Empty; var path = string.Empty;
// communicate with COM in a separate thread // communicate with COM in a separate thread
Task.Run(() => Task.Run(() =>
{ {
var paths = GetCurrentSelection(); var paths = GetCurrentSelection();
if (paths.Any()) if (paths.Any())
path = paths.First(); path = paths.First();
})
.Wait();
}).Wait(); if (string.IsNullOrEmpty(path))
if (String.IsNullOrEmpty(path))
return; return;
var matched = PluginManager.FindMatch(path); var matched = PluginManager.FindMatch(path);

View File

@@ -14,14 +14,14 @@
ResizeMode="CanResizeWithGrip" ResizeMode="CanResizeWithGrip"
x:ClassModifier="internal"> x:ClassModifier="internal">
<Window.Background> <Window.Background>
<SolidColorBrush Color="#7FFFFFFF" /> <SolidColorBrush Color="#BFFFFFFF" />
</Window.Background> </Window.Background>
<Border BorderThickness="1" BorderBrush="#FF7B7B7B"> <Border BorderThickness="1" BorderBrush="#FF7B7B7B">
<Grid> <Grid>
<DockPanel Opacity="1"> <DockPanel Opacity="1">
<DockPanel x:Name="titlebar" Height="28" Dock="Top"> <DockPanel x:Name="titlebar" Height="28" Dock="Top">
<DockPanel.Background> <DockPanel.Background>
<SolidColorBrush Color="#FFB8B8B8" /> <SolidColorBrush Color="#00B8B8B8" />
</DockPanel.Background> </DockPanel.Background>
<!--<DockPanel.Style> <!--<DockPanel.Style>
<Style TargetType="{x:Type DockPanel}"> <Style TargetType="{x:Type DockPanel}">
@@ -47,20 +47,23 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</DockPanel.Style>--> </DockPanel.Style>-->
<fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="WindowClose" Height="15" Margin="10,0" <fa:ImageAwesome DockPanel.Dock="Right" x:Name="buttonCloseWindow" Icon="WindowClose" Height="15"
Margin="10,0"
Cursor="Hand" /> Cursor="Hand" />
<Label x:Name="titlebarTitleArea" Content="{Binding Title, ElementName=viewContentContainer}" FontSize="14" HorizontalContentAlignment="Center" <Label x:Name="titlebarTitleArea" Content="{Binding Title, ElementName=viewContentContainer}"
FontSize="14" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" /> VerticalContentAlignment="Center" />
</DockPanel> </DockPanel>
<Grid> <Grid>
<plugin:ViewContentContainer x:Name="viewContentContainer"/> <plugin:ViewContentContainer x:Name="viewContentContainer" />
</Grid> </Grid>
</DockPanel> </DockPanel>
<Grid x:Name="loadingIconLayer" Opacity="0.3"> <Grid x:Name="loadingIconLayer" Opacity="0.3">
<Grid.Background> <Grid.Background>
<SolidColorBrush Color="#FFFFFFFF" /> <SolidColorBrush Color="#FFFFFFFF" />
</Grid.Background> </Grid.Background>
<Grid x:Name="loadingIcon" Height="50" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid x:Name="loadingIcon" Height="50" Width="50" HorizontalAlignment="Center"
VerticalAlignment="Center">
<fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="1" /> <fa:ImageAwesome Icon="CircleOutlineNotch" Spin="True" SpinDuration="1" />
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Remoting.Channels;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
@@ -30,6 +29,8 @@ namespace QuickLook
titlebarTitleArea.MouseDown += (sender, e) => DragMove(); titlebarTitleArea.MouseDown += (sender, e) => DragMove();
} }
public event PropertyChangedEventHandler PropertyChanged;
private void MainWindow_Closed(object sender, EventArgs e) private void MainWindow_Closed(object sender, EventArgs e)
{ {
viewContentContainer.ViewerPlugin.Close(); viewContentContainer.ViewerPlugin.Close();
@@ -42,6 +43,8 @@ namespace QuickLook
Height = viewContentContainer.PreferedSize.Height + titlebar.Height; Height = viewContentContainer.PreferedSize.Height + titlebar.Height;
Width = viewContentContainer.PreferedSize.Width; Width = viewContentContainer.PreferedSize.Width;
ResizeMode = viewContentContainer.CanResize ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;
base.Show(); base.Show();
} }
@@ -51,17 +54,17 @@ namespace QuickLook
var sb = new Storyboard(); var sb = new Storyboard();
var ptl = new ParallelTimeline(); var ptl = new ParallelTimeline();
var aOpacityR = new DoubleAnimation var aOpacityR = new DoubleAnimation
{ {
From = 1, From = 1,
To = 0, To = 0,
Duration = TimeSpan.FromMilliseconds(speed) Duration = TimeSpan.FromMilliseconds(speed)
}; };
Storyboard.SetTarget(aOpacityR, loadingIconLayer); Storyboard.SetTarget(aOpacityR, loadingIconLayer);
Storyboard.SetTargetProperty(aOpacityR, new PropertyPath(OpacityProperty)); Storyboard.SetTargetProperty(aOpacityR, new PropertyPath(OpacityProperty));
ptl.Children.Add(aOpacityR); ptl.Children.Add(aOpacityR);
sb.Children.Add(ptl); sb.Children.Add(ptl);
@@ -77,8 +80,6 @@ namespace QuickLook
Close(); Close();
} }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] [NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ {

View File

@@ -10,9 +10,9 @@ namespace QuickLook.Plugin
/// <summary> /// <summary>
/// Interaction logic for ViewContentContainer.xaml /// Interaction logic for ViewContentContainer.xaml
/// </summary> /// </summary>
public partial class ViewContentContainer : UserControl,INotifyPropertyChanged public partial class ViewContentContainer : UserControl, INotifyPropertyChanged
{ {
private string _title = String.Empty; private string _title = string.Empty;
public ViewContentContainer() public ViewContentContainer()
{ {
@@ -29,6 +29,14 @@ namespace QuickLook.Plugin
get => _title; get => _title;
} }
public IViewer ViewerPlugin { get; set; }
public Size PreferedSize { get; set; }
public bool CanResize { get; set; } = true;
public event PropertyChangedEventHandler PropertyChanged;
public void SetContent(object content) public void SetContent(object content)
{ {
container.Content = content; container.Content = content;
@@ -41,8 +49,8 @@ namespace QuickLook.Plugin
var max = GetMaximumDisplayBound(); var max = GetMaximumDisplayBound();
var widthRatio = (max.Width * maxRatio) / size.Width; var widthRatio = max.Width * maxRatio / size.Width;
var heightRatio = (max.Height * maxRatio) / size.Height; var heightRatio = max.Height * maxRatio / size.Height;
var ratio = Math.Min(widthRatio, heightRatio); var ratio = Math.Min(widthRatio, heightRatio);
@@ -51,17 +59,11 @@ namespace QuickLook.Plugin
return ratio; return ratio;
} }
public IViewer ViewerPlugin { get; set; }
public Size PreferedSize { get; set; }
public Size GetMaximumDisplayBound() public Size GetMaximumDisplayBound()
{ {
return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight); return new Size(SystemParameters.VirtualScreenWidth, SystemParameters.VirtualScreenHeight);
} }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] [NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -59,9 +59,9 @@ namespace QuickLook.Utilities
private struct AccentPolicy private struct AccentPolicy
{ {
public AccentState AccentState; public AccentState AccentState;
public int AccentFlags; public readonly int AccentFlags;
public int GradientColor; public readonly int GradientColor;
public int AnimationId; public readonly int AnimationId;
} }
} }
} }