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 @@ + + + + + +