diff --git a/Pilz.Collections/Pilz.Collections.vbproj b/Pilz.Collections/Pilz.Collections.vbproj
index b0fc5b8..654c6b2 100644
--- a/Pilz.Collections/Pilz.Collections.vbproj
+++ b/Pilz.Collections/Pilz.Collections.vbproj
@@ -98,7 +98,7 @@
-
+
diff --git a/Pilz.Collections/SimpleHistory/ObjectValueType.vb b/Pilz.Collections/SimpleHistory/ObjectValueType.vb
new file mode 100644
index 0000000..8438552
--- /dev/null
+++ b/Pilz.Collections/SimpleHistory/ObjectValueType.vb
@@ -0,0 +1,12 @@
+Namespace SimpleHistory
+
+ '''
+ ''' Specify which member types you would include.
+ '''
+ Public Enum ObjectValueType
+ None = 0
+ Field = 1
+ [Property] = 2
+ End Enum
+
+End Namespace
\ No newline at end of file
diff --git a/Pilz.Collections/SimpleHistory/SimpleHistory.vb b/Pilz.Collections/SimpleHistory/SimpleHistory.vb
index 74c7339..a4d7d88 100644
--- a/Pilz.Collections/SimpleHistory/SimpleHistory.vb
+++ b/Pilz.Collections/SimpleHistory/SimpleHistory.vb
@@ -32,15 +32,12 @@ Namespace SimpleHistory
Dim ret As HistoryPoint
If stackPast.Count > 0 Then
-
Dim hp As HistoryPoint = stackPast.Pop
hp.Undo()
stackFuture.Push(hp)
ret = hp
-
Else
ret = Nothing
-
End If
Return ret
@@ -53,15 +50,12 @@ Namespace SimpleHistory
Dim ret As HistoryPoint
If stackFuture.Count > 0 Then
-
Dim hp As HistoryPoint = stackFuture.Pop
hp.Redo()
stackPast.Push(hp)
ret = hp
-
Else
ret = Nothing
-
End If
Return ret
diff --git a/Pilz.Configuration/Pilz.Configuration.vbproj b/Pilz.Configuration/Pilz.Configuration.vbproj
index 6d1c540..5f5d09f 100644
--- a/Pilz.Configuration/Pilz.Configuration.vbproj
+++ b/Pilz.Configuration/Pilz.Configuration.vbproj
@@ -45,7 +45,7 @@
- ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
diff --git a/Pilz.Configuration/packages.config b/Pilz.Configuration/packages.config
index 7f83af3..93b0be8 100644
--- a/Pilz.Configuration/packages.config
+++ b/Pilz.Configuration/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj
index 1829246..ad9d693 100644
--- a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj
@@ -43,11 +43,11 @@
On
-
- ..\packages\OpenTK.3.0.1\lib\net20\OpenTK.dll
+
+ ..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll
-
- ..\packages\OpenTK.GLControl.3.0.1\lib\net20\OpenTK.GLControl.dll
+
+ ..\packages\OpenTK.GLControl.3.1.0\lib\net20\OpenTK.GLControl.dll
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb
index 2990e15..3744f88 100644
--- a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb
@@ -23,7 +23,6 @@ Namespace PreviewN
Private camMtx As Matrix4 = Matrix4.Identity
Private savedCamPos As New Vector3
Private _isMouseDown As Boolean = False
- 'Private myPressedKeys As New List(Of Keys)
Private isDeactivated As Boolean = False
Private ReadOnly myModels As New Dictionary(Of Object3D, Renderer)
@@ -32,12 +31,6 @@ Namespace PreviewN
Public Property Scaling As Single = 500.0F
Public Property ClearColor As Color = Color.CornflowerBlue
- 'Public ReadOnly Property PressedKeys As IReadOnlyList(Of Keys)
- ' Get
- ' Return myPressedKeys
- ' End Get
- 'End Property
-
Public ReadOnly Property Camera As Camera
Get
Return MyCamera
@@ -56,9 +49,14 @@ Namespace PreviewN
End Get
End Property
+ Public ReadOnly Property GLControl As Control
+ Get
+ Return glControl1
+ End Get
+ End Property
+
Private ReadOnly Property IsStrgPressed As Boolean
Get
- 'Return myPressedKeys.Contains(Keys.ControlKey)
Dim state As KeyboardState = Keyboard.GetState()
Return state(Key.ControlLeft) OrElse state(Key.ControlRight)
End Get
@@ -66,7 +64,6 @@ Namespace PreviewN
Private ReadOnly Property IsShiftPressed As Boolean
Get
- 'Return myPressedKeys.Contains(Keys.ShiftKey)
Dim state As KeyboardState = Keyboard.GetState()
Return state(Key.ShiftLeft) OrElse state(Key.ShiftRight)
End Get
@@ -142,7 +139,6 @@ Namespace PreviewN
Public Sub UpdateView()
glControl1.Invalidate()
- 'glControl1.Update()
End Sub
Public Function AddModel(obj As Object3D) As Renderer
@@ -226,38 +222,8 @@ Namespace PreviewN
Next
glControl1.SwapBuffers()
-
- 'If Not IsMouseDown AndAlso obj3d IsNot Nothing Then
- ' e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
- ' e.Graphics.DrawString(GetModelInfoAsString, New Font(FontFamily.GenericSerif, 10), New SolidBrush(Panel1.ForeColor), New Drawing.Point(10, 10))
- 'End If
End Sub
- Private Function GetModelInfoAsString() As String
- Dim matsCount As Long = 0
- Dim facesCount As Long = 0
- Dim vertsCount As Long = 0
- Dim vcCount As Long = 0
- Dim uvCount As Long = 0
-
- For Each obj3d As Object3D In myModels.Keys
- matsCount += obj3d.Materials.Count
- For Each m As Mesh In obj3d.Meshes
- vertsCount += m.Vertices.Count
- facesCount += m.Faces.Count
- vcCount += m.VertexColors.Count
- uvCount += m.UVs.Count
- Next
- Next
-
- Return String.Format("Materials:{0}{1}
-Faces:{0}{0}{2}
-Vertices:{0}{3}
-Vertex Colors{0}{4}
-UVs:{0}{0}{5}",
- vbTab, matsCount, facesCount, vertsCount, vcCount, uvCount)
- End Function
-
Private Sub glControl1_Resize(sender As Object, e As EventArgs) Handles glControl1.Resize
glControl1.Context.Update(glControl1.WindowInfo)
GL.Viewport(0, 0, glControl1.Width, glControl1.Height)
@@ -293,44 +259,10 @@ UVs:{0}{0}{5}",
End If
End Sub
- 'Public Sub HandlesOnKeyDown(sender As Object, e As KeyEventArgs) Handles glControl1.KeyDown
- ' If Not myPressedKeys.Contains(e.KeyCode) Then myPressedKeys.Add(e.KeyCode)
- 'End Sub
-
- 'Public Sub HandlesOnKeyUp(sender As Object, e As KeyEventArgs) Handles MyBase.KeyUp
- ' If myPressedKeys.Contains(e.KeyCode) Then myPressedKeys.Remove(e.KeyCode)
- 'End Sub
-
Public Sub MoveCameraViaWASDQE()
Dim moveSpeed As Integer = Convert.ToInt32(Math.Round((If(IsShiftPressed, 60, 30)) * (MyCamera.CamSpeedMultiplier), 0))
Dim allowCamMove As Boolean = Not (IsMouseDown AndAlso IsShiftPressed)
- 'For Each k As Keys In myPressedKeys
- ' If allowCamMove Then
- ' Select Case k
- ' Case Keys.W
- ' 'camera.Move(moveSpeed, moveSpeed, camMtx)
- ' MyCamera.UpdateCameraMatrixWithScrollWheel(moveSpeed, camMtx)
- ' savedCamPos = MyCamera.Position
- ' Case Keys.S
- ' 'camera.Move(-moveSpeed, -moveSpeed, camMtx)
- ' MyCamera.UpdateCameraMatrixWithScrollWheel(-moveSpeed, camMtx)
- ' savedCamPos = MyCamera.Position
- ' Case Keys.A
- ' 'camera.Move(-moveSpeed, 0, camMtx)
- ' MyCamera.UpdateCameraOffsetDirectly(-moveSpeed, 0, camMtx)
- ' Case Keys.D
- ' 'camera.Move(moveSpeed, 0, camMtx)
- ' MyCamera.UpdateCameraOffsetDirectly(moveSpeed, 0, camMtx)
- ' Case Keys.E
- ' 'camera.Move(0, -moveSpeed, camMtx)
- ' MyCamera.UpdateCameraOffsetDirectly(0, -moveSpeed, camMtx)
- ' Case Keys.Q
- ' 'camera.Move(0, moveSpeed, camMtx)
- ' MyCamera.UpdateCameraOffsetDirectly(0, moveSpeed, camMtx)
- ' End Select
- ' End If
- 'Next
If allowCamMove Then
Dim state As KeyboardState = Keyboard.GetState
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config b/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config
index d8280d7..0a27f2e 100644
--- a/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config
@@ -1,6 +1,6 @@
-
-
+
+
\ No newline at end of file
diff --git a/Pilz.Drawing/HelpfulDrawingFunctions.vb b/Pilz.Drawing/HelpfulDrawingFunctions.vb
index b7d74d3..5fb2c28 100644
--- a/Pilz.Drawing/HelpfulDrawingFunctions.vb
+++ b/Pilz.Drawing/HelpfulDrawingFunctions.vb
@@ -1,9 +1,9 @@
Imports System.Drawing
Imports System.Drawing.Drawing2D
-Public Class HelpfulDrawingFunctions
+Public Module HelpfulDrawingFunctions
- Public Shared Function IsPointInRectangle(p As PointF, rect As RectangleF) As Boolean
+ Public Function IsPointInRectangle(p As PointF, rect As RectangleF) As Boolean
Dim bList As New List(Of Boolean)
bList.Add(p.X > rect.Left)
@@ -14,11 +14,20 @@ Public Class HelpfulDrawingFunctions
Return Not bList.Contains(False)
End Function
- Public Shared Function OverlapsTwoRectangles(a As RectangleF, b As RectangleF) As Boolean
+ Public Function OverlapsTwoRectangles(a As RectangleF, b As RectangleF) As Boolean
Return a.IntersectsWith(b) 'RectangleF.Intersect(a, b) <> RectangleF.Empty
End Function
- Public Shared Function GetRectangle(p1 As PointF, p2 As PointF) As RectangleF
+ Public Function RectangleContainsRectangle(parent As RectangleF, child As RectangleF) As Boolean
+ Return parent.Contains(child)
+ 'Return _
+ ' IsPointInRectangle(New PointF(child.Top, child.Left), parent) AndAlso
+ ' IsPointInRectangle(New PointF(child.Top, child.Right), parent) AndAlso
+ ' IsPointInRectangle(New PointF(child.Bottom, child.Left), parent) AndAlso
+ ' IsPointInRectangle(New PointF(child.Bottom, child.Right), parent)
+ End Function
+
+ Public Function GetRectangle(p1 As PointF, p2 As PointF) As RectangleF
Dim rect As New RectangleF
Dim startIsEnd As Boolean = p1.X > p2.X AndAlso p1.Y > p2.Y
@@ -37,5 +46,5 @@ Public Class HelpfulDrawingFunctions
Return rect
End Function
-End Class
+End Module
diff --git a/Pilz.Networking/ConnectionManagerBase.vb b/Pilz.Networking/ConnectionManagerBase.vb
new file mode 100644
index 0000000..7c0fa48
--- /dev/null
+++ b/Pilz.Networking/ConnectionManagerBase.vb
@@ -0,0 +1,84 @@
+Imports System.IO
+Imports Newtonsoft.Json.Linq
+
+Public MustInherit Class ConnectionManagerBase
+
+ Private listening As Boolean = False
+
+ Public ReadOnly Property Port As Integer
+
+ Public Event RetriveData(manager As ConnectionManagerBase, senderIP As String, cmd As String, content As Object)
+
+ Public Property IsListening As Boolean
+ Get
+ Return listening
+ End Get
+ Protected Set(value As Boolean)
+ listening = value
+ End Set
+ End Property
+
+ Public Sub New(port As Integer)
+ Me.Port = port
+ End Sub
+
+ Protected Overrides Sub Finalize()
+ [Stop]()
+ End Sub
+
+ Public MustOverride Sub Start()
+ Public MustOverride Sub [Stop]()
+ Public MustOverride Sub Send(empfängerIP As String, cmd As String, content As Object)
+
+ Public Overridable Sub Send(empfängerIP As String, cmd As String)
+ Send(empfängerIP, cmd, String.Empty)
+ End Sub
+
+ Public Overridable Sub Send(empfängerIP As String, cmd As String, info As String)
+ Send(empfängerIP, cmd, CObj(info))
+ End Sub
+
+ Public Sub RaiseRetriveData(senderIP As String, cmd As String, content As Object)
+ RaiseEvent RetriveData(Me, senderIP, cmd, content)
+ End Sub
+
+ Protected Shared Function EncodeToBytes(cmd As String, content As Object) As Byte()
+ Dim ms As New MemoryStream()
+ Dim bw As New BinaryWriter(ms)
+ Dim obj As New JObject
+
+ 'Write header
+ obj("Cmd") = cmd
+ obj("ContentType") = content?.GetType?.ToString
+
+ 'Content
+ obj("Content") = JToken.FromObject(content)
+
+ 'Write Json to MemoryStream
+ bw.Write(Text.Encoding.Default.GetBytes(obj.ToString))
+
+ 'Get Buffer Bytes
+ Dim buf As Byte() = ms.ToArray
+ ms.Close()
+
+ Return buf
+ End Function
+
+ Protected Shared Function DecodeFromBytes(buf As Byte()) As (cmd As String, content As Object)
+ Dim contentstring As String = Text.Encoding.Default.GetString(buf)
+ Dim content As Object = Nothing
+ Dim contentobj As JObject = JObject.Parse(contentstring)
+
+ Dim cmd As String = contentobj("Cmd")
+ Dim contenttypestring As String = contentobj("ContentType")
+ Dim contentlinq As JToken = contentobj("Content")
+
+ If Not String.IsNullOrEmpty(contenttypestring) Then
+ Dim contenttype As Type = Type.GetType(contenttypestring)
+ content = contentlinq.ToObject(contenttype)
+ End If
+
+ Return (cmd, content)
+ End Function
+
+End Class
diff --git a/Pilz.Networking/My Project/Application.Designer.vb b/Pilz.Networking/My Project/Application.Designer.vb
new file mode 100644
index 0000000..88dd01c
--- /dev/null
+++ b/Pilz.Networking/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/Pilz.Networking/My Project/Application.myapp b/Pilz.Networking/My Project/Application.myapp
new file mode 100644
index 0000000..758895d
--- /dev/null
+++ b/Pilz.Networking/My Project/Application.myapp
@@ -0,0 +1,10 @@
+
+
+ false
+ false
+ 0
+ true
+ 0
+ 1
+ true
+
diff --git a/Pilz.Networking/My Project/AssemblyInfo.vb b/Pilz.Networking/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..c81f2f8
--- /dev/null
+++ b/Pilz.Networking/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' Allgemeine Informationen über eine Assembly werden über die folgenden
+' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+' die einer Assembly zugeordnet sind.
+
+' Werte der Assemblyattribute überprüfen
+
+
+
+
+
+
+
+
+
+
+'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
+
+
+' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+'
+' Hauptversion
+' Nebenversion
+' Buildnummer
+' Revision
+'
+' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+' übernehmen, indem Sie "*" eingeben:
+'
+
+
+
diff --git a/Pilz.Networking/My Project/Resources.Designer.vb b/Pilz.Networking/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..a2b623f
--- /dev/null
+++ b/Pilz.Networking/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.Networking.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set(ByVal value As Global.System.Globalization.CultureInfo)
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Networking/My Project/Resources.resx b/Pilz.Networking/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Pilz.Networking/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pilz.Networking/My Project/Settings.Designer.vb b/Pilz.Networking/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..ee067b4
--- /dev/null
+++ b/Pilz.Networking/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
+
+#Region "My.Settings Auto-Save Functionality"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.Pilz.Networking.My.MySettings
+ Get
+ Return Global.Pilz.Networking.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Networking/My Project/Settings.settings b/Pilz.Networking/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/Pilz.Networking/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Pilz.Networking/NetworkFeatures.vb b/Pilz.Networking/NetworkFeatures.vb
new file mode 100644
index 0000000..3c2f5df
--- /dev/null
+++ b/Pilz.Networking/NetworkFeatures.vb
@@ -0,0 +1,54 @@
+Imports System.Net
+Imports System.Net.NetworkInformation
+Imports System.Net.Sockets
+
+Public Module NetworkFeatures
+
+ Public Function GetIPFromHost(hostName As String) As IPAddress
+ Return Dns.GetHostAddresses(hostName).FirstOrDefault(Function(n) n.AddressFamily = AddressFamily.InterNetwork)
+ End Function
+
+ Public Function GetHostFromIP(ip As String)
+ Return Dns.GetHostEntry(ip)?.HostName
+ End Function
+
+ Public Function GetLocalIPInformations() As UnicastIPAddressInformation
+ Dim addr As UnicastIPAddressInformation = Nothing
+
+ For Each adapter As NetworkInterface In NetworkInterface.GetAllNetworkInterfaces
+ If addr Is Nothing AndAlso adapter.OperationalStatus = OperationalStatus.Up AndAlso adapter.NetworkInterfaceType <> NetworkInterfaceType.Tunnel AndAlso adapter.NetworkInterfaceType <> NetworkInterfaceType.Loopback Then
+ For Each uni As UnicastIPAddressInformation In adapter.GetIPProperties.UnicastAddresses
+ If addr Is Nothing AndAlso uni.Address.AddressFamily = AddressFamily.InterNetwork Then
+ addr = uni
+ End If
+ Next
+ End If
+ Next
+
+ Return addr
+ End Function
+
+ Public Function GetLocalIPAddress() As IPAddress
+ Return GetLocalIPInformations()?.Address
+ End Function
+
+ Public Function GetLocalIPv4Mask() As IPAddress
+ Return GetLocalIPInformations()?.IPv4Mask
+ End Function
+
+ Public Function GetLocalBoradcastIP(ipInfo As UnicastIPAddressInformation) As IPAddress
+ Dim ip As IPAddress = Nothing
+ Dim myIPBytes As Byte() = ipInfo.Address.GetAddressBytes
+ Dim subnetBytes As Byte() = ipInfo.IPv4Mask.GetAddressBytes
+ Dim broadcastBytes As Byte() = New Byte(myIPBytes.Length - 1) {}
+
+ For i As Integer = 0 To subnetBytes.Length - 1
+ broadcastBytes(i) = myIPBytes(i) Or Not subnetBytes(i)
+ Next
+
+ ip = New IPAddress(broadcastBytes)
+
+ Return ip
+ End Function
+
+End Module
diff --git a/Pilz.Networking/Pilz.Networking.vbproj b/Pilz.Networking/Pilz.Networking.vbproj
new file mode 100644
index 0000000..20c6cb5
--- /dev/null
+++ b/Pilz.Networking/Pilz.Networking.vbproj
@@ -0,0 +1,114 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}
+ Library
+ Pilz.Networking
+ Pilz.Networking
+ 512
+ Windows
+ v4.5
+ true
+
+
+ true
+ full
+ true
+ true
+ bin\Debug\
+ Pilz.Networking.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ Pilz.Networking.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+ ..\..\ConsoleApp2\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Networking/TCPManager.vb b/Pilz.Networking/TCPManager.vb
new file mode 100644
index 0000000..fe032c5
--- /dev/null
+++ b/Pilz.Networking/TCPManager.vb
@@ -0,0 +1,83 @@
+Imports System.IO
+Imports System.Net
+Imports System.Net.NetworkInformation
+Imports System.Net.Sockets
+Imports Newtonsoft.Json.Linq
+
+Public Class TCPManager
+ Inherits ConnectionManagerBase
+
+ Private ReadOnly listener As TcpListener
+ Public Property BufferSize As Integer = 10240
+
+ Public Sub New(port As Integer)
+ MyBase.New(port)
+ listener = New TcpListener(IPAddress.Any, port)
+ End Sub
+
+ Public Overrides Sub Start()
+ If Not IsListening Then
+ listener.Start()
+ IsListening = True
+ Task.Run(AddressOf CheckRetriveData)
+ End If
+ End Sub
+
+ '''
+ ''' Stop listening on given port.
+ '''
+ Public Overrides Sub [Stop]()
+ If IsListening Then
+ IsListening = False
+ listener.Stop()
+ End If
+ End Sub
+
+ Private Sub CheckRetriveData()
+ Do While IsListening
+ If listener.Pending Then
+ Dim tcp As TcpClient = listener.AcceptTcpClient()
+ Dim ip As String = CType(tcp.Client.RemoteEndPoint, IPEndPoint).Address.ToString
+ Dim Stream As NetworkStream = tcp.GetStream
+ Dim buf As Byte() = New Byte(BufferSize - 1) {}
+
+ tcp.ReceiveBufferSize = BufferSize
+ Stream.Read(buf, 0, buf.Length)
+
+ Dim contentstring As String = Text.Encoding.Default.GetString(buf)
+ Dim content As Object = Nothing
+ Dim cmd As String = String.Empty
+
+ Try
+ Dim res = DecodeFromBytes(buf)
+ cmd = res.cmd
+ content = res.content
+ Catch ex As Exception
+ End Try
+
+ tcp.Close()
+
+ RaiseRetriveData(ip, cmd, content)
+ End If
+ Loop
+ End Sub
+
+ Public Overrides Sub Send(empfängerIP As String, cmd As String, content As Object)
+ Dim ep As New IPEndPoint(GetIPFromHost(empfängerIP).MapToIPv4, Port)
+ Dim tcp As New TcpClient
+
+ tcp.SendBufferSize = BufferSize
+ tcp.Connect(ep)
+
+ Dim stream As NetworkStream = tcp.GetStream()
+ Dim buf As Byte() = EncodeToBytes(cmd, content)
+
+ 'Send Data
+ stream.Write(buf, 0, buf.Length)
+ stream.Flush()
+
+ tcp.Client.Shutdown(SocketShutdown.Both)
+ tcp.Close()
+ End Sub
+
+End Class
diff --git a/Pilz.Networking/UDPManager.vb b/Pilz.Networking/UDPManager.vb
new file mode 100644
index 0000000..01b57d0
--- /dev/null
+++ b/Pilz.Networking/UDPManager.vb
@@ -0,0 +1,94 @@
+Imports System.IO
+Imports System.Net
+Imports System.Net.NetworkInformation
+Imports System.Net.Sockets
+Imports System.Threading
+Imports Newtonsoft.Json.Linq
+
+Public Class UDPManager
+ Inherits ConnectionManagerBase
+
+ Private ReadOnly client As UdpClient
+ Private listenTask As Task = Nothing
+ Private ReadOnly cancelTokenSource As New CancellationTokenSource
+ Private ReadOnly cancelToken As CancellationToken = cancelTokenSource.Token
+
+ Public Sub New(port As Integer)
+ MyBase.New(port)
+ client = New UdpClient(port)
+ End Sub
+
+ Protected Overrides Sub Finalize()
+ MyBase.Finalize()
+ client.Client.Shutdown(SocketShutdown.Both)
+ client.Close()
+ End Sub
+
+ Public Overrides Sub Start()
+ If Not IsListening Then
+ StartInternal()
+ End If
+ End Sub
+
+ Private Sub StartInternal()
+ IsListening = True
+ listenTask = Task.Run(
+ Sub()
+ Try
+ RetriveAnyData(cancelToken)
+ Catch ex As Exception
+ IsListening = False
+ End Try
+ End Sub)
+ End Sub
+
+ '''
+ ''' Stop listening on given port.
+ '''
+ Public Overrides Sub [Stop]()
+ If IsListening Then
+ IsListening = False
+ cancelTokenSource.Cancel()
+ listenTask.Wait()
+ End If
+ End Sub
+
+ Private Sub RetriveAnyData(ct As CancellationToken)
+ Dim doExit = Sub() ct.ThrowIfCancellationRequested()
+ Dim receiveTask As Task(Of UdpReceiveResult) = client.ReceiveAsync()
+
+ 'Wait for the data and cancel if requested
+ receiveTask.Wait(ct)
+
+ Dim buf As Byte() = receiveTask.Result.Buffer
+ Dim ip As String = receiveTask.Result.RemoteEndPoint.Address.ToString
+ Dim cmd As String = String.Empty
+ Dim content As Object = Nothing
+
+ doExit()
+
+ Try
+ Dim res = DecodeFromBytes(buf)
+ cmd = res.cmd
+ content = res.content
+ Catch ex As Exception
+ End Try
+
+ RaiseRetriveData(ip, cmd, content)
+
+ doExit()
+ StartInternal()
+ End Sub
+
+ Public Overrides Sub Send(empfängerIP As String, cmd As String, content As Object)
+ Dim ep As New IPEndPoint(GetIPFromHost(empfängerIP).MapToIPv4, Port)
+ Dim udp As New UdpClient
+ Dim buf As Byte() = EncodeToBytes(cmd, content)
+
+ udp.Connect(ep)
+ udp.Send(buf, buf.Length)
+ udp.Client.Shutdown(SocketShutdown.Both)
+ udp.Close()
+ End Sub
+
+End Class
diff --git a/Pilz.Networking/packages.config b/Pilz.Networking/packages.config
new file mode 100644
index 0000000..5f639a6
--- /dev/null
+++ b/Pilz.Networking/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/Model/Mesh.vb b/Pilz.Simple3DFileParser/Model/Mesh.vb
index 53dfa0b..392c850 100644
--- a/Pilz.Simple3DFileParser/Model/Mesh.vb
+++ b/Pilz.Simple3DFileParser/Model/Mesh.vb
@@ -8,34 +8,35 @@ Public Class Mesh
Public ReadOnly Property VertexColors As New List(Of VertexColor)
Public ReadOnly Property Faces As New List(Of Face)
- Friend Function GetCenterModelAvg() As Vector3
+ Public Sub CenterModel()
+ CenterModel({Me})
+ End Sub
+
+ Public Shared Sub CenterModel(meshes As IEnumerable(Of Mesh))
Dim avgX As Integer = 0
Dim avgY As Integer = 0
Dim avgZ As Integer = 0
+ Dim vertsCount As Long = 0
- For Each v As Vertex In Vertices
- avgX += v.X
- avgY += v.Y
- avgZ += v.Z
+ For Each m As Mesh In meshes
+ For Each v As Vertex In m.Vertices
+ avgX += v.X
+ avgY += v.Y
+ avgZ += v.Z
+ Next
+ vertsCount += m.Vertices.Count
Next
- Return New Vector3(avgX, avgY, avgZ)
- End Function
+ Dim avg As New Vector3(avgX, avgY, avgZ)
+ avg /= New Vector3(vertsCount)
- Public Sub CenterModel()
- Dim avg As Vector3 = GetCenterModelAvg()
-
- avg /= New Vector3(Vertices.Count)
-
- CenterModel(avg)
- End Sub
-
- Public Sub CenterModel(avg As Vector3)
- For Each v As Vertex In Vertices
- v.X -= avg.X
- v.Y -= avg.Y
- v.Z -= avg.Z
+ For Each m As Mesh In meshes
+ For Each v As Vertex In m.Vertices
+ v.X -= avg.X
+ v.Y -= avg.Y
+ v.Z -= avg.Z
+ Next
Next
End Sub
-End Class
\ No newline at end of file
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Object3D.vb b/Pilz.Simple3DFileParser/Model/Object3D.vb
index 52e5aa8..7e36721 100644
--- a/Pilz.Simple3DFileParser/Model/Object3D.vb
+++ b/Pilz.Simple3DFileParser/Model/Object3D.vb
@@ -179,22 +179,17 @@ Public Class Object3D
End Function
Public Sub CenterModel()
- Dim avg As Vector3 = Vector3.Zero
- Dim vertsCount As ULong = 0
-
- For Each m As Mesh In Meshes
- avg += m.GetCenterModelAvg
- vertsCount += m.Vertices.Count
- Next
-
- avg /= vertsCount
-
- CenterModel(avg)
+ Mesh.CenterModel(Meshes)
End Sub
- Public Sub CenterModel(avg As Vector3)
- For Each m As Mesh In Meshes
- m.CenterModel(avg)
+
+ Public Shared Sub CenterModel(objs As IEnumerable(Of Object3D))
+ Dim meshes As New List(Of Mesh)
+
+ For Each obj As Object3D In objs
+ meshes.AddRange(obj.Meshes)
Next
+
+ Mesh.CenterModel(meshes)
End Sub
End Class
diff --git a/Pilz.Simple3DFileParser/Other/LoaderModule.vb b/Pilz.Simple3DFileParser/Other/LoaderModule.vb
index a34a287..620657f 100644
--- a/Pilz.Simple3DFileParser/Other/LoaderModule.vb
+++ b/Pilz.Simple3DFileParser/Other/LoaderModule.vb
@@ -69,8 +69,11 @@ Public Class File3DLoaderModule
AssimpModule.AssimpLoader.LoadAssimpLibs()
Dim exts As New Dictionary(Of String, String)
For Each fd As Assimp.ExportFormatDescription In AssimpLibrary.Instance.GetExportFormatDescriptions
- If Not exts.ContainsKey(fd.FileExtension) Then exts.Add(fd.FileExtension, fd.FormatId & " - " & fd.Description)
+ If Not exts.ContainsKey(fd.FileExtension) Then
+ exts.Add(fd.FileExtension, fd.FormatId & " - " & fd.Description)
+ End If
Next
+ exts.Add("blend", "Blender")
list.Add(New File3DLoaderModule("Assimp",
AddressOf LoadViaAssimp,
diff --git a/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj b/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj
index 058d877..88d207c 100644
--- a/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj
+++ b/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj
@@ -52,12 +52,11 @@
..\packages\Aspose.3D.18.4.0\lib\net40\Aspose.3D.dll
-
- False
+
..\Shared Libs\AssimpNet.dll
- ..\..\..\DLL's\ColladaSchema.dll
+ ..\Shared Libs\ColladaSchema.dll
diff --git a/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb b/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
index d76539a..b802cb7 100644
--- a/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
+++ b/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
@@ -143,20 +143,18 @@ Public Class DefaultDrawMethodes
Public Shared Sub DrawTriangle(e As PaintingObjectPaintEventArgs)
Dim obj As PaintingObject = e.PaintingObject
+ Dim p1 As New Point(obj.Size.Width / 2 + e.X, e.Y)
+ Dim p2 As New Point(e.X, e.Y + obj.Size.Height)
+ Dim p3 As New Point(e.X + obj.Size.Width, e.Y + obj.Size.Height)
+
If obj.EnableFill Then
Dim b As New SolidBrush(obj.FillColor)
- Dim p1 As New Point(obj.Size.Width / 2 + e.X, e.Y)
- Dim p2 As New Point(e.X, e.Y + obj.Size.Height)
- Dim p3 As New Point(e.X + obj.Size.Width, e.Y + obj.Size.Height)
e.Graphics.FillPolygon(b, {p1, p2, p3})
End If
If obj.EnableOutline Then
Dim lw As Single = obj.OutlineThicknes
Dim p As New Pen(obj.OutlineColor, obj.OutlineThicknes) With {.DashStyle = obj.OutlineDashStyle, .Alignment = PenAlignment.Inset}
- Dim p1 As New Point(obj.Size.Width / 2 + e.X, e.Y)
- Dim p2 As New Point(e.X, e.Y + obj.Size.Height)
- Dim p3 As New Point(e.X + obj.Size.Width, e.Y + obj.Size.Height)
e.Graphics.DrawPolygon(p, {p1, p2, p3})
End If
End Sub
@@ -225,10 +223,10 @@ Public Class DefaultDrawMethodes
End Sub
Public Shared Sub DrawAreaSelection(e As PaintEventArgs, pc As PaintingControl, startMousePos As PointF, lastMousePos As PointF)
- Dim p As New Pen(pc.AreaSelectionColor)
- p.DashStyle = DashStyle.DashDot
- p.Width = 3
Dim rectToDraw As RectangleF = HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos)
+ Dim p As New Pen(pc.AreaSelectionColor)
+ p.DashStyle = If(startMousePos.X >= lastMousePos.X, DashStyle.DashDot, DashStyle.Solid)
+ p.Width = 3
e.Graphics.DrawRectangle(p, rectToDraw.X, rectToDraw.Y, rectToDraw.Width, rectToDraw.Height)
End Sub
diff --git a/Pilz.UI/PaintingControl/PaintingControl.vb b/Pilz.UI/PaintingControl/PaintingControl.vb
index bbc72a7..fb0f27e 100644
--- a/Pilz.UI/PaintingControl/PaintingControl.vb
+++ b/Pilz.UI/PaintingControl/PaintingControl.vb
@@ -23,6 +23,8 @@ Public Class PaintingControl
Public Property Offset As PointF = PointF.Empty
Public ReadOnly Property PaintingObjects As New PaintingObjectList(Me)
+ 'Public Property EnableRealTransparency As Boolean = False
+ Public Property VisibleForMouseEvents As Boolean = True
Public Property AutoAreaSelection As Boolean = True
Public Property AutoSingleSelection As Boolean = True
Public Property AutoMultiselection As Boolean = True
@@ -90,9 +92,10 @@ Public Class PaintingControl
End Get
Set(value As Color)
bgColor = value
- If value <> Color.Transparent Then
- MyBase.BackColor = value
- End If
+ MyBase.BackColor = value
+ 'If value <> Color.Transparent Then
+ ' MyBase.BackColor = value
+ 'End If
End Set
End Property
Public ReadOnly Property IsAreaSelecting As Boolean
@@ -114,6 +117,7 @@ Public Class PaintingControl
End Property
Public Sub New()
+ 'SetStyle(ControlStyles.Opaque, True) 'For real transparency
DoubleBuffered = True
End Sub
@@ -150,7 +154,7 @@ Public Class PaintingControl
curObjMouseDown = GetObjects(lastMousePos).Where(Function(n) Not n.MouseTransparency).LastOrDefault
curObjMouseDown?.RaiseMouseDown(GetMouseEventArgs(e, curObjMouseDown))
- If Not GetSelectedObjects.Contains(curObjMouseDown) Then
+ If curObjMouseDown Is Nothing OrElse Not curObjMouseDown.Selected OrElse pressedControl Then
Dim hasMovedObjects As Boolean = False
If _IsMovingObjects Then
For Each obj As PaintingObject In GetSelectedObjects()
@@ -164,7 +168,7 @@ Public Class PaintingControl
If (Not hasMovedObjects) AndAlso (Not _IsAreaSelecting) Then
Dim selChanged As New List(Of PaintingObject)
- If AutoRemoveSelection AndAlso Not pressedShift Then
+ If AutoRemoveSelection AndAlso Not pressedControl Then
For Each obj As PaintingObject In PaintingObjects
If obj.Selected Then
obj.SelectedDirect = False
@@ -175,9 +179,9 @@ Public Class PaintingControl
Next
End If
- If AutoSingleSelection Then
+ If AutoSingleSelection AndAlso curObjMouseDown IsNot Nothing Then
Dim objtosel As PaintingObject = curObjMouseDown
- If objtosel?.EnableSelection Then
+ If objtosel.EnableSelection Then
objtosel.SelectedDirect = Not objtosel.Selected
If Not selChanged.Contains(objtosel) Then
selChanged.Add(objtosel)
@@ -418,7 +422,7 @@ Public Class PaintingControl
Get
Dim cp = MyBase.CreateParams
- 'If EnableFullTransparentBackground Then
+ 'If EnableRealTransparency Then
' cp.ExStyle = cp.ExStyle Or &H20 'WS_EX_TRANSPARENT
'End If
@@ -431,16 +435,14 @@ Public Class PaintingControl
'''
'''
Protected Overrides Sub WndProc(ByRef m As Message)
- Dim WM_NCHITTEST As Integer = &H84
- Dim HTTRANSPARENT As Integer = -1
+ Const WM_NCHITTEST As Integer = &H84
+ Const HTTRANSPARENT As Integer = -1
- 'If m.Msg = WM_NCHITTEST Then
- ' m.Result = CType(HTTRANSPARENT, IntPtr)
- 'Else
- ' MyBase.WndProc(m)
- 'End If
-
- MyBase.WndProc(m)
+ If Not VisibleForMouseEvents AndAlso m.Msg = WM_NCHITTEST Then
+ m.Result = CType(HTTRANSPARENT, IntPtr)
+ Else
+ MyBase.WndProc(m)
+ End If
End Sub
Protected Overrides Sub OnPaintBackground(e As PaintEventArgs)
@@ -448,13 +450,13 @@ Public Class PaintingControl
Me.SuspendLayout()
'Draw Background
+ 'If Not EnableRealTransparency Then
MyBase.OnPaintBackground(e)
+ 'End If
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
- 'Do default Drawing Methode
- MyBase.OnPaint(e)
-
+ 'Draw PaintingObjects stuff
If StopDrawing Then
e.Graphics.DrawImage(bufferedImg, Point.Empty)
Else
@@ -482,6 +484,9 @@ Public Class PaintingControl
End If
End If
+ 'Do default Drawing Methode
+ MyBase.OnPaint(e)
+
'Start Drawing directly to the Form
ResumeLayout(False)
End Sub
@@ -501,53 +506,76 @@ Public Class PaintingControl
Private Function CalcTextSize(obj As PaintingObject) As SizeF
Return CalcTextSize(obj, Parent.CreateGraphics)
End Function
+
Private Function CalcTextSize(obj As PaintingObject, g As Graphics) As SizeF
Return g.MeasureString(obj.Text, obj.TextFont, obj.Width)
End Function
Private Sub SelectControlsInArea()
- Dim rect As RectangleF = HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos)
+ Dim rect As RectangleF = GetRectangle(startMousePos, lastMousePos)
For Each obj As PaintingObject In PaintingObjects
- obj.Selected = HelpfulDrawingFunctions.OverlapsTwoRectangles(obj.Rectangle, rect)
+ obj.Selected = If(startMousePos.X >= lastMousePos.X,
+ OverlapsTwoRectangles(obj.Rectangle, rect),
+ RectangleContainsRectangle(rect, obj.Rectangle))
Next
End Sub
- Public Sub ArrangeToGrid(obj As PaintingObject)
- Dim zoomedGridChunkSize As New SizeF(GridChunkSize.Width * ZoomFactor.Width, Me.GridChunkSize.Height * ZoomFactor.Height)
+ Public Sub ArrangeToGrid(obj As PaintingObject, snapPinnedObjects As Boolean)
+ If snapPinnedObjects OrElse Not IsPinnedObject(obj) Then
+ Dim zoomedGridChunkSize As New SizeF(GridChunkSize.Width * ZoomFactor.Width, Me.GridChunkSize.Height * ZoomFactor.Height)
- Dim modTop As Integer = obj.Y Mod zoomedGridChunkSize.Height
- Dim modLeft As Integer = obj.X Mod zoomedGridChunkSize.Width
+ Dim modTop As Integer = obj.Y Mod zoomedGridChunkSize.Height
+ Dim modLeft As Integer = obj.X Mod zoomedGridChunkSize.Width
- Dim halfHeight As Integer = zoomedGridChunkSize.Height / 2
- Dim halfWidth As Integer = zoomedGridChunkSize.Width / 2
+ Dim halfHeight As Integer = zoomedGridChunkSize.Height / 2
+ Dim halfWidth As Integer = zoomedGridChunkSize.Width / 2
- If modTop > halfHeight Then
- obj.Y += (zoomedGridChunkSize.Height - modTop)
- Else
- obj.Y -= modTop
- End If
+ Dim zoomLocation =
+ Sub(obj2 As PaintingObject)
+ If modTop > halfHeight Then
+ obj2.Y += (zoomedGridChunkSize.Height - modTop)
+ Else
+ obj2.Y -= modTop
+ End If
- If modLeft > halfWidth Then
- obj.X += (zoomedGridChunkSize.Width - modLeft)
- Else
- obj.X -= modLeft
- End If
+ If modLeft > halfWidth Then
+ obj2.X += (zoomedGridChunkSize.Width - modLeft)
+ Else
+ obj2.X -= modLeft
+ End If
+ End Sub
+
+ zoomLocation(obj)
+
+ For Each pinned As PaintingObject In obj.PinnedObjects
+ zoomLocation(pinned)
+ Next
- If obj.EnableResize AndAlso Not obj.HardcodedSize Then
Dim modH As Integer = obj.Height Mod zoomedGridChunkSize.Height
Dim modW As Integer = obj.Width Mod zoomedGridChunkSize.Width
- If modH > halfHeight Then
- obj.Height += (zoomedGridChunkSize.Height - modH)
- Else
- obj.Height -= modH
- End If
+ Dim zoomSize =
+ Sub(obj2 As PaintingObject)
+ If obj2.EnableResize AndAlso Not obj2.HardcodedSize Then
+ If modH > halfHeight Then
+ obj2.Height += (zoomedGridChunkSize.Height - modH)
+ Else
+ obj2.Height -= modH
+ End If
- If modW > halfWidth Then
- obj.Width += (zoomedGridChunkSize.Width - modW)
- Else
- obj.Width -= modW
- End If
+ If modW > halfWidth Then
+ obj2.Width += (zoomedGridChunkSize.Width - modW)
+ Else
+ obj2.Width -= modW
+ End If
+ End If
+ End Sub
+
+ zoomSize(obj)
+
+ For Each pinned As PaintingObject In obj.PinnedObjects
+ zoomSize(pinned)
+ Next
End If
End Sub
@@ -564,7 +592,7 @@ Public Class PaintingControl
If GridEnabled Then
For Each obj As PaintingObject In GetSelectedObjects()
If obj.AutoAlignToGrid Then
- ArrangeToGrid(obj)
+ ArrangeToGrid(obj, False)
End If
Next
If Not StopDrawing Then Refresh()
diff --git a/Pilz.UI/PaintingControl/PaintingObject.vb b/Pilz.UI/PaintingControl/PaintingObject.vb
index 97c90d8..b2bc438 100644
--- a/Pilz.UI/PaintingControl/PaintingObject.vb
+++ b/Pilz.UI/PaintingControl/PaintingObject.vb
@@ -432,7 +432,7 @@ Imports Newtonsoft.Json
Public Sub ArrangeToGrid()
If Parent IsNot Nothing Then
- Parent.ArrangeToGrid(Me)
+ Parent.ArrangeToGrid(Me, True)
If Not Parent.StopDrawing Then Parent.Refresh()
End If
End Sub
diff --git a/Pilz.UI/PaintingControl/PaintingObjectResizing.vb b/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
index 76f1b9a..9edbea5 100644
--- a/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
+++ b/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
@@ -66,7 +66,6 @@ Imports Pilz.Drawing
End Sub
Private Sub mControl_MouseMove(sender As Object, e As MouseEventArgs) Handles mObjControl.MouseMove
-
If mMouseDown AndAlso mEdge <> EdgeEnum.None Then
Dim eX As Integer = e.X + mObj.Parent.Offset.X
@@ -97,6 +96,8 @@ Imports Pilz.Drawing
Dim eXo As Integer = e.X
Dim eYo As Integer = e.Y
+ Dim realX As Integer = eXo + mObj.Parent.Offset.X
+ Dim realY As Integer = eYo + mObj.Parent.Offset.Y
Dim eXwo As Integer = eXo - mObj.X
Dim eYwo As Integer = eYo - mObj.Y
Dim eX As Integer = eXwo + mObj.Parent.Offset.X
@@ -112,7 +113,7 @@ Imports Pilz.Drawing
newRect.Height = (extRect.Height - oldRect.Height) / 2
Dim setToNone As Boolean = False
- Dim isOnTop As Boolean = mObj.Parent.GetObject(New PointF(eXo, eYo), True) Is mObj
+ Dim isOnTop As Boolean = mObj.Parent.GetObject(New PointF(realX, realY), True) Is mObj
If Enabled AndAlso isOnTop Then
Select Case True
diff --git a/Pilz.UI/Pilz.UI.vbproj b/Pilz.UI/Pilz.UI.vbproj
index 772d1bb..945ae42 100644
--- a/Pilz.UI/Pilz.UI.vbproj
+++ b/Pilz.UI/Pilz.UI.vbproj
@@ -68,7 +68,7 @@
- ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
diff --git a/Pilz.UI/packages.config b/Pilz.UI/packages.config
index 7f83af3..93b0be8 100644
--- a/Pilz.UI/packages.config
+++ b/Pilz.UI/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/Pilz.Updating.Updater/App.config b/Pilz.Updating.Updater/App.config
new file mode 100644
index 0000000..bc3672d
--- /dev/null
+++ b/Pilz.Updating.Updater/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Updating.Updater/My Project/Application.Designer.vb b/Pilz.Updating.Updater/My Project/Application.Designer.vb
new file mode 100644
index 0000000..8be2678
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Application.Designer.vb
@@ -0,0 +1,38 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ 'HINWEIS: Diese Datei wird automatisch generiert und darf nicht direkt bearbeitet werden. Wenn Sie Änderungen vornehmen möchten
+ ' oder in dieser Datei Buildfehler auftreten, wechseln Sie zum Projekt-Designer.
+ ' (Wechseln Sie dazu zu den Projekteigenschaften, oder doppelklicken Sie auf den Knoten "Mein Projekt" im
+ ' Projektmappen-Explorer). Nehmen Sie auf der Registerkarte "Anwendung" entsprechende Änderungen vor.
+ '
+ Partial Friend Class MyApplication
+
+ _
+ Public Sub New()
+ MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows)
+ Me.IsSingleInstance = false
+ Me.EnableVisualStyles = true
+ Me.SaveMySettingsOnExit = true
+ Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses
+ End Sub
+
+ _
+ Protected Overrides Sub OnCreateMainForm()
+ Me.MainForm = Global.Pilz.Updating.UpdateInstaller.Form1
+ End Sub
+ End Class
+End Namespace
diff --git a/Pilz.Updating.Updater/My Project/Application.myapp b/Pilz.Updating.Updater/My Project/Application.myapp
new file mode 100644
index 0000000..1243847
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Application.myapp
@@ -0,0 +1,11 @@
+
+
+ true
+ Form1
+ false
+ 0
+ true
+ 0
+ 0
+ true
+
diff --git a/Pilz.Updating.Updater/My Project/AssemblyInfo.vb b/Pilz.Updating.Updater/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..ab0119f
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' Allgemeine Informationen über eine Assembly werden über die folgenden
+' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+' die einer Assembly zugeordnet sind.
+
+' Werte der Assemblyattribute überprüfen
+
+
+
+
+
+
+
+
+
+
+'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
+
+
+' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+'
+' Hauptversion
+' Nebenversion
+' Buildnummer
+' Revision
+'
+' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+' übernehmen, indem Sie "*" eingeben:
+'
+
+
+
diff --git a/Pilz.Updating.Updater/My Project/Resources.Designer.vb b/Pilz.Updating.Updater/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..315ae38
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Resources.Designer.vb
@@ -0,0 +1,63 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+Imports System
+
+Namespace My.Resources
+
+ 'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+ '-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+ 'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+ 'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
+ '''
+ ''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.Updating.UpdateInstaller.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+ ''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Updating.Updater/My Project/Resources.resx b/Pilz.Updating.Updater/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pilz.Updating.Updater/My Project/Settings.Designer.vb b/Pilz.Updating.Updater/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..174e4f9
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
+
+#Region "Automatische My.Settings-Speicherfunktion"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.Pilz.Updating.UpdateInstaller.My.MySettings
+ Get
+ Return Global.Pilz.Updating.UpdateInstaller.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Updating.Updater/My Project/Settings.settings b/Pilz.Updating.Updater/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/Pilz.Updating.Updater/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Pilz.Updating.Updater/Pilz.Updating.UpdateInstaller.vbproj b/Pilz.Updating.Updater/Pilz.Updating.UpdateInstaller.vbproj
new file mode 100644
index 0000000..30ba063
--- /dev/null
+++ b/Pilz.Updating.Updater/Pilz.Updating.UpdateInstaller.vbproj
@@ -0,0 +1,136 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}
+ WinExe
+ Pilz.Updating.UpdateInstaller.My.MyApplication
+ Pilz.Updating.UpdateInstaller
+ Pilz.Updating.UpdateInstaller
+ 512
+ WindowsForms
+ v4.5
+ true
+
+
+ AnyCPU
+ true
+ full
+ true
+ true
+ bin\Debug\
+ Pilz.Updating.UpdateInstaller.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ AnyCPU
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ Pilz.Updating.UpdateInstaller.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ UpdateInstaller.vb
+ Form
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+ UpdateInstaller.vb
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
+
+
+ {354255d9-9536-4400-b915-ffc49c2ce93f}
+ Pilz.Updating
+
+
+ {277d2b83-7613-4c49-9cab-e080195a6e0c}
+ Pilz
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Updating.Updater/UpdateInstaller.Designer.vb b/Pilz.Updating.Updater/UpdateInstaller.Designer.vb
new file mode 100644
index 0000000..154fd55
--- /dev/null
+++ b/Pilz.Updating.Updater/UpdateInstaller.Designer.vb
@@ -0,0 +1,65 @@
+ _
+Partial Class UpdateInstaller
+ Inherits System.Windows.Forms.Form
+
+ 'Das Formular überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen.
+ _
+ Protected Overrides Sub Dispose(ByVal disposing As Boolean)
+ Try
+ If disposing AndAlso components IsNot Nothing Then
+ components.Dispose()
+ End If
+ Finally
+ MyBase.Dispose(disposing)
+ End Try
+ End Sub
+
+ 'Wird vom Windows Form-Designer benötigt.
+ Private components As System.ComponentModel.IContainer
+
+ 'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
+ 'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
+ 'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
+ _
+ Private Sub InitializeComponent()
+ Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(UpdateInstaller))
+ Me.ProgressBar1 = New System.Windows.Forms.ProgressBar()
+ Me.Label1 = New System.Windows.Forms.Label()
+ Me.SuspendLayout()
+ '
+ 'ProgressBar1
+ '
+ Me.ProgressBar1.Location = New System.Drawing.Point(15, 25)
+ Me.ProgressBar1.Name = "ProgressBar1"
+ Me.ProgressBar1.Size = New System.Drawing.Size(390, 16)
+ Me.ProgressBar1.TabIndex = 0
+ '
+ 'Label1
+ '
+ Me.Label1.AutoSize = True
+ Me.Label1.Location = New System.Drawing.Point(12, 9)
+ Me.Label1.Name = "Label1"
+ Me.Label1.Size = New System.Drawing.Size(62, 13)
+ Me.Label1.TabIndex = 1
+ Me.Label1.Text = "Updating ..."
+ '
+ 'Form1
+ '
+ Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
+ Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
+ Me.ClientSize = New System.Drawing.Size(417, 55)
+ Me.ControlBox = False
+ Me.Controls.Add(Me.Label1)
+ Me.Controls.Add(Me.ProgressBar1)
+ Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
+ Me.Name = "Form1"
+ Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
+ Me.Text = "Updater"
+ Me.ResumeLayout(False)
+ Me.PerformLayout()
+
+ End Sub
+
+ Friend WithEvents ProgressBar1 As ProgressBar
+ Friend WithEvents Label1 As Label
+End Class
diff --git a/Pilz.Updating.Updater/UpdateInstaller.resx b/Pilz.Updating.Updater/UpdateInstaller.resx
new file mode 100644
index 0000000..7c83c6d
--- /dev/null
+++ b/Pilz.Updating.Updater/UpdateInstaller.resx
@@ -0,0 +1,643 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+
+
+ AAABAAkAICAQAAEABADoAgAAlgAAABAQEAABAAQAKAEAAH4DAAAwMAAAAQAIAKgOAACmBAAAICAAAAEA
+ CACoCAAAThMAABAQAAABAAgAaAUAAPYbAAAAAAAAAQAgAEIdAABeIQAAMDAAAAEAIACoJQAAoD4AACAg
+ AAABACAAqBAAAEhkAAAQEAAAAQAgAGgEAADwdAAAKAAAACAAAABAAAAAAQAEAAAAAACAAgAAAAAAAAAA
+ AAAQAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8A
+ AAD/AP8A//8AAP///wAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIiIiIiIiIiIgAAACHd3d3d3d3d3d3d3d3
+ gAAAh3d3d3d3d3d3d3d3d4AAAId3d3d3d3d3d3d3d3iAAACHd3d3d3d3d3d3d3d3gAAAh3d3d3d3d3d3
+ d3d3d4AAAIh4eHh3h3h3h3h3h3iAAACIeHh3h4eHh4eHh4eIgAAAiHd3d4eHh4eHh4eHh4AAAIiId0Z3
+ h4h4d4h4d4iAAACId3Z2d4eHiIiHiIiHgAAAiHZ2ZnZ4h4eHh4eHiIAAAIh3ZnZ2d4iIiIiIiIiAAACI
+ d3Z2Z3eIiIiIiIiIgAAAiIh2xneIiIiIiIiIiIAAAIh4dnZniIiIiIiIiIiAAACIiHZ8d4iIiIiIiIiI
+ gAAACIhnZneIiIiIiIiIiIAAAAh3dmdnh4iIeHh4eHgAAAAIh3Z8Z4iIiHh4eHiIAAAACIh2dneHiIiI
+ iIiIiAAAAACIdnZniIiIiIiIiIAAAAAAiHZnx3iIiIiIiIiAAAAAAAiHZ2dniIiIiIiIAAAAAAAAB2dn
+ ZnZ2dnZ2doAAAAAAAABnx2dnZ2dmdsaAAAAAAAAAB2dnxnxnZ2dngAAAAAAAAAB2dnZ2fGfHZoAAAAAA
+ AAAACHZ2dnZ2ZmeAAAAAAAAAAAAAAAAIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAP/////gAAAPwAAAB8AA
+ AAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB+AA
+ AAfgAAAP4AAAD+AAAA/wAAAf8AAAH/gAAD/+AAAf/wAAH/+AAB//wAAf/+AAH///4P//////KAAAABAA
+ AAAgAAAAAQAEAAAAAADAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICA
+ AACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP///wAAAAAAAAAAAAh3d3d3d3cACHd3d3d3
+ dwAId3h3d3d4AAiHd4eHh3gACHdnh4d4eAAIdmd4iIiIAAh3Z3iIiIgACIdniIiIiAAId2eIh4eIAACH
+ d3iIiIgAAIdmiIiIgAAACHZ3d3dwAAAAdnZ2Z2AAAAAIZ2dnYAAAAAAAAAAAAP////+AA///gAP//4AD
+ //+AA///gAP//4AD//+AA///gAP//4AD///AA///wAf//+AH///wB///+Af///////8oAAAAMAAAAGAA
+ AAABAAgAAAAAAIAKAAAAAAAAAAAAAAABAAAAAAAAAAAAAJ5gLgCbYjEAnWMyAJpjNACbZDUAnGQ1AJ1n
+ OQChYi8Ao2MwAKJkMQClZDAAomY0AKVnNACoZjEApmg1AKpoMgCtaTMAqWk1AK5qNAClaTkApWs8AKZs
+ PACtbDgAqW09ALBqNACybDUAtW01ALhvNwCwbTgArnA+ALlwNwC2cDoAsnE/ALtxOAC9cjgAwHM5AMF0
+ OQDEdjsAxXc8AJxqQAClbUAAs3JAALRzQQC1dkUAvXlFALJ5TQC0e08AsHpQAI1+bQCRf20Ax3tBAMh/
+ RgC6hl0AvoleAJOAbgCKg3gAjIN4AI6FegCVgnAAl4RxAJmFcgCRiHwAmYx+AKCCZwCogmQAoYNoAKOE
+ aAClhWkAqYdqAK2JawCsiWwAsYVjALCGZADHgEoAz4xaAMCKYADJlm4AzJdvAM2YbwDSlGUAyZlyAM+Z
+ cADKmnQA0JlwANKddADWnnQA1aB4ANejfABokKkAapKsAGyUrQBvl7AAcZmyAHOatAB0nLYAfZ+zAHqf
+ tgB3nrgAeJ+5AH2gtQB5oLoAfqK4AHuivAB8o70AfaS+AH6lwACVjoQAkY+IAJyTigCNkZQAlpaSAJGU
+ mACVmpsAkpmdAJacnQCYn58AnJ+fAKmWhQCim5IAvaKLAImYpACPnKgAkZ6qAI+iqwCaoKAAkaKsAJOl
+ rQCVpq8Am6etAIGjtwCOpbIAgaS5AIWmuwCCprwAhai9AImqvgCRpbAAlKazAJaosACZqrIAn6uxAJOt
+ vwDbqYMA3K6LANWwkwDftpcAgKfBAIOnxACBqMIAhqnBAIOqxACEqMUAhazGAIiswgCJr8cAh6vIAIau
+ yACJq8gAia7KAImwygCKsswAjLHMAI20zgCbtMMAkbHKAJK0ywCTs8wAlLPNAJO0zgCUtM4Am7jNAJy5
+ zgCPt9AAkLbQAJa20ACRudIAlbrSAJS81ACYudIAnbrQAJi80wCfvNEAmr3VAJ2/1ACgvdIAnMDWAJvB
+ 2ACgwdYAocPYAKXD2ACuyNsArczfALPL3QC1z98AuMzcALTQ4QC40uEAwdPiAMDW5QDL2eIAyd3pAP9R
+ xwD/cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx
+ /wD0Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR
+ /wCmMf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA
+ 8AA+Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAC0rKysrKysrKysrKysq6usrKysq6urq6urq6urq6urq6urrKurq8MAAAAAAAAA
+ AABeWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZW6sAAAAAAAAAAABfWVlZWVlZWVlZ
+ WVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWVlZWqsAAAAAAAAAAABfW1tbW1tbW1tbW1tbW1tbW1tbW1tb
+ W1tbW1tbW1tbW1tbW1taW6wAAAAAAAAAAABfW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tb
+ W1tbXKwAAAAAAAAAAABiXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXawAAAAAAAAA
+ AABlXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXqwAAAAAAAAAAABlXl9eXl5eXl5e
+ X15fXl5eXl9eX19fX19fX19fX19fX15fXl9fX6wAAAAAAAAAAABnYmJiYmJiYmJfYl9iYmJiYmJfYl9i
+ X2JfYl9iX2JfYl9iX2JfYrQAAAAAAAAAAABnY2NjYmNjY2NjY2NjY2NjY2NjZWVlZWVlZWVlZWVlY2Nj
+ ZWNjZbQAAAAAAAAAAABpZWdlZ2VlZ2FlZWdlZWdlZ2VlZWVlZWVlZWVlZWVlZ2VlZWdlZbQAAAAAAAAA
+ AABpaGhoaGhoYDE4ZGhoaGhoaGhpaGhoaGhoaGhoaGhoaGhoaGhoaLQAAAAAAAAAAABqaWlqaWlkMgIF
+ OWZpaWpqaWpqampqampqampqampqampqamlpabYAAAAAAAAAAACTk5OTk4IyAwEBBTqGk5OTk5OTk5OT
+ k5OTk5OTk5OTk5OTk5OTk7QAAAAAAAAAAACVlZeVhDcDCAEBAQU6hpWVl5WVlZWVlZWVlZWVlZWVl5WX
+ l5WVlbQAAAAAAAAAAACVl5eFOwwICAgIAQEFPoeXmZeXl5eXl5eXl5eXl5eXl5eXl5eXl7YAAAAAAAAA
+ AACVnYc9DAgJCAgICAEIBj6amZ2dnZ2dnZ2dnZ2dnZ2dmZ2ZnZ2ZmbYAAAAAAAAAAACXiD0PCwsKCQgJ
+ CAgBAQY+mpudm5ubm5udm52bnZudm6CdoJ2bnbYAAAAAAAAAAACWPykVFAsLCwoJCggIBgcobJugoKGg
+ oKGgoaChoKGgoaChoaChn7kAAAAAAAAAAACWiX5+bxULCwsKCgkKa3x8g6Kjo6OjoaOho6GjoaOhoaGj
+ oaOhoLkAAAAAAAAAAACdo6OjfxYODg4LCwoMcaOjraOjo6Ojo6Ojo6Ojo6Oto6Ojo62jobkAAAAAAAAA
+ AACdra2tgBgSDg4LCwsMc62tra2xsbWxra2tra2wrbCtra2wrbCto7kAAAAAAAAAAACfsLCwixgQEBAO
+ DgsNc7CtsLrFxcXFu7CwrbCtsK2wsLCwsLCwrbkAAAAAAAAAAACfsLKyjB4SEBAQDg4PdLKwsrvExMXE
+ u7KysrKysrKysrCysrCyrbkAAAAAAAAAAAChsrKyjB4TEREREBISfbKysrvAwMDAu7KysrKysrKysrKy
+ srKysrkAAAAAAAAAAACdo62jih4TExMRERASc62to7G9vr29saOto62tra2tra6jraOuobkAAAAAAAAA
+ AACYampqeR4aGRkTEREXbmqTk5inqKinlJRqampqampqamqUampqarkAAAAAAAAAAAC0mJiceiEaGhoZ
+ GRMXcJiYmJ6or6qonpyYnJicmJyYnJicmJicmAAAAAAAAAAAAADGnJyceysbGxoaGhkXcpycnJ+qr6+q
+ opycnJycnJycnJycnJycpwAAAAAAAAAAAAAAqZ+ffiscHBsbGhodcZ+fn6Kzs6+vop+fn5+fn5+fn5+f
+ n5+fwQAAAAAAAAAAAAAAv6KiiiwcHBwbGxoabaKioqmzs7Ozo6KioqKioqKioqOioqKjAAAAAAAAAAAA
+ AAAAAKOuji8fHxwcHBsbQaWjo663t7e3rq6jrqOuo66jrqOuo66+AAAAAAAAAAAAAAAAAL2tpkgjIiIf
+ HBwcKnWusLC3t7q3sq2wrbCtsK2wra2wra0AAAAAAAAAAAAAAAAAAMewsHYkIyIiIh8cHDCBsLK8urq7
+ srGwsrCysLCysLKwsLoAAAAAAAAAAAAAAAAAAAC6so0tJCQjIiIiHBwud6S8uLy8tbKxsbGxsbGxsbGx
+ scIAAAAAAAAAAAAAAAAAAAAAychTJSQkJCMiHx8fIC5JRkZHRUVFRERERENDQ0NCQHgAAAAAAAAAAAAA
+ AAAAAAAAAAAASiUlJCQjIyIfHxwcHBsbGhoaGRMTEREQEBAODjUAAAAAAAAAAAAAAAAAAAAAAAAAkicm
+ JSUkIyMjIh8cHBsbGxoaGhkTExEREBAQEDUAAAAAAAAAAAAAAAAAAAAAAAAAAFgmJiYlJSQkIyIiHxwc
+ HBsbGhoaGhMTEREREDUAAAAAAAAAAAAAAAAAAAAAAAAAAABWJyYmJSUkJCMjIh8fHBwbGxsaGhoZExMR
+ ETYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjzMnJiYlJSQkIyMiIh8cHBsbGhoaGRkTETYAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAABLJyYmJiUkJCQjIyIiHBwcGxsaGhoZGUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAFA0JiYlJSQkIyMiHx8cHBsbGxoaGUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJBYV1dX
+ VVRST09PTk5NTU1NUZEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//
+ /////wAA////////AADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAf
+ AADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAA
+ AAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAf
+ AADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAB8AAPAAAAAAHwAA8AAAAAAfAADwAAAAAD8AAPAA
+ AAAAPwAA+AAAAAA/AAD4AAAAAH8AAPwAAAAAfwAA/AAAAAD/AAD8AAAAAP8AAP4AAAAA/wAA/wAAAAD/
+ AAD/4AAAAP8AAP/gAAAA/wAA//AAAAD/AAD/+AAAAP8AAP/8AAAA/wAA//8AAAD/AAD//8AAAP8AAP//
+ +AAA/wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEACAAAAAAAgAQAAAAAAAAAAAAAAAEAAAAA
+ AAAAAAAAnmEuAJtjNACcYzUAnWQ1AJtoPgCdaj8AoWIvAKNjMACjZDAApWQwAKhmMQCqaDIArWkzAK9q
+ NACkajsApWs8AKZtPQCpbj4AsGs0ALJsNQC1bTUAuG83AK1wPwC5cDcAtnA6ALZxPAC6cTgAvXI4AL91
+ PADAczkAwXQ6AMR2OwDFdzwAl2pDAJtrQgCgbEAAqW9AAK1xQAChdE4AsnJBALRzQQC0dkYArXpTALR8
+ UADGe0IAyX9IAJmCbACLgnYAjoV5AJGHfACZhngAmYl6AJyLfQCdjX0Aq4hrALCJagCiiHMApY98AMiA
+ SgDOi1gAzoxZAM6SZABpkasAa5OtAGyUrQB/l6MAbpawAHCYsQBzm7QAdJy1AHuftQB3n7gAeqG6AH6i
+ uAB8pL0Af6fBAIeOjgCRkIoAipCQAI2TkgCQlZUAlZqaALCnnQCPm6EAjJ2rAJChrwCPo7AAj6WxAI6o
+ tgCBpbsAgKe/AISovgCNqboAkaaxAJKmtQCTqLMAlqq1AJirtQCZrLYAkq2/AJituACfr7gAo6alAKOw
+ twCjsrkAzaiLANCqjADNrJEA37OSANq1mQDct5oAg6fEAICowQCHq8EAg6vEAISpxACFrcYAia/HAIat
+ yACIrcoAjK3JAJOuwQCJsMoAjLLKAIuxzACPscwAjrbPAJS0ygCRtc4AlbXOAJm3zwCOtdAAk7fQAJa3
+ 0ACRuNIAlbnSAJO71ACZudEAmbzUAJ2+1ACdwNcAosTaAKTF2gCtyt0AuMzaALrO3AC80N4AsM3gALbR
+ 4QC90eAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJ
+ AACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAA
+ IQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAA
+ NgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwA
+ LwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAA
+ AAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP//
+ /wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR
+ /wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRkZGRkZGRkZGRkZGRkZGRkZGR
+ kZGRkZGRAAAAAAAAkUE/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/P0CRAAAAAACSQT8/P0A/QD8/Pz9APz8/
+ Pz8/Pz8/Pz9AQZEAAAAAAJFDQUNBQ0FDQ0NBQ0NDQ0NDQ0NDQ0NDQUNDkgAAAAAAkUVERERERERERERE
+ REREREREREREREREREWSAAAAAACSRkVGRUVFRkZFRUVGRkZGRkZGRkVGRUZGRpIAAAAAAJJISEhISEhI
+ SEhISEhISEhISEhISEhISEhIkgAAAAAAkktLSUlJQkdLSUtJS0lLSUlJS0lLSUtJS0mSAAAAAACTS0tL
+ S00iMEpLW0tLTEtMS0xLW0tMS0xLS5MAAAAAAJNMcVtPBQECMVpxcXFxcXFxcXFxcXFxcXFMkgAAAAAA
+ k3NzUAYHAQEDMlxzc3N1c3N1c3Nzc3Nzc3OTAAAAAACTc1EkCAkHBwcEMnJ3dXZ1dnV2dXZ1dnZ3dZMA
+ AAAAAJNUJxAKCQgJBwQjTnZ7e3t7e317e317e3t2lgAAAAAAk11eUhAKCgkJL1hZfH99fX1/fX1/fX1/
+ fH2WAAAAAACWfX9gJQsLCgk0f4SHiIiHf39/f39/f39/fZYAAAAAAJZ/h2ElDAwLCjaHiY+VlY+Hh4eH
+ h4eHh4mElgAAAAAAloeJZSYODAwMNomJj5SUj4mJiYmJiYmJiYeWAAAAAAAAeHtXJg4NDQ00e3uFjIyF
+ e3t7e3t7e3t7d5MAAAAAAAB0cFUmFBMODTNwcHmCgnlwcHBwcHBwcHB0AAAAAAAAAIp4VigVFRQTNXh4
+ foaGfnh4eXh4eHh4eIMAAAAAAAAAln1fKhYVFRU5fH2BioiFfX19fX19fX19lgAAAAAAAAAAiHosGxgW
+ FSt6hIiLi4iEhISEhISEhIgAAAAAAAAAAACQhTgcGxgWGTqAi42Ni4mIh4mHiIeIkAAAAAAAAAAAAACO
+ Ux0eHBsYGjdnaGlmY2NjY2NiYmEAAAAAAAAAAAAAAAAAPh8eHBwbGBopKSgmFxcXEhIREWwAAAAAAAAA
+ AAAAAAAAOyAfHhwcGxYWFRUUFA4NDQwMagAAAAAAAAAAAAAAAAAALiAfHx4cGxsWFRUUFBQODQ1rAAAA
+ AAAAAAAAAAAAAAAAPCEgHx4eHBsYFhUVFBMTDWsAAAAAAAAAAAAAAAAAAAAAbT0tHx8eHBwbGBYVFRQT
+ awAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG9vbm5uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAP/////gAAAPwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AA
+ AAfAAAAHwAAAB8AAAAfAAAAHwAAAB+AAAAfgAAAP4AAAD+AAAA/wAAAf8AAAH/gAAD/+AAAf/wAAH/+A
+ AB//wAAf/+AAH///4P//////KAAAABAAAAAgAAAAAQAIAAAAAABAAQAAAAAAAAAAAAAAAQAAAAAAAAAA
+ AACcZDUAnWc5AKFiLwCjZTIApWUwAKlnMgCuajMArGs2AKVtPwCxazQAtW01ALlwNwC1cDoAs3I+ALpx
+ OQC+cjkAu3M8AL52PgDAdDkAl3RWAJ52VACpcUMArXJDALF1RQC0ek0AontbAKd8WwChfF0AtH5UAJp/
+ ZwDCeUEAjoR4AKyOdQChjXoApI57AKmSfQDJg08A0ZZpAG6VrQBvl7AAc5qyAHSasgB1nbYAeZ+4AHyg
+ tgB7o7wAfqW9AIaKiACQj4oAgJmoAIafrQCUoKQAmaSqAI2isgCCprwAkaa1AJCptgCVrboAy6iMANur
+ hgCBqcIAh67GAIiqwwCMq8QAhq3IAImuyQCNtM0AkrbOAJW2zwCZtskAnLnMAJ+8zwCQttAAkbjRAJi7
+ 0gCYvNQAornJAKi7yACiv9IAoL3UAKnC0QCnx9sAqsfaAK3H2QAKsAAAC88AAA7wAAAg/xIAPf8xAFv/
+ UQB5/3EAmP+RALX/sQDU/9EA////AAAAAAAULwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/
+ MQCc/1EArv9xAMD/kQDS/7EA5P/RAP///wAAAAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/
+ EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/0QD///8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDD
+ AAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/wsQD/9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9b
+ AADwaQAA/3kRAP+KMQD/nVEA/69xAP/BkQD/0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAK
+ AADPDAAA8A4AAP8gEgD/PjEA/1xRAP96cQD/l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAA
+ KwCwADYAzwBAAPAASQD/EVoA/zFwAP9RhgD/cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAA
+ TACQAGIAsAB4AM8AjgDwAKQA/xGzAP8xvgD/UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsA
+ UABpAHAAhwCQAKUAsADEAM8A4QDwAPAR/wDyMf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsA
+ 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
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAH9//wJ/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78I
+ f5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78I
+ f5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+fvwh/n78If5+/CH+qqgYAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHWcujR1nbuydZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3
+ dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3
+ dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3dZ26t3Wdurd1nbq3
+ dZ26t3eevYR/qqoGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0hvl7P3aJCq/2iQqv9okKr/
+ aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/
+ aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/aJCq/2iQqv9okKr/
+ aJCq/2iQqv9okKr/apKt/3Wdurd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0hvl7P3
+ aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/
+ aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/
+ aJCp/2iQqf9okKn/aJCp/2iQqf9okKn/apKs/3Wdurd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHifu0hxmbT3a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/
+ a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/
+ a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/a5Os/2uTrP9rk6z/bZWu/3adurd/n78IAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHifu0hxmbX3bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/
+ bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/
+ bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bJSt/2yUrf9slK3/bpav/3aeurd/n78I
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0hzm7b3b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/
+ b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/
+ b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/
+ cJiy/3aevLd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h0nLf3cZmy/3GZsv9xmbL/
+ cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/
+ cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/cZmy/3GZsv9xmbL/
+ cZmy/3GZsv9xmbL/cpqz/3aevLd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h1nbj3
+ c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/
+ c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/
+ c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/dJy1/3eevLd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHifu0h2nrn3dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/
+ dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/
+ dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ23/3egvbd/n78IAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHifu0h3oLr3d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/
+ d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/
+ d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+5/3egvbd/n78I
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h4obv3eaG6/3mhuv95obr/eaG6/3mhuv95obr/
+ eaG6/3qftv96n7f/eaG6/3mhuv95obr/eaG6/3mhuv95obr/eaG6/3mhuv95obr/eaG6/3mhuv95obr/
+ eaG6/3mhuv95obr/eaG6/3mhuv95obr/eaG6/3mhuv95obr/eaG6/3mhuv95obr/eaG6/3mhuv95obr/
+ eaG7/3egvbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h5orz3e6O8/3ujvP97o7z/
+ e6O8/3ujvP97o7z/fZ+z/4x+b/+Kg3j/fKC2/3ujvP97o7z/e6O8/3ujvP97o7z/e6O8/3ujvP97o7z/
+ e6O8/3ujvP97o7z/e6O8/3ujvP97o7z/e6O8/3ujvP97o7z/e6O8/3ujvP97o7z/e6O8/3ujvP97o7z/
+ e6O8/3ujvP97o7z/e6O8/3mgvbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h6o733
+ faW+/32lvv99pb7/faW+/32lvv9/obX/j35s/5tiMf+aYzT/jIN4/36iuP99pb7/faW+/32lvv99pb7/
+ faW+/32lvv99pb7/faW+/32lvv99pb7/faW+/32lvv99pb7/faW+/32lvv99pb7/faW+/32lvv99pb7/
+ faW+/32lvv99pb7/faW+/32lvv99pb7/fKS+/3mhvrd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHifu0h7pL73f6fA/3+nwP9/p8D/f6fA/4Gjt/+Rf23/nWMy/51gLv+cYC3/m2M0/42Eef+ApLr/
+ f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/
+ f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/f6fA/3+nwP9/p8D/fqbA/3mhvrd/n78IAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHifu0h8pcD3ganC/4Gpwv+BqcL/g6W5/5OAbv+eYzP/n2Eu/55hLv+eYC7/
+ nWAu/5tkNf+Ohnr/gqa8/4Gpwv+BqcL/ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/
+ ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/gKjC/3mhvrd/n78I
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h9psH3g6vE/4OrxP+Fprv/lYJw/6BlM/+hYi//
+ oGIv/59hLv+fYS7/nmEu/51gLv+cZDX/j4d7/4Sovv+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/
+ g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/
+ gqrD/3qhvrd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0h+p8L3ha3G/4epvP+XhHH/
+ omY0/6JjL/+iYy//oWIv/6BiL/+gYi//n2Eu/55hLv+eYS7/nGQ1/5GIfP+GqsD/ha3G/4Wtxv+Frcb/
+ ha3G/4Wtxv+Frcb/ha3G/4Wtxv+Frcb/ha3G/4Wtxv+Frcb/ha3G/4Wtxv+Frcb/ha3G/4Wtxv+Frcb/
+ ha3G/4Wtxv+Frcb/hKzF/3qjwLd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0iAqMP3
+ iaq+/5mFcv+lZzX/pWQw/6RkMP+jZDD/omMv/6JjL/+hYi//oGIv/59iL/+fYS7/nmEu/5xkNf+SiX3/
+ iKzC/4evyP+Hr8j/h6/I/4evyP+Hr8j/h6/I/4evyP+Hr8j/h6/I/4evyP+Hr8j/h6/I/4evyP+Hr8j/
+ h6/I/4evyP+Hr8j/h6/I/4evyP+Hr8j/ha3H/3qjwLd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHifu0iCpr33mYx+/6VtQP+lazz/pWk5/6VlMf+lZDD/pGQw/6NjMP+iYy//oWMv/6FiL/+gYi//
+ nmU1/51nOf+cakD/kY+I/4mvx/+Jscr/ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/
+ ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/h6/J/3qjwLd/n78IAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHifu0iDp8H3kaWw/5GjrP+Ro6z/lpaS/6VqOv+mZTH/pWUw/6RkMP+jZDD/
+ o2Mw/6JjL/+hZDL/lY6E/4+iq/+Poqv/jqWy/4uxyf+Ls8z/i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/
+ i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/ibHK/3yjwLd/n78I
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0iDq8b3jbXO/421zv+Ntc7/k6Wt/6ZsPP+nZjH/
+ p2Ux/6ZlMf+lZTD/pGQw/6NkMP+iZTP/lJub/421zv+Ntc7/jbXO/421zv+Ntc7/jbXO/421zv+Ntc7/
+ jbXO/421zv+Ntc7/jbXO/421zv+Ntc7/jbXO/421zv+Ntc7/jbXO/421zv+Ntc7/jbXO/421zv+Ntc7/
+ irLM/3ykwbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0iErMf3j7fQ/4+30P+Pt9D/
+ laav/6htPf+pZzL/qGYx/6dmMf+mZTH/pWUw/6VkMP+jZjT/lZyc/4+30P+Pt9D/j7fQ/5C40P+Vu9L/
+ lbvS/5W70v+Vu9L/kLjQ/4+30P+Pt9D/j7fQ/4+30P+Pt9D/j7fQ/4+30P+Pt9D/j7fQ/4+30P+Pt9D/
+ j7fQ/4+30P+Pt9D/jLTO/3ykwbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0iErMj3
+ kLjR/5C40f+QuNH/lqiw/6ltPf+raDL/qmcy/6lnMv+oZjH/p2Yx/6ZlMf+lZzT/l52e/5C40f+QuNH/
+ kLjR/5zA1v+40uH/udLi/7nS4v+40uH/nMDW/5C40f+QuNH/kLjR/5C40f+QuNH/kLjR/5C40f+QuNH/
+ kLjR/5C40f+QuNH/kLjR/5C40f+QuNH/jbXP/3ykwbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHifu0iFrcn3krrT/5K60/+SutP/mKmy/6tuPv+saTP/q2gy/6poMv+pZzL/qGcy/6hmMf+maDX/
+ mJ+f/5K60/+SutP/krrT/5zA1/+00OH/tdHh/7XR4f+00OH/nMDX/5K60/+SutP/krrT/5K60/+SutP/
+ krrT/5K60/+SutP/krrT/5K60/+SutP/krrT/5K60/+SutP/j7fQ/32kwbd/n78IAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHifu0iGrsr3lLzV/5S81f+UvNX/mquz/61wP/+uajP/rWkz/6xoM/+raDL/
+ qmcy/6lnMv+oaDX/mqCg/5S81f+UvNX/lLzV/5vB2P+tzN//rszf/67M3/+tzN//m8HY/5S81f+UvNX/
+ lLzV/5S81f+UvNX/lLzV/5S81f+UvNX/lLzV/5S81f+UvNX/lLzV/5S81f+UvNX/kbnS/32lwbd/n78I
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHifu0iDq8f3jbXP/421z/+Ntc//laav/65wP/+vajT/
+ rmoz/65pM/+taTP/rGgz/6toMv+paTb/lpyd/421z/+Ntc//jbXP/5O50v+hw9j/osPY/6LD2P+hw9j/
+ k7nS/421z/+Ntc//jbXP/421z/+Ntc//jbXP/421z/+Ntc//jbXP/421z/+Ntc//jbXP/421z/+Ntc//
+ irLN/3ykwbd/n78IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHufv0B9o8HyfqTC/36kwv9+pML/
+ iZik/69wPv+xazT/sGs0/69qNP+uajP/rWkz/6xpM/+qajb/jZGU/36kwv9+pML/fqTC/4SoxP+Sssv/
+ lLTN/5OzzP+Rssv/hKjE/36kwv9+pML/fqTC/36kwv9+pML/fqTC/36kwv9+pML/fqTC/36kwv9+pML/
+ fqTC/36kwv9+pML/fqTC/3yjwbKRttoHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH+qyRiEqMXM
+ hajG/4Woxv+FqMb/j5yo/7FxP/+zbDX/smw1/7FrNP+wazT/r2o0/65qM/+sazf/kZSY/4Woxv+FqMb/
+ hajG/4mryP+Vs83/l7bQ/5W0zv+Us83/iavI/4Woxv+FqMb/hajG/4Woxv+FqMb/hajG/4Woxv+FqMb/
+ hajG/4Woxv+FqMb/hajG/4Woxv+FqMb/hKfF/IOnw3T///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAH9//wKHqsiCh6vI/YeryP+Hq8j/kZ6q/7NyQP+1bTb/tG01/7NsNf+ybDX/sWs0/7BqNP+tbDj/
+ kpmd/4eryP+Hq8j/h6vI/4uuyv+Vtc7/l7fQ/5W1z/+Vtc7/i67K/4eryP+Hq8j/h6vI/4eryP+Hq8j/
+ h6vI/4eryP+Hq8j/h6vI/4eryP+Hq8j/h6vI/4eryP+Hq8j/hqrH4oirySsAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAACIrss2ia7K6Ymuyv+Jrsr/k6Gs/7RzQf+3bjb/tm42/7VtNv+0bTX/
+ s2w1/7JrNf+wbTj/lpmb/4muyv+Jrsr/ia7K/42xzP+Wt9D/l7jR/5a30P+Wt9D/jbHM/4muyv+Jrsr/
+ ia7K/4muyv+Jrsr/ia7K/4muyv+Jrsr/ia7K/4muyv+Jrsr/ia7K/4muyv+Jrsr/iK7LopG22gcAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLudALi7HMsYyxzf+Msc3/lKaz/7V2Rf+5bzf/
+ t282/7ZuNv+1bjb/tG01/7NsNf+ybDb/nJOK/4yxzP+Msc3/jLHN/4+zzv+YudL/mbrT/5i50v+YudL/
+ j7PO/4yxzf+Msc3/jLHN/4yxzf+Msc3/jLHN/4yxzf+Msc3/jLHN/4yxzf+Msc3/jLHN/4yxzf+LsMv1
+ jLLMUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj7HPYI2zzvmOtM//
+ k62//7R7T/+6cDf/uXA3/7hvN/+3bzb/tm42/7VtNv+0bTX/qIJk/5CxyP+OtM//jrTP/5G20P+avNT/
+ mbvT/5q81P+avNT/kbbQ/460z/+OtM//jrTP/460z/+OtM//jrTP/460z/+OtM//jrTP/460z/+OtM//
+ jrTP/460z/+OtM/KkLHHFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ j7fPIJC20NeQt9H/krTL/7GFY/+8cjj/u3E4/7pwN/+5cDf/uG83/7dvNv+2bjb/s3I//5yfn/+QttD/
+ kLfR/5O50v+bvtb/mr3V/5u+1v+bvtb/k7nS/5C30f+Qt9H/kLfR/5C30f+Qt9H/kLfR/5C30f+Qt9H/
+ kLfR/5C30f+Qt9H/kLfR/5C20P2PttB+f39/AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAf7+/BJK505KSudP+k7nT/6mWhf++czr/vXI4/7xxOP+7cTj/unA3/7lwN/+4bzf/
+ t242/7B6UP+bp63/k7nS/5W81P+dwdf/m7/W/53B1/+dwdf/lbzU/5K60/+SutP/krrT/5K60/+SutP/
+ krrT/5K60/+SutP/krrT/5K60/+SutP/krrT/5G50ueTvNYyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJK91EKUu9XvlLzV/5+rsf+9eUX/v3M5/75yOf+9cjj/
+ vHE4/7txOP+6cDf/uG83/7dvN/+yeUz/opuS/5u0w/+gv9P/nb/U/5/B1v+gwdb/mLzT/5W60/+VutP/
+ lbrS/5W60v+VutL/lbrS/5W60v+VutL/lbrS/5W60v+VutL/lbrS/5S60a6ZsswKAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJzE1w2WvNZrlb3VgJq1x4G8fk3G
+ wXQ6/8B0Of+/czn/vnI5/71yOP+8cTj/unA3/7lwN/+4bzf/tnA6/7J6Tv+whmT/rYlr/62JbP+siWz/
+ qYdq/6eGav+nhmr/poVp/6WFaf+lhWn/pIRo/6SEaP+jhGj/ooNo/6KDaP+hg2j/oIJn/6B5WLCiXC4L
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAADDdDxEw3U66sJ1Ov/BdDr/wHM5/79zOf+9cjn/vHE4/7txOP+6cDf/uXA3/7hvN/+3bzb/
+ tm42/7VtNv+0bTX/s2w1/7JsNf+xazT/sGo0/69qNP+uaTP/rWkz/6xoM/+raDL/qmcy/6lnMv+oZjH/
+ p2Yx/6ZlMMevXy8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAC2bUgHxHU6hsN1OvrDdTr/wnQ6/8B0Of+/czn/vnI5/71yOP+8cTj/
+ u3E4/7pwN/+5bzf/t282/7ZuNv+1bjb/tG01/7NsNf+ybDX/sWs0/7BrNP+vajT/rmoz/61pM/+saTP/
+ q2gy/6poMv+qZzL/qWcy/6dmMMevXy8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxXM5FsV2O6zEdTr9xHY7/8N1Ov/BdDr/
+ wHQ5/79zOf++czn/vXI4/7xxOP+7cTj/uXA3/7hvN/+3bzf/tm42/7VuNv+0bTX/s2w1/7JsNf+xazT/
+ sGs0/69qNP+uajP/rWkz/6xpM/+raDL/qmgy/6lmMcevby8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMN4PCLGdju0
+ xXY6/MV2O//Ddjv/wnU6/8F0Ov/AdDn/v3M5/75yOf+9cjj/u3E4/7pwN/+5cDf/uG83/7dvNv+2bjb/
+ tW02/7RtNf+zbDX/smw1/7FrNP+wazT/r2o0/65pM/+taTP/rGgz/6tnMcevby8QAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAADFczkfx3c6oMV3O/bFdzv/xHY7/8N1Ov/CdTr/wXQ6/8BzOf++czn/vXI4/7xxOP+7cTj/
+ unA3/7lwN/+4bzf/t242/7ZuNv+1bTb/s201/7JsNf+xbDX/sGs0/69qNP+uajT/rWkz/6xpM8evby8Q
+ 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
+ AAAAAHObuYBslK3/apKr/2qSq/9qkqv/apKr/2qSq/9qkqv/apKr/2qSq/9qkqv/apKr/2qSq/9qkqv/
+ apKr/2qSq/9qkqv/apKr/2qSq/9qkqv/apKr/2qSq/9qkqv/apKr/2qSq/9slK3/c5u5gAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAdZ25gG6WsP9tla7/bZWu/22Vrv9tla7/bZWu/22Vrv9tla7/bZWu/22Vrv9tla7/
+ bZWu/22Vrv9tla7/bZWu/22Vrv9tla7/bZWu/22Vrv9tla7/bZWu/22Vrv9tla7/bZWu/26WsP91nbmA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAB1nbmAcZmz/3CYsf9wmLH/cJix/3CYsf9wmLH/cJix/3CYsf9wmLH/
+ cJix/3CYsf9wmLH/cJix/3CYsf9wmLH/cJix/3CYsf9wmLH/cJix/3CYsf9wmLH/cJix/3CYsf9wmLH/
+ cZmz/3WduYAAAAAAAAAAAAAAAAAAAAAAAAAAAHefu4B0nLX/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/
+ c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/c5u0/3ObtP9zm7T/
+ c5u0/3ObtP90nLX/d5+7gAAAAAAAAAAAAAAAAAAAAAAAAAAAd5+7gHefuf93n7j/d5+4/3efuP93n7j/
+ d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/d5+4/3efuP93n7j/
+ d5+4/3efuP93n7j/d5+4/3efuf93n7uAAAAAAAAAAAAAAAAAAAAAAAAAAAB3n72AeqK7/3qiu/96orv/
+ eqK7/3qhuf9/l6P/e5+1/3qiu/96orv/eqK7/3qiu/96orv/eqK7/3qiu/96orv/eqK7/3qiu/96orv/
+ eqK7/3qiu/96orv/eqK7/3qiu/96orv/eqK7/3efvYAAAAAAAAAAAAAAAAAAAAAAAAAAAHmhvYB8pL7/
+ faW+/32lvv99pLz/h46O/5dqQ/+Lgnb/fqK4/32lvv99pb7/faW+/32lvv99pb7/faW+/32lvv99pb7/
+ faW+/32lvv99pb7/faW+/32lvv99pb7/faW+/32lvv98pL7/eaG9gAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ eaG9gH+nwf+AqMH/gKe//4qQkP+baD7/nWAu/5tjNP+NhHj/gaW7/4Cowf+AqMH/gKjB/4Cowf+AqMH/
+ gKjB/4Cowf+AqMH/gKjB/4Cowf+AqMH/gKjB/4Cowf+AqMH/gKjB/3+nwf95ob2AAAAAAAAAAAAAAAAA
+ AAAAAAAAAAB5ob+AgqrD/4Oqwv+Nk5L/nWo//6BiL/+fYS7/nmEu/5xjNf+Phnr/hKi+/4OrxP+Dq8T/
+ g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/g6vE/4OrxP+Dq8T/gqrD/3mhv4AAAAAA
+ AAAAAAAAAAAAAAAAAAAAAHujv4CEq8T/kJWV/6BsQP+jYzD/omMv/6FiL/+fYi//n2Eu/51kNf+Rh3z/
+ h6vB/4aux/+Grsf/hq7H/4aux/+Grsf/hq7H/4aux/+Grsf/hq7H/4aux/+Grsf/hq7H/4aux/+ErMb/
+ e6O/gAAAAAAAAAAAAAAAAAAAAAAAAAAAe6O/gI+bof+hdE7/pGo7/6VlMf+kZDD/o2Mw/6FjL/+gYi//
+ nmU1/5trQv+RkIr/ia/H/4mxyv+Jscr/ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/ibHK/4mxyv+Jscr/
+ ibHK/4evyP97o8GAAAAAAAAAAAAAAAAAAAAAAAAAAAB9o7+Ajam6/5Gmsf+Vmpr/pWs8/6ZlMf+lZDD/
+ o2Qw/6JjL/+Zgmz/j6Wx/46otv+Mssr/i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/i7PM/4uzzP+Ls8z/
+ i7PM/4uzzP+Ls8z/ibHL/32lwYAAAAAAAAAAAAAAAAAAAAAAAAAAAH2lwYCLs83/jrbP/5Oos/+nbj//
+ qGYx/6dlMf+lZTH/pGQw/5mKe/+Ots//jrbP/5G40f+VutL/lbrS/5G40f+Ots//jrbP/462z/+Ots//
+ jrbP/462z/+Ots//jrbP/462z/+Ls83/faXBgAAAAAAAAAAAAAAAAAAAAAAAAAAAfaXDgI620P+RudL/
+ lqu2/6lvQP+qaDL/qWcy/6hmMf+mZTH/nI18/5G50v+RudL/pMXa/7bR4f+20eH/pMXa/5G50v+RudL/
+ kbnS/5G50v+RudL/kbnS/5G50v+RudL/kbnS/4620P99pcOAAAAAAAAAAAAAAAAAAAAAAAAAAAB/p8OA
+ kLjR/5O71P+Yrbj/rHFB/61pM/+raDL/qmcy/6lnMv+ejn7/k7vU/5O71P+ixdr/sM3g/7DN4P+ixdr/
+ k7vU/5O71P+Tu9T/k7vU/5O71P+Tu9T/k7vU/5O71P+Tu9T/kLjR/3+nw4AAAAAAAAAAAAAAAAAAAAAA
+ AAAAAHyiwH+Grcn/iK/L/4+jsP+tcUH/r2o0/65pM/+saTP/q2gy/5qJev+Ir8v/iK/L/5O30P+evtT/
+ nb7U/5O30P+Ir8v/iK/L/4ivy/+Ir8v/iK/L/4ivy/+Ir8v/iK/L/4ivy/+Grcn/faPBgAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAgqXCWIKmxPiDp8T/jJ2r/69xQf+ybDX/sGs0/69qNP+taTP/mYZ4/4OnxP+Dp8T/
+ jK3J/5W1zv+VtM3/jK3J/4OnxP+Dp8T/g6fE/4OnxP+Dp8T/g6fE/4OnxP+Dp8T/g6fE/4OmxPmCpcNe
+ AAAAAAAAAAAAAAAAAAAAAAAAAACDp8Edh6zI1Iisyf+Qoa//snNC/7VtNv+zbDX/sms1/7BrNP+ci33/
+ iKzJ/4isyf+Pscz/lrfQ/5W2z/+Pscz/iKzJ/4isyf+IrMn/iKzJ/4isyf+IrMn/iKzJ/4isyf+IrMn/
+ h6vH2IenxyAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqqgOKsMuMi7DL/pKmtf+0dkb/t282/7ZuNv+0bTX/
+ s2w1/6KIc/+LsMv/i7DM/5G1z/+YudL/l7nR/5G1z/+LsMz/i7DM/4uwzP+LsMz/i7DM/4uwzP+LsMz/
+ i7DM/4uwzP6Kr8uRf7+/BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI6z0T2Os87uk67B/7R8UP+6cDf/
+ uW83/7dvNv+1bjb/rXpT/5Ktv/+PtdD/lbnT/5q81P+avNX/lbnT/4+10P+PtdD/j7XQ/4+10P+PtdD/
+ j7XQ/4+10P+PtdD/jrTQ74+zz0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkbbaDpC40buTt87/
+ sIlq/71yOP+7cTj/unA3/7hvN/+2cDn/pY98/5S0yv+YvdX/nL/W/53A1/+YvdX/krnT/5K50/+SudP/
+ krnT/5K50/+SudP/krnT/5K50/+RuNK9iLvMDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8B
+ lbzVY5S81d2nnZLkv3Q6/L5zOf+9cjj/u3E4/7lwN/+2cTz/q4hr/6Ompf+jsLf/o7K5/5+vuP+arLb/
+ mqy2/5mstv+ZrLb/mau2/5irtf+Yq7X/l6q0/piosHz/AP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAACZsswKlL3VH6uWgjHBdTrIwXQ6/8BzOf++cjn/vHI4/7pxOP+5cDf/tnE7/7RzQf+zc0H/
+ sXJA/69xQP+ucD//rHA//6tvPv+qbj7/qG0+/6dtPf+mbDz/pWg3i/8AAAEAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAcR1Ok7EdTrqw3U6/8F0Ov+/czn/vXI5/7xxOP+6cDf/
+ uG83/7duNv+1bjb/tG01/7JsNf+xazT/r2o0/65pM/+saTP/q2gy/6lnMv+nZTGP/wAAAQAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzGYzBcV3O2vFdjvtxHY7/8J1Ov/AdDr/
+ v3M5/71yOP+7cTj/unA3/7hvN/+2bjb/tW02/7NsNf+ybDX/sGs0/69qNP+taTP/rGgz/6lnMY//AAAB
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtm1IB8Z3O17GdzvZ
+ xXY7/cN1O//CdTr/wHQ5/75zOf+8cjj/u3E4/7lwN/+4bzf/tm42/7RtNf+zbDX/sWs0/7BrNP+uajP/
+ rGkzj/8AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ /39/AsVzOSzGdzuNxnc718R2O/XCdDr9wXQ6/r9zOf+9cjn/vHE4/7pxOP+5cDf/t282/7ZuNv+0bTX/
+ smw1/7FrNP+uaTOP/wAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAL9/PwTMdzsexng8SMV1OWrCdTl3wXQ5eL5yN3u+cjh/u3E3gLlvN4C3bzWA
+ t201gLVtNYC0bDZ/sms1e7JqNUP/AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAfAAAAH
+ wAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAHwAAAB8AAAAfAAAAH
+ wAAAB8AAAAfAAAAHwAAAB+AAAA/gAAAP4AAAD/AAAA/8AAAP/gAAD/8AAA//gAAP/+AAD/////8oAAAA
+ EAAAACAAAAABACAAAAAAAEAEAAAAAAAAAAAAAAAAAAAAAAAAf3//AnObuTNxmLRIcZi0SHGYtEhxmLRI
+ cZi0SHGYtEhxmLRIcZi0SHGYtEhxmLRIcZi0SHKbtUVymb8UAAAAAH+fvwhul7KxapKr92qSq/dqkqv3
+ apKr92qSq/dqkqv3apKr92qSq/dqkqv3apKr92qSq/drlK3vcJi2RgAAAAB/n78Icpq1t2+XsP9vl7D/
+ b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew/2+XsP9vl7D/b5ew93SbuEgAAAAAf5+/CHaeubd1nbb/
+ dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wdtv91nbb/dZ22/3Wctvd0n7hIAAAAAH+fvwh6o723
+ e6O8/4CZqP+Gioj/fKC2/3ujvP97o7z/e6O8/3ujvP97o7z/e6O8/3ujvP96o7v3eJ+7SAAAAAB/n78I
+ fqfBt4afrf+XdFb/nGQ1/46EeP+Cprz/ganC/4Gpwv+BqcL/ganC/4Gpwv+BqcL/gKjC93uiv0gAAAAA
+ f5+/CIehs7eaf2f/o2Uy/6FiL/+dZzn/kI+K/4euxv+Hr8j/h6/I/4evyP+Hr8j/h6/I/4atx/d/psJI
+ AAAAAH+fvwiIq8C3lKCk/6VtP/+lZTD/nnZU/5Cptv+Rt87/kbjQ/421zv+Ntc7/jbXO/421zv+Lssz3
+ f6nCSAAAAAB/n78IibLMt5Wtuv+pcUP/qWcy/6F8Xf+Tt83/p8fb/6fH2/+SutP/kbnS/5G50v+RudL/
+ jrbQ94OpxkgAAAAAf6qqBoSrx6qNorL/rXJD/65qM/+ie1v/iKrD/5W2z/+Vts//h6zI/4asyP+GrMj/
+ hqzI/4Wrx/OBqcY/AAAAAAAAAACJrclkj6W0+rF1Rv+0bTX/p3xb/4yrxP+Ttc//k7XP/4muyv+Jrsr/
+ ia7K/4muyv+JrcrMhabHFwAAAAAAAAAAjrTSIpOuwdu0flT/uXA3/7J1Rf+ZpKr/mLvS/5i81P+Qt9H/
+ kLfR/5C30f+QttD9jrTQf39/fwIAAAAAAAAAAH+/vwSWuM5atoRcs75yOP27cTj/tHpN/6yOdf+pkn3/
+ pI57/6KNev+hjXr/n4t4+J2JdUwAAAAAAAAAAAAAAAAAAAAAAAAAAMN4PCLDdTrBwHQ5/r5yOf+7cTj/
+ t282/7RtNf+xazT/rmoz/6toMvmpaDFOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyXg8JsV3OpzDdDrj
+ wHQ59LxyN/a5bzb3tm4197NsNPevajPxrWkySwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADakUgH
+ xXI5KMR1OkHAcjtFu3E4SLhtNUi0bTVIsWszRbZtMBUAAAAAAAAAAAABJgAAASYAAAEmAAABJgAAASYA
+ AAEmAAABJgAAASYAAAEmAAABJgCAASYAgAEmAIADJgDgAyYA8AMmAPgDJgA=
+
+
+
\ No newline at end of file
diff --git a/Pilz.Updating.Updater/UpdateInstaller.vb b/Pilz.Updating.Updater/UpdateInstaller.vb
new file mode 100644
index 0000000..6daede9
--- /dev/null
+++ b/Pilz.Updating.Updater/UpdateInstaller.vb
@@ -0,0 +1,115 @@
+Imports System.IO
+Imports Newtonsoft.Json.Linq
+Imports Pilz.Updating.Model
+Imports Pilz.Updating.Scripts
+
+Public Class UpdateInstaller
+
+ Private restartHostApplication As Boolean
+ Private autoCloseHostApplication As Boolean
+ Private packageDir As String
+ Private appExePath As String
+
+ Private Sub UpdateInstaller_Shown(sender As Object, e As EventArgs) Handles Me.Shown
+ CheckCommandLines()
+
+ If autoCloseHostApplication Then
+ CloseHostApplication()
+ End If
+
+ InstallUpdates()
+
+ If restartHostApplication Then
+ StartHostApplication()
+ End If
+ End Sub
+
+ Private Sub CloseHostApplication()
+ Dim myProcesses As New List(Of Process)
+
+ For Each p As Process In Process.GetProcesses
+ If p.MainModule.FileName = appExePath Then
+ myProcesses.Add(p)
+ End If
+ Next
+
+ For Each p As Process In myProcesses
+ p.Close()
+ Next
+
+ Dim waited As Byte = 5
+ Do While myProcesses.Where(Function(n) Not n.HasExited).Any AndAlso waited > 0
+ Sleep(1000)
+ waited -= 1
+ Loop
+
+ For Each p As Process In myProcesses
+ If Not p.HasExited Then
+ p.Kill()
+ End If
+ Next
+ End Sub
+
+ Private Sub StartHostApplication()
+ Process.Start(appExePath)
+ End Sub
+
+ Private Sub CheckCommandLines()
+ For Each cmd As String In My.Application.CommandLineArgs
+ Dim splitted As String() = cmd.Split("#")
+
+ If splitted.Length = 2 Then
+ Select Case splitted(0).ToLower
+ Case "restartHostApp".ToLower
+ restartHostApplication = splitted(1)
+ Case "autoCloseHostApp".ToLower
+ autoCloseHostApplication = splitted(1)
+ Case "updatePackage".ToLower
+ packageDir = splitted(1)
+ Case "applicationPath"
+ appExePath = splitted(1)
+ End Select
+ End If
+ Next
+ End Sub
+
+ Private Sub InstallUpdates()
+ Dim packagePath As String = Path.Combine(packageDir, "package.json")
+ Dim packageFilesDir As String = Path.Combine(packageDir, "files")
+ Dim systemFilesDir As String = Path.GetDirectoryName(appExePath)
+
+ 'Load update package
+ Dim package As UpdatePackage = JObject.Parse(File.ReadAllText(packagePath)).ToObject(Of UpdatePackage)
+
+ 'Execute ScriptBefore
+ ExecuteScriptsWithPriority(ScriptPriority.Before, package.Scripts, systemFilesDir, packageFilesDir)
+
+ 'Update Files
+ For Each rFile As String In package.Fileupdates
+ Dim packageFile As String = Path.Combine(packageFilesDir, rFile)
+ Dim systemFile As String = Path.Combine(systemFilesDir, rFile)
+ Dim systemFileDir As String = Path.GetDirectoryName(systemFile)
+
+ 'Create destination directory if not exists
+ If Not Directory.Exists(systemFileDir) Then
+ Directory.CreateDirectory(systemFileDir)
+ End If
+
+ 'Copy package file to system file
+ File.Copy(packageFile, systemFile, True)
+ Next
+
+ 'ExecuteScriptAfter
+ ExecuteScriptsWithPriority(ScriptPriority.After, package.Scripts, systemFilesDir, packageFilesDir)
+ End Sub
+
+ Private Sub ExecuteScriptsWithPriority(priority As ScriptPriority, scripts As IEnumerable(Of Script), applicationPath As String, updatePackagePath As String)
+ For Each script As Script In scripts
+ If script.Priority = priority Then
+ Dim mgr As New ScriptManager(applicationPath, updatePackagePath)
+ mgr.ExecuteScript(script)
+ End If
+ Next
+ End Sub
+
+End Class
diff --git a/Pilz.Updating.Updater/packages.config b/Pilz.Updating.Updater/packages.config
new file mode 100644
index 0000000..93b0be8
--- /dev/null
+++ b/Pilz.Updating.Updater/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Updating/General.vb b/Pilz.Updating/General.vb
new file mode 100644
index 0000000..822d1ef
--- /dev/null
+++ b/Pilz.Updating/General.vb
@@ -0,0 +1,21 @@
+Imports System.IO
+
+Public Module General
+
+ Public ReadOnly Property MyTempPath As String
+ Get
+ Static p As String = String.Empty
+
+ If String.IsNullOrEmpty(p) Then
+ p = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Pilz.Updating")
+
+ If Not Directory.Exists(p) Then
+ Directory.CreateDirectory(p)
+ End If
+ End If
+
+ Return p
+ End Get
+ End Property
+
+End Module
diff --git a/Pilz.Updating/Model/BuildState.vb b/Pilz.Updating/Model/BuildState.vb
new file mode 100644
index 0000000..60a6871
--- /dev/null
+++ b/Pilz.Updating/Model/BuildState.vb
@@ -0,0 +1,10 @@
+Namespace Model
+
+ Public Enum BuildState
+ Release
+ ReleaseCandidate
+ Beta
+ Alpha
+ End Enum
+
+End Namespace
diff --git a/Pilz.Updating/Model/CodeLanguage.vb b/Pilz.Updating/Model/CodeLanguage.vb
new file mode 100644
index 0000000..66a1911
--- /dev/null
+++ b/Pilz.Updating/Model/CodeLanguage.vb
@@ -0,0 +1,8 @@
+Namespace Model
+
+ Public Enum CodeLanguage
+ VB
+ CSharp
+ End Enum
+
+End Namespace
diff --git a/Pilz.Updating/Model/UpdateInfo.vb b/Pilz.Updating/Model/UpdateInfo.vb
new file mode 100644
index 0000000..ffbcc9f
--- /dev/null
+++ b/Pilz.Updating/Model/UpdateInfo.vb
@@ -0,0 +1,13 @@
+Namespace Model
+
+ Public Class UpdateInfo
+
+ Public Property Name As String
+ Public Property Version As Version
+ Public Property State As BuildState
+ Public Property Build As UInteger
+ Public Property Changelog As String
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Updating/Model/UpdatePackage.vb b/Pilz.Updating/Model/UpdatePackage.vb
new file mode 100644
index 0000000..5978157
--- /dev/null
+++ b/Pilz.Updating/Model/UpdatePackage.vb
@@ -0,0 +1,12 @@
+Imports Pilz.Updating.Scripts
+
+Namespace Model
+
+ Public Class UpdatePackage
+
+ Public ReadOnly Property Fileupdates As New List(Of String)
+ Public ReadOnly Property Scripts As New List(Of Script)
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Updating/My Project/Application.Designer.vb b/Pilz.Updating/My Project/Application.Designer.vb
new file mode 100644
index 0000000..88dd01c
--- /dev/null
+++ b/Pilz.Updating/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/Pilz.Updating/My Project/Application.myapp b/Pilz.Updating/My Project/Application.myapp
new file mode 100644
index 0000000..758895d
--- /dev/null
+++ b/Pilz.Updating/My Project/Application.myapp
@@ -0,0 +1,10 @@
+
+
+ false
+ false
+ 0
+ true
+ 0
+ 1
+ true
+
diff --git a/Pilz.Updating/My Project/AssemblyInfo.vb b/Pilz.Updating/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..8941d19
--- /dev/null
+++ b/Pilz.Updating/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' Allgemeine Informationen über eine Assembly werden über die folgenden
+' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+' die einer Assembly zugeordnet sind.
+
+' Werte der Assemblyattribute überprüfen
+
+
+
+
+
+
+
+
+
+
+'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
+
+
+' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+'
+' Hauptversion
+' Nebenversion
+' Buildnummer
+' Revision
+'
+' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+' übernehmen, indem Sie "*" eingeben:
+'
+
+
+
diff --git a/Pilz.Updating/My Project/Resources.Designer.vb b/Pilz.Updating/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..af39fa0
--- /dev/null
+++ b/Pilz.Updating/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.Updating.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set(ByVal value As Global.System.Globalization.CultureInfo)
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Updating/My Project/Resources.resx b/Pilz.Updating/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Pilz.Updating/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pilz.Updating/My Project/Settings.Designer.vb b/Pilz.Updating/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..b7968de
--- /dev/null
+++ b/Pilz.Updating/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
+
+#Region "My.Settings Auto-Save Functionality"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.Pilz.Updating.My.MySettings
+ Get
+ Return Global.Pilz.Updating.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Updating/My Project/Settings.settings b/Pilz.Updating/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/Pilz.Updating/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Pilz.Updating/MyEventArgs/UpdatesFoundEventArgs.vb b/Pilz.Updating/MyEventArgs/UpdatesFoundEventArgs.vb
new file mode 100644
index 0000000..e3e33c0
--- /dev/null
+++ b/Pilz.Updating/MyEventArgs/UpdatesFoundEventArgs.vb
@@ -0,0 +1,17 @@
+Imports Pilz.Updating.Model
+
+Namespace MyEventArgs
+
+ Public Class UpdatesFoundEventArgs
+ Inherits EventArgs
+
+ Public Property Cancel As Boolean = False
+ Public Property Updates As UpdateInfo()
+
+ Public Sub New(updates As UpdateInfo())
+ Me.Updates = updates
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Updating/Pilz.Updating.vbproj b/Pilz.Updating/Pilz.Updating.vbproj
new file mode 100644
index 0000000..d024abb
--- /dev/null
+++ b/Pilz.Updating/Pilz.Updating.vbproj
@@ -0,0 +1,119 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}
+ Library
+ Pilz.Updating
+ Pilz.Updating
+ 512
+ Windows
+ v4.5
+ true
+
+
+ true
+ full
+ true
+ true
+ bin\Debug\
+ Pilz.Updating.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ Pilz.Updating.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Updating/Scripts/Script.vb b/Pilz.Updating/Scripts/Script.vb
new file mode 100644
index 0000000..a7f7ae9
--- /dev/null
+++ b/Pilz.Updating/Scripts/Script.vb
@@ -0,0 +1,13 @@
+Imports Pilz.Updating.Model
+
+Namespace Scripts
+
+ Public Class Script
+
+ Public Property Priority As ScriptPriority = ScriptPriority.Before
+ Public Property Language As CodeLanguage = CodeLanguage.CSharp
+ Public Property Code As String
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Updating/Scripts/ScriptManager.vb b/Pilz.Updating/Scripts/ScriptManager.vb
new file mode 100644
index 0000000..325e310
--- /dev/null
+++ b/Pilz.Updating/Scripts/ScriptManager.vb
@@ -0,0 +1,71 @@
+Imports System.CodeDom.Compiler
+Imports System.Reflection
+Imports Microsoft.CSharp
+Imports Pilz.Updating.Model
+Imports Pilz.Updating.Scripts
+
+Namespace Scripts
+
+ Public Class ScriptManager
+
+ Public Property ApplicationPath As String
+ Public Property UpdatePackagePath As String
+
+ Public Sub New(applicationPath As String, updatePackagePath As String)
+ Me.ApplicationPath = applicationPath
+ Me.UpdatePackagePath = updatePackagePath
+ End Sub
+
+ Private Function CompileScript(script As Script) As CompilerResults
+ Dim provider As CodeDomProvider = Nothing
+ Dim params As New CompilerParameters
+
+ 'Create code provider
+ Select Case script.Language
+ Case CodeLanguage.CSharp
+ provider = New CSharpCodeProvider
+ Case CodeLanguage.VB
+ provider = New VBCodeProvider
+ End Select
+
+ 'Set general options
+ params.GenerateExecutable = False
+ params.GenerateInMemory = True
+
+ 'Set references
+ params.ReferencedAssemblies.Add()
+
+ 'Compile
+ Dim res As CompilerResults = provider.CompileAssemblyFromSource(params, script.Code)
+
+ Return res
+ End Function
+
+ Public Function CheckScriptForErrors(script As Script) As CompilerErrorCollection
+ Return CompileScript(script).Errors
+ End Function
+
+ Public Sub ExecuteScript(script As Script)
+ 'Compile script
+ Dim res As CompilerResults = CompileScript(script)
+
+ If Not res.Errors.HasErrors Then
+ 'Get Method
+ Dim mi As MethodInfo = res.CompiledAssembly.GetType("Program")?.GetMethod("Main")
+
+ If mi IsNot Nothing Then
+ 'Create params
+ Dim params As New Dictionary(Of String, String) From {
+ {"ApplicationPath", ApplicationPath},
+ {"UpdatePackagePath", UpdatePackagePath}
+ }
+
+ 'Execute method
+ mi.Invoke(Nothing, {params})
+ End If
+ End If
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Updating/Scripts/ScriptPriority.vb b/Pilz.Updating/Scripts/ScriptPriority.vb
new file mode 100644
index 0000000..f2835a5
--- /dev/null
+++ b/Pilz.Updating/Scripts/ScriptPriority.vb
@@ -0,0 +1,8 @@
+Namespace Scripts
+
+ Public Enum ScriptPriority
+ Before
+ After
+ End Enum
+
+End Namespace
diff --git a/Pilz.Updating/UpdateManager b/Pilz.Updating/UpdateManager
new file mode 100644
index 0000000..875798b
--- /dev/null
+++ b/Pilz.Updating/UpdateManager
@@ -0,0 +1,3 @@
+Public Class Class1
+
+End Class
diff --git a/Pilz.Updating/Updater.vb b/Pilz.Updating/Updater.vb
new file mode 100644
index 0000000..fbd27df
--- /dev/null
+++ b/Pilz.Updating/Updater.vb
@@ -0,0 +1,86 @@
+Imports System.IO
+Imports System.IO.Compression
+Imports System.Net
+Imports System.Reflection
+Imports Newtonsoft.Json.Linq
+Imports Pilz.Updating.Model
+Imports Pilz.Updating.MyEventArgs
+
+Public Class Updater
+
+ Public Event UpdatesFound(sender As Object, e As UpdatesFoundEventArgs)
+ Public Event NoUpdatesFound(sender As Object, e As EventArgs)
+ Public Event UpdateInstallerStarted(Sender As Object, e As EventArgs)
+
+ Public Property InstallAsAdmin As Boolean = True
+ Public Property RestartHostApplication As Boolean = True
+ Public Property AutomaticlyCloseHostApplication As Boolean = True
+ Public Property UpdateDirURL As String
+ Public Property UpdateInfoURL As String
+
+ Public Sub New(updateUrl As String)
+ UpdateInfoURL = updateUrl
+ UpdateDirURL = updateUrl.Remove(updateUrl.LastIndexOf("/"c))
+ End Sub
+
+ Public Async Function Update() As Task
+ Dim wc As New WebClient
+ Dim updateInstallerZipPath As String = Path.Combine(MyTempPath, "Pilz.Updating.UpdateInstaller.zip")
+ Dim updateInstallerPath As String = updateInstallerZipPath & "_unpacked"
+ Dim updateInstallerExePath As String = Path.Combine(updateInstallerPath, "Pilz.Updating.UpdateInstaller.exe")
+
+ 'Clean AppData
+ For Each dir As String In Directory.GetDirectories(MyTempPath, "*", SearchOption.TopDirectoryOnly)
+ Directory.Delete(dir, True)
+ Next
+
+ 'Download UpdateInfos
+ Dim strUpdateInfos As String = Await wc.DownloadStringTaskAsync(UpdateInfoURL)
+ Dim updateInfos As UpdateInfo() = JArray.Parse(strUpdateInfos).ToObject(Of UpdateInfo())
+
+ If updateInfos.Any Then
+ 'Order update infos from newest to oldest
+ updateInfos = updateInfos.OrderByDescending(
+ Function(n)
+ Return n.Version.ToString &
+ (Byte.MaxValue - n.State).ToString("X2") &
+ n.Build.ToString("X4")
+ End Function).ToArray
+
+ 'Interagate with user
+ Dim e As New UpdatesFoundEventArgs(updateInfos)
+ RaiseEvent UpdatesFound(Me, e)
+
+ 'Install updates
+ If Not e.Cancel Then
+ Dim updateInfo As UpdateInfo = updateInfos(0)
+ Dim updatePackageZipFilename As String = $"{updateInfo.Version.ToString} {CByte(updateInfo.State)} {updateInfo.Build}.zip"
+ Dim updatePackageZipPath As String = Path.Combine(MyTempPath, updatePackageZipFilename)
+ Dim updatePackagePath As String = updatePackageZipPath & "_unpacked"
+
+ 'Download UpdateInstaller
+ Await wc.DownloadFileTaskAsync(UpdateDirURL & "/Pilz.Updating.UpdateInstaller.zip", updateInstallerZipPath)
+ ZipFile.ExtractToDirectory(updateInstallerZipPath, updateInstallerPath)
+
+ 'Download Update Package
+ Await wc.DownloadFileTaskAsync(UpdateDirURL & "/" & updatePackageZipFilename, updatePackageZipPath)
+ ZipFile.ExtractToDirectory(updatePackageZipFilename, updatePackagePath)
+
+ 'Build process arguments
+ Dim applicationExePath As String = Assembly.GetExecutingAssembly.Location
+ Dim procArgs As String = $"restartHostApp#{RestartHostApplication} autoCloseHostApp#{AutomaticlyCloseHostApplication} ""updatePackage#{updatePackagePath}"" ""applicationPath#{applicationExePath}"""
+
+ 'Finally start update installer to install updates
+ Process.Start(updateInstallerExePath, procArgs)
+
+ 'Interagate with user
+ RaiseEvent UpdateInstallerStarted(Me, New EventArgs)
+ End If
+ Else
+ RaiseEvent NoUpdatesFound(Me, New EventArgs)
+ End If
+
+ wc.Dispose()
+ End Function
+
+End Class
diff --git a/Pilz.Updating/packages.config b/Pilz.Updating/packages.config
new file mode 100644
index 0000000..93b0be8
--- /dev/null
+++ b/Pilz.Updating/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.sln b/Pilz.sln
index aba4084..c7094ce 100644
--- a/Pilz.sln
+++ b/Pilz.sln
@@ -29,6 +29,12 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Simple3DFileParser", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pilz.LicenseHelper", "Pilz.LicenseHelper\Pilz.LicenseHelper.csproj", "{67593FF7-C1D1-4529-98C4-61CBD0615F08}"
EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Updating", "Pilz.Updating\Pilz.Updating.vbproj", "{354255D9-9536-4400-B915-FFC49C2CE93F}"
+EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Updating.UpdateInstaller", "Pilz.Updating.Updater\Pilz.Updating.UpdateInstaller.vbproj", "{1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}"
+EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Networking", "Pilz.Networking\Pilz.Networking.vbproj", "{4584B121-09C6-40AC-849B-7E410125EF66}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -141,6 +147,30 @@ Global
{67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|Any CPU.Build.0 = Release|Any CPU
{67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|x86.ActiveCfg = Release|Any CPU
{67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|x86.Build.0 = Release|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Debug|x86.Build.0 = Debug|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Release|x86.ActiveCfg = Release|Any CPU
+ {354255D9-9536-4400-B915-FFC49C2CE93F}.Release|x86.Build.0 = Release|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Debug|x86.Build.0 = Debug|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Release|x86.ActiveCfg = Release|Any CPU
+ {1BA3D8E8-C514-4182-9E6E-9E6BB7AF0403}.Release|x86.Build.0 = Release|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Debug|x86.Build.0 = Debug|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Release|x86.ActiveCfg = Release|Any CPU
+ {4584B121-09C6-40AC-849B-7E410125EF66}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Pilz/HelpfulFunctions.vb b/Pilz/HelpfulFunctions.vb
new file mode 100644
index 0000000..1418dd3
--- /dev/null
+++ b/Pilz/HelpfulFunctions.vb
@@ -0,0 +1,17 @@
+Imports System.Windows.Forms
+
+Public Module HelpfulFunctions
+
+ Public Sub Sleep(milliseconds As Integer)
+ Dim stopw As New Stopwatch
+
+ stopw.Start()
+
+ Do While stopw.ElapsedMilliseconds < milliseconds
+ Application.DoEvents()
+ Loop
+
+ stopw.Stop()
+ End Sub
+
+End Module
diff --git a/Pilz/Pilz.vbproj b/Pilz/Pilz.vbproj
index d0f8cda..91edc17 100644
--- a/Pilz/Pilz.vbproj
+++ b/Pilz/Pilz.vbproj
@@ -46,6 +46,7 @@
+
@@ -64,6 +65,7 @@
+
True
diff --git a/Shared Libs/AssimpNet.dll b/Shared Libs/AssimpNet.dll
new file mode 100644
index 0000000..e20102a
Binary files /dev/null and b/Shared Libs/AssimpNet.dll differ
diff --git a/Shared Libs/ColladaSchema.dll b/Shared Libs/ColladaSchema.dll
new file mode 100644
index 0000000..f367603
Binary files /dev/null and b/Shared Libs/ColladaSchema.dll differ