diff --git a/Emby.Common.Implementations/Emby.Common.Implementations.csproj b/Emby.Common.Implementations/Emby.Common.Implementations.csproj
index 50d0d05ec..5b1defccb 100644
--- a/Emby.Common.Implementations/Emby.Common.Implementations.csproj
+++ b/Emby.Common.Implementations/Emby.Common.Implementations.csproj
@@ -32,7 +32,8 @@
- ..\packages\NLog.4.4.10\lib\net45\NLog.dll
+ ..\packages\NLog.4.4.11\lib\net45\NLog.dll
+ True
..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll
@@ -227,6 +228,7 @@
+
@@ -317,6 +319,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -368,7 +387,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
-
- 17, 17
-
-
- 130, 17
-
-
-
- AAABAAgAMDAAAAEAIACoJQAAhgAAADAwAAABAAgAqA4AAC4mAAAgIAAAAQAgAKgQAADWNAAAICAAAAEA
- CACoCAAAfkUAABgYAAABACAAiAkAACZOAAAYGAAAAQAIAMgGAACuVwAAEBAAAAEAIABoBAAAdl4AABAQ
- AAABAAgAaAUAAN5iAAAoAAAAMAAAAGAAAAABACAAAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu2UkpItlMxAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7RQM0u1Uv9LtVL/S7NSJQAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKtFIfS7VS/0u1
- Uv9LtVL/S7VS/0i2SAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuz
- Uz1LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9ItkgHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAS7NRTku1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7NSJQAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLs1FOS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0i2
- UzEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuzUz1LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv/OtgAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASrRSH0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/xsYACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtFAzS7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqAAMAAAAAAAAAAEu2UkpLtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv/atgAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv/MuwAPTLVSUEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/0rwAFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9K8ABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/atgAOAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/8Dkwf9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////bsBk/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//////////////////////9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
- /////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
- ///////////////////////////////////d6sP/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/////////////////////////////////////////////////0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////////////////////
- ////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////
- //////////////////////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
- ////////////////////////////////////////////////////////0uOr/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAA/wABS7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
- ////////////////////////////////////////////////////////////////////////V7lZ/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/////////////////////////////////////////////////////////////////7Dd
- rP9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////////////////////
- ////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9ItlMxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////////////
- /////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0uzUiUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////
- //////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SLZIBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAD/AAFLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////
- ////////////////////////+fff/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9ItkgHAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS//////////////////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9S4ABIAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/1L8AGAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/1q6Xf9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv/OtgAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/8bGAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/atgAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9K8ABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtFHOAAAAAEu1Uv9LtVL/0rwAFwAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0UdQAAAAAAAAAAAAAAADatgAOAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SrVS7AAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0
- UuIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/SrVS0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9KtVLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0q0UuIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9KtVLsAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEq0UdQAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAD///+f//8AAP///w///wAA///+B///
- AAD///wD//8AAP//+AH//wAA///wAP//AAD//+AAf/8AAP//wAA//wAA//+AAB//AAD/8wAAD/8AAP/g
- AAAH/wAA/8AAAAP/AAD/gAAAA/8AAP8AAAAH/wAA/gAAAAP/AAD8AAAAAf8AAPgAAAAA/wAA8AAAAAB/
- AADgAAAAAD8AAMAAAAAAHwAAgAAAAAAPAACAAAAAAAcAAMAAAAAAAwAA4AAAAAABAADwAAAAAAAAAPgA
- AAAAAQAA/AAAAAADAAD+AAAAAAcAAP8AAAAADwAA/4AAAAAfAAD/wAAAAD8AAP/gAAAAfwAA/+AAAAD/
- AAD/wAAAAf8AAP/AAAAD/wAA/+AAAAf/AAD/8AAAT/8AAP/4AAD//wAA//wAAf//AAD//gAD//8AAP//
- AAf//wAA//+AD///AAD//8Af//8AAP//4D///wAA///wf///AAD///j///8AAP///f///wAAKAAAADAA
- AABgAAAAAQAIAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAP9vtzz/cLc8/1+2Rv9RtU//S7VS/0y1
- Uf9NtVH/TrVQ/0+1UP9NtlP/TbZU/062VP9Rt1f/VLla/1W5W/9WuVz/Y7ZD/2C2Rf9htkX/YrZE/2O2
- RP9otkD/Yb5m/2S/aP9mv2j/aMBq/3jHef95x3z/e8h8/3zIfP9+yX//f8qD/4PMiP+R0ZL/ktGS/5TS
- lP+V0pX/mdSY/6jaqP+s3Kv/r92t/7Ddrv/G5sL/xufF/8jnxv/L6cj/3fDb/9/x3f/g8d3/4/Pg/+/4
- 7f/x+e//8vnv//r8+P/7/fn//v/+/////v8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAABQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQUFAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQUFBQAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAUFBQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUF
- BQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUFBQUFBQMA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAUEgAABQUFBQUFBQUFBQUFBQUFBQUFBgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBhIFBQUFBQUF
- BQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQYFBQUFBQUFBQUFBQUFBQUFBQUF
- BQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBhIAAAAAAAAA
- AAAAAAAAAAAAABUHBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCBUAAAAAAAAAAAAAAAAAAAAAFQcF
- BQUFBQUFBQUGBQUFBQUFBQUFBQUFBQUFBQUFEwAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUgKg8F
- BQUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAAAAAAAABUHBQUFBQUFBQUFBQUhOTUkDAUFBQUFBQUFBQUF
- BQUFBQUFAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQUhOTk5MR4FBQUFBQUFBQUFBQUFBQUFBQAAAAAA
- AAAAAAASBwUFBQUFBQUFBQUFBQUhOTk5OTgsGAUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAUFBQUFBQUF
- BQUFBQUFBQUhOTk5OTk5NygOBQUFBQUFBQUFBQUFBQUFAAAAAAAABQUFBQUFBQUFBQUFBQUFBQUhOTk5
- OTk5OTkzIwsFBQUFBQUFBQUFBQUFBQAAAAAFBQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OS8bBQUF
- BQUFBQUFBQUFBQUAAAAFBQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OTk4KxcFBQUFBQUFBQUFBQUF
- AAAABQUFBQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OTk5OTYnDQUFBQUFBQUFBQUFBQAAAAUFBQUFBQUF
- BQUFBQUFBQUhOTk5OTk5OTk5OTk5OTMiCwUFBQUFBQUFBQUFBQUAAAAFBQUFBQUFBQUFBQUFBQUhOTk5
- OTk5OTk5OTk2KQ4FBQUFBQUFBQUFBQUFBQUAAAAABQUFBQUFBQUFBQUFBQUhOTk5OTk5OTk5OS0ZBQUF
- BQUFBQUFBQUFBQUFBQUAAAAAAAUFBQUFBQUFBQUFBQUhOTk5OTk5OTkwHQUFBQUFBQUFBQUFBQUFBQUF
- BQAAAAAAAAAFBQUFBQUFBQUFBQUhOTk5OTk5NCUKBQUFBQUFBQUFBQUFBQUFBQUFAAAAAAAAAAAABQUF
- BQUFBQUFBQUhOTk5OTcpEAUFBQUFBQUFBQUFBQUFBQUFBQUAAAAAAAAAAAAAAAUFBQUFBQUFBQUhOTk5
- LhoFBQUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAFBQUFBQUFBQUhOTIfBQUFBQUFBQUFBQUF
- BQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAABQUFBQUFBQUcJgsFBQUFBQUFBQUFBQUFBQUFBQUFBgMAAAAA
- AAAAAAAAAAAAAAAAFgcFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUGAwAAAAAAAAAAAAAAAAAAAAAW
- CQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQYDAAAAAAAAAAAAAAAAAAAAAAARBwUFBQUFBQUFBQUF
- BQUFBQUFBQUFBQUFBQUFBgMAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQUFBQUFBQUFBQUH
- BQUGAwAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBQUFBQUFBQUFBQUFBQUFBQUFBQUBBAYDAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAUBwUFBQUFBQUFBQUFBQUFBQUFBQUAAhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAFAcFBQUFBQUFBQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQHBQUFBQUF
- BQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVBwUFBQUFBQUFBQUFBQUAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcFBQUFBQUFBQUFBQAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAABQHBQUFBQUFBQUFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAVBwUFBQUFBQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQcF
- BQUFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUHBQUFAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVBwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAD///////8AAP///5///wAA////D///AAD///4H//8AAP///AP//wAA///4Af//AAD///AA//8AAP//
- 4AB//wAA///AAD//AAD//4AAH/8AAP/zAAAP/wAA/+AAAAf/AAD/wAAAA/8AAP+AAAAD/wAA/wAAAAf/
- AAD+AAAAA/8AAPwAAAAB/wAA+AAAAAD/AADwAAAAAH8AAOAAAAAAPwAAwAAAAAAfAACAAAAAAA8AAIAA
- AAAABwAAwAAAAAADAADgAAAAAAEAAPAAAAAAAAAA+AAAAAABAAD8AAAAAAMAAP4AAAAABwAA/wAAAAAP
- AAD/gAAAAB8AAP/AAAAAPwAA/+AAAAB/AAD/4AAAAP8AAP/AAAAB/wAA/8AAAAP/AAD/4AAAB/8AAP/w
- AABP/wAA//gAAP//AAD//AAB//8AAP/+AAP//wAA//8AB///AAD//4AP//8AAP//wB///wAA///gP///
- AAD///B///8AAP//+P///wAA///9////AAAoAAAAIAAAAEAAAAABACAAAAAAAAAgAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtFH+S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv/8/fz/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P///////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVH/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL//P38//////////////////////9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/8/fz/////////////////////////
- ///q8dP/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P//////////////
- ////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL//P38////
- /////////////////////////////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv/8/fz/////////////////////////////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS//z9/P//////////////////////////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL//P38////////////////////////////mspu/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/8/fz//////////////////v7+/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS//z9/P///////////0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL//P38/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAEu1
- Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu0Uf5LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uf9LtVL/S7VS/0u1
- Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//v////x////4P///8B///+AP///AB//9gAP/+AAB//AAAP/gA
- AH/wAAB/4AAAP8AAAB+AAAAPAAAAB4AAAAPAAAAB4AAAAPAAAAH4AAAD/AAAB/4AAA/+AAAf/AAAP/4A
- AH//AAb//4AP///AH///4D////B////4/////f//KAAAACAAAABAAAAAAQAIAAAAAAAACAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAP95tzb/erc2/3u3Nf9wtzz/VrZL/1C1T/9RtU7/UrVO/1O1Tf9VtUz/VbZM/0u1
- Uv9NtVH/TrVQ/0+1UP9NtlT/ULdW/1a5W/9gtkb/Y7ZE/2i2QP9bu2D/Zb9p/2vCb/9vw3L/d8d6/33J
- fv+NuCr/jrgq/4+4Kf+SuSf/k7kn/5C5Kf+SuSj/hcyG/4fNif+U0pX/l9OY/5bUmf+e15//n9eh/63d
- rv+s3bD/uOG5/8jox//Q68//0+zS/97x3f/h8t//5vTl//D47//1+/T/+/36//3+/f//////AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAADAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAADAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwMDAYCAAAAAAAAAAAAAAAAAAAA
- AAAAAAAMDAwMDAwMDAwMDAcBAAAAAAAAAAAAAAAAAAAAIAsTDAwMDAwMDAwMDAwMDAcDAAAAAAAAAAAA
- AAAAACAJDA4MDAwMDAwMDAwMDAwMDAcDAAAAAAAAAAAAAAAdCQwMDAwMDAwMDAwMDAwMDAwMDAoAAAAA
- AAAAAAAAHgkMDAwMDAwMDAwMDAwMDAwMDAwNFAAAAAAAAAAAACAJDAwMDAwMDCkmEAwMDAwMDAwMDAwM
- AAAAAAAAAAAhCQwMDAwMDAwMKzcxGwwMDAwMDAwMDAwMAAAAAAAADAcMDAwMDAwMDAwrNzc3LRcMDAwM
- DAwMDAwMAAAAAAwMDAwMDAwMDAwMDCs3Nzc3NSoSDAwMDAwMDAwMAAAADAwMDAwMDAwMDAwMKzc3Nzc3
- NzMlEAwMDAwMDAwMAAAMDAwMDAwMDAwMDAwrNzc3Nzc3NzcwGgwMDAwMDAwMAAAMDAwMDAwMDAwMDCs3
- Nzc3Nzc3Ny4YDAwMDAwMDAwMAAAMDAwMDAwMDAwMKzc3Nzc3NzIjDAwMDAwMDAwMDAwAAAAMDAwMDAwM
- DAwrNzc3NzQoEQwMDAwMDAwMDAwMDAAAAAAMDAwMDAwMDCs3NzYsFgwMDAwMDAwMDAwMDAwAAAAAAAAM
- DAwMDAwMKzcvGQwMDAwMDAwMDAwMDAcCAAAAAAAAAAAMDAwMDAwnJAwMDAwMDAwMDAwMDAwHAwAAAAAA
- AAAAABUPDAwMDAwMDAwMDAwMDAwMDAwMBwIAAAAAAAAAAAAABQwMDAwMDAwMDAwMDAwMDAwMDAcBAAAA
- AAAAAAAAAAAfCQwMDAwMDAwMDAwMDAwMDwwHAgAAAAAAAAAAAAAAAAAfCQwMDAwMDAwMDAwMDAwEBQIA
- AAAAAAAAAAAAAAAAAAAcCQwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAeCQwMDAwMDAwMDAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAgCQwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeCQwMDAwM
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdCQwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi
- CAwAAAAAAAAAAAAAAAAAAAAA//+/////H////g////wH///4A///8AH//2AA//4AAH/8AAA/+AAAf/AA
- AH/gAAA/wAAAH4AAAA8AAAAHgAAAA8AAAAHgAAAA8AAAAfgAAAP8AAAH/gAAD/4AAB/8AAA//gAAf/8A
- Bv//gA///8Af///gP///8H////j////9//8oAAAAGAAAADAAAAABACAAAAAAAAASAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASrRSQUm1
- Ty0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJtU8tS7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEuz
- UVFLtVL/S7VS/0u1Uv9LtVL/SbVPLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASbVPLUu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/8+/
- ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AABKtFJBS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv/UqgAGAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/2S1QV5LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/1L8AGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL///////////9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL//////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/////////////////////////
- ///29+b/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL//////////////////////////////////////0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/////////
- /////////////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL///////////////////////////+l1ZP/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9JtU8tAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL//////////////////////0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/wAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL///////////9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/0LkAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv/PvwAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/9SqAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u0
- UtJLtVL/1L8AGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/SrVR3gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9KtVLyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u0Uc4AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1
- Uv9LtVL/SrVS8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKtVHeAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP/z/wD/4f8A/8D/AP+AfwD9AD8A+AAfAPAA
- HwDgAA8AwAAHAIAAAwCAAAEAwAAAAOAAAQDwAAMA+AAHAPwADwD4AB8A/AA/AP4A/wD/Af8A/4P/AP/H
- /wD/7/8AKAAAABgAAAAwAAAAAQAIAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9UtUz/VbZM/0u1
- Uv9MtVH/TbVR/061UP9PtVD/TLZT/062VP9SuFj/Vrlc/2W2Qv9htkX/Xr1j/2XAav9qwW7/ccR1/3LF
- dv99yYD/iM6L/5PSlv+j2aX/r92w/73kvv/B5sP/yejJ/9ju1//h8uD/6vbp//H58P/3/Pb/+/36//7+
- /v//////AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAA
- AAADAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAAAAAAAA
- AAAAAAAAAAAAAAADAwMDAwMDAQAAAAAAAAAAAAAAAAANAAMDAwMDAwMDAwEAAAAAAAAAAAAAAAIEBgMD
- AwMDAwMDAwMBAAAAAAAAAAAAAgQDAwMDAwMDAwMDAwMEDQAAAAAAAAACBAMDAwMRCQMDAwMDAwMFAwAA
- AAAAAAIEAwMDAwMZHBMDAwMDAwMDAwMAAAAABwQDAwMDAwMZIiIaDwMDAwMDAwMDAAADAwMDAwMDAwMZ
- IiIiIBcLAwMDAwMDAwADAwMDAwMDAwMZIiIiIiIeFQgDAwMDAwMAAwMDAwMDAwMZIiIiIiIdFAMDAwMD
- AwMAAAMDAwMDAwMZIiIiHxYKAwMDAwMDAwMAAAADAwMDAwMZIiEYDgMDAwMDAwMDAwAAAAAAAwMDAwMZ
- GxIDAwMDAwMDAwMBAAAAAAAAAAYDAwMQBAMDAwMDAwMDAwEAAAAAAAAADAUDAwMDAwMDAwMDAwMDAQAA
- AAAAAAAAAAIEAwMDAwMDAwMDBQUBAAAAAAAAAAAAAAACBAMDAwMDAwMDAwwAAAAAAAAAAAAAAAAAAgQD
- AwMDAwMDAAAAAAAAAAAAAAAAAAAAAAIEAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAACBAMDAwAAAAAAAAAA
- AAAAAAAAAAAAAAAAAgQDAAAAAAAAAAAAAAD///8A//P/AP/h/wD/wP8A/4B/AP0APwD4AB8A8AAfAOAA
- DwDAAAcAgAADAIAAAQDAAAAA4AABAPAAAwD4AAcA/AAPAPgAHwD8AD8A/gD/AP8B/wD/g/8A/8f/AP/v
- /wAoAAAAEAAAACAAAAABACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv//////S7VS/0u1Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAA
- AAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/////////////////S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv8AAAAAAAAAAEu1Uv9LtVL/S7VS/0u1Uv9LtVL/S7VS////////////////////////////S7VS/0u1
- Uv9LtVL/S7VS/wAAAAAAAAAAS7VS/0u1Uv9LtVL/S7VS/0u1Uv//////////////////////sN2s/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/////////////////S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS//////9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAABLtVL/S7VS/0u1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEu1Uv9LtVL/S7VS/0u1
- Uv9LtVL/S7VS/0u1Uv9LtVL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS7VS/0u1
- Uv9LtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AABLtVL/S7VS/0u1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAEu1Uv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP9/AAD+PwAA/B8AAPAP
- AADgBwAAwAcAAIADAAAAAQAAgAAAAMABAADgAwAA4AcAAPAPAAD4PwAA/H8AAP7/AAAoAAAAEAAAACAA
- AAABAAgAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAA/0+1T/9QtU//VLVM/1W2TP9LtVL/TLVR/021
- Uf9PtVD/U7hZ/1a5XP9hvmb/ZsBr/3bGev99yYH/qNuq/6/esf+y37T/uOK6/8Lmw//K6cr/1u7X//n8
- +f/7/fv////+/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
- AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAFBQUAAAAAAAAAAAAAAAAFBQUF
- BQAAAAAAAAAAAAAFBQUFBQYDAAAAAAAAAAQBBQUFBQUFBgMAAAAAAAQGBQUFBQUFBQUIAAAAAAQGBQUF
- Eg4FBQUFBQUAAAUGBQUFBRUYFAwFBQUFBQAFBQUFBQUVGBgXEAoFBQUFBQUFBQUFFRgYFg8JBQUFBQAF
- BQUFBRUYEwsFBQUFBQUAAAUFBQURDQUFBQUFBgMAAAAAAgUFBQUFBQUFBgMAAAAAAAQGBQUFBQUFAQMA
- AAAAAAAABAYFBQUFBQAAAAAAAAAAAAAEBgUFBQAAAAAAAAAAAAAAAAQHBQAAAAAAAAD/fwAA/j8AAPwf
- AADwDwAA4AcAAMAHAACAAwAAAAEAAIAAAADAAQAA4AMAAOAHAADwDwAA+D8AAPx/AAD+/wAA
-
-
-
\ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index a0494b3e5..8cd8138fd 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -53,31 +53,10 @@ namespace MediaBrowser.ServerApplication
private static IFileSystem FileSystem;
- public static bool TryGetLocalFromUncDirectory(string local, out string unc)
- {
- if ((local == null) || (local == ""))
- {
- unc = "";
- throw new ArgumentNullException("local");
- }
-
- ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name FROM Win32_share WHERE path ='" + local.Replace("\\", "\\\\") + "'");
- ManagementObjectCollection coll = searcher.Get();
- if (coll.Count == 1)
- {
- foreach (ManagementObject share in searcher.Get())
- {
- unc = share["Name"] as String;
- unc = "\\\\" + SystemInformation.ComputerName + "\\" + unc;
- return true;
- }
- }
- unc = "";
- return false;
- }
///
/// Defines the entry point of the application.
///
+ [STAThread]
public static void Main()
{
var options = new StartupOptions(Environment.GetCommandLineArgs());
@@ -321,8 +300,6 @@ namespace MediaBrowser.ServerApplication
}
}
- private static readonly TaskCompletionSource ApplicationTaskCompletionSource = new TaskCompletionSource();
-
///
/// Runs the application.
///
@@ -394,9 +371,6 @@ namespace MediaBrowser.ServerApplication
HideSplashScreen();
ShowTrayIcon();
-
- task = ApplicationTaskCompletionSource.Task;
- Task.WaitAll(task);
}
}
@@ -487,7 +461,6 @@ namespace MediaBrowser.ServerApplication
/// The instance containing the event data.
static void service_Disposed(object sender, EventArgs e)
{
- ApplicationTaskCompletionSource.SetResult(true);
OnServiceShutdown();
}
@@ -706,14 +679,10 @@ namespace MediaBrowser.ServerApplication
_serverNotifyIcon = null;
}
- //_logger.Info("Calling Application.Exit");
+ _logger.Info("Calling Application.Exit");
//Application.Exit();
-
- _logger.Info("Calling Environment.Exit");
+
Environment.Exit(0);
-
- _logger.Info("Calling ApplicationTaskCompletionSource.SetResult");
- ApplicationTaskCompletionSource.SetResult(true);
}
private static void ShutdownWindowsService()
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 4cc3fd6a5..19f4921d3 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -78,7 +78,8 @@
..\packages\ImageMagickSharp.1.0.0.18\lib\net45\ImageMagickSharp.dll
- ..\packages\NLog.4.4.10\lib\net45\NLog.dll
+ ..\packages\NLog.4.4.11\lib\net45\NLog.dll
+ True
..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll
@@ -95,11 +96,11 @@
..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll
- ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll
+ ..\packages\SQLitePCLRaw.core.1.1.6\lib\net45\SQLitePCLRaw.core.dll
True
- ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
+ ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.6\lib\net45\SQLitePCLRaw.provider.sqlite3.dll
True
@@ -129,12 +130,6 @@
Component
-
- Form
-
-
- MainForm.cs
-
@@ -166,9 +161,6 @@
-
- MainForm.cs
-
ResXFileCodeGenerator
Resources.Designer.cs
@@ -190,887 +182,14 @@
MediaBrowser.Updater.exe
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
PreserveNewest
-
+
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
index c421dd9eb..cc8656f23 100644
--- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
+++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
@@ -45,7 +45,6 @@ namespace MediaBrowser.ServerApplication
components = new System.ComponentModel.Container();
- var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
contextMenuStrip1 = new ContextMenuStrip(components);
notifyIcon1 = new NotifyIcon(components);
@@ -62,7 +61,7 @@ namespace MediaBrowser.ServerApplication
// notifyIcon1
//
notifyIcon1.ContextMenuStrip = contextMenuStrip1;
- notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ notifyIcon1.Icon = new System.Drawing.Icon(GetType().Assembly.GetManifestResourceStream(GetType().Namespace + ".Icon.ico"));
notifyIcon1.Text = "Emby";
notifyIcon1.Visible = true;
//
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 9abd370f3..ca382ffb3 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,11 +1,11 @@
-
+
-
-
+
+
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index ee911f0e9..7d825875d 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -101,7 +101,7 @@ namespace MediaBrowser.WebDashboard.Api
var parent = _fileSystem.GetDirectoryName(path);
return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(Path.Combine(_basePath, "voice"), parent, StringComparison.OrdinalIgnoreCase);
+ string.Equals(Path.Combine(_basePath, "offline"), parent, StringComparison.OrdinalIgnoreCase);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index d424cc0ca..3b642eca2 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -107,7 +107,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
/// The metadata file.
/// The settings.
/// The cancellation token.
- private void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
+ protected virtual void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
{
if (!SupportsUrlAfterClosingXmlTag)
{
@@ -233,7 +233,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
get { return "themoviedb.org/movie/"; }
}
- private void ParseProviderLinks(T item, string xml)
+ protected void ParseProviderLinks(T item, string xml)
{
//Look for a match for the Regex pattern "tt" followed by 7 digits
Match m = Regex.Match(xml, @"tt([0-9]{7})", RegexOptions.IgnoreCase);
diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
index d10a55e07..953b59f46 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
@@ -9,6 +9,8 @@ using System.Threading;
using System.Xml;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Xml;
+using System.IO;
+using System.Text;
namespace MediaBrowser.XbmcMetadata.Parsers
{
@@ -24,6 +26,65 @@ namespace MediaBrowser.XbmcMetadata.Parsers
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+ protected override void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
+ {
+ using (var fileStream = FileSystem.OpenRead(metadataFile))
+ {
+ using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
+ {
+ item.ResetPeople();
+
+ var xml = streamReader.ReadToEnd();
+
+ var srch = "";
+ var index = xml.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
+
+ if (index != -1)
+ {
+ xml = xml.Substring(0, index + srch.Length);
+ }
+
+ using (var ms = new MemoryStream())
+ {
+ var bytes = Encoding.UTF8.GetBytes(xml);
+
+ ms.Write(bytes, 0, bytes.Length);
+ ms.Position = 0;
+
+ // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
+ try
+ {
+ // Use XmlReader for best performance
+ using (var reader = XmlReader.Create(ms, settings))
+ {
+ reader.MoveToContent();
+ reader.Read();
+
+ // Loop through each element
+ while (!reader.EOF && reader.ReadState == ReadState.Interactive)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ FetchDataFromXmlNode(reader, item);
+ }
+ else
+ {
+ reader.Read();
+ }
+ }
+ }
+ }
+ catch (XmlException)
+ {
+
+ }
+ }
+ }
+ }
+ }
+
///
/// Fetches the data from XML node.
///
diff --git a/Mono.Nat/NatUtility.cs b/Mono.Nat/NatUtility.cs
index bcbe5d8d0..983e86833 100644
--- a/Mono.Nat/NatUtility.cs
+++ b/Mono.Nat/NatUtility.cs
@@ -41,26 +41,25 @@ using MediaBrowser.Model.Logging;
namespace Mono.Nat
{
- public static class NatUtility
- {
- private static ManualResetEvent searching;
- public static event EventHandler DeviceFound;
- public static event EventHandler DeviceLost;
-
- private static List controllers;
- private static bool verbose;
+ public static class NatUtility
+ {
+ public static event EventHandler DeviceFound;
+ public static event EventHandler DeviceLost;
+
+ private static List controllers;
+ private static bool verbose;
public static List EnabledProtocols { get; set; }
- public static ILogger Logger { get; set; }
+ public static ILogger Logger { get; set; }
public static IHttpClient HttpClient { get; set; }
public static bool Verbose
- {
- get { return verbose; }
- set { verbose = value; }
- }
-
+ {
+ get { return verbose; }
+ set { verbose = value; }
+ }
+
static NatUtility()
{
EnabledProtocols = new List
@@ -68,8 +67,6 @@ namespace Mono.Nat
NatProtocol.Pmp
};
- searching = new ManualResetEvent(false);
-
controllers = new List();
controllers.Add(PmpSearcher.Instance);
@@ -86,23 +83,19 @@ namespace Mono.Nat
DeviceLost(sender, args);
};
});
-
- Task.Factory.StartNew(SearchAndListen, TaskCreationOptions.LongRunning);
}
- internal static void Log(string format, params object[] args)
- {
- var logger = Logger;
- if (logger != null)
- logger.Debug(format, args);
- }
-
- private static async Task SearchAndListen()
+ internal static void Log(string format, params object[] args)
{
- while (true)
- {
- searching.WaitOne();
+ var logger = Logger;
+ if (logger != null)
+ logger.Debug(format, args);
+ }
+ private static async Task SearchAndListen(CancellationToken cancellationToken)
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
try
{
var enabledProtocols = EnabledProtocols.ToList();
@@ -123,67 +116,99 @@ namespace Mono.Nat
}
catch (Exception e)
{
-
+
}
await Task.Delay(100).ConfigureAwait(false);
}
- }
+ }
- static async Task Receive (ISearcher searcher, List clients)
- {
- foreach (UdpClient client in clients)
- {
- if (client.Available > 0)
- {
- IPAddress localAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
- var result = await client.ReceiveAsync().ConfigureAwait(false);
- var data = result.Buffer;
- var received = result.RemoteEndPoint;
- searcher.Handle(localAddress, data, received);
- }
+ static async Task Receive(ISearcher searcher, List clients)
+ {
+ foreach (UdpClient client in clients)
+ {
+ if (client.Available > 0)
+ {
+ IPAddress localAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address;
+ var result = await client.ReceiveAsync().ConfigureAwait(false);
+ var data = result.Buffer;
+ var received = result.RemoteEndPoint;
+ searcher.Handle(localAddress, data, received);
+ }
}
}
-
- public static void StartDiscovery ()
- {
- searching.Set();
- }
- public static void StopDiscovery ()
- {
- searching.Reset();
- }
-
- //checks if an IP address is a private address space as defined by RFC 1918
- public static bool IsPrivateAddressSpace (IPAddress address)
- {
- byte[] ba = address.GetAddressBytes ();
+ private static CancellationTokenSource _currentCancellationTokenSource;
+ private static object _runSyncLock = new object();
+ public static void StartDiscovery()
+ {
+ lock (_runSyncLock)
+ {
+ if (_currentCancellationTokenSource == null)
+ {
+ return;
+ }
- switch ((int)ba[0]) {
- case 10:
- return true; //10.x.x.x
- case 172:
- return ((int)ba[1] & 16) != 0; //172.16-31.x.x
- case 192:
- return (int)ba[1] == 168; //192.168.x.x
- default:
- return false;
- }
- }
+ var tokenSource = new CancellationTokenSource();
- public static void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint, NatProtocol protocol)
- {
- switch (protocol)
- {
+ _currentCancellationTokenSource = tokenSource;
+ //Task.Factory.StartNew(() => SearchAndListen(tokenSource.Token), tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+ }
+
+ public static void StopDiscovery()
+ {
+ lock (_runSyncLock)
+ {
+ var tokenSource = _currentCancellationTokenSource;
+
+ if (tokenSource != null)
+ {
+ try
+ {
+ tokenSource.Cancel();
+ tokenSource.Dispose();
+ }
+ catch
+ {
+
+ }
+
+ _currentCancellationTokenSource = null;
+ }
+ }
+ }
+
+ //checks if an IP address is a private address space as defined by RFC 1918
+ public static bool IsPrivateAddressSpace(IPAddress address)
+ {
+ byte[] ba = address.GetAddressBytes();
+
+ switch ((int)ba[0])
+ {
+ case 10:
+ return true; //10.x.x.x
+ case 172:
+ return ((int)ba[1] & 16) != 0; //172.16-31.x.x
+ case 192:
+ return (int)ba[1] == 168; //192.168.x.x
+ default:
+ return false;
+ }
+ }
+
+ public static void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint, NatProtocol protocol)
+ {
+ switch (protocol)
+ {
case NatProtocol.Upnp:
- //UpnpSearcher.Instance.Handle(localAddress, response, endpoint);
- break;
+ //UpnpSearcher.Instance.Handle(localAddress, response, endpoint);
+ break;
case NatProtocol.Pmp:
- PmpSearcher.Instance.Handle(localAddress, response, endpoint);
- break;
- default:
- throw new ArgumentException("Unexpected protocol: " + protocol);
- }
+ PmpSearcher.Instance.Handle(localAddress, response, endpoint);
+ break;
+ default:
+ throw new ArgumentException("Unexpected protocol: " + protocol);
+ }
}
public static void Handle(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint endpoint, NatProtocol protocol)
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 90663b500..ff58c13ac 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common
- 3.0.703
+ 3.0.704
Emby.Common
Emby Team
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index e5cb120d3..a5707a265 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Server.Core
- 3.0.703
+ 3.0.704
Emby.Server.Core
Emby Team
ebr,Luke,scottisafool
@@ -12,7 +12,7 @@
Contains core components required to build plugins for Emby Server.
Copyright © Emby 2013
-
+
diff --git a/SocketHttpListener/Net/BoundaryType.cs b/SocketHttpListener/Net/BoundaryType.cs
new file mode 100644
index 000000000..c3ac00c0f
--- /dev/null
+++ b/SocketHttpListener/Net/BoundaryType.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ internal enum BoundaryType
+ {
+ ContentLength = 0, // Content-Length: XXX
+ Chunked = 1, // Transfer-Encoding: chunked
+ Multipart = 3,
+ None = 4,
+ Invalid = 5,
+ }
+}
diff --git a/SocketHttpListener/Net/ChunkStream.cs b/SocketHttpListener/Net/ChunkStream.cs
index 2de6c2c18..b41285dbc 100644
--- a/SocketHttpListener/Net/ChunkStream.cs
+++ b/SocketHttpListener/Net/ChunkStream.cs
@@ -79,12 +79,6 @@ namespace SocketHttpListener.Net
private int _trailerState;
private List _chunks;
- public ChunkStream(byte[] buffer, int offset, int size, WebHeaderCollection headers)
- : this(headers)
- {
- Write(buffer, offset, size);
- }
-
public ChunkStream(WebHeaderCollection headers)
{
_headers = headers;
@@ -102,13 +96,6 @@ namespace SocketHttpListener.Net
_chunks.Clear();
}
- public void WriteAndReadBack(byte[] buffer, int offset, int size, ref int read)
- {
- if (offset + read > 0)
- Write(buffer, offset, offset + read);
- read = Read(buffer, offset, size);
- }
-
public int Read(byte[] buffer, int offset, int size)
{
return ReadFromChunks(buffer, offset, size);
@@ -143,6 +130,9 @@ namespace SocketHttpListener.Net
public void Write(byte[] buffer, int offset, int size)
{
+ // Note, the logic here only works when offset is 0 here.
+ // Otherwise, it would treat "size" as the end offset instead of an actual byte count from offset.
+
if (offset < size)
InternalWrite(buffer, ref offset, size);
}
diff --git a/SocketHttpListener/Net/ChunkedInputStream.cs b/SocketHttpListener/Net/ChunkedInputStream.cs
index 2e0e1964b..919bd95ea 100644
--- a/SocketHttpListener/Net/ChunkedInputStream.cs
+++ b/SocketHttpListener/Net/ChunkedInputStream.cs
@@ -122,11 +122,19 @@ namespace SocketHttpListener.Net
try
{
int nread = base.EndRead(base_ares);
+ if (nread == 0)
+ {
+ _no_more_data = true;
+ ares._count = rb.InitialCount - rb.Count;
+ ares.Complete();
+ return;
+ }
+
_decoder.Write(ares._buffer, ares._offset, nread);
nread = _decoder.Read(rb.Buffer, rb.Offset, rb.Count);
rb.Offset += nread;
rb.Count -= nread;
- if (rb.Count == 0 || !_decoder.WantMore || nread == 0)
+ if (rb.Count == 0 || !_decoder.WantMore)
{
_no_more_data = !_decoder.WantMore && nread == 0;
ares._count = rb.InitialCount - rb.Count;
@@ -164,7 +172,7 @@ namespace SocketHttpListener.Net
asyncResult.AsyncWaitHandle.WaitOne();
if (ares._error != null)
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "Bad Request");
+ throw new HttpListenerException((int)HttpStatusCode.BadRequest, "Operation aborted");
return ares._count;
}
diff --git a/SocketHttpListener/Net/EntitySendFormat.cs b/SocketHttpListener/Net/EntitySendFormat.cs
new file mode 100644
index 000000000..6e585bdc9
--- /dev/null
+++ b/SocketHttpListener/Net/EntitySendFormat.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ internal enum EntitySendFormat
+ {
+ ContentLength = 0, // Content-Length: XXX
+ Chunked = 1, // Transfer-Encoding: chunked
+ }
+}
diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs
index 9c87ff076..e66443c59 100644
--- a/SocketHttpListener/Net/HttpConnection.cs
+++ b/SocketHttpListener/Net/HttpConnection.cs
@@ -25,7 +25,7 @@ namespace SocketHttpListener.Net
StringBuilder _currentLine;
ListenerPrefix _prefix;
HttpRequestStream _requestStream;
- Stream _responseStream;
+ HttpResponseStream _responseStream;
bool _chunked;
int _reuses;
bool _contextBound;
@@ -202,7 +202,7 @@ namespace SocketHttpListener.Net
return _requestStream;
}
- public Stream GetResponseStream(bool isExpect100Continue = false)
+ public HttpResponseStream GetResponseStream(bool isExpect100Continue = false)
{
// TODO: can we get this _stream before reading the input?
if (_responseStream == null)
@@ -268,7 +268,8 @@ namespace SocketHttpListener.Net
if (!_epl.BindContext(_context))
{
- SendError("Invalid host", 400);
+ const int NotFoundErrorCode = 404;
+ SendError(HttpStatusDescription.Get(NotFoundErrorCode), NotFoundErrorCode);
Close(true);
return;
}
@@ -423,14 +424,14 @@ namespace SocketHttpListener.Net
HttpListenerResponse response = _context.Response;
response.StatusCode = status;
response.ContentType = "text/html";
- string description = HttpListenerResponse.GetStatusDescription(status);
+ string description = HttpStatusDescription.Get(status);
string str;
if (msg != null)
str = string.Format("{0} ({1})
", description, msg);
else
str = string.Format("{0}
", description);
- byte[] error = Encoding.Default.GetBytes(str);
+ byte[] error = _textEncoding.GetDefaultEncoding().GetBytes(str);
response.Close(error, false);
}
catch
diff --git a/SocketHttpListener/Net/HttpListenerContext.cs b/SocketHttpListener/Net/HttpListenerContext.cs
index 58d769f22..1bf39589d 100644
--- a/SocketHttpListener/Net/HttpListenerContext.cs
+++ b/SocketHttpListener/Net/HttpListenerContext.cs
@@ -29,7 +29,7 @@ namespace SocketHttpListener.Net
_memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding;
request = new HttpListenerRequest(this, _textEncoding);
- response = new HttpListenerResponse(this, logger, _textEncoding, fileSystem);
+ response = new HttpListenerResponse(this, _textEncoding);
}
internal int ErrorStatus
diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs
index 6a99eb078..f9df52593 100644
--- a/SocketHttpListener/Net/HttpListenerRequest.cs
+++ b/SocketHttpListener/Net/HttpListenerRequest.cs
@@ -31,7 +31,7 @@ namespace SocketHttpListener.Net
HttpListenerContext context;
bool is_chunked;
bool ka_set;
- bool keep_alive;
+ bool? _keepAlive;
private readonly ITextEncoding _textEncoding;
@@ -525,29 +525,35 @@ namespace SocketHttpListener.Net
{
get
{
- if (ka_set)
- return keep_alive;
+ if (!_keepAlive.HasValue)
+ {
+ string header = Headers["Proxy-Connection"];
+ if (string.IsNullOrEmpty(header))
+ {
+ header = Headers["Connection"];
+ }
+ if (string.IsNullOrEmpty(header))
+ {
+ if (ProtocolVersion >= HttpVersion.Version11)
+ {
+ _keepAlive = true;
+ }
+ else
+ {
+ header = Headers["Keep-Alive"];
+ _keepAlive = !string.IsNullOrEmpty(header);
+ }
+ }
+ else
+ {
+ header = header.ToLower(CultureInfo.InvariantCulture);
+ _keepAlive =
+ header.IndexOf("close", StringComparison.OrdinalIgnoreCase) < 0 ||
+ header.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0;
+ }
+ }
- ka_set = true;
- // 1. Connection header
- // 2. Protocol (1.1 == keep-alive by default)
- // 3. Keep-Alive header
- string cnc = headers["Connection"];
- if (!String.IsNullOrEmpty(cnc))
- {
- keep_alive = (0 == String.Compare(cnc, "keep-alive", StringComparison.OrdinalIgnoreCase));
- }
- else if (version == HttpVersion.Version11)
- {
- keep_alive = true;
- }
- else
- {
- cnc = headers["keep-alive"];
- if (!String.IsNullOrEmpty(cnc))
- keep_alive = (0 != String.Compare(cnc, "closed", StringComparison.OrdinalIgnoreCase));
- }
- return keep_alive;
+ return _keepAlive.Value;
}
}
diff --git a/SocketHttpListener/Net/HttpListenerResponse.Managed.cs b/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
new file mode 100644
index 000000000..83fcc09ca
--- /dev/null
+++ b/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Text;
+using SocketHttpListener.Primitives;
+using System.Threading;
+using MediaBrowser.Model.IO;
+
+namespace SocketHttpListener.Net
+{
+ public sealed partial class HttpListenerResponse : IDisposable
+ {
+ private long _contentLength;
+ private Version _version = HttpVersion.Version11;
+ private int _statusCode = 200;
+ internal object _headersLock = new object();
+ private bool _forceCloseChunked;
+ private ITextEncoding _textEncoding;
+
+ internal HttpListenerResponse(HttpListenerContext context, ITextEncoding textEncoding)
+ {
+ _httpContext = context;
+ _textEncoding = textEncoding;
+ }
+
+ internal bool ForceCloseChunked => _forceCloseChunked;
+
+ private void EnsureResponseStream()
+ {
+ if (_responseStream == null)
+ {
+ _responseStream = _httpContext.Connection.GetResponseStream();
+ }
+ }
+
+ public Version ProtocolVersion
+ {
+ get { return _version; }
+ set
+ {
+ CheckDisposed();
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+ if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
+ {
+ throw new ArgumentException("Wrong version");
+ }
+
+ _version = new Version(value.Major, value.Minor); // match Windows behavior, trimming to just Major.Minor
+ }
+ }
+
+ public int StatusCode
+ {
+ get { return _statusCode; }
+ set
+ {
+ CheckDisposed();
+
+ if (value < 100 || value > 999)
+ throw new ProtocolViolationException("Invalid status");
+
+ _statusCode = value;
+ }
+ }
+
+ private void Dispose()
+ {
+ Close(true);
+ }
+
+ public void Close()
+ {
+ if (Disposed)
+ return;
+
+ Close(false);
+ }
+
+ public void Abort()
+ {
+ if (Disposed)
+ return;
+
+ Close(true);
+ }
+
+ private void Close(bool force)
+ {
+ Disposed = true;
+ _httpContext.Connection.Close(force);
+ }
+
+ public void Close(byte[] responseEntity, bool willBlock)
+ {
+ CheckDisposed();
+
+ if (responseEntity == null)
+ {
+ throw new ArgumentNullException(nameof(responseEntity));
+ }
+
+ if (!SentHeaders && _boundaryType != BoundaryType.Chunked)
+ {
+ ContentLength64 = responseEntity.Length;
+ }
+
+ if (willBlock)
+ {
+ try
+ {
+ OutputStream.Write(responseEntity, 0, responseEntity.Length);
+ }
+ finally
+ {
+ Close(false);
+ }
+ }
+ else
+ {
+ OutputStream.BeginWrite(responseEntity, 0, responseEntity.Length, iar =>
+ {
+ var thisRef = (HttpListenerResponse)iar.AsyncState;
+ try
+ {
+ try
+ {
+ thisRef.OutputStream.EndWrite(iar);
+ }
+ finally
+ {
+ thisRef.Close(false);
+ }
+ }
+ catch (Exception)
+ {
+ // In case response was disposed during this time
+ }
+ }, this);
+ }
+ }
+
+ public void CopyFrom(HttpListenerResponse templateResponse)
+ {
+ _webHeaders.Clear();
+ //_webHeaders.Add(templateResponse._webHeaders);
+ _contentLength = templateResponse._contentLength;
+ _statusCode = templateResponse._statusCode;
+ _statusDescription = templateResponse._statusDescription;
+ _keepAlive = templateResponse._keepAlive;
+ _version = templateResponse._version;
+ }
+
+ internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandshake = false)
+ {
+ if (!isWebSocketHandshake)
+ {
+ if (_webHeaders["Server"] == null)
+ {
+ _webHeaders.Set("Server", "Microsoft-NetCore/2.0");
+ }
+
+ if (_webHeaders["Date"] == null)
+ {
+ _webHeaders.Set("Date", DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture));
+ }
+
+ if (_boundaryType == BoundaryType.None)
+ {
+ if (HttpListenerRequest.ProtocolVersion <= HttpVersion.Version10)
+ {
+ _keepAlive = false;
+ }
+ else
+ {
+ _boundaryType = BoundaryType.Chunked;
+ }
+
+ if (CanSendResponseBody(_httpContext.Response.StatusCode))
+ {
+ _contentLength = -1;
+ }
+ else
+ {
+ _boundaryType = BoundaryType.ContentLength;
+ _contentLength = 0;
+ }
+ }
+
+ if (_boundaryType != BoundaryType.Chunked)
+ {
+ if (_boundaryType != BoundaryType.ContentLength && closing)
+ {
+ _contentLength = CanSendResponseBody(_httpContext.Response.StatusCode) ? -1 : 0;
+ }
+
+ if (_boundaryType == BoundaryType.ContentLength)
+ {
+ _webHeaders.Set("Content-Length", _contentLength.ToString("D", CultureInfo.InvariantCulture));
+ }
+ }
+
+ /* Apache forces closing the connection for these status codes:
+ * HttpStatusCode.BadRequest 400
+ * HttpStatusCode.RequestTimeout 408
+ * HttpStatusCode.LengthRequired 411
+ * HttpStatusCode.RequestEntityTooLarge 413
+ * HttpStatusCode.RequestUriTooLong 414
+ * HttpStatusCode.InternalServerError 500
+ * HttpStatusCode.ServiceUnavailable 503
+ */
+ bool conn_close = (_statusCode == (int)HttpStatusCode.BadRequest || _statusCode == (int)HttpStatusCode.RequestTimeout
+ || _statusCode == (int)HttpStatusCode.LengthRequired || _statusCode == (int)HttpStatusCode.RequestEntityTooLarge
+ || _statusCode == (int)HttpStatusCode.RequestUriTooLong || _statusCode == (int)HttpStatusCode.InternalServerError
+ || _statusCode == (int)HttpStatusCode.ServiceUnavailable);
+
+ if (!conn_close)
+ {
+ conn_close = !_httpContext.Request.KeepAlive;
+ }
+
+ // They sent both KeepAlive: true and Connection: close
+ if (!_keepAlive || conn_close)
+ {
+ _webHeaders.Set("Connection", "Close");
+ conn_close = true;
+ }
+
+ if (SendChunked)
+ {
+ _webHeaders.Set("Transfer-Encoding", "Chunked");
+ }
+
+ int reuses = _httpContext.Connection.Reuses;
+ if (reuses >= 100)
+ {
+ _forceCloseChunked = true;
+ if (!conn_close)
+ {
+ _webHeaders.Set("Connection", "Close");
+ conn_close = true;
+ }
+ }
+
+ if (HttpListenerRequest.ProtocolVersion <= HttpVersion.Version10)
+ {
+ if (_keepAlive)
+ {
+ Headers["Keep-Alive"] = "true";
+ }
+
+ if (!conn_close)
+ {
+ _webHeaders.Set("Connection", "Keep-Alive");
+ }
+ }
+
+ ComputeCookies();
+ }
+
+ Encoding encoding = _textEncoding.GetDefaultEncoding();
+ StreamWriter writer = new StreamWriter(ms, encoding, 256);
+ writer.Write("HTTP/1.1 {0} ", _statusCode); // "1.1" matches Windows implementation, which ignores the response version
+ writer.Flush();
+ byte[] statusDescriptionBytes = WebHeaderEncoding.GetBytes(StatusDescription);
+ ms.Write(statusDescriptionBytes, 0, statusDescriptionBytes.Length);
+ writer.Write("\r\n");
+
+ writer.Write(FormatHeaders(_webHeaders));
+ writer.Flush();
+ int preamble = encoding.GetPreamble().Length;
+ EnsureResponseStream();
+
+ /* Assumes that the ms was at position 0 */
+ ms.Position = preamble;
+ SentHeaders = !isWebSocketHandshake;
+ }
+
+ private static bool HeaderCanHaveEmptyValue(string name) =>
+ !string.Equals(name, "Location", StringComparison.OrdinalIgnoreCase);
+
+ private static string FormatHeaders(WebHeaderCollection headers)
+ {
+ var sb = new StringBuilder();
+
+ for (int i = 0; i < headers.Count; i++)
+ {
+ string key = headers.GetKey(i);
+ string[] values = headers.GetValues(i);
+
+ int startingLength = sb.Length;
+
+ sb.Append(key).Append(": ");
+ bool anyValues = false;
+ for (int j = 0; j < values.Length; j++)
+ {
+ string value = values[j];
+ if (!string.IsNullOrWhiteSpace(value))
+ {
+ if (anyValues)
+ {
+ sb.Append(", ");
+ }
+ sb.Append(value);
+ anyValues = true;
+ }
+ }
+
+ if (anyValues || HeaderCanHaveEmptyValue(key))
+ {
+ // Complete the header
+ sb.Append("\r\n");
+ }
+ else
+ {
+ // Empty header; remove it.
+ sb.Length = startingLength;
+ }
+ }
+
+ return sb.Append("\r\n").ToString();
+ }
+
+ private bool Disposed { get; set; }
+ internal bool SentHeaders { get; set; }
+
+ public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ {
+ return ((HttpResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
+ }
+ }
+}
diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs
index da7aff081..fc57e8485 100644
--- a/SocketHttpListener/Net/HttpListenerResponse.cs
+++ b/SocketHttpListener/Net/HttpListenerResponse.cs
@@ -1,149 +1,128 @@
-using System;
-using System.Globalization;
+using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Net;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
namespace SocketHttpListener.Net
{
- public sealed class HttpListenerResponse : IDisposable
+ public sealed unsafe partial class HttpListenerResponse : IDisposable
{
- bool disposed;
- Encoding content_encoding;
- long content_length;
- bool cl_set;
- string content_type;
- CookieCollection cookies;
- WebHeaderCollection headers = new WebHeaderCollection();
- bool keep_alive = true;
- Stream output_stream;
- Version version = HttpVersion.Version11;
- string location;
- int status_code = 200;
- string status_description = "OK";
- bool chunked;
- HttpListenerContext context;
+ private BoundaryType _boundaryType = BoundaryType.None;
+ private CookieCollection _cookies;
+ private HttpListenerContext _httpContext;
+ private bool _keepAlive = true;
+ private HttpResponseStream _responseStream;
+ private string _statusDescription;
+ private WebHeaderCollection _webHeaders = new WebHeaderCollection();
- internal bool HeadersSent;
- internal object headers_lock = new object();
-
- private readonly ILogger _logger;
- private readonly ITextEncoding _textEncoding;
- private readonly IFileSystem _fileSystem;
-
- internal HttpListenerResponse(HttpListenerContext context, ILogger logger, ITextEncoding textEncoding, IFileSystem fileSystem)
+ public WebHeaderCollection Headers
{
- this.context = context;
- _logger = logger;
- _textEncoding = textEncoding;
- _fileSystem = fileSystem;
+ get { return _webHeaders; }
}
- internal bool CloseConnection
- {
- get
- {
- return headers["Connection"] == "close";
- }
- }
+ public Encoding ContentEncoding { get; set; }
- public bool ForceCloseChunked
+ public string ContentType
{
- get { return false; }
- }
-
- public Encoding ContentEncoding
- {
- get
- {
- if (content_encoding == null)
- content_encoding = _textEncoding.GetDefaultEncoding();
- return content_encoding;
- }
+ get { return Headers["Content-Type"]; }
set
{
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- content_encoding = value;
+ CheckDisposed();
+ if (string.IsNullOrEmpty(value))
+ {
+ Headers.Remove("Content-Type");
+ }
+ else
+ {
+ Headers.Set("Content-Type", value);
+ }
}
}
+ private HttpListenerContext HttpListenerContext { get { return _httpContext; } }
+
+ private HttpListenerRequest HttpListenerRequest { get { return HttpListenerContext.Request; } }
+
+ internal EntitySendFormat EntitySendFormat
+ {
+ get { return (EntitySendFormat)_boundaryType; }
+ set
+ {
+ CheckDisposed();
+ CheckSentHeaders();
+ if (value == EntitySendFormat.Chunked && HttpListenerRequest.ProtocolVersion.Minor == 0)
+ {
+ throw new ProtocolViolationException("net_nochunkuploadonhttp10");
+ }
+ _boundaryType = (BoundaryType)value;
+ if (value != EntitySendFormat.ContentLength)
+ {
+ _contentLength = -1;
+ }
+ }
+ }
+
+ public bool SendChunked
+ {
+ get { return EntitySendFormat == EntitySendFormat.Chunked; ; }
+ set { EntitySendFormat = value ? EntitySendFormat.Chunked : EntitySendFormat.ContentLength; }
+ }
+
+ // We MUST NOT send message-body when we send responses with these Status codes
+ private static readonly int[] s_noResponseBody = { 100, 101, 204, 205, 304 };
+
+ private static bool CanSendResponseBody(int responseCode)
+ {
+ for (int i = 0; i < s_noResponseBody.Length; i++)
+ {
+ if (responseCode == s_noResponseBody[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public long ContentLength64
{
- get { return content_length; }
+ get { return _contentLength; }
set
{
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (HeadersSent)
- throw new InvalidOperationException("Cannot be changed after headers are sent.");
-
- if (value < 0)
- throw new ArgumentOutOfRangeException("Must be >= 0", "value");
-
- cl_set = true;
- content_length = value;
+ CheckDisposed();
+ CheckSentHeaders();
+ if (value >= 0)
+ {
+ _contentLength = value;
+ _boundaryType = BoundaryType.ContentLength;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("net_clsmall");
+ }
}
}
- public string ContentType
- {
- get { return content_type; }
- set
- {
- // TODO: is null ok?
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- content_type = value;
- }
- }
-
- // RFC 2109, 2965 + the netscape specification at http://wp.netscape.com/newsref/std/cookie_spec.html
public CookieCollection Cookies
{
- get
- {
- if (cookies == null)
- cookies = new CookieCollection();
- return cookies;
- }
- set { cookies = value; } // null allowed?
- }
-
- public WebHeaderCollection Headers
- {
- get { return headers; }
- set
- {
- /**
- * "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or
- * WWW-Authenticate header using the Headers property, an exception will be
- * thrown. Use the KeepAlive or ContentLength64 properties to set these headers.
- * You cannot set the Transfer-Encoding or WWW-Authenticate headers manually."
- */
- // TODO: check if this is marked readonly after headers are sent.
- headers = value;
- }
+ get { return _cookies ?? (_cookies = new CookieCollection()); }
+ set { _cookies = value; }
}
public bool KeepAlive
{
- get { return keep_alive; }
+ get { return _keepAlive; }
set
{
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- keep_alive = value;
+ CheckDisposed();
+ _keepAlive = value;
}
}
@@ -151,422 +130,176 @@ namespace SocketHttpListener.Net
{
get
{
- if (output_stream == null)
- output_stream = context.Connection.GetResponseStream();
- return output_stream;
- }
- }
-
- public Version ProtocolVersion
- {
- get { return version; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (value == null)
- throw new ArgumentNullException("value");
-
- if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
- throw new ArgumentException("Must be 1.0 or 1.1", "value");
-
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- version = value;
+ CheckDisposed();
+ EnsureResponseStream();
+ return _responseStream;
}
}
public string RedirectLocation
{
- get { return location; }
+ get { return Headers["Location"]; }
set
{
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- location = value;
+ // note that this doesn't set the status code to a redirect one
+ CheckDisposed();
+ if (string.IsNullOrEmpty(value))
+ {
+ Headers.Remove("Location");
+ }
+ else
+ {
+ Headers.Set("Location", value);
+ }
}
}
- public bool SendChunked
- {
- get { return chunked; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- chunked = value;
- }
- }
-
- public int StatusCode
- {
- get { return status_code; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (value < 100 || value > 999)
- throw new ProtocolViolationException("StatusCode must be between 100 and 999.");
- status_code = value;
- status_description = GetStatusDescription(value);
- }
- }
-
- internal static string GetStatusDescription(int code)
- {
- switch (code)
- {
- case 100: return "Continue";
- case 101: return "Switching Protocols";
- case 102: return "Processing";
- case 200: return "OK";
- case 201: return "Created";
- case 202: return "Accepted";
- case 203: return "Non-Authoritative Information";
- case 204: return "No Content";
- case 205: return "Reset Content";
- case 206: return "Partial Content";
- case 207: return "Multi-Status";
- case 300: return "Multiple Choices";
- case 301: return "Moved Permanently";
- case 302: return "Found";
- case 303: return "See Other";
- case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 307: return "Temporary Redirect";
- case 400: return "Bad Request";
- case 401: return "Unauthorized";
- case 402: return "Payment Required";
- case 403: return "Forbidden";
- case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Request Entity Too Large";
- case 414: return "Request-Uri Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested Range Not Satisfiable";
- case 417: return "Expectation Failed";
- case 422: return "Unprocessable Entity";
- case 423: return "Locked";
- case 424: return "Failed Dependency";
- case 500: return "Internal Server Error";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "Http Version Not Supported";
- case 507: return "Insufficient Storage";
- }
- return "";
- }
-
public string StatusDescription
{
- get { return status_description; }
+ get
+ {
+ if (_statusDescription == null)
+ {
+ // if the user hasn't set this, generated on the fly, if possible.
+ // We know this one is safe, no need to verify it as in the setter.
+ _statusDescription = HttpStatusDescription.Get(StatusCode);
+ }
+ if (_statusDescription == null)
+ {
+ _statusDescription = string.Empty;
+ }
+ return _statusDescription;
+ }
set
{
- status_description = value;
+ CheckDisposed();
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ // Need to verify the status description doesn't contain any control characters except HT. We mask off the high
+ // byte since that's how it's encoded.
+ for (int i = 0; i < value.Length; i++)
+ {
+ char c = (char)(0x000000ff & (uint)value[i]);
+ if ((c <= 31 && c != (byte)'\t') || c == 127)
+ {
+ throw new ArgumentException("net_WebHeaderInvalidControlChars");
+ }
+ }
+
+ _statusDescription = value;
}
}
- void IDisposable.Dispose()
- {
- Close(true); //TODO: Abort or Close?
- }
-
- public void Abort()
- {
- if (disposed)
- return;
-
- Close(true);
- }
-
public void AddHeader(string name, string value)
{
- if (name == null)
- throw new ArgumentNullException("name");
+ Headers.Set(name, value);
+ }
- if (name == "")
- throw new ArgumentException("'name' cannot be empty", "name");
-
- //TODO: check for forbidden headers and invalid characters
- if (value.Length > 65535)
- throw new ArgumentOutOfRangeException("value");
-
- headers.Set(name, value);
+ public void AppendHeader(string name, string value)
+ {
+ Headers.Add(name, value);
}
public void AppendCookie(Cookie cookie)
{
if (cookie == null)
- throw new ArgumentNullException("cookie");
-
+ {
+ throw new ArgumentNullException(nameof(cookie));
+ }
Cookies.Add(cookie);
}
- public void AppendHeader(string name, string value)
+ private void ComputeCookies()
{
- if (name == null)
- throw new ArgumentNullException("name");
-
- if (name == "")
- throw new ArgumentException("'name' cannot be empty", "name");
-
- if (value.Length > 65535)
- throw new ArgumentOutOfRangeException("value");
-
- headers.Add(name, value);
- }
-
- private void Close(bool force)
- {
- if (force)
+ if (_cookies != null)
{
- _logger.Debug("HttpListenerResponse force closing HttpConnection");
+ // now go through the collection, and concatenate all the cookies in per-variant strings
+ //string setCookie2 = null, setCookie = null;
+ //for (int index = 0; index < _cookies.Count; index++)
+ //{
+ // Cookie cookie = _cookies[index];
+ // string cookieString = cookie.ToServerString();
+ // if (cookieString == null || cookieString.Length == 0)
+ // {
+ // continue;
+ // }
+
+ // if (cookie.IsRfc2965Variant())
+ // {
+ // setCookie2 = setCookie2 == null ? cookieString : setCookie2 + ", " + cookieString;
+ // }
+ // else
+ // {
+ // setCookie = setCookie == null ? cookieString : setCookie + ", " + cookieString;
+ // }
+ //}
+
+ //if (!string.IsNullOrEmpty(setCookie))
+ //{
+ // Headers.Set(HttpKnownHeaderNames.SetCookie, setCookie);
+ // if (string.IsNullOrEmpty(setCookie2))
+ // {
+ // Headers.Remove(HttpKnownHeaderNames.SetCookie2);
+ // }
+ //}
+
+ //if (!string.IsNullOrEmpty(setCookie2))
+ //{
+ // Headers.Set(HttpKnownHeaderNames.SetCookie2, setCookie2);
+ // if (string.IsNullOrEmpty(setCookie))
+ // {
+ // Headers.Remove(HttpKnownHeaderNames.SetCookie);
+ // }
+ //}
}
- disposed = true;
- context.Connection.Close(force);
- }
-
- public void Close(byte[] responseEntity, bool willBlock)
- {
- //CheckDisposed();
-
- if (responseEntity == null)
- {
- throw new ArgumentNullException(nameof(responseEntity));
- }
-
- //if (_boundaryType != BoundaryType.Chunked)
- {
- ContentLength64 = responseEntity.Length;
- }
-
- if (willBlock)
- {
- try
- {
- OutputStream.Write(responseEntity, 0, responseEntity.Length);
- }
- finally
- {
- Close(false);
- }
- }
- else
- {
- OutputStream.BeginWrite(responseEntity, 0, responseEntity.Length, iar =>
- {
- var thisRef = (HttpListenerResponse)iar.AsyncState;
- try
- {
- thisRef.OutputStream.EndWrite(iar);
- }
- finally
- {
- thisRef.Close(false);
- }
- }, this);
- }
- }
-
- public void Close()
- {
- if (disposed)
- return;
-
- Close(false);
}
public void Redirect(string url)
{
- StatusCode = 302; // Found
- location = url;
- }
-
- bool FindCookie(Cookie cookie)
- {
- string name = cookie.Name;
- string domain = cookie.Domain;
- string path = cookie.Path;
- foreach (Cookie c in cookies)
- {
- if (name != c.Name)
- continue;
- if (domain != c.Domain)
- continue;
- if (path == c.Path)
- return true;
- }
-
- return false;
- }
-
- public void DetermineIfChunked()
- {
- if (chunked)
- {
- return;
- }
-
- Version v = context.Request.ProtocolVersion;
- if (!cl_set && !chunked && v >= HttpVersion.Version11)
- chunked = true;
- if (!chunked && string.Equals(headers["Transfer-Encoding"], "chunked"))
- {
- chunked = true;
- }
- }
-
- internal void SendHeaders(bool closing, MemoryStream ms)
- {
- Encoding encoding = content_encoding;
- if (encoding == null)
- encoding = _textEncoding.GetDefaultEncoding();
-
- if (content_type != null)
- {
- if (content_encoding != null && content_type.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) == -1)
- {
- string enc_name = content_encoding.WebName;
- headers.SetInternal("Content-Type", content_type + "; charset=" + enc_name);
- }
- else
- {
- headers.SetInternal("Content-Type", content_type);
- }
- }
-
- if (headers["Server"] == null)
- headers.SetInternal("Server", "Mono-HTTPAPI/1.0");
-
- CultureInfo inv = CultureInfo.InvariantCulture;
- if (headers["Date"] == null)
- headers.SetInternal("Date", DateTime.UtcNow.ToString("r", inv));
-
- if (!chunked)
- {
- if (!cl_set && closing)
- {
- cl_set = true;
- content_length = 0;
- }
-
- if (cl_set)
- headers.SetInternal("Content-Length", content_length.ToString(inv));
- }
-
- Version v = context.Request.ProtocolVersion;
- if (!cl_set && !chunked && v >= HttpVersion.Version11)
- chunked = true;
-
- /* Apache forces closing the connection for these status codes:
- * HttpStatusCode.BadRequest 400
- * HttpStatusCode.RequestTimeout 408
- * HttpStatusCode.LengthRequired 411
- * HttpStatusCode.RequestEntityTooLarge 413
- * HttpStatusCode.RequestUriTooLong 414
- * HttpStatusCode.InternalServerError 500
- * HttpStatusCode.ServiceUnavailable 503
- */
- bool conn_close = status_code == 400 || status_code == 408 || status_code == 411 ||
- status_code == 413 || status_code == 414 ||
- status_code == 500 ||
- status_code == 503;
-
- if (conn_close == false)
- conn_close = !context.Request.KeepAlive;
-
- // They sent both KeepAlive: true and Connection: close!?
- if (!keep_alive || conn_close)
- {
- headers.SetInternal("Connection", "close");
- conn_close = true;
- }
-
- if (chunked)
- headers.SetInternal("Transfer-Encoding", "chunked");
-
- //int reuses = context.Connection.Reuses;
- //if (reuses >= 100)
- //{
- // _logger.Debug("HttpListenerResponse - keep alive has exceeded 100 uses and will be closed.");
-
- // force_close_chunked = true;
- // if (!conn_close)
- // {
- // headers.SetInternal("Connection", "close");
- // conn_close = true;
- // }
- //}
-
- if (!conn_close)
- {
- if (context.Request.ProtocolVersion <= HttpVersion.Version10)
- headers.SetInternal("Connection", "keep-alive");
- }
-
- if (location != null)
- headers.SetInternal("Location", location);
-
- if (cookies != null)
- {
- foreach (Cookie cookie in cookies)
- headers.SetInternal("Set-Cookie", cookie.ToString());
- }
-
- headers.SetInternal("Status", status_code.ToString(CultureInfo.InvariantCulture));
-
- using (StreamWriter writer = new StreamWriter(ms, encoding, 256, true))
- {
- writer.Write("HTTP/{0} {1} {2}\r\n", version, status_code, status_description);
- string headers_str = headers.ToStringMultiValue();
- writer.Write(headers_str);
- writer.Flush();
- }
-
- int preamble = encoding.GetPreamble().Length;
- if (output_stream == null)
- output_stream = context.Connection.GetResponseStream();
-
- /* Assumes that the ms was at position 0 */
- ms.Position = preamble;
- HeadersSent = true;
+ Headers["Location"] = url;
+ StatusCode = (int)HttpStatusCode.Redirect;
+ StatusDescription = "Found";
}
public void SetCookie(Cookie cookie)
{
if (cookie == null)
- throw new ArgumentNullException("cookie");
-
- if (cookies != null)
{
- if (FindCookie(cookie))
- throw new ArgumentException("The cookie already exists.");
- }
- else
- {
- cookies = new CookieCollection();
+ throw new ArgumentNullException(nameof(cookie));
}
- cookies.Add(cookie);
+ //Cookie newCookie = cookie.Clone();
+ //int added = Cookies.InternalAdd(newCookie, true);
+
+ //if (added != 1)
+ //{
+ // // The Cookie already existed and couldn't be replaced.
+ // throw new ArgumentException("Cookie exists");
+ //}
}
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ void IDisposable.Dispose()
{
- return ((HttpResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
+ Dispose();
+ }
+
+ private void CheckDisposed()
+ {
+ if (Disposed)
+ {
+ throw new ObjectDisposedException(GetType().FullName);
+ }
+ }
+
+ private void CheckSentHeaders()
+ {
+ if (SentHeaders)
+ {
+ throw new InvalidOperationException();
+ }
}
}
-}
\ No newline at end of file
+}
diff --git a/SocketHttpListener/Net/HttpRequestStream.Managed.cs b/SocketHttpListener/Net/HttpRequestStream.Managed.cs
index cb02a4d5a..92f4bbb02 100644
--- a/SocketHttpListener/Net/HttpRequestStream.Managed.cs
+++ b/SocketHttpListener/Net/HttpRequestStream.Managed.cs
@@ -104,9 +104,24 @@ namespace SocketHttpListener.Net
return nread;
}
+ if (_remainingBody > 0)
+ {
+ size = (int)Math.Min(_remainingBody, (long)size);
+ }
+
nread = _stream.Read(buffer, offset, size);
- if (nread > 0 && _remainingBody > 0)
+
+ if (_remainingBody > 0)
+ {
+ if (nread == 0)
+ {
+ throw new Exception("Bad request");
+ }
+
+ //Debug.Assert(nread <= _remainingBody);
_remainingBody -= nread;
+ }
+
return nread;
}
@@ -139,7 +154,7 @@ namespace SocketHttpListener.Net
// for HTTP pipelining
if (_remainingBody >= 0 && size > _remainingBody)
{
- size = (int)Math.Min(int.MaxValue, _remainingBody);
+ size = (int)Math.Min(_remainingBody, (long)size);
}
return _stream.BeginRead(buffer, offset, size, cback, state);
@@ -151,7 +166,6 @@ namespace SocketHttpListener.Net
throw new ArgumentNullException(nameof(asyncResult));
var r = asyncResult as HttpStreamAsyncResult;
-
if (r != null)
{
if (!ReferenceEquals(this, r._parent))
@@ -160,7 +174,7 @@ namespace SocketHttpListener.Net
}
if (r._endCalled)
{
- throw new InvalidOperationException("Invalid end call");
+ throw new InvalidOperationException("invalid end call");
}
r._endCalled = true;
@@ -185,8 +199,13 @@ namespace SocketHttpListener.Net
throw e.InnerException;
}
- if (_remainingBody > 0 && nread > 0)
+ if (_remainingBody > 0)
{
+ if (nread == 0)
+ {
+ throw new Exception("Bad request");
+ }
+
_remainingBody -= nread;
}
diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs
index 42db03e47..116c3280a 100644
--- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs
+++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs
@@ -132,27 +132,28 @@ namespace SocketHttpListener.Net
private MemoryStream GetHeaders(bool closing, bool isWebSocketHandshake = false)
{
- // SendHeaders works on shared headers
- lock (_response.headers_lock)
- {
- if (_response.HeadersSent)
- return null;
- var ms = _memoryStreamFactory.CreateNew();
- _response.SendHeaders(closing, ms);
- return ms;
- }
-
- //lock (_response._headersLock)
+ //// SendHeaders works on shared headers
+ //lock (_response.headers_lock)
//{
- // if (_response.SentHeaders)
- // {
+ // if (_response.HeadersSent)
// return null;
- // }
-
- // MemoryStream ms = new MemoryStream();
- // _response.SendHeaders(closing, ms, isWebSocketHandshake);
+ // var ms = _memoryStreamFactory.CreateNew();
+ // _response.SendHeaders(closing, ms);
// return ms;
//}
+
+ // SendHeaders works on shared headers
+ lock (_response._headersLock)
+ {
+ if (_response.SentHeaders)
+ {
+ return null;
+ }
+
+ MemoryStream ms = new MemoryStream();
+ _response.SendHeaders(closing, ms, isWebSocketHandshake);
+ return ms;
+ }
}
private static byte[] s_crlf = new byte[] { 13, 10 };
diff --git a/SocketHttpListener/Net/HttpStatusDescription.cs b/SocketHttpListener/Net/HttpStatusDescription.cs
new file mode 100644
index 000000000..8d490c511
--- /dev/null
+++ b/SocketHttpListener/Net/HttpStatusDescription.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ internal static class HttpStatusDescription
+ {
+ internal static string Get(HttpStatusCode code)
+ {
+ return Get((int)code);
+ }
+
+ internal static string Get(int code)
+ {
+ switch (code)
+ {
+ case 100: return "Continue";
+ case 101: return "Switching Protocols";
+ case 102: return "Processing";
+
+ case 200: return "OK";
+ case 201: return "Created";
+ case 202: return "Accepted";
+ case 203: return "Non-Authoritative Information";
+ case 204: return "No Content";
+ case 205: return "Reset Content";
+ case 206: return "Partial Content";
+ case 207: return "Multi-Status";
+
+ case 300: return "Multiple Choices";
+ case 301: return "Moved Permanently";
+ case 302: return "Found";
+ case 303: return "See Other";
+ case 304: return "Not Modified";
+ case 305: return "Use Proxy";
+ case 307: return "Temporary Redirect";
+
+ case 400: return "Bad Request";
+ case 401: return "Unauthorized";
+ case 402: return "Payment Required";
+ case 403: return "Forbidden";
+ case 404: return "Not Found";
+ case 405: return "Method Not Allowed";
+ case 406: return "Not Acceptable";
+ case 407: return "Proxy Authentication Required";
+ case 408: return "Request Timeout";
+ case 409: return "Conflict";
+ case 410: return "Gone";
+ case 411: return "Length Required";
+ case 412: return "Precondition Failed";
+ case 413: return "Request Entity Too Large";
+ case 414: return "Request-Uri Too Long";
+ case 415: return "Unsupported Media Type";
+ case 416: return "Requested Range Not Satisfiable";
+ case 417: return "Expectation Failed";
+ case 422: return "Unprocessable Entity";
+ case 423: return "Locked";
+ case 424: return "Failed Dependency";
+ case 426: return "Upgrade Required"; // RFC 2817
+
+ case 500: return "Internal Server Error";
+ case 501: return "Not Implemented";
+ case 502: return "Bad Gateway";
+ case 503: return "Service Unavailable";
+ case 504: return "Gateway Timeout";
+ case 505: return "Http Version Not Supported";
+ case 507: return "Insufficient Storage";
+ }
+ return null;
+ }
+ }
+}
diff --git a/SocketHttpListener/Net/HttpStreamAsyncResult.cs b/SocketHttpListener/Net/HttpStreamAsyncResult.cs
index e7e516c6b..d96988fce 100644
--- a/SocketHttpListener/Net/HttpStreamAsyncResult.cs
+++ b/SocketHttpListener/Net/HttpStreamAsyncResult.cs
@@ -66,10 +66,7 @@ namespace SocketHttpListener.Net
}
}
- public bool CompletedSynchronously
- {
- get { return (_synchRead == _count); }
- }
+ public bool CompletedSynchronously => false;
public bool IsCompleted
{
diff --git a/SocketHttpListener/Net/UriScheme.cs b/SocketHttpListener/Net/UriScheme.cs
new file mode 100644
index 000000000..eb13619c9
--- /dev/null
+++ b/SocketHttpListener/Net/UriScheme.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ internal class UriScheme
+ {
+ public const string File = "file";
+ public const string Ftp = "ftp";
+ public const string Gopher = "gopher";
+ public const string Http = "http";
+ public const string Https = "https";
+ public const string News = "news";
+ public const string NetPipe = "net.pipe";
+ public const string NetTcp = "net.tcp";
+ public const string Nntp = "nntp";
+ public const string Mailto = "mailto";
+ public const string Ws = "ws";
+ public const string Wss = "wss";
+
+ public const string SchemeDelimiter = "://";
+ }
+}
diff --git a/SocketHttpListener/Net/WebHeaderEncoding.cs b/SocketHttpListener/Net/WebHeaderEncoding.cs
new file mode 100644
index 000000000..64330c1b4
--- /dev/null
+++ b/SocketHttpListener/Net/WebHeaderEncoding.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ // we use this static class as a helper class to encode/decode HTTP headers.
+ // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF
+ // and a byte in the range 0x00-0xFF (which is the range that can hit the network).
+ // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow.
+ // It doesn't work for string -> byte[] because of best-fit-mapping problems.
+ internal static class WebHeaderEncoding
+ {
+ // We don't want '?' replacement characters, just fail.
+ private static readonly Encoding s_utf8Decoder = Encoding.GetEncoding("utf-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
+
+ internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount)
+ {
+ fixed (byte* pBytes = bytes)
+ return GetString(pBytes + byteIndex, byteCount);
+ }
+
+ internal static unsafe string GetString(byte* pBytes, int byteCount)
+ {
+ if (byteCount < 1)
+ return "";
+
+ string s = new string('\0', byteCount);
+
+ fixed (char* pStr = s)
+ {
+ char* pString = pStr;
+ while (byteCount >= 8)
+ {
+ pString[0] = (char)pBytes[0];
+ pString[1] = (char)pBytes[1];
+ pString[2] = (char)pBytes[2];
+ pString[3] = (char)pBytes[3];
+ pString[4] = (char)pBytes[4];
+ pString[5] = (char)pBytes[5];
+ pString[6] = (char)pBytes[6];
+ pString[7] = (char)pBytes[7];
+ pString += 8;
+ pBytes += 8;
+ byteCount -= 8;
+ }
+ for (int i = 0; i < byteCount; i++)
+ {
+ pString[i] = (char)pBytes[i];
+ }
+ }
+
+ return s;
+ }
+
+ internal static int GetByteCount(string myString)
+ {
+ return myString.Length;
+ }
+ internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex)
+ {
+ if (myString.Length == 0)
+ {
+ return;
+ }
+ fixed (byte* bufferPointer = bytes)
+ {
+ byte* newBufferPointer = bufferPointer + byteIndex;
+ int finalIndex = charIndex + charCount;
+ while (charIndex < finalIndex)
+ {
+ *newBufferPointer++ = (byte)myString[charIndex++];
+ }
+ }
+ }
+ internal static unsafe byte[] GetBytes(string myString)
+ {
+ byte[] bytes = new byte[myString.Length];
+ if (myString.Length != 0)
+ {
+ GetBytes(myString, 0, myString.Length, bytes, 0);
+ }
+ return bytes;
+ }
+
+ // The normal client header parser just casts bytes to chars (see GetString).
+ // Check if those bytes were actually utf-8 instead of ASCII.
+ // If not, just return the input value.
+ internal static string DecodeUtf8FromString(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ return input;
+ }
+
+ bool possibleUtf8 = false;
+ for (int i = 0; i < input.Length; i++)
+ {
+ if (input[i] > (char)255)
+ {
+ return input; // This couldn't have come from the wire, someone assigned it directly.
+ }
+ else if (input[i] > (char)127)
+ {
+ possibleUtf8 = true;
+ break;
+ }
+ }
+ if (possibleUtf8)
+ {
+ byte[] rawBytes = new byte[input.Length];
+ for (int i = 0; i < input.Length; i++)
+ {
+ if (input[i] > (char)255)
+ {
+ return input; // This couldn't have come from the wire, someone assigned it directly.
+ }
+ rawBytes[i] = (byte)input[i];
+ }
+ try
+ {
+ return s_utf8Decoder.GetString(rawBytes);
+ }
+ catch (ArgumentException) { } // Not actually Utf-8
+ }
+ return input;
+ }
+ }
+}
diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj
index fde6ed544..1aa788931 100644
--- a/SocketHttpListener/SocketHttpListener.csproj
+++ b/SocketHttpListener/SocketHttpListener.csproj
@@ -21,6 +21,7 @@
DEBUG;TRACE
prompt
4
+ true
pdbonly
@@ -29,6 +30,7 @@
TRACE
prompt
4
+ true
@@ -56,27 +58,33 @@
+
+
+
+
+
+