@srcpush/react-native-code-push 1.0.3-develop.2 → 1.0.3-develop.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/windows/CodePush/CodePush.def +0 -3
- package/windows/CodePush/CodePush.vcxproj +0 -198
- package/windows/CodePush/CodePush.vcxproj.filters +0 -91
- package/windows/CodePush/CodePushConfig.cpp +0 -104
- package/windows/CodePush/CodePushConfig.h +0 -66
- package/windows/CodePush/CodePushConfig.idl +0 -12
- package/windows/CodePush/CodePushDownloadHandler.cpp +0 -73
- package/windows/CodePush/CodePushDownloadHandler.h +0 -32
- package/windows/CodePush/CodePushNativeModule.cpp +0 -937
- package/windows/CodePush/CodePushNativeModule.h +0 -247
- package/windows/CodePush/CodePushPackage.cpp +0 -456
- package/windows/CodePush/CodePushPackage.h +0 -49
- package/windows/CodePush/CodePushTelemetryManager.cpp +0 -213
- package/windows/CodePush/CodePushTelemetryManager.h +0 -29
- package/windows/CodePush/CodePushUpdateUtils.cpp +0 -86
- package/windows/CodePush/CodePushUpdateUtils.h +0 -38
- package/windows/CodePush/CodePushUtils.cpp +0 -29
- package/windows/CodePush/CodePushUtils.h +0 -18
- package/windows/CodePush/FileUtils.cpp +0 -131
- package/windows/CodePush/FileUtils.h +0 -28
- package/windows/CodePush/PropertySheet.props +0 -16
- package/windows/CodePush/ReactPackageProvider.cpp +0 -15
- package/windows/CodePush/ReactPackageProvider.h +0 -22
- package/windows/CodePush/ReactPackageProvider.idl +0 -9
- package/windows/CodePush/miniz/LICENSE +0 -22
- package/windows/CodePush/miniz/miniz.c +0 -7657
- package/windows/CodePush/miniz/miniz.h +0 -1338
- package/windows/CodePush/miniz/readme.md +0 -37
- package/windows/CodePush/packages.config +0 -4
- package/windows/CodePush/pch.cpp +0 -1
- package/windows/CodePush/pch.h +0 -4
- package/windows-legacy/CodePush/CodePush.csproj +0 -128
- package/windows-legacy/CodePush/CodePushUtils.cs +0 -47
- package/windows-legacy/CodePush/FileUtils.cs +0 -40
- package/windows-legacy/CodePush/Properties/AssemblyInfo.cs +0 -29
- package/windows-legacy/CodePush/Properties/CodePush.rd.xml +0 -33
- package/windows-legacy/CodePush/UpdateManager.cs +0 -305
- package/windows-legacy/CodePush/UpdateUtils.cs +0 -46
- package/windows-legacy/CodePush.Net46/Adapters/Http/HttpProgress.cs +0 -28
- package/windows-legacy/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs +0 -106
- package/windows-legacy/CodePush.Net46/CodePush.Net46.csproj +0 -103
- package/windows-legacy/CodePush.Net46/CodePushUtils.cs +0 -158
- package/windows-legacy/CodePush.Net46/FileUtils.cs +0 -55
- package/windows-legacy/CodePush.Net46/Properties/AssemblyInfo.cs +0 -36
- package/windows-legacy/CodePush.Net46/UpdateManager.cs +0 -330
- package/windows-legacy/CodePush.Net46/UpdateUtils.cs +0 -70
- package/windows-legacy/CodePush.Net46/packages.config +0 -5
- package/windows-legacy/CodePush.Net46.Test/ApplicationDataContainerTest.cs +0 -105
- package/windows-legacy/CodePush.Net46.Test/CodePush.Net46.Test.csproj +0 -137
- package/windows-legacy/CodePush.Net46.Test/Properties/AssemblyInfo.cs +0 -36
- package/windows-legacy/CodePush.Net46.Test/TelemetryManagerTest.cs +0 -117
- package/windows-legacy/CodePush.Net46.Test/app.config +0 -11
- package/windows-legacy/CodePush.Net46.Test/packages.config +0 -4
- package/windows-legacy/CodePush.Shared/CodePush.Shared.projitems +0 -22
- package/windows-legacy/CodePush.Shared/CodePush.Shared.shproj +0 -13
- package/windows-legacy/CodePush.Shared/CodePushConstants.cs +0 -35
- package/windows-legacy/CodePush.Shared/CodePushNativeModule.cs +0 -329
- package/windows-legacy/CodePush.Shared/CodePushReactPackage.cs +0 -235
- package/windows-legacy/CodePush.Shared/CodePushUtils.cs +0 -70
- package/windows-legacy/CodePush.Shared/InstallMode.cs +0 -9
- package/windows-legacy/CodePush.Shared/MinimumBackgroundListener.cs +0 -44
- package/windows-legacy/CodePush.Shared/SettingsManager.cs +0 -148
- package/windows-legacy/CodePush.Shared/TelemetryManager.cs +0 -250
- package/windows-legacy/CodePush.Shared/UpdateState.cs +0 -9
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
## Miniz
|
|
2
|
-
|
|
3
|
-
Miniz is a lossless, high performance data compression library in a single source file that implements the zlib (RFC 1950) and Deflate (RFC 1951) compressed data format specification standards. It supports the most commonly used functions exported by the zlib library, but is a completely independent implementation so zlib's licensing requirements do not apply. Miniz also contains simple to use functions for writing .PNG format image files and reading/writing/appending .ZIP format archives. Miniz's compression speed has been tuned to be comparable to zlib's, and it also has a specialized real-time compressor function designed to compare well against fastlz/minilzo.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
Please use the files from the [releases page](https://github.com/richgel999/miniz/releases) in your projects. Do not use the git checkout directly! The different source and header files are [amalgamated](https://www.sqlite.org/amalgamation.html) into one `miniz.c`/`miniz.h` pair in a build step (`amalgamate.sh`). Include `miniz.c` and `miniz.h` in your project to use Miniz.
|
|
8
|
-
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
* MIT licensed
|
|
12
|
-
* A portable, single source and header file library written in plain C. Tested with GCC, clang and Visual Studio.
|
|
13
|
-
* Easily tuned and trimmed down by defines
|
|
14
|
-
* A drop-in replacement for zlib's most used API's (tested in several open source projects that use zlib, such as libpng and libzip).
|
|
15
|
-
* Fills a single threaded performance vs. compression ratio gap between several popular real-time compressors and zlib. For example, at level 1, miniz.c compresses around 5-9% better than minilzo, but is approx. 35% slower. At levels 2-9, miniz.c is designed to compare favorably against zlib's ratio and speed. See the miniz performance comparison page for example timings.
|
|
16
|
-
* Not a block based compressor: miniz.c fully supports stream based processing using a coroutine-style implementation. The zlib-style API functions can be called a single byte at a time if that's all you've got.
|
|
17
|
-
* Easy to use. The low-level compressor (tdefl) and decompressor (tinfl) have simple state structs which can be saved/restored as needed with simple memcpy's. The low-level codec API's don't use the heap in any way.
|
|
18
|
-
* Entire inflater (including optional zlib header parsing and Adler-32 checking) is implemented in a single function as a coroutine, which is separately available in a small (~550 line) source file: miniz_tinfl.c
|
|
19
|
-
* A fairly complete (but totally optional) set of .ZIP archive manipulation and extraction API's. The archive functionality is intended to solve common problems encountered in embedded, mobile, or game development situations. (The archive API's are purposely just powerful enough to write an entire archiver given a bit of additional higher-level logic.)
|
|
20
|
-
|
|
21
|
-
## Known Problems
|
|
22
|
-
|
|
23
|
-
* No support for encrypted archives. Not sure how useful this stuff is in practice.
|
|
24
|
-
* Minimal documentation. The assumption is that the user is already familiar with the basic zlib API. I need to write an API wiki - for now I've tried to place key comments before each enum/API, and I've included 6 examples that demonstrate how to use the module's major features.
|
|
25
|
-
|
|
26
|
-
## Special Thanks
|
|
27
|
-
|
|
28
|
-
Thanks to Alex Evans for the PNG writer function. Also, thanks to Paul Holden and Thorsten Scheuermann for feedback and testing, Matt Pritchard for all his encouragement, and Sean Barrett's various public domain libraries for inspiration (and encouraging me to write miniz.c in C, which was much more enjoyable and less painful than I thought it would be considering I've been programming in C++ for so long).
|
|
29
|
-
|
|
30
|
-
Thanks to Bruce Dawson for reporting a problem with the level_and_flags archive API parameter (which is fixed in v1.12) and general feedback, and Janez Zemva for indirectly encouraging me into writing more examples.
|
|
31
|
-
|
|
32
|
-
## Patents
|
|
33
|
-
|
|
34
|
-
I was recently asked if miniz avoids patent issues. miniz purposely uses the same core algorithms as the ones used by zlib. The compressor uses vanilla hash chaining as described [here](http://www.gzip.org/zlib/rfc-deflate.html#algorithm). Also see the [gzip FAQ](http://www.gzip.org/#faq11). In my opinion, if miniz falls prey to a patent attack then zlib/gzip are likely to be at serious risk too.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
[](https://travis-ci.org/uroni/miniz)
|
package/windows/CodePush/pch.cpp
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#include "pch.h"
|
package/windows/CodePush/pch.h
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
3
|
-
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
4
|
-
<PropertyGroup>
|
|
5
|
-
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
6
|
-
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
7
|
-
<ProjectGuid>{446A85D9-55EB-4C7D-8B9D-448306C833D6}</ProjectGuid>
|
|
8
|
-
<OutputType>Library</OutputType>
|
|
9
|
-
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
10
|
-
<RootNamespace>CodePush</RootNamespace>
|
|
11
|
-
<AssemblyName>CodePush</AssemblyName>
|
|
12
|
-
<DefaultLanguage>en-US</DefaultLanguage>
|
|
13
|
-
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
|
14
|
-
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
|
|
15
|
-
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
|
|
16
|
-
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
|
17
|
-
<FileAlignment>512</FileAlignment>
|
|
18
|
-
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
19
|
-
</PropertyGroup>
|
|
20
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
|
21
|
-
<PlatformTarget>x86</PlatformTarget>
|
|
22
|
-
<DebugSymbols>true</DebugSymbols>
|
|
23
|
-
<OutputPath>bin\x86\Debug\</OutputPath>
|
|
24
|
-
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
25
|
-
<NoWarn>;2008</NoWarn>
|
|
26
|
-
<DebugType>full</DebugType>
|
|
27
|
-
<PlatformTarget>x86</PlatformTarget>
|
|
28
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
29
|
-
<ErrorReport>prompt</ErrorReport>
|
|
30
|
-
</PropertyGroup>
|
|
31
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
|
32
|
-
<PlatformTarget>x86</PlatformTarget>
|
|
33
|
-
<OutputPath>bin\x86\Release\</OutputPath>
|
|
34
|
-
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
35
|
-
<Optimize>true</Optimize>
|
|
36
|
-
<NoWarn>;2008</NoWarn>
|
|
37
|
-
<DebugType>pdbonly</DebugType>
|
|
38
|
-
<PlatformTarget>x86</PlatformTarget>
|
|
39
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
40
|
-
<ErrorReport>prompt</ErrorReport>
|
|
41
|
-
</PropertyGroup>
|
|
42
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
|
43
|
-
<PlatformTarget>ARM</PlatformTarget>
|
|
44
|
-
<DebugSymbols>true</DebugSymbols>
|
|
45
|
-
<OutputPath>bin\ARM\Debug\</OutputPath>
|
|
46
|
-
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
47
|
-
<NoWarn>;2008</NoWarn>
|
|
48
|
-
<DebugType>full</DebugType>
|
|
49
|
-
<PlatformTarget>ARM</PlatformTarget>
|
|
50
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
51
|
-
<ErrorReport>prompt</ErrorReport>
|
|
52
|
-
</PropertyGroup>
|
|
53
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
|
54
|
-
<PlatformTarget>ARM</PlatformTarget>
|
|
55
|
-
<OutputPath>bin\ARM\Release\</OutputPath>
|
|
56
|
-
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
57
|
-
<Optimize>true</Optimize>
|
|
58
|
-
<NoWarn>;2008</NoWarn>
|
|
59
|
-
<DebugType>pdbonly</DebugType>
|
|
60
|
-
<PlatformTarget>ARM</PlatformTarget>
|
|
61
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
62
|
-
<ErrorReport>prompt</ErrorReport>
|
|
63
|
-
</PropertyGroup>
|
|
64
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
|
65
|
-
<PlatformTarget>x64</PlatformTarget>
|
|
66
|
-
<DebugSymbols>true</DebugSymbols>
|
|
67
|
-
<OutputPath>bin\x64\Debug\</OutputPath>
|
|
68
|
-
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
69
|
-
<NoWarn>;2008</NoWarn>
|
|
70
|
-
<DebugType>full</DebugType>
|
|
71
|
-
<PlatformTarget>x64</PlatformTarget>
|
|
72
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
73
|
-
<ErrorReport>prompt</ErrorReport>
|
|
74
|
-
</PropertyGroup>
|
|
75
|
-
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
|
76
|
-
<PlatformTarget>x64</PlatformTarget>
|
|
77
|
-
<OutputPath>bin\x64\Release\</OutputPath>
|
|
78
|
-
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
|
79
|
-
<Optimize>true</Optimize>
|
|
80
|
-
<NoWarn>;2008</NoWarn>
|
|
81
|
-
<DebugType>pdbonly</DebugType>
|
|
82
|
-
<PlatformTarget>x64</PlatformTarget>
|
|
83
|
-
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
84
|
-
<ErrorReport>prompt</ErrorReport>
|
|
85
|
-
</PropertyGroup>
|
|
86
|
-
<PropertyGroup>
|
|
87
|
-
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
|
88
|
-
</PropertyGroup>
|
|
89
|
-
<ItemGroup>
|
|
90
|
-
<Compile Include="UpdateManager.cs" />
|
|
91
|
-
<Compile Include="UpdateUtils.cs" />
|
|
92
|
-
<Compile Include="CodePushUtils.cs" />
|
|
93
|
-
<Compile Include="FileUtils.cs" />
|
|
94
|
-
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
95
|
-
<EmbeddedResource Include="Properties\CodePush.rd.xml" />
|
|
96
|
-
</ItemGroup>
|
|
97
|
-
<ItemGroup>
|
|
98
|
-
<ProjectReference Include="..\..\..\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj">
|
|
99
|
-
<Project>{c7673ad5-e3aa-468c-a5fd-fa38154e205c}</Project>
|
|
100
|
-
<Name>ReactNative</Name>
|
|
101
|
-
</ProjectReference>
|
|
102
|
-
</ItemGroup>
|
|
103
|
-
<ItemGroup>
|
|
104
|
-
<PackageReference Include="Newtonsoft.Json">
|
|
105
|
-
<Version>13.0.1</Version>
|
|
106
|
-
</PackageReference>
|
|
107
|
-
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
|
108
|
-
<Version>6.0.6</Version>
|
|
109
|
-
</PackageReference>
|
|
110
|
-
</ItemGroup>
|
|
111
|
-
<ItemGroup>
|
|
112
|
-
<SDKReference Include="WindowsMobile, Version=10.0.14393.0">
|
|
113
|
-
<Name>Windows Mobile Extensions for the UWP</Name>
|
|
114
|
-
</SDKReference>
|
|
115
|
-
</ItemGroup>
|
|
116
|
-
<Import Project="..\CodePush.Shared\CodePush.Shared.projitems" Label="Shared" />
|
|
117
|
-
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
|
118
|
-
<VisualStudioVersion>14.0</VisualStudioVersion>
|
|
119
|
-
</PropertyGroup>
|
|
120
|
-
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
|
121
|
-
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
122
|
-
Other similar extension points exist, see Microsoft.Common.targets.
|
|
123
|
-
<Target Name="BeforeBuild">
|
|
124
|
-
</Target>
|
|
125
|
-
<Target Name="AfterBuild">
|
|
126
|
-
</Target>
|
|
127
|
-
-->
|
|
128
|
-
</Project>
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
using Newtonsoft.Json.Linq;
|
|
2
|
-
using System;
|
|
3
|
-
using System.Threading.Tasks;
|
|
4
|
-
using Windows.Storage;
|
|
5
|
-
using Windows.Storage.Streams;
|
|
6
|
-
using Windows.System.Profile;
|
|
7
|
-
|
|
8
|
-
namespace CodePush.ReactNative
|
|
9
|
-
{
|
|
10
|
-
internal partial class CodePushUtils
|
|
11
|
-
{
|
|
12
|
-
internal static string GetFileBundlePrefix()
|
|
13
|
-
{
|
|
14
|
-
return CodePushConstants.FileBundlePrefix;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
internal async static Task<JObject> GetJObjectFromFileAsync(StorageFile file)
|
|
18
|
-
{
|
|
19
|
-
string jsonString = await FileIO.ReadTextAsync(file).AsTask().ConfigureAwait(false);
|
|
20
|
-
if (jsonString.Length == 0)
|
|
21
|
-
{
|
|
22
|
-
return new JObject();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try
|
|
26
|
-
{
|
|
27
|
-
return JObject.Parse(jsonString);
|
|
28
|
-
}
|
|
29
|
-
catch (Exception)
|
|
30
|
-
{
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static string GetDeviceIdImpl()
|
|
36
|
-
{
|
|
37
|
-
HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null);
|
|
38
|
-
IBuffer hardwareId = token.Id;
|
|
39
|
-
var dataReader = DataReader.FromBuffer(hardwareId);
|
|
40
|
-
|
|
41
|
-
var bytes = new byte[hardwareId.Length];
|
|
42
|
-
dataReader.ReadBytes(bytes);
|
|
43
|
-
|
|
44
|
-
return BitConverter.ToString(bytes);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Threading.Tasks;
|
|
3
|
-
using Windows.Storage;
|
|
4
|
-
|
|
5
|
-
namespace CodePush.ReactNative
|
|
6
|
-
{
|
|
7
|
-
internal class FileUtils
|
|
8
|
-
{
|
|
9
|
-
internal async static Task MergeFoldersAsync(StorageFolder source, StorageFolder target)
|
|
10
|
-
{
|
|
11
|
-
foreach (StorageFile sourceFile in await source.GetFilesAsync().AsTask().ConfigureAwait(false))
|
|
12
|
-
{
|
|
13
|
-
await sourceFile.CopyAndReplaceAsync(await target.CreateFileAsync(sourceFile.Name, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false)).AsTask().ConfigureAwait(false);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
foreach (StorageFolder sourceDirectory in await source.GetFoldersAsync().AsTask().ConfigureAwait(false))
|
|
17
|
-
{
|
|
18
|
-
StorageFolder nextTargetSubDir = await target.CreateFolderAsync(sourceDirectory.Name, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
|
|
19
|
-
await MergeFoldersAsync(sourceDirectory, nextTargetSubDir).ConfigureAwait(false);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
internal async static Task ClearReactDevBundleCacheAsync()
|
|
24
|
-
{
|
|
25
|
-
var devBundleCacheFile = (StorageFile)await ApplicationData.Current.LocalFolder.TryGetItemAsync(CodePushConstants.ReactDevBundleCacheFileName).AsTask().ConfigureAwait(false);
|
|
26
|
-
if (devBundleCacheFile != null)
|
|
27
|
-
{
|
|
28
|
-
await devBundleCacheFile.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
internal async static Task<long> GetBinaryResourcesModifiedTimeAsync(string fileName)
|
|
33
|
-
{
|
|
34
|
-
var assetJSBundleFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(CodePushConstants.AssetsBundlePrefix + fileName)).AsTask().ConfigureAwait(false);
|
|
35
|
-
var fileProperties = await assetJSBundleFile.GetBasicPropertiesAsync().AsTask().ConfigureAwait(false);
|
|
36
|
-
return fileProperties.DateModified.ToUnixTimeMilliseconds();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
using System.Reflection;
|
|
2
|
-
using System.Runtime.CompilerServices;
|
|
3
|
-
using System.Runtime.InteropServices;
|
|
4
|
-
|
|
5
|
-
// General Information about an assembly is controlled through the following
|
|
6
|
-
// set of attributes. Change these attribute values to modify the information
|
|
7
|
-
// associated with an assembly.
|
|
8
|
-
[assembly: AssemblyTitle("CodePush")]
|
|
9
|
-
[assembly: AssemblyDescription("")]
|
|
10
|
-
[assembly: AssemblyConfiguration("")]
|
|
11
|
-
[assembly: AssemblyCompany("")]
|
|
12
|
-
[assembly: AssemblyProduct("CodePush")]
|
|
13
|
-
[assembly: AssemblyCopyright("Copyright © 2016")]
|
|
14
|
-
[assembly: AssemblyTrademark("")]
|
|
15
|
-
[assembly: AssemblyCulture("")]
|
|
16
|
-
|
|
17
|
-
// Version information for an assembly consists of the following four values:
|
|
18
|
-
//
|
|
19
|
-
// Major Version
|
|
20
|
-
// Minor Version
|
|
21
|
-
// Build Number
|
|
22
|
-
// Revision
|
|
23
|
-
//
|
|
24
|
-
// You can specify all the values or you can default the Build and Revision Numbers
|
|
25
|
-
// by using the '*' as shown below:
|
|
26
|
-
// [assembly: AssemblyVersion("1.0.*")]
|
|
27
|
-
[assembly: AssemblyVersion("1.0.0.0")]
|
|
28
|
-
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
29
|
-
[assembly: ComVisible(false)]
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<!--
|
|
3
|
-
This file contains Runtime Directives, specifications about types your application accesses
|
|
4
|
-
through reflection and other dynamic code patterns. Runtime Directives are used to control the
|
|
5
|
-
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
|
|
6
|
-
library does not do any reflection, then you generally do not need to edit this file. However,
|
|
7
|
-
if your library reflects over types, especially types passed to it or derived from its types,
|
|
8
|
-
then you should write Runtime Directives.
|
|
9
|
-
|
|
10
|
-
The most common use of reflection in libraries is to discover information about types passed
|
|
11
|
-
to the library. Runtime Directives have three ways to express requirements on types passed to
|
|
12
|
-
your library.
|
|
13
|
-
|
|
14
|
-
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
|
|
15
|
-
Use these directives to reflect over types passed as a parameter.
|
|
16
|
-
|
|
17
|
-
2. SubTypes
|
|
18
|
-
Use a SubTypes directive to reflect over types derived from another type.
|
|
19
|
-
|
|
20
|
-
3. AttributeImplies
|
|
21
|
-
Use an AttributeImplies directive to indicate that your library needs to reflect over
|
|
22
|
-
types or methods decorated with an attribute.
|
|
23
|
-
|
|
24
|
-
For more information on writing Runtime Directives for libraries, please visit
|
|
25
|
-
http://go.microsoft.com/fwlink/?LinkID=391919
|
|
26
|
-
-->
|
|
27
|
-
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
|
28
|
-
<Library Name="CodePush">
|
|
29
|
-
|
|
30
|
-
<!-- add directives for your library here -->
|
|
31
|
-
|
|
32
|
-
</Library>
|
|
33
|
-
</Directives>
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
using Newtonsoft.Json;
|
|
2
|
-
using Newtonsoft.Json.Linq;
|
|
3
|
-
using System;
|
|
4
|
-
using System.IO;
|
|
5
|
-
using System.IO.Compression;
|
|
6
|
-
using System.Threading;
|
|
7
|
-
using System.Threading.Tasks;
|
|
8
|
-
using Windows.Storage;
|
|
9
|
-
using Windows.Storage.Streams;
|
|
10
|
-
using Windows.Web.Http;
|
|
11
|
-
|
|
12
|
-
namespace CodePush.ReactNative
|
|
13
|
-
{
|
|
14
|
-
internal class UpdateManager
|
|
15
|
-
{
|
|
16
|
-
#region Internal methods
|
|
17
|
-
|
|
18
|
-
internal async Task ClearUpdatesAsync()
|
|
19
|
-
{
|
|
20
|
-
await (await GetCodePushFolderAsync().ConfigureAwait(false)).DeleteAsync().AsTask().ConfigureAwait(false);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
internal async Task DownloadPackageAsync(JObject updatePackage, string expectedBundleFileName, Progress<HttpProgress> downloadProgress)
|
|
24
|
-
{
|
|
25
|
-
// Using its hash, get the folder where the new update will be saved
|
|
26
|
-
StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);
|
|
27
|
-
var newUpdateHash = (string)updatePackage[CodePushConstants.PackageHashKey];
|
|
28
|
-
StorageFolder newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, false).ConfigureAwait(false);
|
|
29
|
-
if (newUpdateFolder != null)
|
|
30
|
-
{
|
|
31
|
-
// This removes any stale data in newUpdateFolder that could have been left
|
|
32
|
-
// uncleared due to a crash or error during the download or install process.
|
|
33
|
-
await newUpdateFolder.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, true).ConfigureAwait(false);
|
|
37
|
-
StorageFile newUpdateMetadataFile = await newUpdateFolder.CreateFileAsync(CodePushConstants.PackageFileName).AsTask().ConfigureAwait(false);
|
|
38
|
-
var downloadUrlString = (string)updatePackage[CodePushConstants.DownloadUrlKey];
|
|
39
|
-
StorageFile downloadFile = await GetDownloadFileAsync().ConfigureAwait(false);
|
|
40
|
-
var downloadUri = new Uri(downloadUrlString);
|
|
41
|
-
|
|
42
|
-
// Download the file and send progress event asynchronously
|
|
43
|
-
var request = new HttpRequestMessage(HttpMethod.Get, downloadUri);
|
|
44
|
-
var client = new HttpClient();
|
|
45
|
-
var cancellationTokenSource = new CancellationTokenSource();
|
|
46
|
-
using (HttpResponseMessage response = await client.SendRequestAsync(request).AsTask(cancellationTokenSource.Token, downloadProgress).ConfigureAwait(false))
|
|
47
|
-
using (IInputStream inputStream = await response.Content.ReadAsInputStreamAsync().AsTask().ConfigureAwait(false))
|
|
48
|
-
using (IRandomAccessStream downloadFileStream = await downloadFile.OpenAsync(FileAccessMode.ReadWrite).AsTask().ConfigureAwait(false))
|
|
49
|
-
{
|
|
50
|
-
await RandomAccessStream.CopyAsync(inputStream, downloadFileStream).AsTask().ConfigureAwait(false);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
try
|
|
54
|
-
{
|
|
55
|
-
// Unzip the downloaded file and then delete the zip
|
|
56
|
-
StorageFolder unzippedFolder = await CreateUnzippedFolderAsync().ConfigureAwait(false);
|
|
57
|
-
ZipFile.ExtractToDirectory(downloadFile.Path, unzippedFolder.Path);
|
|
58
|
-
await downloadFile.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
59
|
-
|
|
60
|
-
// Merge contents with current update based on the manifest
|
|
61
|
-
StorageFile diffManifestFile = (StorageFile)await unzippedFolder.TryGetItemAsync(CodePushConstants.DiffManifestFileName).AsTask().ConfigureAwait(false);
|
|
62
|
-
if (diffManifestFile != null)
|
|
63
|
-
{
|
|
64
|
-
StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);
|
|
65
|
-
if (currentPackageFolder == null)
|
|
66
|
-
{
|
|
67
|
-
throw new InvalidDataException("Received a diff update, but there is no current version to diff against.");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
await UpdateUtils.CopyNecessaryFilesFromCurrentPackageAsync(diffManifestFile, currentPackageFolder, newUpdateFolder).ConfigureAwait(false);
|
|
71
|
-
await diffManifestFile.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await FileUtils.MergeFoldersAsync(unzippedFolder, newUpdateFolder).ConfigureAwait(false);
|
|
75
|
-
await unzippedFolder.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
76
|
-
|
|
77
|
-
// For zip updates, we need to find the relative path to the jsBundle and save it in the
|
|
78
|
-
// metadata so that we can find and run it easily the next time.
|
|
79
|
-
string relativeBundlePath = await UpdateUtils.FindJSBundleInUpdateContentsAsync(newUpdateFolder, expectedBundleFileName).ConfigureAwait(false);
|
|
80
|
-
if (relativeBundlePath == null)
|
|
81
|
-
{
|
|
82
|
-
throw new InvalidDataException("Update is invalid - A JS bundle file named \"" + expectedBundleFileName + "\" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.");
|
|
83
|
-
}
|
|
84
|
-
else
|
|
85
|
-
{
|
|
86
|
-
if (diffManifestFile != null)
|
|
87
|
-
{
|
|
88
|
-
// TODO verify hash for diff update
|
|
89
|
-
// CodePushUpdateUtils.verifyHashForDiffUpdate(newUpdateFolderPath, newUpdateHash);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
updatePackage[CodePushConstants.RelativeBundlePathKey] = relativeBundlePath;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
catch (InvalidDataException)
|
|
96
|
-
{
|
|
97
|
-
// Downloaded file is not a zip, assume it is a jsbundle
|
|
98
|
-
await downloadFile.RenameAsync(expectedBundleFileName).AsTask().ConfigureAwait(false);
|
|
99
|
-
await downloadFile.MoveAsync(newUpdateFolder).AsTask().ConfigureAwait(false);
|
|
100
|
-
}
|
|
101
|
-
/*TODO: ZipFile.ExtractToDirectory is not reliable and throws exceptions if:
|
|
102
|
-
- path is too long
|
|
103
|
-
it needs to be handled
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
// Save metadata to the folder
|
|
107
|
-
await FileIO.WriteTextAsync(newUpdateMetadataFile, JsonConvert.SerializeObject(updatePackage)).AsTask().ConfigureAwait(false);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
internal async Task<JObject> GetCurrentPackageAsync()
|
|
111
|
-
{
|
|
112
|
-
string packageHash = await GetCurrentPackageHashAsync().ConfigureAwait(false);
|
|
113
|
-
return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
internal async Task<StorageFile> GetCurrentPackageBundleAsync(string bundleFileName)
|
|
117
|
-
{
|
|
118
|
-
StorageFolder packageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);
|
|
119
|
-
if (packageFolder == null)
|
|
120
|
-
{
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
JObject currentPackage = await GetCurrentPackageAsync().ConfigureAwait(false);
|
|
125
|
-
var relativeBundlePath = (string)currentPackage[CodePushConstants.RelativeBundlePathKey];
|
|
126
|
-
|
|
127
|
-
return relativeBundlePath == null
|
|
128
|
-
? await packageFolder.GetFileAsync(bundleFileName).AsTask().ConfigureAwait(false)
|
|
129
|
-
: await packageFolder.GetFileAsync(relativeBundlePath).AsTask().ConfigureAwait(false);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
internal async Task<string> GetCurrentPackageHashAsync()
|
|
133
|
-
{
|
|
134
|
-
JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);
|
|
135
|
-
string currentPackageShortHash = (string)info[CodePushConstants.CurrentPackageKey];
|
|
136
|
-
if (currentPackageShortHash == null)
|
|
137
|
-
{
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
JObject currentPackageMetadata = await GetPackageAsync(currentPackageShortHash).ConfigureAwait(false);
|
|
142
|
-
return currentPackageMetadata == null ? null : (string)currentPackageMetadata[CodePushConstants.PackageHashKey];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
internal async Task<JObject> GetPackageAsync(string packageHash)
|
|
146
|
-
{
|
|
147
|
-
StorageFolder packageFolder = await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);
|
|
148
|
-
if (packageFolder == null)
|
|
149
|
-
{
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
try
|
|
154
|
-
{
|
|
155
|
-
StorageFile packageFile = await packageFolder.GetFileAsync(CodePushConstants.PackageFileName).AsTask().ConfigureAwait(false);
|
|
156
|
-
return await CodePushUtils.GetJObjectFromFileAsync(packageFile).ConfigureAwait(false);
|
|
157
|
-
}
|
|
158
|
-
catch (IOException)
|
|
159
|
-
{
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
internal async Task<StorageFolder> GetPackageFolderAsync(string packageHash, bool createIfNotExists)
|
|
165
|
-
{
|
|
166
|
-
StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);
|
|
167
|
-
try
|
|
168
|
-
{
|
|
169
|
-
packageHash = ShortenPackageHash(packageHash);
|
|
170
|
-
return createIfNotExists
|
|
171
|
-
? await codePushFolder.CreateFolderAsync(packageHash, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false)
|
|
172
|
-
: await codePushFolder.GetFolderAsync(packageHash).AsTask().ConfigureAwait(false);
|
|
173
|
-
}
|
|
174
|
-
catch (FileNotFoundException)
|
|
175
|
-
{
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
internal async Task<JObject> GetPreviousPackageAsync()
|
|
181
|
-
{
|
|
182
|
-
string packageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);
|
|
183
|
-
return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
internal async Task<string> GetPreviousPackageHashAsync()
|
|
187
|
-
{
|
|
188
|
-
JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);
|
|
189
|
-
string previousPackageShortHash = (string)info[CodePushConstants.PreviousPackageKey];
|
|
190
|
-
if (previousPackageShortHash == null)
|
|
191
|
-
{
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
JObject previousPackageMetadata = await GetPackageAsync(previousPackageShortHash).ConfigureAwait(false);
|
|
196
|
-
return previousPackageMetadata == null ? null : (string)previousPackageMetadata[CodePushConstants.PackageHashKey];
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
internal async Task InstallPackageAsync(JObject updatePackage, bool currentUpdateIsPending)
|
|
200
|
-
{
|
|
201
|
-
var packageHash = (string)updatePackage[CodePushConstants.PackageHashKey];
|
|
202
|
-
JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);
|
|
203
|
-
if (currentUpdateIsPending)
|
|
204
|
-
{
|
|
205
|
-
// Don't back up current update to the "previous" position because
|
|
206
|
-
// it is an unverified update which should not be rolled back to.
|
|
207
|
-
StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);
|
|
208
|
-
if (currentPackageFolder != null)
|
|
209
|
-
{
|
|
210
|
-
await currentPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else
|
|
214
|
-
{
|
|
215
|
-
string previousPackageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);
|
|
216
|
-
if (previousPackageHash != null && !previousPackageHash.Equals(packageHash))
|
|
217
|
-
{
|
|
218
|
-
StorageFolder previousPackageFolder = await GetPackageFolderAsync(previousPackageHash, false).ConfigureAwait(false);
|
|
219
|
-
if (previousPackageFolder != null)
|
|
220
|
-
{
|
|
221
|
-
await previousPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
info[CodePushConstants.PreviousPackageKey] = info[CodePushConstants.CurrentPackageKey];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
info[CodePushConstants.CurrentPackageKey] = packageHash;
|
|
229
|
-
await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
internal async Task RollbackPackageAsync()
|
|
233
|
-
{
|
|
234
|
-
JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);
|
|
235
|
-
StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);
|
|
236
|
-
if (currentPackageFolder != null)
|
|
237
|
-
{
|
|
238
|
-
await currentPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
info[CodePushConstants.CurrentPackageKey] = info[CodePushConstants.PreviousPackageKey];
|
|
242
|
-
info[CodePushConstants.PreviousPackageKey] = null;
|
|
243
|
-
await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
#endregion
|
|
247
|
-
|
|
248
|
-
#region Private methods
|
|
249
|
-
|
|
250
|
-
private async Task<StorageFolder> GetCodePushFolderAsync()
|
|
251
|
-
{
|
|
252
|
-
return await ApplicationData.Current.LocalFolder.CreateFolderAsync(CodePushConstants.CodePushFolderPrefix, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
private async Task<StorageFolder> GetCurrentPackageFolderAsync()
|
|
256
|
-
{
|
|
257
|
-
JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);
|
|
258
|
-
var packageHash = (string)info[CodePushConstants.CurrentPackageKey];
|
|
259
|
-
return packageHash == null ? null : await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private async Task<JObject> GetCurrentPackageInfoAsync()
|
|
263
|
-
{
|
|
264
|
-
StorageFile statusFile = await GetStatusFileAsync().ConfigureAwait(false);
|
|
265
|
-
return await CodePushUtils.GetJObjectFromFileAsync(statusFile).ConfigureAwait(false);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
private async Task<StorageFile> GetDownloadFileAsync()
|
|
269
|
-
{
|
|
270
|
-
var codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);
|
|
271
|
-
return await codePushFolder.CreateFileAsync(CodePushConstants.DownloadFileName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private async Task<StorageFile> GetStatusFileAsync()
|
|
275
|
-
{
|
|
276
|
-
StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);
|
|
277
|
-
return await codePushFolder.CreateFileAsync(CodePushConstants.StatusFileName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
private async Task<StorageFolder> CreateUnzippedFolderAsync()
|
|
281
|
-
{
|
|
282
|
-
StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);
|
|
283
|
-
var unzippedFolder = await codePushFolder.TryGetItemAsync(CodePushConstants.UnzippedFolderName).AsTask().ConfigureAwait(false);
|
|
284
|
-
|
|
285
|
-
if (unzippedFolder != null)
|
|
286
|
-
{
|
|
287
|
-
await unzippedFolder.DeleteAsync();
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return await codePushFolder.CreateFolderAsync(CodePushConstants.UnzippedFolderName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
private string ShortenPackageHash(string longPackageHash)
|
|
294
|
-
{
|
|
295
|
-
return longPackageHash.Substring(0, 8);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
private async Task UpdateCurrentPackageInfoAsync(JObject packageInfo)
|
|
299
|
-
{
|
|
300
|
-
await FileIO.WriteTextAsync(await GetStatusFileAsync().ConfigureAwait(false), JsonConvert.SerializeObject(packageInfo)).AsTask().ConfigureAwait(false);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
#endregion
|
|
304
|
-
}
|
|
305
|
-
}
|