diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fd5204b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,183 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Roslyn cache directories
+*.ide/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding addin-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# If using the old MSBuild-Integrated Package Restore, uncomment this:
+#!**/packages/repositories.config
+
+# Windows Azure Build Output
+csx/
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
diff --git a/App/MiteDesk.WinForms/Activities.Designer.cs b/App/MiteDesk.WinForms/Activities.Designer.cs
new file mode 100644
index 0000000..deda871
--- /dev/null
+++ b/App/MiteDesk.WinForms/Activities.Designer.cs
@@ -0,0 +1,321 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class Activities
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.TabCustomers = new System.Windows.Forms.TabControl();
+ this.ActiveActivitiesTabPage = new System.Windows.Forms.TabPage();
+ this.ActivActivitiesTree = new System.Windows.Forms.TreeView();
+ this.TreeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.ArchivedCustomersTabPage = new System.Windows.Forms.TabPage();
+ this.ArchivedActivitiesTree = new System.Windows.Forms.TreeView();
+ this.FormGroup = new System.Windows.Forms.GroupBox();
+ this.BoxHourlyRate = new System.Windows.Forms.TextBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.CheckBoxBillable = new System.Windows.Forms.CheckBox();
+ this.CheckBoxArchived = new System.Windows.Forms.CheckBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.BoxNote = new System.Windows.Forms.TextBox();
+ this.BoxName = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.BtnNewActivity = new System.Windows.Forms.Button();
+ this.BtnCancel = new System.Windows.Forms.Button();
+ this.BtnSave = new System.Windows.Forms.Button();
+ this.ErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+ this.TreeDataBackgroundWorker = new System.ComponentModel.BackgroundWorker();
+ this.TabCustomers.SuspendLayout();
+ this.ActiveActivitiesTabPage.SuspendLayout();
+ this.TreeContextMenu.SuspendLayout();
+ this.ArchivedCustomersTabPage.SuspendLayout();
+ this.FormGroup.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).BeginInit();
+ this.SuspendLayout();
+ //
+ // TabCustomers
+ //
+ this.TabCustomers.Controls.Add(this.ActiveActivitiesTabPage);
+ this.TabCustomers.Controls.Add(this.ArchivedCustomersTabPage);
+ this.TabCustomers.Location = new System.Drawing.Point(9, 9);
+ this.TabCustomers.Name = "TabCustomers";
+ this.TabCustomers.SelectedIndex = 0;
+ this.TabCustomers.Size = new System.Drawing.Size(189, 277);
+ this.TabCustomers.TabIndex = 10;
+ //
+ // ActiveActivitiesTabPage
+ //
+ this.ActiveActivitiesTabPage.Controls.Add(this.ActivActivitiesTree);
+ this.ActiveActivitiesTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ActiveActivitiesTabPage.Name = "ActiveActivitiesTabPage";
+ this.ActiveActivitiesTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ActiveActivitiesTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ActiveActivitiesTabPage.TabIndex = 0;
+ this.ActiveActivitiesTabPage.Text = "Aktive";
+ this.ActiveActivitiesTabPage.UseVisualStyleBackColor = true;
+ //
+ // ActivActivitiesTree
+ //
+ this.ActivActivitiesTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ActivActivitiesTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ActivActivitiesTree.FullRowSelect = true;
+ this.ActivActivitiesTree.HideSelection = false;
+ this.ActivActivitiesTree.Location = new System.Drawing.Point(3, 3);
+ this.ActivActivitiesTree.Name = "ActivActivitiesTree";
+ this.ActivActivitiesTree.ShowLines = false;
+ this.ActivActivitiesTree.ShowPlusMinus = false;
+ this.ActivActivitiesTree.ShowRootLines = false;
+ this.ActivActivitiesTree.Size = new System.Drawing.Size(175, 245);
+ this.ActivActivitiesTree.TabIndex = 2;
+ //
+ // TreeContextMenu
+ //
+ this.TreeContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.DeleteToolStripMenuItem});
+ this.TreeContextMenu.Name = "TreeContextMenu";
+ this.TreeContextMenu.Size = new System.Drawing.Size(119, 26);
+ //
+ // DeleteToolStripMenuItem
+ //
+ this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
+ this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(118, 22);
+ this.DeleteToolStripMenuItem.Text = "Löschen";
+ this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click);
+ //
+ // ArchivedCustomersTabPage
+ //
+ this.ArchivedCustomersTabPage.Controls.Add(this.ArchivedActivitiesTree);
+ this.ArchivedCustomersTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ArchivedCustomersTabPage.Name = "ArchivedCustomersTabPage";
+ this.ArchivedCustomersTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ArchivedCustomersTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ArchivedCustomersTabPage.TabIndex = 1;
+ this.ArchivedCustomersTabPage.Text = "Archivierte";
+ this.ArchivedCustomersTabPage.UseVisualStyleBackColor = true;
+ //
+ // ArchivedActivitiesTree
+ //
+ this.ArchivedActivitiesTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ArchivedActivitiesTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ArchivedActivitiesTree.FullRowSelect = true;
+ this.ArchivedActivitiesTree.HideSelection = false;
+ this.ArchivedActivitiesTree.Location = new System.Drawing.Point(3, 3);
+ this.ArchivedActivitiesTree.Name = "ArchivedActivitiesTree";
+ this.ArchivedActivitiesTree.ShowLines = false;
+ this.ArchivedActivitiesTree.ShowPlusMinus = false;
+ this.ArchivedActivitiesTree.ShowRootLines = false;
+ this.ArchivedActivitiesTree.Size = new System.Drawing.Size(175, 245);
+ this.ArchivedActivitiesTree.TabIndex = 1;
+ //
+ // FormGroup
+ //
+ this.FormGroup.Controls.Add(this.BoxHourlyRate);
+ this.FormGroup.Controls.Add(this.label3);
+ this.FormGroup.Controls.Add(this.CheckBoxBillable);
+ this.FormGroup.Controls.Add(this.CheckBoxArchived);
+ this.FormGroup.Controls.Add(this.label2);
+ this.FormGroup.Controls.Add(this.BoxNote);
+ this.FormGroup.Controls.Add(this.BoxName);
+ this.FormGroup.Controls.Add(this.label1);
+ this.FormGroup.Enabled = false;
+ this.FormGroup.Location = new System.Drawing.Point(215, 10);
+ this.FormGroup.Name = "FormGroup";
+ this.FormGroup.Size = new System.Drawing.Size(313, 276);
+ this.FormGroup.TabIndex = 11;
+ this.FormGroup.TabStop = false;
+ //
+ // BoxHourlyRate
+ //
+ this.BoxHourlyRate.Location = new System.Drawing.Point(10, 175);
+ this.BoxHourlyRate.Name = "BoxHourlyRate";
+ this.BoxHourlyRate.Size = new System.Drawing.Size(43, 20);
+ this.BoxHourlyRate.TabIndex = 5;
+ this.BoxHourlyRate.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(7, 159);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(86, 13);
+ this.label3.TabIndex = 7;
+ this.label3.Text = "Stundensatz in €";
+ //
+ // CheckBoxBillable
+ //
+ this.CheckBoxBillable.AutoSize = true;
+ this.CheckBoxBillable.Location = new System.Drawing.Point(89, 177);
+ this.CheckBoxBillable.Name = "CheckBoxBillable";
+ this.CheckBoxBillable.Size = new System.Drawing.Size(96, 17);
+ this.CheckBoxBillable.TabIndex = 6;
+ this.CheckBoxBillable.Text = "Verrechenbar?";
+ this.CheckBoxBillable.UseVisualStyleBackColor = true;
+ this.CheckBoxBillable.CheckedChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // CheckBoxArchived
+ //
+ this.CheckBoxArchived.AutoSize = true;
+ this.CheckBoxArchived.Location = new System.Drawing.Point(216, 177);
+ this.CheckBoxArchived.Name = "CheckBoxArchived";
+ this.CheckBoxArchived.Size = new System.Drawing.Size(70, 17);
+ this.CheckBoxArchived.TabIndex = 7;
+ this.CheckBoxArchived.Text = "Archiviert";
+ this.CheckBoxArchived.UseVisualStyleBackColor = true;
+ this.CheckBoxArchived.CheckedChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(7, 63);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(61, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Bemerkung";
+ //
+ // BoxNote
+ //
+ this.BoxNote.Location = new System.Drawing.Point(10, 79);
+ this.BoxNote.Multiline = true;
+ this.BoxNote.Name = "BoxNote";
+ this.BoxNote.Size = new System.Drawing.Size(276, 75);
+ this.BoxNote.TabIndex = 4;
+ this.BoxNote.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // BoxName
+ //
+ this.BoxName.Location = new System.Drawing.Point(10, 37);
+ this.BoxName.Name = "BoxName";
+ this.BoxName.Size = new System.Drawing.Size(276, 20);
+ this.BoxName.TabIndex = 3;
+ this.BoxName.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(7, 20);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(35, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Name";
+ //
+ // BtnNewActivity
+ //
+ this.BtnNewActivity.Location = new System.Drawing.Point(10, 296);
+ this.BtnNewActivity.Name = "BtnNewActivity";
+ this.BtnNewActivity.Size = new System.Drawing.Size(87, 23);
+ this.BtnNewActivity.TabIndex = 11;
+ this.BtnNewActivity.Text = "Neue Leistung";
+ this.BtnNewActivity.UseVisualStyleBackColor = true;
+ this.BtnNewActivity.Click += new System.EventHandler(this.BtnNewActivity_Click);
+ //
+ // BtnCancel
+ //
+ this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.BtnCancel.Location = new System.Drawing.Point(445, 296);
+ this.BtnCancel.Name = "BtnCancel";
+ this.BtnCancel.Size = new System.Drawing.Size(83, 23);
+ this.BtnCancel.TabIndex = 9;
+ this.BtnCancel.Text = "Schließen";
+ this.BtnCancel.UseVisualStyleBackColor = true;
+ this.BtnCancel.Click += new System.EventHandler(this.BtnCancel_Click);
+ //
+ // BtnSave
+ //
+ this.BtnSave.Enabled = false;
+ this.BtnSave.Location = new System.Drawing.Point(356, 296);
+ this.BtnSave.Name = "BtnSave";
+ this.BtnSave.Size = new System.Drawing.Size(83, 23);
+ this.BtnSave.TabIndex = 8;
+ this.BtnSave.Text = "Übernehmen";
+ this.BtnSave.UseVisualStyleBackColor = true;
+ this.BtnSave.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // ErrorProvider
+ //
+ this.ErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+ this.ErrorProvider.ContainerControl = this;
+ //
+ // Activities
+ //
+ this.AcceptButton = this.BtnSave;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.BtnCancel;
+ this.ClientSize = new System.Drawing.Size(537, 327);
+ this.Controls.Add(this.TabCustomers);
+ this.Controls.Add(this.FormGroup);
+ this.Controls.Add(this.BtnNewActivity);
+ this.Controls.Add(this.BtnCancel);
+ this.Controls.Add(this.BtnSave);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MaximumSize = new System.Drawing.Size(553, 365);
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(553, 365);
+ this.Name = "Activities";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Leistungen";
+ this.TabCustomers.ResumeLayout(false);
+ this.ActiveActivitiesTabPage.ResumeLayout(false);
+ this.TreeContextMenu.ResumeLayout(false);
+ this.ArchivedCustomersTabPage.ResumeLayout(false);
+ this.FormGroup.ResumeLayout(false);
+ this.FormGroup.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TabControl TabCustomers;
+ private System.Windows.Forms.TabPage ActiveActivitiesTabPage;
+ private System.Windows.Forms.TreeView ActivActivitiesTree;
+ private System.Windows.Forms.TabPage ArchivedCustomersTabPage;
+ private System.Windows.Forms.TreeView ArchivedActivitiesTree;
+ private System.Windows.Forms.GroupBox FormGroup;
+ private System.Windows.Forms.CheckBox CheckBoxArchived;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox BoxNote;
+ private System.Windows.Forms.TextBox BoxName;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Button BtnNewActivity;
+ private System.Windows.Forms.Button BtnCancel;
+ private System.Windows.Forms.Button BtnSave;
+ private System.Windows.Forms.ContextMenuStrip TreeContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
+ private System.Windows.Forms.ErrorProvider ErrorProvider;
+ private System.ComponentModel.BackgroundWorker TreeDataBackgroundWorker;
+ private System.Windows.Forms.TextBox BoxHourlyRate;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.CheckBox CheckBoxBillable;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Activities.cs b/App/MiteDesk.WinForms/Activities.cs
new file mode 100644
index 0000000..43bd6d1
--- /dev/null
+++ b/App/MiteDesk.WinForms/Activities.cs
@@ -0,0 +1,265 @@
+using System.Collections.Generic;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+using StructureMap;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class Activities : Form
+ {
+
+ #region Setup
+
+ public Activities()
+ {
+ InitializeComponent();
+
+ LocalizeForm();
+
+ ActivityService = ObjectFactory.GetInstance();
+
+ TreeDataBackgroundWorker.DoWork += TreeDataBackgroundWorker_DoWork;
+ TreeDataBackgroundWorker.RunWorkerCompleted += TreeDataBackgroundWorker_RunWorkerCompleted;
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+
+ ActivActivitiesTree.NodeMouseClick += Tree_NodeMouseClick;
+ ArchivedActivitiesTree.NodeMouseClick += Tree_NodeMouseClick;
+
+ PrepareFormForNewActivity();
+ }
+
+ private IList ActiveActivities;
+ private IList ArchivedActivities;
+ private readonly IActivityService ActivityService;
+
+ private Activity CurrentActivity;
+ private bool CreateNewActivity;
+
+ #endregion
+
+ #region Lokalisierung
+
+ private void LocalizeForm()
+ {
+ Text = ActivitiesLabels.FormTitle;
+ ActiveActivitiesTabPage.Text = ActivitiesLabels.TabActiveTitle;
+ ArchivedCustomersTabPage.Text = ActivitiesLabels.TabArchivedTitle;
+ BtnNewActivity.Text = ActivitiesLabels.ButtonNewActivity;
+ BtnSave.Text = ActivitiesLabels.ButtonApply;
+ BtnCancel.Text = ActivitiesLabels.ButtonCancel;
+ label1.Text = ActivitiesLabels.LabelName;
+ label2.Text = ActivitiesLabels.LabelNote;
+ label3.Text = ActivitiesLabels.LabelHourlyNote;
+ CheckBoxBillable.Text = ActivitiesLabels.LabelBillable;
+ CheckBoxArchived.Text = ActivitiesLabels.LabelArchived;
+ DeleteToolStripMenuItem.Text = ActivitiesLabels.ButtonDelete;
+ }
+
+ #endregion
+
+ #region Treeviews befüllen
+
+ void TreeDataBackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
+ {
+ if (TreeDataBackgroundWorker.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ ActiveActivities = ActivityService.GetAllActiveActivities();
+ ArchivedActivities = ActivityService.GetAllArchivedActivities();
+ }
+
+ void TreeDataBackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
+ {
+
+ if (ActiveActivities == null || ArchivedActivities == null || e.Cancelled)
+ return;
+
+ ActivActivitiesTree.Nodes.Clear();
+
+ foreach (var activity in ActiveActivities)
+ ActivActivitiesTree.Nodes.Add(activity.ID.ToString(), activity.Name);
+
+ ArchivedActivitiesTree.Nodes.Clear();
+
+ foreach (var activity in ArchivedActivities)
+ ArchivedActivitiesTree.Nodes.Add(activity.ID.ToString(), activity.Name);
+ }
+
+ #endregion
+
+ #region Leistung darstellen
+
+ private void LoadSingleActivityInForm(int activityID)
+ {
+
+ FormGroup.Text = ActivitiesLabels.GroupBoxTitleEditMode;
+ CreateNewActivity = false;
+ CheckBoxArchived.Visible = true;
+ CurrentActivity = ActivityService.GetActivityByID(activityID);
+ BoxName.Text = CurrentActivity.Name;
+ BoxNote.Text = CurrentActivity.Note;
+
+ if(CurrentActivity.HourlyRate % 100 == 0)
+ {
+ BoxHourlyRate.Text = (CurrentActivity.HourlyRate/100).ToString();
+ }
+ else
+ {
+ BoxHourlyRate.Text = (CurrentActivity.HourlyRate/100) + "," +
+ (CurrentActivity.HourlyRate%100).ToString().PadRight(2, '0');
+ }
+
+ if (BoxHourlyRate.Text == "0")
+ BoxHourlyRate.Text = null;
+
+ CheckBoxArchived.Checked = CurrentActivity.Archived;
+ CheckBoxBillable.Checked = CurrentActivity.Billable;
+ FormGroup.Enabled = true;
+ BtnSave.Enabled = false;
+ BoxName.Focus();
+ }
+
+ #endregion
+
+ #region Formular zurücksetzen
+
+ private void PrepareFormForNewActivity()
+ {
+ ResetForm();
+ FormGroup.Text = ActivitiesLabels.GroupBoxTitleCreateMode;
+ FormGroup.Enabled = true;
+ CreateNewActivity = true;
+ CheckBoxArchived.Visible = false;
+ BtnSave.Enabled = false;
+ BoxName.Focus();
+ }
+
+ private void ResetForm()
+ {
+ FormGroup.Text = null;
+ CheckBoxArchived.Visible = true;
+ CurrentActivity = null;
+ CreateNewActivity = false;
+ ActivActivitiesTree.SelectedNode = null;
+ ArchivedActivitiesTree.SelectedNode = null;
+ BoxName.Text = null;
+ BoxNote.Text = null;
+ BoxHourlyRate.Text = null;
+ CheckBoxArchived.Checked = false;
+ CheckBoxBillable.Checked = false;
+ FormGroup.Enabled = false;
+ BtnSave.Enabled = false;
+ ErrorProvider.Clear();
+ }
+
+ #endregion
+
+ #region Leistung erstellen/aktualisieren
+
+ private void BtnSave_Click(object sender, System.EventArgs e)
+ {
+
+ Cursor = Cursors.WaitCursor;
+
+ var activity = CurrentActivity ?? new Activity();
+ activity.Name = BoxName.Text;
+ activity.Note = BoxNote.Text;
+ activity.Archived = CheckBoxArchived.Checked;
+ activity.Billable = CheckBoxBillable.Checked;
+
+ var result = CurrentActivity != null
+ ? ActivityService.UpdateActivity(activity, BoxHourlyRate.Text)
+ : ActivityService.CreateActivity(activity, BoxHourlyRate.Text);
+
+ ErrorProvider.Clear();
+
+ if (result.Count == 0)
+ {
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ if (CreateNewActivity)
+ PrepareFormForNewActivity();
+ else
+ BtnSave.Enabled = false;
+ Cursor = Cursors.Default;
+ return;
+ }
+
+ if (result.ContainsKey("Name"))
+ ErrorProvider.SetError(BoxName, result["Name"]);
+
+ Cursor = Cursors.Default;
+
+ }
+
+ #endregion
+
+ #region Leistung löschen
+
+ private void DeleteActivity(int activityID)
+ {
+
+ var timeEntries = ObjectFactory.GetInstance().GetTimeEntriesByActivityID(activityID);
+
+ if (timeEntries.Count > 0)
+ {
+ MessageBox.Show(ActivitiesLabels.MsgBoxDeleteErrorText, ActivitiesLabels.MsgBoxDeleteQuestionTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+
+ var question = MessageBox.Show(ActivitiesLabels.MsgBoxDeleteQuestionText, ActivitiesLabels.MsgBoxDeleteQuestionTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+ if (question == DialogResult.Yes)
+ {
+ ActivityService.DeleteActivity(activityID);
+ ResetForm();
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ }
+ }
+
+ #endregion
+
+ #region Event-Handler
+
+ private void BtnNewActivity_Click(object sender, System.EventArgs e)
+ {
+ PrepareFormForNewActivity();
+ }
+
+ private void BtnCancel_Click(object sender, System.EventArgs e)
+ {
+ Close();
+ }
+
+ void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
+ {
+ e.Node.TreeView.SelectedNode = e.Node;
+ LoadSingleActivityInForm(int.Parse(e.Node.Name));
+ }
+
+ private void DeleteToolStripMenuItem_Click(object sender, System.EventArgs e)
+ {
+ if (ActiveActivitiesTabPage.Visible)
+ DeleteActivity(int.Parse(ActivActivitiesTree.SelectedNode.Name));
+ else
+ DeleteActivity(int.Parse(ArchivedActivitiesTree.SelectedNode.Name));
+ }
+
+ protected override void OnClosed(System.EventArgs e)
+ {
+ Helper.StartBackgroundWorker(((Main)Owner).InitializationBackgroundWorker, null);
+ base.OnClosed(e);
+ }
+
+ private void EnableBtnSave(object sender, System.EventArgs e)
+ {
+ if (FormGroup.Enabled)
+ BtnSave.Enabled = true;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/App/MiteDesk.WinForms/Activities.resx b/App/MiteDesk.WinForms/Activities.resx
new file mode 100644
index 0000000..f3715c5
--- /dev/null
+++ b/App/MiteDesk.WinForms/Activities.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 32, 22
+
+
+ 172, 22
+
+
+ 289, 22
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Bootstrapper.cs b/App/MiteDesk.WinForms/Bootstrapper.cs
new file mode 100644
index 0000000..788d73e
--- /dev/null
+++ b/App/MiteDesk.WinForms/Bootstrapper.cs
@@ -0,0 +1,69 @@
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using StructureMap;
+using StructureMap.Configuration.DSL;
+using System.Windows.Forms;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+
+ public class Bootstrapper : IBootstrapper
+ {
+
+ public void BootstrapStructureMap()
+ {
+ const string applicationID = "22b622bd-9a87-4bc8-b3b3-1d6bcd7084f9";
+ ObjectFactory.Initialize(c =>
+ {
+ c.AddRegistry(new InfraStructureRegistry(applicationID));
+ c.AddRegistry(new ServicesRegistry());
+ c.AddRegistry(new RepositoriesRegistry());
+ });
+ }
+
+ public static void Initialize()
+ {
+ new Bootstrapper().BootstrapStructureMap();
+ }
+
+ }
+
+ public class InfraStructureRegistry : Registry
+ {
+ public InfraStructureRegistry(string applicationID)
+ {
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType()
+ .TheDefault.Is.OfConcreteType()
+ .WithCtorArg("applicationID").EqualTo(applicationID)
+ .WithCtorArg("executablePath").EqualTo(Application.ExecutablePath);
+ }
+ }
+
+ public class ServicesRegistry : Registry
+ {
+ public ServicesRegistry()
+ {
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ }
+ }
+
+ public class RepositoriesRegistry : Registry
+ {
+ public RepositoriesRegistry()
+ {
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ ForRequestedType().TheDefaultIsConcreteType();
+ }
+ }
+
+}
diff --git a/App/MiteDesk.WinForms/Customers.Designer.cs b/App/MiteDesk.WinForms/Customers.Designer.cs
new file mode 100644
index 0000000..2604c32
--- /dev/null
+++ b/App/MiteDesk.WinForms/Customers.Designer.cs
@@ -0,0 +1,284 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class Customers
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.ActiveCustomersTree = new System.Windows.Forms.TreeView();
+ this.TreeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.BtnSave = new System.Windows.Forms.Button();
+ this.FormGroup = new System.Windows.Forms.GroupBox();
+ this.CheckBoxArchived = new System.Windows.Forms.CheckBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.BoxNote = new System.Windows.Forms.TextBox();
+ this.BoxName = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.TabCustomers = new System.Windows.Forms.TabControl();
+ this.ActiveCustomersTabPage = new System.Windows.Forms.TabPage();
+ this.ArchivedCustomersTabPage = new System.Windows.Forms.TabPage();
+ this.ArchivedCustomersTree = new System.Windows.Forms.TreeView();
+ this.ErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+ this.TreeDataBackgroundWorker = new System.ComponentModel.BackgroundWorker();
+ this.BtnCancel = new System.Windows.Forms.Button();
+ this.BtnNewCustomer = new System.Windows.Forms.Button();
+ this.TreeContextMenu.SuspendLayout();
+ this.FormGroup.SuspendLayout();
+ this.TabCustomers.SuspendLayout();
+ this.ActiveCustomersTabPage.SuspendLayout();
+ this.ArchivedCustomersTabPage.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).BeginInit();
+ this.SuspendLayout();
+ //
+ // ActiveCustomersTree
+ //
+ this.ActiveCustomersTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ActiveCustomersTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ActiveCustomersTree.FullRowSelect = true;
+ this.ActiveCustomersTree.HideSelection = false;
+ this.ActiveCustomersTree.Location = new System.Drawing.Point(3, 3);
+ this.ActiveCustomersTree.Name = "ActiveCustomersTree";
+ this.ActiveCustomersTree.ShowLines = false;
+ this.ActiveCustomersTree.ShowPlusMinus = false;
+ this.ActiveCustomersTree.ShowRootLines = false;
+ this.ActiveCustomersTree.Size = new System.Drawing.Size(175, 245);
+ this.ActiveCustomersTree.TabIndex = 2;
+ //
+ // TreeContextMenu
+ //
+ this.TreeContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.DeleteToolStripMenuItem});
+ this.TreeContextMenu.Name = "TreeContextMenu";
+ this.TreeContextMenu.Size = new System.Drawing.Size(119, 26);
+ //
+ // DeleteToolStripMenuItem
+ //
+ this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
+ this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(118, 22);
+ this.DeleteToolStripMenuItem.Text = "Löschen";
+ this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click);
+ //
+ // BtnSave
+ //
+ this.BtnSave.Enabled = false;
+ this.BtnSave.Location = new System.Drawing.Point(355, 295);
+ this.BtnSave.Name = "BtnSave";
+ this.BtnSave.Size = new System.Drawing.Size(83, 23);
+ this.BtnSave.TabIndex = 6;
+ this.BtnSave.Text = "Übernehmen";
+ this.BtnSave.UseVisualStyleBackColor = true;
+ this.BtnSave.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // FormGroup
+ //
+ this.FormGroup.Controls.Add(this.CheckBoxArchived);
+ this.FormGroup.Controls.Add(this.label2);
+ this.FormGroup.Controls.Add(this.BoxNote);
+ this.FormGroup.Controls.Add(this.BoxName);
+ this.FormGroup.Controls.Add(this.label1);
+ this.FormGroup.Enabled = false;
+ this.FormGroup.Location = new System.Drawing.Point(214, 9);
+ this.FormGroup.Name = "FormGroup";
+ this.FormGroup.Size = new System.Drawing.Size(313, 276);
+ this.FormGroup.TabIndex = 3;
+ this.FormGroup.TabStop = false;
+ //
+ // CheckBoxArchived
+ //
+ this.CheckBoxArchived.AutoSize = true;
+ this.CheckBoxArchived.Location = new System.Drawing.Point(10, 160);
+ this.CheckBoxArchived.Name = "CheckBoxArchived";
+ this.CheckBoxArchived.Size = new System.Drawing.Size(70, 17);
+ this.CheckBoxArchived.TabIndex = 5;
+ this.CheckBoxArchived.Text = "Archiviert";
+ this.CheckBoxArchived.UseVisualStyleBackColor = true;
+ this.CheckBoxArchived.CheckedChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(7, 63);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(61, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Bemerkung";
+ //
+ // BoxNote
+ //
+ this.BoxNote.Location = new System.Drawing.Point(10, 79);
+ this.BoxNote.Multiline = true;
+ this.BoxNote.Name = "BoxNote";
+ this.BoxNote.Size = new System.Drawing.Size(276, 75);
+ this.BoxNote.TabIndex = 4;
+ this.BoxNote.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // BoxName
+ //
+ this.BoxName.Location = new System.Drawing.Point(10, 37);
+ this.BoxName.Name = "BoxName";
+ this.BoxName.Size = new System.Drawing.Size(276, 20);
+ this.BoxName.TabIndex = 3;
+ this.BoxName.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(7, 20);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(35, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Name";
+ //
+ // TabCustomers
+ //
+ this.TabCustomers.Controls.Add(this.ActiveCustomersTabPage);
+ this.TabCustomers.Controls.Add(this.ArchivedCustomersTabPage);
+ this.TabCustomers.Location = new System.Drawing.Point(8, 8);
+ this.TabCustomers.Name = "TabCustomers";
+ this.TabCustomers.SelectedIndex = 0;
+ this.TabCustomers.Size = new System.Drawing.Size(189, 277);
+ this.TabCustomers.TabIndex = 1;
+ //
+ // ActiveCustomersTabPage
+ //
+ this.ActiveCustomersTabPage.Controls.Add(this.ActiveCustomersTree);
+ this.ActiveCustomersTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ActiveCustomersTabPage.Name = "ActiveCustomersTabPage";
+ this.ActiveCustomersTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ActiveCustomersTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ActiveCustomersTabPage.TabIndex = 0;
+ this.ActiveCustomersTabPage.Text = "Aktive";
+ this.ActiveCustomersTabPage.UseVisualStyleBackColor = true;
+ //
+ // ArchivedCustomersTabPage
+ //
+ this.ArchivedCustomersTabPage.Controls.Add(this.ArchivedCustomersTree);
+ this.ArchivedCustomersTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ArchivedCustomersTabPage.Name = "ArchivedCustomersTabPage";
+ this.ArchivedCustomersTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ArchivedCustomersTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ArchivedCustomersTabPage.TabIndex = 1;
+ this.ArchivedCustomersTabPage.Text = "Archivierte";
+ this.ArchivedCustomersTabPage.UseVisualStyleBackColor = true;
+ //
+ // ArchivedCustomersTree
+ //
+ this.ArchivedCustomersTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ArchivedCustomersTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ArchivedCustomersTree.FullRowSelect = true;
+ this.ArchivedCustomersTree.HideSelection = false;
+ this.ArchivedCustomersTree.Location = new System.Drawing.Point(3, 3);
+ this.ArchivedCustomersTree.Name = "ArchivedCustomersTree";
+ this.ArchivedCustomersTree.ShowLines = false;
+ this.ArchivedCustomersTree.ShowPlusMinus = false;
+ this.ArchivedCustomersTree.ShowRootLines = false;
+ this.ArchivedCustomersTree.Size = new System.Drawing.Size(175, 245);
+ this.ArchivedCustomersTree.TabIndex = 1;
+ //
+ // ErrorProvider
+ //
+ this.ErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+ this.ErrorProvider.ContainerControl = this;
+ //
+ // BtnCancel
+ //
+ this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.BtnCancel.Location = new System.Drawing.Point(444, 295);
+ this.BtnCancel.Name = "BtnCancel";
+ this.BtnCancel.Size = new System.Drawing.Size(83, 23);
+ this.BtnCancel.TabIndex = 7;
+ this.BtnCancel.Text = "Schließen";
+ this.BtnCancel.UseVisualStyleBackColor = true;
+ this.BtnCancel.Click += new System.EventHandler(this.BtnCancel_Click_1);
+ //
+ // BtnNewCustomer
+ //
+ this.BtnNewCustomer.Location = new System.Drawing.Point(9, 295);
+ this.BtnNewCustomer.Name = "BtnNewCustomer";
+ this.BtnNewCustomer.Size = new System.Drawing.Size(87, 23);
+ this.BtnNewCustomer.TabIndex = 9;
+ this.BtnNewCustomer.Text = "Neuer Kunde";
+ this.BtnNewCustomer.UseVisualStyleBackColor = true;
+ this.BtnNewCustomer.Click += new System.EventHandler(this.BtnNewCustomer_Click);
+ //
+ // Customers
+ //
+ this.AcceptButton = this.BtnSave;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.BtnCancel;
+ this.ClientSize = new System.Drawing.Size(537, 327);
+ this.Controls.Add(this.TabCustomers);
+ this.Controls.Add(this.FormGroup);
+ this.Controls.Add(this.BtnNewCustomer);
+ this.Controls.Add(this.BtnCancel);
+ this.Controls.Add(this.BtnSave);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MaximumSize = new System.Drawing.Size(553, 365);
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(553, 365);
+ this.Name = "Customers";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Kunden";
+ this.TreeContextMenu.ResumeLayout(false);
+ this.FormGroup.ResumeLayout(false);
+ this.FormGroup.PerformLayout();
+ this.TabCustomers.ResumeLayout(false);
+ this.ActiveCustomersTabPage.ResumeLayout(false);
+ this.ArchivedCustomersTabPage.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TreeView ActiveCustomersTree;
+ private System.Windows.Forms.Button BtnSave;
+ private System.Windows.Forms.GroupBox FormGroup;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox BoxNote;
+ private System.Windows.Forms.TextBox BoxName;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TabControl TabCustomers;
+ private System.Windows.Forms.TabPage ActiveCustomersTabPage;
+ private System.Windows.Forms.TreeView ArchivedCustomersTree;
+ private System.Windows.Forms.TabPage ArchivedCustomersTabPage;
+ private System.Windows.Forms.ErrorProvider ErrorProvider;
+ private System.ComponentModel.BackgroundWorker TreeDataBackgroundWorker;
+ private System.Windows.Forms.CheckBox CheckBoxArchived;
+ private System.Windows.Forms.Button BtnCancel;
+ private System.Windows.Forms.Button BtnNewCustomer;
+ private System.Windows.Forms.ContextMenuStrip TreeContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Customers.cs b/App/MiteDesk.WinForms/Customers.cs
new file mode 100644
index 0000000..5e733ee
--- /dev/null
+++ b/App/MiteDesk.WinForms/Customers.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+using StructureMap;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class Customers : Form
+ {
+
+ #region Setup
+
+ public Customers()
+ {
+ InitializeComponent();
+ LocalizeForm();
+
+ CustomerService = ObjectFactory.GetInstance();
+
+ TreeDataBackgroundWorker.DoWork += TreeDataBackgroundWorker_DoWork;
+ TreeDataBackgroundWorker.RunWorkerCompleted += TreeDataBackgroundWorker_RunWorkerCompleted;
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+
+ ActiveCustomersTree.NodeMouseClick += Tree_NodeMouseClick;
+ ArchivedCustomersTree.NodeMouseClick += Tree_NodeMouseClick;
+
+ PrepareFormForNewCustomer();
+ }
+
+ private IList ActiveCustomers;
+ private IList ArchivedCustomers;
+ private readonly ICustomerService CustomerService;
+
+ private Customer CurrentCustomer;
+ private bool CreateNewCustomer;
+
+ #endregion
+
+ #region Lokalisierung
+
+ private void LocalizeForm()
+ {
+ Text = CustomersLabels.FormTitle;
+ ActiveCustomersTabPage.Text = CustomersLabels.TabActiveTitle;
+ ArchivedCustomersTabPage.Text = CustomersLabels.TabArchivedTitle;
+ BtnNewCustomer.Text = CustomersLabels.ButtonNewActivity;
+ BtnSave.Text = CustomersLabels.ButtonApply;
+ BtnCancel.Text = CustomersLabels.ButtonCancel;
+ label1.Text = CustomersLabels.LabelName;
+ label2.Text = CustomersLabels.LabelNote;
+ CheckBoxArchived.Text = CustomersLabels.LabelArchived;
+ DeleteToolStripMenuItem.Text = CustomersLabels.ButtonDelete;
+ }
+
+ #endregion
+
+ #region Treeviews befüllen
+
+ void TreeDataBackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
+ {
+ if (TreeDataBackgroundWorker.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ ActiveCustomers = CustomerService.GetAllActiveCustomers();
+ ArchivedCustomers = CustomerService.GetAllArchivedCustomers();
+ }
+
+ void TreeDataBackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
+ {
+
+ if (ActiveCustomers == null || ArchivedCustomers == null || e.Cancelled)
+ return;
+
+ ActiveCustomersTree.Nodes.Clear();
+
+ foreach (var customer in ActiveCustomers)
+ ActiveCustomersTree.Nodes.Add(customer.ID.ToString(), customer.Name);
+
+ ArchivedCustomersTree.Nodes.Clear();
+
+ foreach (var customer in ArchivedCustomers)
+ ArchivedCustomersTree.Nodes.Add(customer.ID.ToString(), customer.Name);
+ }
+
+ #endregion
+
+ #region Kundendatensatz darstellen
+
+ private void LoadSingleCustomerInForm(int customerID)
+ {
+ FormGroup.Text = CustomersLabels.GroupBoxTitleEditMode;
+ CreateNewCustomer = false;
+ CheckBoxArchived.Visible = true;
+ CurrentCustomer = CustomerService.GetCustomerByID(customerID);
+ BoxName.Text = CurrentCustomer.Name;
+ BoxNote.Text = CurrentCustomer.Note;
+ CheckBoxArchived.Checked = CurrentCustomer.Archived;
+ FormGroup.Enabled = true;
+ BoxName.Focus();
+ BtnSave.Enabled = false;
+ }
+
+ #endregion
+
+ #region Formular zurücksetzen
+
+ private void PrepareFormForNewCustomer()
+ {
+ ResetForm();
+ FormGroup.Text = CustomersLabels.GroupBoxTitleCreateMode;
+ BtnSave.Enabled = false;
+ FormGroup.Enabled = true;
+ CreateNewCustomer = true;
+ CheckBoxArchived.Visible = false;
+ BoxName.Focus();
+ }
+
+ private void ResetForm()
+ {
+ FormGroup.Text = null;
+ CheckBoxArchived.Visible = true;
+ CurrentCustomer = null;
+ CreateNewCustomer = false;
+ ActiveCustomersTree.SelectedNode = null;
+ ArchivedCustomersTree.SelectedNode = null;
+ BoxName.Text = null;
+ BoxNote.Text = null;
+ CheckBoxArchived.Checked = false;
+ FormGroup.Enabled = false;
+ BtnSave.Enabled = false;
+ ErrorProvider.Clear();
+ }
+
+ #endregion
+
+ #region Kunde erstellen/aktualisieren
+
+ private void BtnSave_Click(object sender, EventArgs e)
+ {
+
+ Cursor = Cursors.WaitCursor;
+
+ var customer = CurrentCustomer ?? new Customer();
+ customer.Name = BoxName.Text;
+ customer.Note = BoxNote.Text;
+ customer.Archived = CheckBoxArchived.Checked;
+
+ var result = CurrentCustomer != null
+ ? CustomerService.UpdateCustomer(customer)
+ : CustomerService.CreateCustomer(customer);
+
+ ErrorProvider.Clear();
+
+ if(result.Count == 0)
+ {
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ if (CreateNewCustomer)
+ PrepareFormForNewCustomer();
+ else
+ BtnSave.Enabled = false;
+ Cursor = Cursors.Default;
+ return;
+ }
+
+ if (result.ContainsKey("Name"))
+ ErrorProvider.SetError(BoxName, result["Name"]);
+
+ Cursor = Cursors.Default;
+
+ }
+
+ #endregion
+
+ #region Kunde löschen
+
+ private void DeleteCustomer(int customerID)
+ {
+
+ var projects = ObjectFactory.GetInstance().GetProjectsByCustomer(customerID);
+
+ if(projects.Count > 0)
+ {
+ MessageBox.Show(CustomersLabels.MsgBoxDeleteErrorText, CustomersLabels.MsgBoxDeleteErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+
+ var question = MessageBox.Show(CustomersLabels.MsgBoxDeleteQuestionText, CustomersLabels.MsgBoxDeleteQuestionTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+ if (question == DialogResult.Yes)
+ {
+ CustomerService.DeleteCustomer(customerID);
+ ResetForm();
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ }
+ }
+
+ #endregion
+
+ #region Event-Handler
+
+ private void BtnNewCustomer_Click(object sender, EventArgs e)
+ {
+ PrepareFormForNewCustomer();
+ }
+
+ private void BtnCancel_Click_1(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
+ {
+ e.Node.TreeView.SelectedNode = e.Node;
+ LoadSingleCustomerInForm(int.Parse(e.Node.Name));
+ }
+
+ private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if(ActiveCustomersTabPage.Visible)
+ DeleteCustomer(int.Parse(ActiveCustomersTree.SelectedNode.Name));
+ else
+ DeleteCustomer(int.Parse(ArchivedCustomersTree.SelectedNode.Name));
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ if (Owner is Main)
+ Helper.StartBackgroundWorker(((Main)Owner).InitializationBackgroundWorker, null);
+ else if(Owner is Projects)
+ Helper.StartBackgroundWorker(((Projects)Owner).TreeDataBackgroundWorker, null);
+ base.OnClosed(e);
+ }
+
+ private void EnableBtnSave(object sender, EventArgs e)
+ {
+ if (FormGroup.Enabled)
+ BtnSave.Enabled = true;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/App/MiteDesk.WinForms/Customers.resx b/App/MiteDesk.WinForms/Customers.resx
new file mode 100644
index 0000000..04e2688
--- /dev/null
+++ b/App/MiteDesk.WinForms/Customers.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 326, 17
+
+
+ 209, 17
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/DebugConsole.Designer.cs b/App/MiteDesk.WinForms/DebugConsole.Designer.cs
new file mode 100644
index 0000000..8d5ff27
--- /dev/null
+++ b/App/MiteDesk.WinForms/DebugConsole.Designer.cs
@@ -0,0 +1,150 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class DebugConsole
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.groupBox1 = new System.Windows.Forms.GroupBox();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.button1 = new System.Windows.Forms.Button();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.button2 = new System.Windows.Forms.Button();
+ this.button3 = new System.Windows.Forms.Button();
+ this.groupBox1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // groupBox1
+ //
+ this.groupBox1.Controls.Add(this.textBox1);
+ this.groupBox1.Location = new System.Drawing.Point(13, 65);
+ this.groupBox1.Name = "groupBox1";
+ this.groupBox1.Size = new System.Drawing.Size(594, 315);
+ this.groupBox1.TabIndex = 0;
+ this.groupBox1.TabStop = false;
+ this.groupBox1.Text = "Fehlermeldung";
+ //
+ // textBox1
+ //
+ this.textBox1.HideSelection = false;
+ this.textBox1.Location = new System.Drawing.Point(9, 22);
+ this.textBox1.Margin = new System.Windows.Forms.Padding(15);
+ this.textBox1.Multiline = true;
+ this.textBox1.Name = "textBox1";
+ this.textBox1.ReadOnly = true;
+ this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+ this.textBox1.Size = new System.Drawing.Size(573, 269);
+ this.textBox1.TabIndex = 0;
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(386, 388);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(131, 23);
+ this.button1.TabIndex = 1;
+ this.button1.Text = "mite.desk neu starten";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.Location = new System.Drawing.Point(13, 15);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(251, 13);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Oops ... Es ist leider ein Fehler aufgetreten";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(13, 39);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(597, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Es würde uns sehr helfen, wenn du uns die unten aufgeführte Fehlermeldung per E-M" +
+ "ail an info@69grad.de senden würdest.";
+ //
+ // button2
+ //
+ this.button2.Location = new System.Drawing.Point(532, 388);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(75, 23);
+ this.button2.TabIndex = 7;
+ this.button2.Text = "OK";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // button3
+ //
+ this.button3.Location = new System.Drawing.Point(13, 388);
+ this.button3.Name = "button3";
+ this.button3.Size = new System.Drawing.Size(245, 23);
+ this.button3.TabIndex = 8;
+ this.button3.Text = "Fehlermeldung in die Zwischenablage kopieren";
+ this.button3.UseVisualStyleBackColor = true;
+ this.button3.Click += new System.EventHandler(this.button3_Click);
+ //
+ // DebugConsole
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(619, 418);
+ this.Controls.Add(this.button3);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.groupBox1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MaximumSize = new System.Drawing.Size(635, 456);
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(635, 456);
+ this.Name = "DebugConsole";
+ this.ShowIcon = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Es ist ein Fehler aufgetreten";
+ this.groupBox1.ResumeLayout(false);
+ this.groupBox1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.GroupBox groupBox1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Button button2;
+ private System.Windows.Forms.Button button3;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/DebugConsole.cs b/App/MiteDesk.WinForms/DebugConsole.cs
new file mode 100644
index 0000000..fc67369
--- /dev/null
+++ b/App/MiteDesk.WinForms/DebugConsole.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class DebugConsole : Form
+ {
+ public DebugConsole(Exception exception)
+ {
+
+ InitializeComponent();
+ LocalizeForm();
+
+ textBox1.Text = "================================================================" + Environment.NewLine;
+ textBox1.Text += "Version:" + Environment.NewLine;
+ textBox1.Text += Helper.CurrentVersion + " (Build " + Helper.CurrentBuild + ")" + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ textBox1.Text += "================================================================"+ Environment.NewLine;
+ textBox1.Text += "Message:" + Environment.NewLine;
+ textBox1.Text += exception.Message + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ textBox1.Text += "================================================================"+ Environment.NewLine;
+ textBox1.Text += "StackTrace:" + Environment.NewLine;
+ textBox1.Text += exception.StackTrace + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ textBox1.Text += "================================================================"+ Environment.NewLine;
+ textBox1.Text += "HelpLink:" + Environment.NewLine;
+ textBox1.Text += exception.HelpLink + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ textBox1.Text += "================================================================"+ Environment.NewLine;
+ textBox1.Text += "Source:" + Environment.NewLine;
+ textBox1.Text += exception.Source + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ textBox1.Text += "================================================================"+ Environment.NewLine;
+ textBox1.Text += "TargetSite:" + Environment.NewLine;
+ textBox1.Text += exception.TargetSite.Name + Environment.NewLine;
+ textBox1.Text += "================================================================";
+ textBox1.Text += Environment.NewLine + Environment.NewLine;
+
+ }
+
+ private void LocalizeForm()
+ {
+ Text = DebugConsoleLabels.FormTitle;
+ groupBox1.Text = DebugConsoleLabels.GroupBoxTitle;
+ button3.Text = DebugConsoleLabels.CopyToClipboardButton;
+ button1.Text = DebugConsoleLabels.RestartButton;
+ button2.Text = DebugConsoleLabels.OKButton;
+ label1.Text = DebugConsoleLabels.LabelTitle;
+ label2.Text = DebugConsoleLabels.LabelText;
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ Application.Restart();
+ }
+
+ private void button2_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ private void button3_Click(object sender, EventArgs e)
+ {
+ Clipboard.SetText(textBox1.Text);
+ }
+
+ }
+}
diff --git a/App/MiteDesk.WinForms/DebugConsole.resx b/App/MiteDesk.WinForms/DebugConsole.resx
new file mode 100644
index 0000000..19dc0dd
--- /dev/null
+++ b/App/MiteDesk.WinForms/DebugConsole.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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/App/MiteDesk.WinForms/Localization/ActivitiesLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.Designer.cs
new file mode 100644
index 0000000..95234fc
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.Designer.cs
@@ -0,0 +1,225 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class ActivitiesLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ActivitiesLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.ActivitiesLabels", typeof(ActivitiesLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Übernehmen.
+ ///
+ internal static string ButtonApply {
+ get {
+ return ResourceManager.GetString("ButtonApply", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Schließen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string ButtonDelete {
+ get {
+ return ResourceManager.GetString("ButtonDelete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neue Leistung.
+ ///
+ internal static string ButtonNewActivity {
+ get {
+ return ResourceManager.GetString("ButtonNewActivity", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Leistungen.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neue Leistung.
+ ///
+ internal static string GroupBoxTitleCreateMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleCreateMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Leistung bearbeiten.
+ ///
+ internal static string GroupBoxTitleEditMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleEditMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archiviert.
+ ///
+ internal static string LabelArchived {
+ get {
+ return ResourceManager.GetString("LabelArchived", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verrechenbar?.
+ ///
+ internal static string LabelBillable {
+ get {
+ return ResourceManager.GetString("LabelBillable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stundensatz in €.
+ ///
+ internal static string LabelHourlyNote {
+ get {
+ return ResourceManager.GetString("LabelHourlyNote", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Name.
+ ///
+ internal static string LabelName {
+ get {
+ return ResourceManager.GetString("LabelName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bemerkung.
+ ///
+ internal static string LabelNote {
+ get {
+ return ResourceManager.GetString("LabelNote", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Dieser Leistung ist mindestens ein Zeiteintrag zugeordnet, sie darf deshalb nicht gelöscht werden..
+ ///
+ internal static string MsgBoxDeleteErrorText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Leistung darf nicht gelöscht werden.
+ ///
+ internal static string MsgBoxDeleteErrorTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Möchtest du diese Leistung wirklich löschen?.
+ ///
+ internal static string MsgBoxDeleteQuestionText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string MsgBoxDeleteQuestionTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Aktive.
+ ///
+ internal static string TabActiveTitle {
+ get {
+ return ResourceManager.GetString("TabActiveTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archivierte.
+ ///
+ internal static string TabArchivedTitle {
+ get {
+ return ResourceManager.GetString("TabArchivedTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/ActivitiesLabels.en.resx b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.en.resx
new file mode 100644
index 0000000..fd2ced4
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.en.resx
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Apply
+
+
+ Close
+
+
+ Delete
+
+
+ Add service
+
+
+ Services
+
+
+ Add service
+
+
+ Edit service
+
+
+ Archived
+
+
+ Billable?
+
+
+ Hourly rate in €
+
+
+ Name
+
+
+ Note
+
+
+ This service cannot be deleted. There are associated time entries.
+
+
+ Service cannot be deleted
+
+
+ Do you really want to delete this service?
+
+
+ Delete
+
+
+ Active
+
+
+ Archived
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/ActivitiesLabels.resx b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.resx
new file mode 100644
index 0000000..d6c938d
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ActivitiesLabels.resx
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Übernehmen
+
+
+ Schließen
+
+
+ Löschen
+
+
+ Neue Leistung
+
+
+ Leistungen
+
+
+ Neue Leistung
+
+
+ Leistung bearbeiten
+
+
+ Archiviert
+
+
+ Verrechenbar?
+
+
+ Stundensatz in €
+
+
+ Name
+
+
+ Bemerkung
+
+
+ Dieser Leistung ist mindestens ein Zeiteintrag zugeordnet, sie darf deshalb nicht gelöscht werden.
+
+
+ Leistung darf nicht gelöscht werden
+
+
+ Möchtest du diese Leistung wirklich löschen?
+
+
+ Löschen
+
+
+ Aktive
+
+
+ Archivierte
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/CustomersLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/CustomersLabels.Designer.cs
new file mode 100644
index 0000000..d716a0a
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/CustomersLabels.Designer.cs
@@ -0,0 +1,207 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CustomersLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CustomersLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.CustomersLabels", typeof(CustomersLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Übernehmen.
+ ///
+ internal static string ButtonApply {
+ get {
+ return ResourceManager.GetString("ButtonApply", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Schließen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string ButtonDelete {
+ get {
+ return ResourceManager.GetString("ButtonDelete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neuer Kunde.
+ ///
+ internal static string ButtonNewActivity {
+ get {
+ return ResourceManager.GetString("ButtonNewActivity", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunden.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neuer Kunde.
+ ///
+ internal static string GroupBoxTitleCreateMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleCreateMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunde bearbeiten.
+ ///
+ internal static string GroupBoxTitleEditMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleEditMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archiviert.
+ ///
+ internal static string LabelArchived {
+ get {
+ return ResourceManager.GetString("LabelArchived", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Name.
+ ///
+ internal static string LabelName {
+ get {
+ return ResourceManager.GetString("LabelName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bemerkung.
+ ///
+ internal static string LabelNote {
+ get {
+ return ResourceManager.GetString("LabelNote", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diesem Kunden ist mindestens ein Projekt zugeordnet, er darf deshalb nicht gelöscht werden..
+ ///
+ internal static string MsgBoxDeleteErrorText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunde darf nicht gelöscht werden.
+ ///
+ internal static string MsgBoxDeleteErrorTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Möchtest du diesen Kunden wirklich löschen?.
+ ///
+ internal static string MsgBoxDeleteQuestionText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string MsgBoxDeleteQuestionTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Aktive.
+ ///
+ internal static string TabActiveTitle {
+ get {
+ return ResourceManager.GetString("TabActiveTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archivierte.
+ ///
+ internal static string TabArchivedTitle {
+ get {
+ return ResourceManager.GetString("TabArchivedTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/CustomersLabels.en.resx b/App/MiteDesk.WinForms/Localization/CustomersLabels.en.resx
new file mode 100644
index 0000000..925e9bc
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/CustomersLabels.en.resx
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Apply
+
+
+ Close
+
+
+ Delete
+
+
+ Add customer
+
+
+ Customers
+
+
+ Add customer
+
+
+ Edit customer
+
+
+ Archived
+
+
+ Name
+
+
+ Note
+
+
+ This customer cannot be deleted. There are associated projects.
+
+
+ Customer cannot be deleted
+
+
+ Do you really want to delete this customer?
+
+
+ Delete
+
+
+ Active
+
+
+ Archived
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/CustomersLabels.resx b/App/MiteDesk.WinForms/Localization/CustomersLabels.resx
new file mode 100644
index 0000000..b0455a6
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/CustomersLabels.resx
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Übernehmen
+
+
+ Schließen
+
+
+ Löschen
+
+
+ Neuer Kunde
+
+
+ Kunden
+
+
+ Neuer Kunde
+
+
+ Kunde bearbeiten
+
+
+ Archiviert
+
+
+ Name
+
+
+ Bemerkung
+
+
+ Diesem Kunden ist mindestens ein Projekt zugeordnet, er darf deshalb nicht gelöscht werden.
+
+
+ Kunde darf nicht gelöscht werden
+
+
+ Möchtest du diesen Kunden wirklich löschen?
+
+
+ Löschen
+
+
+ Aktive
+
+
+ Archivierte
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.Designer.cs
new file mode 100644
index 0000000..db73fb7
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.Designer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class DebugConsoleLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal DebugConsoleLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.DebugConsoleLabels", typeof(DebugConsoleLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Fehlermeldung in die Zwischenablage kopieren.
+ ///
+ internal static string CopyToClipboardButton {
+ get {
+ return ResourceManager.GetString("CopyToClipboardButton", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Es ist ein Fehler aufgetreten.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Fehlermeldung.
+ ///
+ internal static string GroupBoxTitle {
+ get {
+ return ResourceManager.GetString("GroupBoxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Es würde uns sehr helfen, wenn du uns die unten aufgeführte Fehlermeldung per E-Mail an info@69grad.de senden würdest..
+ ///
+ internal static string LabelText {
+ get {
+ return ResourceManager.GetString("LabelText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Oops ... Es ist leider ein Fehler aufgetreten.
+ ///
+ internal static string LabelTitle {
+ get {
+ return ResourceManager.GetString("LabelTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OK.
+ ///
+ internal static string OKButton {
+ get {
+ return ResourceManager.GetString("OKButton", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to mite.desk neu starten.
+ ///
+ internal static string RestartButton {
+ get {
+ return ResourceManager.GetString("RestartButton", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.en.resx b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.en.resx
new file mode 100644
index 0000000..4b3217d
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.en.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Copy error message to clip board
+
+
+ An error has occurred
+
+
+ Error Message
+
+
+ It would be greatly appreciated if you could send us the error message below via Email to info@69grad.de
+
+
+ Oops ... An error has occurred
+
+
+ OK
+
+
+ Restart mite.desk
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.resx b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.resx
new file mode 100644
index 0000000..7700f6b
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/DebugConsoleLabels.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Fehlermeldung in die Zwischenablage kopieren
+
+
+ Es ist ein Fehler aufgetreten
+
+
+ Fehlermeldung
+
+
+ Es würde uns sehr helfen, wenn du uns die unten aufgeführte Fehlermeldung per E-Mail an info@69grad.de senden würdest.
+
+
+ Oops ... Es ist leider ein Fehler aufgetreten
+
+
+ OK
+
+
+ mite.desk neu starten
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/FeedbackLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/FeedbackLabels.Designer.cs
new file mode 100644
index 0000000..bf5b2c0
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/FeedbackLabels.Designer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class FeedbackLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal FeedbackLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.FeedbackLabels", typeof(FeedbackLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Abbrechen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Senden.
+ ///
+ internal static string ButtonSend {
+ get {
+ return ResourceManager.GetString("ButtonSend", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Feedback senden.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to (Nach dem Klick auf Senden öffnet sich dein Mailprogramm).
+ ///
+ internal static string LabelInfo {
+ get {
+ return ResourceManager.GetString("LabelInfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Mein Feedback zu mite.desk:.
+ ///
+ internal static string LabelTitle {
+ get {
+ return ResourceManager.GetString("LabelTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Das Senden klappt nicht. Wahrscheinlich hast du kein Standard-Mail-Programm konfiguriert. Alternativ kannst du uns eine E-Mail an info@69grad.de senden - danke!.
+ ///
+ internal static string MsgBoxErrorText {
+ get {
+ return ResourceManager.GetString("MsgBoxErrorText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Senden fehlgeschlagen.
+ ///
+ internal static string MsgBoxErrorTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxErrorTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/FeedbackLabels.en.resx b/App/MiteDesk.WinForms/Localization/FeedbackLabels.en.resx
new file mode 100644
index 0000000..dee1d0a
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/FeedbackLabels.en.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Cancel
+
+
+ Send
+
+
+ Give feedback
+
+
+ (After clicking the send button your email app will appear)
+
+
+ What I ever wanted to tell you about mite.desk:
+
+
+ Opening your email app has failed. Propably you don't have configured a default email application on this computer. But you can send us your feedback also by mail to info@69grad.de - thank you!
+
+
+ Sending feedback failed
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/FeedbackLabels.resx b/App/MiteDesk.WinForms/Localization/FeedbackLabels.resx
new file mode 100644
index 0000000..0b2e33a
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/FeedbackLabels.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Abbrechen
+
+
+ Senden
+
+
+ Feedback senden
+
+
+ (Nach dem Klick auf Senden öffnet sich dein Mailprogramm)
+
+
+ Mein Feedback zu mite.desk:
+
+
+ Das Senden klappt nicht. Wahrscheinlich hast du kein Standard-Mail-Programm konfiguriert. Alternativ kannst du uns eine E-Mail an info@69grad.de senden - danke!
+
+
+ Senden fehlgeschlagen
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/MainLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/MainLabels.Designer.cs
new file mode 100644
index 0000000..4ea9257
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/MainLabels.Designer.cs
@@ -0,0 +1,522 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class MainLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal MainLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.MainLabels", typeof(MainLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Soll die Stoppuhr angehalten werden?.
+ ///
+ internal static string AskForStoppingStopwatch {
+ get {
+ return ResourceManager.GetString("AskForStoppingStopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbunden als.
+ ///
+ internal static string AuthenticatedAs {
+ get {
+ return ResourceManager.GetString("AuthenticatedAs", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verwerfen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Erstellen.
+ ///
+ internal static string ButtonCreate {
+ get {
+ return ResourceManager.GetString("ButtonCreate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string ButtonDelete {
+ get {
+ return ResourceManager.GetString("ButtonDelete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Speichern.
+ ///
+ internal static string ButtonSave {
+ get {
+ return ResourceManager.GetString("ButtonSave", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung herstellen.
+ ///
+ internal static string Connect {
+ get {
+ return ResourceManager.GetString("Connect", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbunden.
+ ///
+ internal static string Connected {
+ get {
+ return ResourceManager.GetString("Connected", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung zu mite. fehlgeschlagen.
+ ///
+ internal static string ConnectionFailed {
+ get {
+ return ResourceManager.GetString("ConnectionFailed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung trennen.
+ ///
+ internal static string Disconnect {
+ get {
+ return ResourceManager.GetString("Disconnect", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Nicht verbunden.
+ ///
+ internal static string Disconnected {
+ get {
+ return ResourceManager.GetString("Disconnected", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kalender.
+ ///
+ internal static string GroupboxCalendarTitle {
+ get {
+ return ResourceManager.GetString("GroupboxCalendarTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neuen Zeiteintrag erstellen.
+ ///
+ internal static string GroupboxFormCreateMode {
+ get {
+ return ResourceManager.GetString("GroupboxFormCreateMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Zeiteintrag bearbeiten.
+ ///
+ internal static string GroupboxFormEditMode {
+ get {
+ return ResourceManager.GetString("GroupboxFormEditMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Einträge für den.
+ ///
+ internal static string GroupboxTimeEntriesTitle {
+ get {
+ return ResourceManager.GetString("GroupboxTimeEntriesTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Leistung.
+ ///
+ internal static string LabelActivity {
+ get {
+ return ResourceManager.GetString("LabelActivity", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Gewählte Kalenderwoche:.
+ ///
+ internal static string LabelCalendarWeek {
+ get {
+ return ResourceManager.GetString("LabelCalendarWeek", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Dauer.
+ ///
+ internal static string LabelDuration {
+ get {
+ return ResourceManager.GetString("LabelDuration", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bemerkung.
+ ///
+ internal static string LabelNote {
+ get {
+ return ResourceManager.GetString("LabelNote", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekt.
+ ///
+ internal static string LabelProject {
+ get {
+ return ResourceManager.GetString("LabelProject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Abgeschlossen.
+ ///
+ internal static string Locked {
+ get {
+ return ResourceManager.GetString("Locked", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Als abgeschlossen markieren.
+ ///
+ internal static string MarkAsLocked {
+ get {
+ return ResourceManager.GetString("MarkAsLocked", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Als nicht-abgeschlossen markieren.
+ ///
+ internal static string MarkAsUnlocked {
+ get {
+ return ResourceManager.GetString("MarkAsUnlocked", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Über mite.desk.
+ ///
+ internal static string MenuAbout {
+ get {
+ return ResourceManager.GetString("MenuAbout", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Aktivieren.
+ ///
+ internal static string MenuActivate {
+ get {
+ return ResourceManager.GetString("MenuActivate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Leistungen.
+ ///
+ internal static string MenuActivities {
+ get {
+ return ResourceManager.GetString("MenuActivities", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Auf Updates prüfen.
+ ///
+ internal static string MenuCheckForUpdates {
+ get {
+ return ResourceManager.GetString("MenuCheckForUpdates", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunden.
+ ///
+ internal static string MenuCustomers {
+ get {
+ return ResourceManager.GetString("MenuCustomers", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Daten.
+ ///
+ internal static string MenuData {
+ get {
+ return ResourceManager.GetString("MenuData", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Beenden.
+ ///
+ internal static string MenuExit {
+ get {
+ return ResourceManager.GetString("MenuExit", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Feedback senden.
+ ///
+ internal static string MenuFeedback {
+ get {
+ return ResourceManager.GetString("MenuFeedback", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to mite.account.
+ ///
+ internal static string MenuMiteAccount {
+ get {
+ return ResourceManager.GetString("MenuMiteAccount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neuen Zeiteintrag erstellen.
+ ///
+ internal static string MenuNewTimeEntry {
+ get {
+ return ResourceManager.GetString("MenuNewTimeEntry", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Onlinehilfe.
+ ///
+ internal static string MenuOnlinehelp {
+ get {
+ return ResourceManager.GetString("MenuOnlinehelp", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekte.
+ ///
+ internal static string MenuProjects {
+ get {
+ return ResourceManager.GetString("MenuProjects", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekte/Leistungen neu laden.
+ ///
+ internal static string MenuRefreshProjectsAndActivities {
+ get {
+ return ResourceManager.GetString("MenuRefreshProjectsAndActivities", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Einstellungen.
+ ///
+ internal static string MenuSettings {
+ get {
+ return ResourceManager.GetString("MenuSettings", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to mite.desk-Website.
+ ///
+ internal static string MenuWebsite {
+ get {
+ return ResourceManager.GetString("MenuWebsite", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die Verbindung zu mite. konnte nicht hergestellt werden.
+ ///
+ internal static string MsgBoxConnectionErrorText {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionErrorText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindungsfehler.
+ ///
+ internal static string MsgBoxConnectionErrorTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Möchtest du diesen Zeiteintrag wirklich löschen?.
+ ///
+ internal static string MsgBoxDeleteTimeEntryText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteTimeEntryText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string MsgBoxDeleteTimeEntryTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteTimeEntryTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Beenden.
+ ///
+ internal static string NotifyContextMenuExit {
+ get {
+ return ResourceManager.GetString("NotifyContextMenuExit", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Wiederherstellen.
+ ///
+ internal static string NotifyContextMenuRestoreWindow {
+ get {
+ return ResourceManager.GetString("NotifyContextMenuRestoreWindow", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr starten.
+ ///
+ internal static string NotifyContextMenuStartStopwatch {
+ get {
+ return ResourceManager.GetString("NotifyContextMenuStartStopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr anhalten.
+ ///
+ internal static string NotifyContextMenuStopStopwatch {
+ get {
+ return ResourceManager.GetString("NotifyContextMenuStopStopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr starten.
+ ///
+ internal static string StartStopwatch {
+ get {
+ return ResourceManager.GetString("StartStopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr anhalten.
+ ///
+ internal static string StopStopwatch {
+ get {
+ return ResourceManager.GetString("StopStopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr.
+ ///
+ internal static string Stopwatch {
+ get {
+ return ResourceManager.GetString("Stopwatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stoppuhr nicht gestartet.
+ ///
+ internal static string StopwatchNotStarted {
+ get {
+ return ResourceManager.GetString("StopwatchNotStarted", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Zeit gesamt:.
+ ///
+ internal static string TimeTotal {
+ get {
+ return ResourceManager.GetString("TimeTotal", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/MainLabels.en.resx b/App/MiteDesk.WinForms/Localization/MainLabels.en.resx
new file mode 100644
index 0000000..c8e7408
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/MainLabels.en.resx
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Should the stopwatch be stopped?
+
+
+ Connected as
+
+
+ Cancel
+
+
+ Create
+
+
+ Delete
+
+
+ Save
+
+
+ Connect
+
+
+ Connected
+
+
+ Could not connect to mite.
+
+
+ Disconnect
+
+
+ Disconnected
+
+
+ Calendar
+
+
+ Create new time entry
+
+
+ Edit time entry
+
+
+ Time entries for
+
+
+ Service
+
+
+ Calendar week:
+
+
+ Hours
+
+
+ Note
+
+
+ Project
+
+
+ Locked
+
+
+ Lock
+
+
+ Unlock
+
+
+ About mite.desk
+
+
+ Activate
+
+
+ Services
+
+
+ Check for updates
+
+
+ Customers
+
+
+ Data
+
+
+ Exit
+
+
+ Give feedback
+
+
+ mite.account
+
+
+ Create new time entry
+
+
+ Online help
+
+
+ Projects
+
+
+ Refresh Projects/Services
+
+
+ Settings
+
+
+ mite.desk website
+
+
+ Could not connect to mite.
+
+
+ Connection error
+
+
+ Do you really want to delete this time entry?
+
+
+ Delete
+
+
+ Exit
+
+
+ Restore
+
+
+ Start stopwatch
+
+
+ Stop stopwatch
+
+
+ Start stopwatch
+
+
+ Stop stopwatch
+
+
+ Stopwatch
+
+
+ Stopwatch not started
+
+
+ Time total:
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/MainLabels.resx b/App/MiteDesk.WinForms/Localization/MainLabels.resx
new file mode 100644
index 0000000..a5b708e
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/MainLabels.resx
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Soll die Stoppuhr angehalten werden?
+
+
+ Verbunden als
+
+
+ Verwerfen
+
+
+ Erstellen
+
+
+ Löschen
+
+
+ Speichern
+
+
+ Verbindung herstellen
+
+
+ Verbunden
+
+
+ Verbindung zu mite. fehlgeschlagen
+
+
+ Verbindung trennen
+
+
+ Nicht verbunden
+
+
+ Kalender
+
+
+ Neuen Zeiteintrag erstellen
+
+
+ Zeiteintrag bearbeiten
+
+
+ Einträge für den
+
+
+ Leistung
+
+
+ Gewählte Kalenderwoche:
+
+
+ Dauer
+
+
+ Bemerkung
+
+
+ Projekt
+
+
+ Abgeschlossen
+
+
+ Als abgeschlossen markieren
+
+
+ Als nicht-abgeschlossen markieren
+
+
+ Über mite.desk
+
+
+ Aktivieren
+
+
+ Leistungen
+
+
+ Auf Updates prüfen
+
+
+ Kunden
+
+
+ Daten
+
+
+ Beenden
+
+
+ Feedback senden
+
+
+ mite.account
+
+
+ Neuen Zeiteintrag erstellen
+
+
+ Onlinehilfe
+
+
+ Projekte
+
+
+ Projekte/Leistungen neu laden
+
+
+ Einstellungen
+
+
+ mite.desk-Website
+
+
+ Die Verbindung zu mite. konnte nicht hergestellt werden
+
+
+ Verbindungsfehler
+
+
+ Möchtest du diesen Zeiteintrag wirklich löschen?
+
+
+ Löschen
+
+
+ Beenden
+
+
+ Wiederherstellen
+
+
+ Stoppuhr starten
+
+
+ Stoppuhr anhalten
+
+
+ Stoppuhr starten
+
+
+ Stoppuhr anhalten
+
+
+ Stoppuhr
+
+
+ Stoppuhr nicht gestartet
+
+
+ Zeit gesamt:
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/ProjectsLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/ProjectsLabels.Designer.cs
new file mode 100644
index 0000000..439a17c
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ProjectsLabels.Designer.cs
@@ -0,0 +1,252 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class ProjectsLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal ProjectsLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.ProjectsLabels", typeof(ProjectsLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Euro.
+ ///
+ internal static string BudgetEuro {
+ get {
+ return ResourceManager.GetString("BudgetEuro", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stunden.
+ ///
+ internal static string BudgetHours {
+ get {
+ return ResourceManager.GetString("BudgetHours", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Übernehmen.
+ ///
+ internal static string ButtonApply {
+ get {
+ return ResourceManager.GetString("ButtonApply", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Schließen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunden ....
+ ///
+ internal static string ButtonCustomers {
+ get {
+ return ResourceManager.GetString("ButtonCustomers", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string ButtonDelete {
+ get {
+ return ResourceManager.GetString("ButtonDelete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neues Projekt.
+ ///
+ internal static string ButtonNewActivity {
+ get {
+ return ResourceManager.GetString("ButtonNewActivity", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekte.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Neues Projekt.
+ ///
+ internal static string GroupBoxTitleCreateMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleCreateMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekt bearbeiten.
+ ///
+ internal static string GroupBoxTitleEditMode {
+ get {
+ return ResourceManager.GetString("GroupBoxTitleEditMode", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archiviert.
+ ///
+ internal static string LabelArchived {
+ get {
+ return ResourceManager.GetString("LabelArchived", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Budget.
+ ///
+ internal static string LabelBudget {
+ get {
+ return ResourceManager.GetString("LabelBudget", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Kunde.
+ ///
+ internal static string LabelCustomer {
+ get {
+ return ResourceManager.GetString("LabelCustomer", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Name.
+ ///
+ internal static string LabelName {
+ get {
+ return ResourceManager.GetString("LabelName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bemerkung.
+ ///
+ internal static string LabelNote {
+ get {
+ return ResourceManager.GetString("LabelNote", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diesem Projekt ist mindestens ein Zeiteintrag zugeordnet, es darf deshalb nicht gelöscht werden..
+ ///
+ internal static string MsgBoxDeleteErrorText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Projekt darf nicht gelöscht werden.
+ ///
+ internal static string MsgBoxDeleteErrorTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Möchtest du dieses Projekt wirklich löschen?.
+ ///
+ internal static string MsgBoxDeleteQuestionText {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Löschen.
+ ///
+ internal static string MsgBoxDeleteQuestionTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxDeleteQuestionTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Aktive.
+ ///
+ internal static string TabActiveTitle {
+ get {
+ return ResourceManager.GetString("TabActiveTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Archivierte.
+ ///
+ internal static string TabArchivedTitle {
+ get {
+ return ResourceManager.GetString("TabArchivedTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/ProjectsLabels.en.resx b/App/MiteDesk.WinForms/Localization/ProjectsLabels.en.resx
new file mode 100644
index 0000000..7bcc721
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ProjectsLabels.en.resx
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ euros
+
+
+ hours
+
+
+ Apply
+
+
+ Close
+
+
+ Customers ...
+
+
+ Delete
+
+
+ Add project
+
+
+ Projects
+
+
+ Add project
+
+
+ Edit project
+
+
+ Archived
+
+
+ Budget
+
+
+ Customer
+
+
+ Name
+
+
+ Note
+
+
+ This project cannot be deleted. There are associated time entries.
+
+
+ Project cannot be deleted
+
+
+ Do you really want to delete this project?
+
+
+ Delete
+
+
+ Active
+
+
+ Archived
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/ProjectsLabels.resx b/App/MiteDesk.WinForms/Localization/ProjectsLabels.resx
new file mode 100644
index 0000000..7270575
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/ProjectsLabels.resx
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Euro
+
+
+ Stunden
+
+
+ Übernehmen
+
+
+ Schließen
+
+
+ Kunden ...
+
+
+ Löschen
+
+
+ Neues Projekt
+
+
+ Projekte
+
+
+ Neues Projekt
+
+
+ Projekt bearbeiten
+
+
+ Archiviert
+
+
+ Budget
+
+
+ Kunde
+
+
+ Name
+
+
+ Bemerkung
+
+
+ Diesem Projekt ist mindestens ein Zeiteintrag zugeordnet, es darf deshalb nicht gelöscht werden.
+
+
+ Projekt darf nicht gelöscht werden
+
+
+ Möchtest du dieses Projekt wirklich löschen?
+
+
+ Löschen
+
+
+ Aktive
+
+
+ Archivierte
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/SettingsLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/SettingsLabels.Designer.cs
new file mode 100644
index 0000000..a7c3929
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/SettingsLabels.Designer.cs
@@ -0,0 +1,517 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class SettingsLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal SettingsLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.SettingsLabels", typeof(SettingsLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Account.
+ ///
+ internal static string AccountGroupboxTitle {
+ get {
+ return ResourceManager.GetString("AccountGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Login.
+ ///
+ internal static string AccountLabelAccountName {
+ get {
+ return ResourceManager.GetString("AccountLabelAccountName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Schlüssel.
+ ///
+ internal static string AccountLabelAPIKey {
+ get {
+ return ResourceManager.GetString("AccountLabelAPIKey", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Anmelden via.
+ ///
+ internal static string AccountLabelConnectBy {
+ get {
+ return ResourceManager.GetString("AccountLabelConnectBy", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to API-Schlüssel.
+ ///
+ internal static string AccountLabelConnectByApiKey {
+ get {
+ return ResourceManager.GetString("AccountLabelConnectByApiKey", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to E-Mail/Passwort.
+ ///
+ internal static string AccountLabelConnectByEmailAndPassword {
+ get {
+ return ResourceManager.GetString("AccountLabelConnectByEmailAndPassword", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Beenden.
+ ///
+ internal static string AdvancedGroupboxTitle {
+ get {
+ return ResourceManager.GetString("AdvancedGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to mite.desk beim Schließen des Fensters nicht beenden, sondern minimieren.
+ ///
+ internal static string AdvancedLabelMinimizeByClose {
+ get {
+ return ResourceManager.GetString("AdvancedLabelMinimizeByClose", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Vor dem Beenden fragen, ob die Stoppuhr angehalten werden soll.
+ ///
+ internal static string AskForStoppingStopwatchByClosing {
+ get {
+ return ResourceManager.GetString("AskForStoppingStopwatchByClosing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Abbrechen.
+ ///
+ internal static string ButtonCancel {
+ get {
+ return ResourceManager.GetString("ButtonCancel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung testen.
+ ///
+ internal static string ButtonCheckConnection {
+ get {
+ return ResourceManager.GetString("ButtonCheckConnection", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OK.
+ ///
+ internal static string ButtonOK {
+ get {
+ return ResourceManager.GetString("ButtonOK", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Einstellungen.
+ ///
+ internal static string FormTitle {
+ get {
+ return ResourceManager.GetString("FormTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sprache.
+ ///
+ internal static string LanguageGroupboxTitle {
+ get {
+ return ResourceManager.GetString("LanguageGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Anmeldung per E-Mail/Passwort.
+ ///
+ internal static string LoginByAccountGroupboxTitle {
+ get {
+ return ResourceManager.GetString("LoginByAccountGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to E-Mail-Adresse.
+ ///
+ internal static string LoginByAccountLabelEmail {
+ get {
+ return ResourceManager.GetString("LoginByAccountLabelEmail", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Passwort.
+ ///
+ internal static string LoginByAccountLabelPassword {
+ get {
+ return ResourceManager.GetString("LoginByAccountLabelPassword", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Passwort anzeigen.
+ ///
+ internal static string LoginByAccountLabelShowPassword {
+ get {
+ return ResourceManager.GetString("LoginByAccountLabelShowPassword", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Anmeldung per API-Schlüssel.
+ ///
+ internal static string LoginByApiKeyGroupboxTitle {
+ get {
+ return ResourceManager.GetString("LoginByApiKeyGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Fehler: {0}
+ ///
+ ///Hast du den Zugriff auf die mite.api in deinem Account aktiviert?.
+ ///
+ internal static string MsgBoxConnectionTestFailureText {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionTestFailureText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung zu mite. fehlgeschlagen..
+ ///
+ internal static string MsgBoxConnectionTestFailureTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionTestFailureTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Anmeldung erfolgreich. Angemeldet als: {0} ({1}).
+ ///
+ internal static string MsgBoxConnectionTestSuccessText {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionTestSuccessText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verbindung erfolgreich hergestellt.
+ ///
+ internal static string MsgBoxConnectionTestSuccessTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxConnectionTestSuccessTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Gib zunächst deine mite.-Zugangsdaten oder deinen persönlichen API-Schlüssel ein.
+ ///
+ ///(Beachte auch, dass zum Zugriff die mite.api für deinen Account aktiviert sein muss.).
+ ///
+ internal static string MsgBoxFirstSetupMessageText {
+ get {
+ return ResourceManager.GetString("MsgBoxFirstSetupMessageText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Willkommen bei mite.desk!.
+ ///
+ internal static string MsgBoxFirstSetupMessageTitle {
+ get {
+ return ResourceManager.GetString("MsgBoxFirstSetupMessageTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Passwort.
+ ///
+ internal static string ProxyPassword {
+ get {
+ return ResourceManager.GetString("ProxyPassword", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Proxy-Server.
+ ///
+ internal static string ProxyServer {
+ get {
+ return ResourceManager.GetString("ProxyServer", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Proxy-Server verwenden.
+ ///
+ internal static string ProxyServerLabel {
+ get {
+ return ResourceManager.GetString("ProxyServerLabel", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Benutzername.
+ ///
+ internal static string ProxyUser {
+ get {
+ return ResourceManager.GetString("ProxyUser", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sichere Verbindung mit SSL-Verschlüsselung verwenden.
+ ///
+ internal static string SecurityConnectBySSL {
+ get {
+ return ResourceManager.GetString("SecurityConnectBySSL", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sicherheit.
+ ///
+ internal static string SecurityGroupboxTitle {
+ get {
+ return ResourceManager.GetString("SecurityGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Einträge in umgekehrter Reihenfolge sortieren (neueste zuerst).
+ ///
+ internal static string SortDescending {
+ get {
+ return ResourceManager.GetString("SortDescending", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Start.
+ ///
+ internal static string StartGroupboxTitle {
+ get {
+ return ResourceManager.GetString("StartGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to mite.desk bei der Windows-Anmeldung automatisch starten (Autostart).
+ ///
+ internal static string StartLabelAutostart {
+ get {
+ return ResourceManager.GetString("StartLabelAutostart", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Minimiert starten.
+ ///
+ internal static string StartLabelStartMinimized {
+ get {
+ return ResourceManager.GetString("StartLabelStartMinimized", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Beim Beenden die Stoppuhr automatisch anhalten.
+ ///
+ internal static string StopStopwatchByClosing {
+ get {
+ return ResourceManager.GetString("StopStopwatchByClosing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Account.
+ ///
+ internal static string TabAccount {
+ get {
+ return ResourceManager.GetString("TabAccount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Erweitert.
+ ///
+ internal static string TabAdvanced {
+ get {
+ return ResourceManager.GetString("TabAdvanced", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sprache.
+ ///
+ internal static string TabLanguage {
+ get {
+ return ResourceManager.GetString("TabLanguage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Netzwerk.
+ ///
+ internal static string TabNetwork {
+ get {
+ return ResourceManager.GetString("TabNetwork", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Updates.
+ ///
+ internal static string TabUpdates {
+ get {
+ return ResourceManager.GetString("TabUpdates", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Zeiteinträge.
+ ///
+ internal static string TimeEntriesGroupboxTitle {
+ get {
+ return ResourceManager.GetString("TimeEntriesGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Niemals.
+ ///
+ internal static string UpdateCheck0 {
+ get {
+ return ResourceManager.GetString("UpdateCheck0", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Alle 14 Tage.
+ ///
+ internal static string UpdateCheck14 {
+ get {
+ return ResourceManager.GetString("UpdateCheck14", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Alle 30 Tage.
+ ///
+ internal static string UpdateCheck30 {
+ get {
+ return ResourceManager.GetString("UpdateCheck30", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Alle 7 Tage.
+ ///
+ internal static string UpdateCheck7 {
+ get {
+ return ResourceManager.GetString("UpdateCheck7", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to nie.
+ ///
+ internal static string UpdateCheckNever {
+ get {
+ return ResourceManager.GetString("UpdateCheckNever", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Automatische Update-Prüfung.
+ ///
+ internal static string UpdatesGroupboxTitle {
+ get {
+ return ResourceManager.GetString("UpdatesGroupboxTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Auf Updates prüfen.
+ ///
+ internal static string UpdatesLabelInterval {
+ get {
+ return ResourceManager.GetString("UpdatesLabelInterval", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Zuletzt geprüft.
+ ///
+ internal static string UpdatesLabelLastUpdatecheck {
+ get {
+ return ResourceManager.GetString("UpdatesLabelLastUpdatecheck", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/SettingsLabels.en.resx b/App/MiteDesk.WinForms/Localization/SettingsLabels.en.resx
new file mode 100644
index 0000000..53c53a4
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/SettingsLabels.en.resx
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Account
+
+
+ Login
+
+
+ API key
+
+
+ Authenticate by
+
+
+ API key
+
+
+ Email and password
+
+
+ Closing
+
+
+ Don't exit mite.desk by closing the window, minimize it
+
+
+ Cancel
+
+
+ Check connection
+
+
+ OK
+
+
+ Settings
+
+
+ Language
+
+
+ Authenticate by Email/password
+
+
+ Email address
+
+
+ Password
+
+
+ Show password
+
+
+ Authenticate by API key
+
+
+ Error: {0}
+
+Did you allow API access in your account settings?
+
+
+ Cannot connect to mite.
+
+
+ Connected successfully. Authenticated as: {0} ({1})
+
+
+ Connected successfully
+
+
+ Please enter your mite. login data or your personal API key.
+
+(Keep in mind that you have to allow API access in your account)
+
+
+ Welcome to mite.desk!
+
+
+ Use a secure connection with SSL encryption
+
+
+ Security
+
+
+ Startup
+
+
+ Start mite.desk by logging in in Windows automatically (Autostart)
+
+
+ Start minimized
+
+
+ Account
+
+
+ Advanced
+
+
+ Language
+
+
+ Network
+
+
+ Updates
+
+
+ Never
+
+
+ Every 14 days
+
+
+ Every 30 days
+
+
+ Every 7 days
+
+
+ never
+
+
+ Automatic check for updates
+
+
+ Check for updates
+
+
+ Last checked
+
+
+ Proxy Server
+
+
+ Use a proxy server
+
+
+ Password
+
+
+ User name
+
+
+ Ask me for stopping the stopwatch before exiting
+
+
+ Automatically stop the stopwatch before exiting
+
+
+ Sort entries in reverse order (newest first)
+
+
+ Time Entries
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/SettingsLabels.resx b/App/MiteDesk.WinForms/Localization/SettingsLabels.resx
new file mode 100644
index 0000000..2a38ced
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/SettingsLabels.resx
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Account
+
+
+ Login
+
+
+ Schlüssel
+
+
+ Anmelden via
+
+
+ API-Schlüssel
+
+
+ E-Mail/Passwort
+
+
+ Beenden
+
+
+ mite.desk beim Schließen des Fensters nicht beenden, sondern minimieren
+
+
+ Abbrechen
+
+
+ Verbindung testen
+
+
+ OK
+
+
+ Einstellungen
+
+
+ Sprache
+
+
+ Anmeldung per E-Mail/Passwort
+
+
+ E-Mail-Adresse
+
+
+ Passwort
+
+
+ Passwort anzeigen
+
+
+ Anmeldung per API-Schlüssel
+
+
+ Fehler: {0}
+
+Hast du den Zugriff auf die mite.api in deinem Account aktiviert?
+
+
+ Verbindung zu mite. fehlgeschlagen.
+
+
+ Anmeldung erfolgreich. Angemeldet als: {0} ({1})
+
+
+ Verbindung erfolgreich hergestellt
+
+
+ Gib zunächst deine mite.-Zugangsdaten oder deinen persönlichen API-Schlüssel ein.
+
+(Beachte auch, dass zum Zugriff die mite.api für deinen Account aktiviert sein muss.)
+
+
+ Willkommen bei mite.desk!
+
+
+ Sichere Verbindung mit SSL-Verschlüsselung verwenden
+
+
+ Sicherheit
+
+
+ Start
+
+
+ mite.desk bei der Windows-Anmeldung automatisch starten (Autostart)
+
+
+ Minimiert starten
+
+
+ Account
+
+
+ Erweitert
+
+
+ Sprache
+
+
+ Netzwerk
+
+
+ Updates
+
+
+ Niemals
+
+
+ Alle 14 Tage
+
+
+ Alle 30 Tage
+
+
+ Alle 7 Tage
+
+
+ nie
+
+
+ Automatische Update-Prüfung
+
+
+ Auf Updates prüfen
+
+
+ Zuletzt geprüft
+
+
+ Proxy-Server
+
+
+ Proxy-Server verwenden
+
+
+ Passwort
+
+
+ Benutzername
+
+
+ Vor dem Beenden fragen, ob die Stoppuhr angehalten werden soll
+
+
+ Beim Beenden die Stoppuhr automatisch anhalten
+
+
+ Einträge in umgekehrter Reihenfolge sortieren (neueste zuerst)
+
+
+ Zeiteinträge
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.Designer.cs b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.Designer.cs
new file mode 100644
index 0000000..5931070
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.Designer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class UpdateCheckLabels {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal UpdateCheckLabels() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Localization.UpdateCheckLabels", typeof(UpdateCheckLabels).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die aktuelle Version konnte nicht abgerufen werden..
+ ///
+ internal static string Error {
+ get {
+ return ResourceManager.GetString("Error", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to neueste Version.
+ ///
+ internal static string LatestVersion {
+ get {
+ return ResourceManager.GetString("LatestVersion", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Es ist eine neue mite.desk-Version verfügbar!.
+ ///
+ internal static string NewVersionAvailable {
+ get {
+ return ResourceManager.GetString("NewVersionAvailable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Möchtest du diese laden?.
+ ///
+ internal static string Question {
+ get {
+ return ResourceManager.GetString("Question", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Update-Check.
+ ///
+ internal static string Title {
+ get {
+ return ResourceManager.GetString("Title", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Du verwendest die aktuellste Version! :-).
+ ///
+ internal static string UsingLatestVersion {
+ get {
+ return ResourceManager.GetString("UsingLatestVersion", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Deine Version.
+ ///
+ internal static string YourVersion {
+ get {
+ return ResourceManager.GetString("YourVersion", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.en.resx b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.en.resx
new file mode 100644
index 0000000..17a76db
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.en.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Cannot connect to update server.
+
+
+ latest version
+
+
+ It's a new mite.desk version available!
+
+
+ Do you want to download it?
+
+
+ Checking for updates
+
+
+ You're using the latest version! :-)
+
+
+ Your version
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.resx b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.resx
new file mode 100644
index 0000000..c389425
--- /dev/null
+++ b/App/MiteDesk.WinForms/Localization/UpdateCheckLabels.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Die aktuelle Version konnte nicht abgerufen werden.
+
+
+ neueste Version
+
+
+ Es ist eine neue mite.desk-Version verfügbar!
+
+
+ Möchtest du diese laden?
+
+
+ Update-Check
+
+
+ Du verwendest die aktuellste Version! :-)
+
+
+ Deine Version
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/LoginHelp.Designer.cs b/App/MiteDesk.WinForms/LoginHelp.Designer.cs
new file mode 100644
index 0000000..fd6c70d
--- /dev/null
+++ b/App/MiteDesk.WinForms/LoginHelp.Designer.cs
@@ -0,0 +1,84 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class LoginHelp
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.button1 = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.BackColor = System.Drawing.SystemColors.Control;
+ this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.pictureBox1.Image = global::SixtyNineDegrees.MiteDesk.WinForms.Properties.Resources.loginhelp;
+ this.pictureBox1.Location = new System.Drawing.Point(0, 0);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(505, 283);
+ this.pictureBox1.TabIndex = 0;
+ this.pictureBox1.TabStop = false;
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(418, 250);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(75, 23);
+ this.button1.TabIndex = 1;
+ this.button1.Text = "OK";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // LoginHelp
+ //
+ this.AcceptButton = this.button1;
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+ this.ClientSize = new System.Drawing.Size(505, 283);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.pictureBox1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MaximumSize = new System.Drawing.Size(511, 311);
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(511, 311);
+ this.Name = "LoginHelp";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Login";
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Button button1;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/LoginHelp.cs b/App/MiteDesk.WinForms/LoginHelp.cs
new file mode 100644
index 0000000..e142180
--- /dev/null
+++ b/App/MiteDesk.WinForms/LoginHelp.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Windows.Forms;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class LoginHelp : Form
+ {
+ public LoginHelp()
+ {
+ InitializeComponent();
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/LoginHelp.resx b/App/MiteDesk.WinForms/LoginHelp.resx
new file mode 100644
index 0000000..19dc0dd
--- /dev/null
+++ b/App/MiteDesk.WinForms/LoginHelp.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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/App/MiteDesk.WinForms/Main.Designer.cs b/App/MiteDesk.WinForms/Main.Designer.cs
new file mode 100644
index 0000000..bd175f1
--- /dev/null
+++ b/App/MiteDesk.WinForms/Main.Designer.cs
@@ -0,0 +1,708 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class Main
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main));
+ this.MainMenu = new System.Windows.Forms.MenuStrip();
+ this.MainMenuItemExit = new System.Windows.Forms.ToolStripMenuItem();
+ this.MainMenuItemRefreshActivitiesAndProjects = new System.Windows.Forms.ToolStripMenuItem();
+ this.MainMenuItemCreateNewTimeEntry = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.einstellungenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.beendenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.datenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.MainMenuCustomersItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.MainMenuProjectsItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.MainMenuActivitiesItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
+ this.miteZeitenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.TimeEntryDetailView = new System.Windows.Forms.GroupBox();
+ this.Locked = new System.Windows.Forms.CheckBox();
+ this.BtnCancel = new System.Windows.Forms.Button();
+ this.BtnAccept = new System.Windows.Forms.Button();
+ this.Note = new System.Windows.Forms.TextBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.Time = new System.Windows.Forms.TextBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.ListActivities = new System.Windows.Forms.ComboBox();
+ this.ListProjects = new System.Windows.Forms.ComboBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.Calendar = new System.Windows.Forms.MonthCalendar();
+ this.groupBox2 = new System.Windows.Forms.GroupBox();
+ this.ListTimeEntries = new System.Windows.Forms.ListView();
+ this.TextColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.TimeEntryContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.TimeEntryContextMenuStopStopwatchItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.TimeEntryContextMenuStartStopwatchItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
+ this.TimeEntryContextMenuUnlock = new System.Windows.Forms.ToolStripMenuItem();
+ this.TimeEntryContextMenuLock = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
+ this.TimeEntryContextMenuDeleteItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.StatusBar = new System.Windows.Forms.StatusStrip();
+ this.ToolStripConnectionStatus = new System.Windows.Forms.ToolStripDropDownButton();
+ this.ToolStripMenuItemDisconnectFromServer = new System.Windows.Forms.ToolStripMenuItem();
+ this.ToolStripMenuItemConnectToServer = new System.Windows.Forms.ToolStripMenuItem();
+ this.StopwatchStatus = new System.Windows.Forms.ToolStripStatusLabel();
+ this.ErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+ this.Stopwatch = new System.Windows.Forms.Timer(this.components);
+ this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
+ this.NotifyContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.NotifyContextMenuStartStopwatchItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.NotifyContextMenuStopStopwatchItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
+ this.NotifyContextMenuOpenMiteDeskItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator();
+ this.ExitButton = new System.Windows.Forms.ToolStripMenuItem();
+ this.groupBox1 = new System.Windows.Forms.GroupBox();
+ this.WeekOfYear = new System.Windows.Forms.Label();
+ this.InitializationBackgroundWorker = new System.ComponentModel.BackgroundWorker();
+ this.TimeEntriesBackgroundWorker = new System.ComponentModel.BackgroundWorker();
+ this.MainMenu.SuspendLayout();
+ this.TimeEntryDetailView.SuspendLayout();
+ this.groupBox2.SuspendLayout();
+ this.TimeEntryContextMenu.SuspendLayout();
+ this.StatusBar.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).BeginInit();
+ this.NotifyContextMenu.SuspendLayout();
+ this.groupBox1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // MainMenu
+ //
+ this.MainMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.MainMenuItemExit,
+ this.datenToolStripMenuItem,
+ this.toolStripMenuItem1});
+ this.MainMenu.Location = new System.Drawing.Point(0, 0);
+ this.MainMenu.Name = "MainMenu";
+ this.MainMenu.Size = new System.Drawing.Size(572, 24);
+ this.MainMenu.TabIndex = 1;
+ this.MainMenu.Text = "MainMenu";
+ //
+ // MainMenuItemExit
+ //
+ this.MainMenuItemExit.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.MainMenuItemRefreshActivitiesAndProjects,
+ this.MainMenuItemCreateNewTimeEntry,
+ this.toolStripSeparator2,
+ this.einstellungenToolStripMenuItem,
+ this.toolStripSeparator1,
+ this.beendenToolStripMenuItem});
+ this.MainMenuItemExit.Name = "MainMenuItemExit";
+ this.MainMenuItemExit.Size = new System.Drawing.Size(70, 20);
+ this.MainMenuItemExit.Text = "mite.desk";
+ //
+ // MainMenuItemRefreshActivitiesAndProjects
+ //
+ this.MainMenuItemRefreshActivitiesAndProjects.ImageTransparentColor = System.Drawing.Color.Black;
+ this.MainMenuItemRefreshActivitiesAndProjects.Name = "MainMenuItemRefreshActivitiesAndProjects";
+ this.MainMenuItemRefreshActivitiesAndProjects.ShortcutKeyDisplayString = "";
+ this.MainMenuItemRefreshActivitiesAndProjects.ShortcutKeys = System.Windows.Forms.Keys.F5;
+ this.MainMenuItemRefreshActivitiesAndProjects.Size = new System.Drawing.Size(254, 22);
+ this.MainMenuItemRefreshActivitiesAndProjects.Text = "Projekte/Leistungen neu laden";
+ this.MainMenuItemRefreshActivitiesAndProjects.Click += new System.EventHandler(this.MainMenuItemRefreshProjectsAndActivitiesClick);
+ //
+ // MainMenuItemCreateNewTimeEntry
+ //
+ this.MainMenuItemCreateNewTimeEntry.ImageTransparentColor = System.Drawing.Color.Black;
+ this.MainMenuItemCreateNewTimeEntry.Name = "MainMenuItemCreateNewTimeEntry";
+ this.MainMenuItemCreateNewTimeEntry.ShortcutKeyDisplayString = "";
+ this.MainMenuItemCreateNewTimeEntry.ShortcutKeys = System.Windows.Forms.Keys.F4;
+ this.MainMenuItemCreateNewTimeEntry.Size = new System.Drawing.Size(254, 22);
+ this.MainMenuItemCreateNewTimeEntry.Text = "Neuen Zeiteintrag erstellen";
+ this.MainMenuItemCreateNewTimeEntry.Click += new System.EventHandler(this.MainMenuItemCreateNewTimeEntryClick);
+ //
+ // toolStripSeparator2
+ //
+ this.toolStripSeparator2.Name = "toolStripSeparator2";
+ this.toolStripSeparator2.Size = new System.Drawing.Size(251, 6);
+ //
+ // einstellungenToolStripMenuItem
+ //
+ this.einstellungenToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.Fuchsia;
+ this.einstellungenToolStripMenuItem.Name = "einstellungenToolStripMenuItem";
+ this.einstellungenToolStripMenuItem.ShortcutKeyDisplayString = "";
+ this.einstellungenToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F6;
+ this.einstellungenToolStripMenuItem.Size = new System.Drawing.Size(254, 22);
+ this.einstellungenToolStripMenuItem.Text = "Einstellungen";
+ this.einstellungenToolStripMenuItem.Click += new System.EventHandler(this.MainMenuItemSettingsClick);
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(251, 6);
+ //
+ // beendenToolStripMenuItem
+ //
+ this.beendenToolStripMenuItem.Name = "beendenToolStripMenuItem";
+ this.beendenToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
+ this.beendenToolStripMenuItem.Size = new System.Drawing.Size(254, 22);
+ this.beendenToolStripMenuItem.Text = "Beenden";
+ this.beendenToolStripMenuItem.Click += new System.EventHandler(this.Exit);
+ //
+ // datenToolStripMenuItem
+ //
+ this.datenToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.MainMenuCustomersItem,
+ this.MainMenuProjectsItem,
+ this.MainMenuActivitiesItem});
+ this.datenToolStripMenuItem.Name = "datenToolStripMenuItem";
+ this.datenToolStripMenuItem.Size = new System.Drawing.Size(50, 20);
+ this.datenToolStripMenuItem.Text = "Daten";
+ this.datenToolStripMenuItem.Visible = false;
+ //
+ // MainMenuCustomersItem
+ //
+ this.MainMenuCustomersItem.Name = "MainMenuCustomersItem";
+ this.MainMenuCustomersItem.ShortcutKeys = System.Windows.Forms.Keys.F7;
+ this.MainMenuCustomersItem.Size = new System.Drawing.Size(151, 22);
+ this.MainMenuCustomersItem.Text = "Kunden";
+ this.MainMenuCustomersItem.Click += new System.EventHandler(this.MainMenuCustomersItem_Click);
+ //
+ // MainMenuProjectsItem
+ //
+ this.MainMenuProjectsItem.Name = "MainMenuProjectsItem";
+ this.MainMenuProjectsItem.ShortcutKeys = System.Windows.Forms.Keys.F8;
+ this.MainMenuProjectsItem.Size = new System.Drawing.Size(151, 22);
+ this.MainMenuProjectsItem.Text = "Projekte";
+ this.MainMenuProjectsItem.Click += new System.EventHandler(this.MainMenuProjectsItem_Click);
+ //
+ // MainMenuActivitiesItem
+ //
+ this.MainMenuActivitiesItem.Name = "MainMenuActivitiesItem";
+ this.MainMenuActivitiesItem.ShortcutKeys = System.Windows.Forms.Keys.F9;
+ this.MainMenuActivitiesItem.Size = new System.Drawing.Size(151, 22);
+ this.MainMenuActivitiesItem.Text = "Leistungen";
+ this.MainMenuActivitiesItem.Click += new System.EventHandler(this.MainMenuActivitiesItem_Click);
+ //
+ // toolStripMenuItem1
+ //
+ this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.miteZeitenToolStripMenuItem});
+ this.toolStripMenuItem1.Name = "toolStripMenuItem1";
+ this.toolStripMenuItem1.Size = new System.Drawing.Size(24, 20);
+ this.toolStripMenuItem1.Text = "?";
+ //
+ // miteZeitenToolStripMenuItem
+ //
+ this.miteZeitenToolStripMenuItem.Image = global::SixtyNineDegrees.MiteDesk.WinForms.Properties.Resources.faviconico;
+ this.miteZeitenToolStripMenuItem.Name = "miteZeitenToolStripMenuItem";
+ this.miteZeitenToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F10;
+ this.miteZeitenToolStripMenuItem.Size = new System.Drawing.Size(169, 22);
+ this.miteZeitenToolStripMenuItem.Text = "mite.account";
+ this.miteZeitenToolStripMenuItem.Click += new System.EventHandler(this.miteZeitenToolStripMenuItem_Click);
+ //
+ // TimeEntryDetailView
+ //
+ this.TimeEntryDetailView.Controls.Add(this.Locked);
+ this.TimeEntryDetailView.Controls.Add(this.BtnCancel);
+ this.TimeEntryDetailView.Controls.Add(this.BtnAccept);
+ this.TimeEntryDetailView.Controls.Add(this.Note);
+ this.TimeEntryDetailView.Controls.Add(this.label5);
+ this.TimeEntryDetailView.Controls.Add(this.Time);
+ this.TimeEntryDetailView.Controls.Add(this.label4);
+ this.TimeEntryDetailView.Controls.Add(this.ListActivities);
+ this.TimeEntryDetailView.Controls.Add(this.ListProjects);
+ this.TimeEntryDetailView.Controls.Add(this.label3);
+ this.TimeEntryDetailView.Controls.Add(this.label2);
+ this.TimeEntryDetailView.Location = new System.Drawing.Point(7, 34);
+ this.TimeEntryDetailView.Name = "TimeEntryDetailView";
+ this.TimeEntryDetailView.Size = new System.Drawing.Size(343, 216);
+ this.TimeEntryDetailView.TabIndex = 29;
+ this.TimeEntryDetailView.TabStop = false;
+ this.TimeEntryDetailView.Text = "Neuen Zeiteintrag erstellen";
+ //
+ // Locked
+ //
+ this.Locked.AutoSize = true;
+ this.Locked.Location = new System.Drawing.Point(161, 90);
+ this.Locked.Name = "Locked";
+ this.Locked.Size = new System.Drawing.Size(98, 17);
+ this.Locked.TabIndex = 35;
+ this.Locked.Text = "Abgeschlossen";
+ this.Locked.UseVisualStyleBackColor = true;
+ this.Locked.Visible = false;
+ this.Locked.Click += new System.EventHandler(this.Locked_Click);
+ //
+ // BtnCancel
+ //
+ this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.BtnCancel.Location = new System.Drawing.Point(161, 185);
+ this.BtnCancel.Name = "BtnCancel";
+ this.BtnCancel.Size = new System.Drawing.Size(75, 23);
+ this.BtnCancel.TabIndex = 7;
+ this.BtnCancel.Text = "Verwerfen";
+ this.BtnCancel.UseVisualStyleBackColor = true;
+ this.BtnCancel.Click += new System.EventHandler(this.BtnCancel_Click);
+ //
+ // BtnAccept
+ //
+ this.BtnAccept.Location = new System.Drawing.Point(78, 185);
+ this.BtnAccept.Name = "BtnAccept";
+ this.BtnAccept.Size = new System.Drawing.Size(75, 23);
+ this.BtnAccept.TabIndex = 6;
+ this.BtnAccept.Text = "Erstellen";
+ this.BtnAccept.UseVisualStyleBackColor = true;
+ this.BtnAccept.Click += new System.EventHandler(this.BtnAccept_Click);
+ //
+ // Note
+ //
+ this.Note.Location = new System.Drawing.Point(78, 120);
+ this.Note.Multiline = true;
+ this.Note.Name = "Note";
+ this.Note.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.Note.Size = new System.Drawing.Size(242, 59);
+ this.Note.TabIndex = 5;
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(6, 120);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(61, 13);
+ this.label5.TabIndex = 34;
+ this.label5.Text = "Bemerkung";
+ //
+ // Time
+ //
+ this.ErrorProvider.SetIconPadding(this.Time, 3);
+ this.Time.Location = new System.Drawing.Point(78, 88);
+ this.Time.Name = "Time";
+ this.Time.Size = new System.Drawing.Size(55, 20);
+ this.Time.TabIndex = 4;
+ this.Time.Text = "00:00";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(7, 91);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(36, 13);
+ this.label4.TabIndex = 32;
+ this.label4.Text = "Dauer";
+ //
+ // ListActivities
+ //
+ this.ListActivities.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
+ this.ListActivities.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
+ this.ListActivities.FormattingEnabled = true;
+ this.ErrorProvider.SetIconPadding(this.ListActivities, 3);
+ this.ListActivities.Location = new System.Drawing.Point(78, 56);
+ this.ListActivities.Name = "ListActivities";
+ this.ListActivities.Size = new System.Drawing.Size(242, 21);
+ this.ListActivities.TabIndex = 3;
+ //
+ // ListProjects
+ //
+ this.ListProjects.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
+ this.ListProjects.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
+ this.ListProjects.FormattingEnabled = true;
+ this.ErrorProvider.SetIconPadding(this.ListProjects, 3);
+ this.ListProjects.Location = new System.Drawing.Point(78, 24);
+ this.ListProjects.Name = "ListProjects";
+ this.ListProjects.Size = new System.Drawing.Size(242, 21);
+ this.ListProjects.TabIndex = 2;
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(6, 59);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(47, 13);
+ this.label3.TabIndex = 29;
+ this.label3.Text = "Leistung";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(6, 27);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(40, 13);
+ this.label2.TabIndex = 28;
+ this.label2.Text = "Projekt";
+ //
+ // Calendar
+ //
+ this.Calendar.BackColor = System.Drawing.SystemColors.Control;
+ this.Calendar.FirstDayOfWeek = System.Windows.Forms.Day.Monday;
+ this.Calendar.Location = new System.Drawing.Point(12, 24);
+ this.Calendar.MaxSelectionCount = 1;
+ this.Calendar.Name = "Calendar";
+ this.Calendar.ShowTodayCircle = false;
+ this.Calendar.TabIndex = 10;
+ this.Calendar.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.SelectDate);
+ //
+ // groupBox2
+ //
+ this.groupBox2.Controls.Add(this.ListTimeEntries);
+ this.groupBox2.Location = new System.Drawing.Point(7, 256);
+ this.groupBox2.Name = "groupBox2";
+ this.groupBox2.Padding = new System.Windows.Forms.Padding(10);
+ this.groupBox2.Size = new System.Drawing.Size(557, 121);
+ this.groupBox2.TabIndex = 30;
+ this.groupBox2.TabStop = false;
+ this.groupBox2.Text = "Einträge für den 09.07.2009";
+ //
+ // ListTimeEntries
+ //
+ this.ListTimeEntries.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.TextColumn});
+ this.ListTimeEntries.ContextMenuStrip = this.TimeEntryContextMenu;
+ this.ListTimeEntries.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ListTimeEntries.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
+ this.ListTimeEntries.HideSelection = false;
+ this.ListTimeEntries.LabelWrap = false;
+ this.ListTimeEntries.Location = new System.Drawing.Point(10, 23);
+ this.ListTimeEntries.MultiSelect = false;
+ this.ListTimeEntries.Name = "ListTimeEntries";
+ this.ListTimeEntries.ShowGroups = false;
+ this.ListTimeEntries.ShowItemToolTips = true;
+ this.ListTimeEntries.Size = new System.Drawing.Size(537, 88);
+ this.ListTimeEntries.TabIndex = 9;
+ this.ListTimeEntries.UseCompatibleStateImageBehavior = false;
+ this.ListTimeEntries.View = System.Windows.Forms.View.Details;
+ this.ListTimeEntries.SelectedIndexChanged += new System.EventHandler(this.TimeEntries_SelectedIndexChanged);
+ //
+ // TextColumn
+ //
+ this.TextColumn.Text = "TextColumn";
+ this.TextColumn.Width = 500;
+ //
+ // TimeEntryContextMenu
+ //
+ this.TimeEntryContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.TimeEntryContextMenuStopStopwatchItem,
+ this.TimeEntryContextMenuStartStopwatchItem,
+ this.toolStripSeparator9,
+ this.TimeEntryContextMenuUnlock,
+ this.TimeEntryContextMenuLock,
+ this.toolStripSeparator8,
+ this.TimeEntryContextMenuDeleteItem});
+ this.TimeEntryContextMenu.Name = "TimeEntryContextMenu";
+ this.TimeEntryContextMenu.Size = new System.Drawing.Size(259, 126);
+ this.TimeEntryContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.TimeEntryContextMenu_Opening);
+ //
+ // TimeEntryContextMenuStopStopwatchItem
+ //
+ this.TimeEntryContextMenuStopStopwatchItem.Name = "TimeEntryContextMenuStopStopwatchItem";
+ this.TimeEntryContextMenuStopStopwatchItem.Size = new System.Drawing.Size(258, 22);
+ this.TimeEntryContextMenuStopStopwatchItem.Text = "Stoppuhr anhalten";
+ this.TimeEntryContextMenuStopStopwatchItem.Click += new System.EventHandler(this.TimeEntryContextMenuStopStopwatchItem_Click);
+ //
+ // TimeEntryContextMenuStartStopwatchItem
+ //
+ this.TimeEntryContextMenuStartStopwatchItem.Name = "TimeEntryContextMenuStartStopwatchItem";
+ this.TimeEntryContextMenuStartStopwatchItem.Size = new System.Drawing.Size(258, 22);
+ this.TimeEntryContextMenuStartStopwatchItem.Text = "Stoppuhr starten";
+ this.TimeEntryContextMenuStartStopwatchItem.Click += new System.EventHandler(this.TimeEntryContextMenuStartStopwatchItem_Click);
+ //
+ // toolStripSeparator9
+ //
+ this.toolStripSeparator9.Name = "toolStripSeparator9";
+ this.toolStripSeparator9.Size = new System.Drawing.Size(255, 6);
+ //
+ // TimeEntryContextMenuUnlock
+ //
+ this.TimeEntryContextMenuUnlock.Name = "TimeEntryContextMenuUnlock";
+ this.TimeEntryContextMenuUnlock.Size = new System.Drawing.Size(258, 22);
+ this.TimeEntryContextMenuUnlock.Text = "Als nicht-abgeschlossen markieren";
+ this.TimeEntryContextMenuUnlock.Visible = false;
+ this.TimeEntryContextMenuUnlock.Click += new System.EventHandler(this.alsNichtabgeschlossenMarkierenToolStripMenuItem_Click);
+ //
+ // TimeEntryContextMenuLock
+ //
+ this.TimeEntryContextMenuLock.Name = "TimeEntryContextMenuLock";
+ this.TimeEntryContextMenuLock.Size = new System.Drawing.Size(258, 22);
+ this.TimeEntryContextMenuLock.Text = "Als abgeschlossen markieren";
+ this.TimeEntryContextMenuLock.Click += new System.EventHandler(this.alsAbgeschlossenMarkierenToolStripMenuItem_Click);
+ //
+ // toolStripSeparator8
+ //
+ this.toolStripSeparator8.Name = "toolStripSeparator8";
+ this.toolStripSeparator8.Size = new System.Drawing.Size(255, 6);
+ //
+ // TimeEntryContextMenuDeleteItem
+ //
+ this.TimeEntryContextMenuDeleteItem.Name = "TimeEntryContextMenuDeleteItem";
+ this.TimeEntryContextMenuDeleteItem.Size = new System.Drawing.Size(258, 22);
+ this.TimeEntryContextMenuDeleteItem.Text = "Löschen";
+ this.TimeEntryContextMenuDeleteItem.Click += new System.EventHandler(this.TimeEntryContextMenuDeleteItem_Click);
+ //
+ // StatusBar
+ //
+ this.StatusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.ToolStripConnectionStatus,
+ this.StopwatchStatus});
+ this.StatusBar.Location = new System.Drawing.Point(0, 386);
+ this.StatusBar.Name = "StatusBar";
+ this.StatusBar.Size = new System.Drawing.Size(572, 22);
+ this.StatusBar.SizingGrip = false;
+ this.StatusBar.TabIndex = 31;
+ this.StatusBar.Text = "statusStrip1";
+ //
+ // ToolStripConnectionStatus
+ //
+ this.ToolStripConnectionStatus.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.ToolStripMenuItemDisconnectFromServer,
+ this.ToolStripMenuItemConnectToServer});
+ this.ToolStripConnectionStatus.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripConnectionStatus.Image")));
+ this.ToolStripConnectionStatus.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.ToolStripConnectionStatus.Name = "ToolStripConnectionStatus";
+ this.ToolStripConnectionStatus.Size = new System.Drawing.Size(94, 20);
+ this.ToolStripConnectionStatus.Text = "Verbunden";
+ //
+ // ToolStripMenuItemDisconnectFromServer
+ //
+ this.ToolStripMenuItemDisconnectFromServer.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripMenuItemDisconnectFromServer.Image")));
+ this.ToolStripMenuItemDisconnectFromServer.ImageTransparentColor = System.Drawing.Color.Black;
+ this.ToolStripMenuItemDisconnectFromServer.Name = "ToolStripMenuItemDisconnectFromServer";
+ this.ToolStripMenuItemDisconnectFromServer.Size = new System.Drawing.Size(190, 22);
+ this.ToolStripMenuItemDisconnectFromServer.Text = "Verbindung trennen";
+ this.ToolStripMenuItemDisconnectFromServer.Click += new System.EventHandler(this.DisconnectFromServer);
+ //
+ // ToolStripMenuItemConnectToServer
+ //
+ this.ToolStripMenuItemConnectToServer.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripMenuItemConnectToServer.Image")));
+ this.ToolStripMenuItemConnectToServer.ImageTransparentColor = System.Drawing.Color.Black;
+ this.ToolStripMenuItemConnectToServer.Name = "ToolStripMenuItemConnectToServer";
+ this.ToolStripMenuItemConnectToServer.Size = new System.Drawing.Size(190, 22);
+ this.ToolStripMenuItemConnectToServer.Text = "Verbindung herstellen";
+ this.ToolStripMenuItemConnectToServer.Visible = false;
+ this.ToolStripMenuItemConnectToServer.Click += new System.EventHandler(this.ConnectToServer);
+ //
+ // StopwatchStatus
+ //
+ this.StopwatchStatus.Image = global::SixtyNineDegrees.MiteDesk.WinForms.Properties.Resources.mini_clock_animated_15x15;
+ this.StopwatchStatus.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.StopwatchStatus.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.StopwatchStatus.Name = "StopwatchStatus";
+ this.StopwatchStatus.Overflow = System.Windows.Forms.ToolStripItemOverflow.Always;
+ this.StopwatchStatus.Size = new System.Drawing.Size(463, 17);
+ this.StopwatchStatus.Spring = true;
+ this.StopwatchStatus.Text = "Stoppuhr: 00:00";
+ this.StopwatchStatus.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.StopwatchStatus.Visible = false;
+ this.StopwatchStatus.Click += new System.EventHandler(this.StopwatchStatus_Click);
+ //
+ // ErrorProvider
+ //
+ this.ErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+ this.ErrorProvider.ContainerControl = this;
+ //
+ // Stopwatch
+ //
+ this.Stopwatch.Interval = 30000;
+ this.Stopwatch.Tick += new System.EventHandler(this.Stopwatch_Tick);
+ //
+ // NotifyIcon
+ //
+ this.NotifyIcon.ContextMenuStrip = this.NotifyContextMenu;
+ //
+ // NotifyContextMenu
+ //
+ this.NotifyContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.NotifyContextMenuStartStopwatchItem,
+ this.NotifyContextMenuStopStopwatchItem,
+ this.toolStripSeparator5,
+ this.NotifyContextMenuOpenMiteDeskItem,
+ this.toolStripSeparator6,
+ this.ExitButton});
+ this.NotifyContextMenu.Name = "NotifyContextMenu";
+ this.NotifyContextMenu.Size = new System.Drawing.Size(173, 104);
+ this.NotifyContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.NotifyContextMenu_Opening);
+ //
+ // NotifyContextMenuStartStopwatchItem
+ //
+ this.NotifyContextMenuStartStopwatchItem.Name = "NotifyContextMenuStartStopwatchItem";
+ this.NotifyContextMenuStartStopwatchItem.Size = new System.Drawing.Size(172, 22);
+ this.NotifyContextMenuStartStopwatchItem.Text = "Stoppuhr starten";
+ this.NotifyContextMenuStartStopwatchItem.Click += new System.EventHandler(this.NotifyContextMenuStartStopwatchItem_Click);
+ //
+ // NotifyContextMenuStopStopwatchItem
+ //
+ this.NotifyContextMenuStopStopwatchItem.Name = "NotifyContextMenuStopStopwatchItem";
+ this.NotifyContextMenuStopStopwatchItem.Size = new System.Drawing.Size(172, 22);
+ this.NotifyContextMenuStopStopwatchItem.Text = "Stoppuhr anhalten";
+ this.NotifyContextMenuStopStopwatchItem.Click += new System.EventHandler(this.NotifyContextMenuStopStopwatchItem_Click);
+ //
+ // toolStripSeparator5
+ //
+ this.toolStripSeparator5.Name = "toolStripSeparator5";
+ this.toolStripSeparator5.Size = new System.Drawing.Size(169, 6);
+ //
+ // NotifyContextMenuOpenMiteDeskItem
+ //
+ this.NotifyContextMenuOpenMiteDeskItem.Name = "NotifyContextMenuOpenMiteDeskItem";
+ this.NotifyContextMenuOpenMiteDeskItem.Size = new System.Drawing.Size(172, 22);
+ this.NotifyContextMenuOpenMiteDeskItem.Text = "Wiederherstellen";
+ this.NotifyContextMenuOpenMiteDeskItem.Click += new System.EventHandler(this.NotifyContextMenuOpenMiteDeskItem_Click);
+ //
+ // toolStripSeparator6
+ //
+ this.toolStripSeparator6.Name = "toolStripSeparator6";
+ this.toolStripSeparator6.Size = new System.Drawing.Size(169, 6);
+ //
+ // ExitButton
+ //
+ this.ExitButton.Name = "ExitButton";
+ this.ExitButton.Size = new System.Drawing.Size(172, 22);
+ this.ExitButton.Text = "Beenden";
+ this.ExitButton.Click += new System.EventHandler(this.NotifyContextMenuExitApplicationItem_Click);
+ //
+ // groupBox1
+ //
+ this.groupBox1.Controls.Add(this.WeekOfYear);
+ this.groupBox1.Controls.Add(this.Calendar);
+ this.groupBox1.Location = new System.Drawing.Point(364, 34);
+ this.groupBox1.Name = "groupBox1";
+ this.groupBox1.Size = new System.Drawing.Size(200, 216);
+ this.groupBox1.TabIndex = 34;
+ this.groupBox1.TabStop = false;
+ this.groupBox1.Text = "Kalender";
+ //
+ // WeekOfYear
+ //
+ this.WeekOfYear.AutoSize = true;
+ this.WeekOfYear.Location = new System.Drawing.Point(9, 195);
+ this.WeekOfYear.Name = "WeekOfYear";
+ this.WeekOfYear.Size = new System.Drawing.Size(135, 13);
+ this.WeekOfYear.TabIndex = 28;
+ this.WeekOfYear.Text = "Gewählte Kalenderwoche: ";
+ //
+ // InitializationBackgroundWorker
+ //
+ this.InitializationBackgroundWorker.WorkerSupportsCancellation = true;
+ //
+ // TimeEntriesBackgroundWorker
+ //
+ this.TimeEntriesBackgroundWorker.WorkerSupportsCancellation = true;
+ //
+ // Main
+ //
+ this.AcceptButton = this.BtnAccept;
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+ this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.CancelButton = this.BtnCancel;
+ this.ClientSize = new System.Drawing.Size(572, 408);
+ this.Controls.Add(this.groupBox1);
+ this.Controls.Add(this.StatusBar);
+ this.Controls.Add(this.groupBox2);
+ this.Controls.Add(this.MainMenu);
+ this.Controls.Add(this.TimeEntryDetailView);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.HelpButton = true;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MainMenuStrip = this.MainMenu;
+ this.MaximizeBox = false;
+ this.Name = "Main";
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "mite.desk";
+ this.MainMenu.ResumeLayout(false);
+ this.MainMenu.PerformLayout();
+ this.TimeEntryDetailView.ResumeLayout(false);
+ this.TimeEntryDetailView.PerformLayout();
+ this.groupBox2.ResumeLayout(false);
+ this.TimeEntryContextMenu.ResumeLayout(false);
+ this.StatusBar.ResumeLayout(false);
+ this.StatusBar.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).EndInit();
+ this.NotifyContextMenu.ResumeLayout(false);
+ this.groupBox1.ResumeLayout(false);
+ this.groupBox1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.MenuStrip MainMenu;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuItemExit;
+ private System.Windows.Forms.ToolStripMenuItem beendenToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
+ private System.Windows.Forms.ToolStripMenuItem einstellungenToolStripMenuItem;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+ private System.Windows.Forms.GroupBox TimeEntryDetailView;
+ private System.Windows.Forms.Button BtnCancel;
+ private System.Windows.Forms.Button BtnAccept;
+ private System.Windows.Forms.TextBox Note;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.TextBox Time;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.ComboBox ListActivities;
+ private System.Windows.Forms.ComboBox ListProjects;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.MonthCalendar Calendar;
+ private System.Windows.Forms.GroupBox groupBox2;
+ private System.Windows.Forms.StatusStrip StatusBar;
+ private System.Windows.Forms.ErrorProvider ErrorProvider;
+ private System.Windows.Forms.ToolStripStatusLabel StopwatchStatus;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuItemCreateNewTimeEntry;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuItemRefreshActivitiesAndProjects;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+ private System.Windows.Forms.ToolStripDropDownButton ToolStripConnectionStatus;
+ private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemConnectToServer;
+ private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemDisconnectFromServer;
+ private System.Windows.Forms.ListView ListTimeEntries;
+ private System.Windows.Forms.ColumnHeader TextColumn;
+ private System.Windows.Forms.Timer Stopwatch;
+ private System.Windows.Forms.NotifyIcon NotifyIcon;
+ private System.Windows.Forms.GroupBox groupBox1;
+ private System.Windows.Forms.Label WeekOfYear;
+ private System.Windows.Forms.ToolStripMenuItem miteZeitenToolStripMenuItem;
+ private System.Windows.Forms.ContextMenuStrip TimeEntryContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem TimeEntryContextMenuStartStopwatchItem;
+ private System.Windows.Forms.ToolStripMenuItem TimeEntryContextMenuStopStopwatchItem;
+ private System.Windows.Forms.ContextMenuStrip NotifyContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem NotifyContextMenuStartStopwatchItem;
+ private System.Windows.Forms.ToolStripMenuItem NotifyContextMenuStopStopwatchItem;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator5;
+ private System.Windows.Forms.ToolStripMenuItem NotifyContextMenuOpenMiteDeskItem;
+ private System.Windows.Forms.ToolStripMenuItem ExitButton;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator6;
+ private System.ComponentModel.BackgroundWorker TimeEntriesBackgroundWorker;
+ private System.Windows.Forms.ToolStripMenuItem datenToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuCustomersItem;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuProjectsItem;
+ private System.Windows.Forms.ToolStripMenuItem MainMenuActivitiesItem;
+ public System.ComponentModel.BackgroundWorker InitializationBackgroundWorker;
+ private System.Windows.Forms.CheckBox Locked;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator9;
+ private System.Windows.Forms.ToolStripMenuItem TimeEntryContextMenuDeleteItem;
+ private System.Windows.Forms.ToolStripMenuItem TimeEntryContextMenuUnlock;
+ private System.Windows.Forms.ToolStripMenuItem TimeEntryContextMenuLock;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator8;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Main.cs b/App/MiteDesk.WinForms/Main.cs
new file mode 100644
index 0000000..3463595
--- /dev/null
+++ b/App/MiteDesk.WinForms/Main.cs
@@ -0,0 +1,1281 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+using StructureMap;
+using Timer=System.Windows.Forms.Timer;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+
+ public partial class Main : Form
+ {
+
+ #region Setup
+
+ public void Initialize()
+ {
+ TimeEntryService = ObjectFactory.GetInstance();
+ ConfigurationService = ObjectFactory.GetInstance();
+
+ SetAppSettings();
+ Helper.SetCulture(AppSettings.Culture);
+
+ InitializeComponent();
+ LocalizeForm();
+
+ NotificationClockTimer = new Timer();
+ NotificationClockTimer.Interval = 200;
+ NotificationClockTimer.Tick += NotificationClockTimer_Tick;
+
+ ActiveTimeEntryClockTimer = new Timer();
+ ActiveTimeEntryClockTimer.Tick += ActiveTimeEntryClockTimer_Tick;
+ ActiveTimeEntryClockTimer.Interval = 200;
+
+ InitializationBackgroundWorker.DoWork += InitializationBackgroundWorker_DoWork;
+ InitializationBackgroundWorker.RunWorkerCompleted += InitializationBackgroundWorker_RunWorkerCompleted;
+
+ TimeEntriesBackgroundWorker.DoWork += TimeEntriesBackgroundWorker_DoWork;
+ TimeEntriesBackgroundWorker.RunWorkerCompleted += TimeEntriesBackgroundWorker_RunWorkerCompleted;
+
+ ListTimeEntries.MouseClick += TimeEntries_MouseClick;
+ StopwatchStatus.MouseMove += StopwatchStatus_MouseMove;
+ StopwatchStatus.MouseLeave += StopwatchStatus_MouseLeave;
+
+ ListProjects.TextUpdate += Helper.ValidateTextEnteredInComboBox;
+ ListActivities.TextUpdate += Helper.ValidateTextEnteredInComboBox;
+
+ Calendar.SizeChanged += Calendar_SizeChanged;
+
+ InitializeForm(true);
+ }
+
+
+ private AppSettings AppSettings;
+
+ private ITimeEntryService TimeEntryService;
+ private IConfigurationService ConfigurationService;
+
+ private TimeEntry CurrentTimeEntry;
+ private Timer NotificationClockTimer;
+
+ private Timer ActiveTimeEntryClockTimer;
+ private int ActiveTimeEntryClockTimerActiveFrame;
+
+ public bool IsInitialized;
+
+ private int LastTrackedTimeEntryID;
+ public bool StopInitialization;
+
+ private IList ActiveDates;
+ private IList TimeEntries;
+ private IList Projects;
+ private IList Activities;
+ private User AuthenticatedUser;
+ private DateTime CalendarCurrentSelectionStart;
+
+ private TimeEntry trackedTimeEntry;
+ private TimeEntry TrackedTimeEntry
+ {
+ get { return trackedTimeEntry; }
+ set
+ {
+ if (value != null)
+ {
+ int minutes = value.Minutes;
+ trackedTimeEntry = TimeEntryService.GetTimeEntryByID(value.ID);
+ trackedTimeEntry.Minutes = minutes;
+ }
+ else
+ {
+ if (trackedTimeEntry != null)
+ LastTrackedTimeEntryID = trackedTimeEntry.ID;
+ trackedTimeEntry = null;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Initialisierung
+
+ public void SetAppSettings()
+ {
+ AppSettings = ConfigurationService.GetAppSettings();
+ }
+
+ public void LocalizeForm()
+ {
+ MainMenuItemCreateNewTimeEntry.Text = MainLabels.MenuNewTimeEntry;
+ MainMenuItemRefreshActivitiesAndProjects.Text = MainLabels.MenuRefreshProjectsAndActivities;
+ einstellungenToolStripMenuItem.Text = MainLabels.MenuSettings;
+ beendenToolStripMenuItem.Text = MainLabels.MenuExit;
+ datenToolStripMenuItem.Text = MainLabels.MenuData;
+ MainMenuCustomersItem.Text = MainLabels.MenuCustomers;
+ MainMenuProjectsItem.Text = MainLabels.MenuProjects;
+ MainMenuActivitiesItem.Text = MainLabels.MenuActivities;
+ miteZeitenToolStripMenuItem.Text = MainLabels.MenuMiteAccount;
+ groupBox1.Text = MainLabels.GroupboxCalendarTitle;
+ TimeEntryContextMenuDeleteItem.Text = MainLabels.ButtonDelete;
+ BtnCancel.Text = MainLabels.ButtonCancel;
+ BtnAccept.Text = MainLabels.ButtonCreate;
+ WeekOfYear.Text = MainLabels.LabelCalendarWeek;
+ TimeEntryDetailView.Text = MainLabels.GroupboxFormCreateMode;
+ groupBox2.Text = MainLabels.GroupboxTimeEntriesTitle + string.Format(" {0:d}", Calendar.SelectionStart);
+ label2.Text = MainLabels.LabelProject;
+ label3.Text = MainLabels.LabelActivity;
+ label4.Text = MainLabels.LabelDuration;
+ label5.Text = MainLabels.LabelNote;
+ ToolStripConnectionStatus.Text = MainLabels.Connected;
+ ToolStripMenuItemDisconnectFromServer.Text = MainLabels.Disconnect;
+ ToolStripMenuItemConnectToServer.Text = MainLabels.Connect;
+ TimeEntryContextMenuStartStopwatchItem.Text = MainLabels.StartStopwatch;
+ TimeEntryContextMenuStopStopwatchItem.Text = MainLabels.StopStopwatch;
+ NotifyContextMenuStartStopwatchItem.Text = MainLabels.NotifyContextMenuStartStopwatch;
+ NotifyContextMenuStopStopwatchItem.Text = MainLabels.NotifyContextMenuStopStopwatch;
+ NotifyContextMenuOpenMiteDeskItem.Text = MainLabels.NotifyContextMenuRestoreWindow;
+ ExitButton.Text = MainLabels.NotifyContextMenuExit;
+ Locked.Text = MainLabels.Locked;
+ TimeEntryContextMenuLock.Text = MainLabels.MarkAsLocked;
+ TimeEntryContextMenuUnlock.Text = MainLabels.MarkAsUnlocked;
+ }
+
+ public void InitializeForm(bool firstStart)
+ {
+
+ if (!StopInitialization)
+ {
+ if (firstStart && string.IsNullOrEmpty(AppSettings.AccountName))
+ new Settings(true).ShowDialog(this);
+ else
+ Helper.StartBackgroundWorker(InitializationBackgroundWorker, null);
+ }
+
+ if (firstStart && AppSettings.StartMinimized)
+ {
+ WindowState = FormWindowState.Minimized;
+ Visible = false;
+ ShowInTaskbar = false;
+ }
+
+ if (firstStart)
+ {
+ CurrentTimeEntry = null;
+ TrackedTimeEntry = null;
+ StopwatchStatus.Text = null;
+ Stopwatch.Enabled = true;
+ IsInitialized = true;
+ ListProjects.Focus();
+ }
+
+ EnableOrDisableForm(true);
+
+ Stopwatch_Tick(null, null);
+
+ }
+
+ void InitializationBackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
+ {
+ if (InitializationBackgroundWorker.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ AuthenticatedUser = ObjectFactory.GetInstance().GetAuthenticatedUser();
+ Projects = ObjectFactory.GetInstance().GetAllActiveProjects();
+ Activities = ObjectFactory.GetInstance().GetAllActiveActivities();
+ }
+
+ void InitializationBackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
+ {
+ try
+ {
+ if (!e.Cancelled)
+ InitializeProjectsAndActivities();
+ if (!e.Cancelled)
+ DisplayAuthenticatedUserInTitleBar();
+ if (!e.Cancelled)
+ SetWeekOfYear(DateTime.Today);
+ if (!e.Cancelled)
+ EnableOrDisableDataMenuItem();
+ if (!e.Cancelled)
+ InitializeEntryDetailView();
+ if (!e.Cancelled)
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, Calendar.SelectionStart);
+ }
+ catch (TargetInvocationException)
+ {
+ }
+ }
+
+ private void InitializeEntryDetailView()
+ {
+ if (Locked == null || AuthenticatedUser == null)
+ return;
+ Locked.Visible = AuthenticatedUser.Role == UserRole.Admin || AuthenticatedUser.Role == UserRole.Owner;
+ }
+
+ private void InitializeProjectsAndActivities()
+ {
+
+ if (ListActivities == null || Projects == null)
+ return;
+
+ int selectedProjectID = ListProjects.SelectedItem != null ? ((ListItem)ListProjects.SelectedItem).Value : AppSettings.SelectedProjectID;
+
+ ListProjects.Items.Clear();
+ ListProjects.ValueMember = "Value";
+ ListProjects.DisplayMember = "Text";
+ ListProjects.Items.Add(new ListItem { Text = string.Empty, Value = 0 });
+
+ var customers = new Dictionary();
+
+ foreach (var project in Projects)
+ {
+ if(!customers.ContainsKey(project.CustomerID))
+ customers.Add(project.CustomerID, project.CustomerName);
+ }
+
+ if(!customers.ContainsKey(0))
+ customers.Add(0, string.Empty);
+
+ customers.OrderBy(c => c.Value).ToDictionary(c => c.Key, c => c.Value);
+
+ foreach (var customer in customers)
+ {
+ foreach (var project in Projects.Where(p => p.CustomerID == customer.Key))
+ {
+ ListProjects.Items.Add(new ListItem { Text = !string.IsNullOrEmpty(customer.Value) ? customer.Value + ": " + project.Name : project.Name, Value = project.ID });
+ if (selectedProjectID == project.ID)
+ ListProjects.SelectedItem = ListProjects.Items[ListProjects.Items.Count - 1];
+ }
+ }
+
+ int selectedActivityID = ListActivities.SelectedItem != null ? ((ListItem)ListActivities.SelectedItem).Value : AppSettings.SelectedActivityID;
+
+ ListActivities.Items.Clear();
+ ListActivities.ValueMember = "Value";
+ ListActivities.DisplayMember = "Text";
+ ListActivities.Items.Add(new ListItem { Text = string.Empty, Value = 0 });
+
+ foreach (var activity in Activities)
+ {
+ ListActivities.Items.Add(new ListItem { Text = activity.Name, Value = activity.ID });
+ if (selectedActivityID == activity.ID)
+ ListActivities.SelectedItem = ListActivities.Items[ListActivities.Items.Count - 1];
+ }
+
+ }
+
+ #endregion
+
+ #region Menü
+
+ private void EnableOrDisableDataMenuItem()
+ {
+ if (AuthenticatedUser != null)
+ datenToolStripMenuItem.Visible = AuthenticatedUser.Role != UserRole.TimeTracker;
+ }
+
+ private void Exit(object sender, EventArgs e)
+ {
+ if (HandleClosing())
+ Application.Exit();
+ }
+
+ private void MainMenuItemSettingsClick(object sender, EventArgs e)
+ {
+ new Settings(false).ShowDialog(this);
+ }
+
+ private void MainMenuItemCreateNewTimeEntryClick(object sender, EventArgs e)
+ {
+ ResetForm();
+ ListProjects.Focus();
+ }
+
+ private void MainMenuItemRefreshProjectsAndActivitiesClick(object sender, EventArgs e)
+ {
+ Helper.StartBackgroundWorker(InitializationBackgroundWorker, null);
+ }
+
+ private void miteZeitenToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ Helper.OpenBrowser("https://" + AppSettings.AccountName + ".mite.yo.lk/daily");
+ }
+
+ private void MainMenuCustomersItem_Click(object sender, EventArgs e)
+ {
+ new Customers().ShowDialog(this);
+ }
+
+ private void MainMenuProjectsItem_Click(object sender, EventArgs e)
+ {
+ new Projects().ShowDialog(this);
+ }
+
+ private void MainMenuActivitiesItem_Click(object sender, EventArgs e)
+ {
+ new Activities().ShowDialog(this);
+ }
+
+ #endregion
+
+ #region Kopfleiste
+
+ private void DisplayAuthenticatedUserInTitleBar()
+ {
+ if (AuthenticatedUser != null)
+ Text = "mite.desk " + Helper.CurrentVersion + " - " + MainLabels.AuthenticatedAs + " " + AuthenticatedUser.Name + " (" + AuthenticatedUser.Email + ")";
+ }
+
+ #endregion
+
+ #region Zeiteintrag erstellen und bearbeiten
+
+ private void CreateOrUpdateTimeEntry(bool update)
+ {
+
+ TimeEntry entry = update ? CurrentTimeEntry : new TimeEntry();
+
+ if (ListActivities.SelectedIndex > -1)
+ entry.ActivityID = ((ListItem)ListActivities.SelectedItem).Value;
+
+ if (ListProjects.SelectedIndex > -1)
+ entry.ProjectID = ((ListItem)ListProjects.SelectedItem).Value;
+
+ entry.Note = Note.Text;
+ entry.Date = Calendar.SelectionStart;
+ entry.Locked = Locked.Checked;
+
+ IDictionary result = update ? TimeEntryService.UpdateTimeEntry(CurrentTimeEntry, Time.Text) :
+ TimeEntryService.CreateTimeEntry(ref entry, Time.Text);
+
+ if (result.Count > 0)
+ {
+ DisplayValidationMessages(result);
+ return;
+ }
+
+ ErrorProvider.Clear();
+
+ if (!update)
+ {
+
+ if (entry.Minutes == 0 && !entry.Locked)
+ TimeEntryService.StartStopwatch(entry.ID);
+
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, Calendar.SelectionStart);
+ Stopwatch_Tick(null, null);
+
+ Note.Text = string.Empty;
+ Time.Text = "00:00";
+
+ }
+ else
+ {
+ CurrentTimeEntry = null;
+ ResetForm();
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, Calendar.SelectionStart);
+ }
+
+ AppSettings.SelectedProjectID = entry.ProjectID;
+ AppSettings.SelectedActivityID = entry.ActivityID;
+ ConfigurationService.UpdateAppSettings(AppSettings);
+
+ }
+
+ private void Locked_Click(object sender, EventArgs e)
+ {
+ if (CurrentTimeEntry != null && CurrentTimeEntry.Locked && !Locked.Checked)
+ CreateOrUpdateTimeEntry(true);
+ }
+
+ #endregion
+
+ #region Zeiteintrag löschen
+
+ private void DeleteTimeEntry(object sender, EventArgs e)
+ {
+ DeleteTimeEntry(CurrentTimeEntry.ID);
+ }
+
+ private void DeleteTimeEntry(int entryID)
+ {
+ var question = MessageBox.Show(MainLabels.MsgBoxDeleteTimeEntryText, MainLabels.MsgBoxDeleteTimeEntryTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+ if (question == DialogResult.Yes)
+ {
+ TimeEntryService.DeleteTimeEntry(entryID);
+ ResetForm();
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, Calendar.SelectionStart);
+ }
+ }
+
+ #endregion
+
+ #region Zeiteintrag darstellen
+
+ private void LoadSingleTimeEntryInForm(int id)
+ {
+
+ CurrentTimeEntry = TimeEntryService.GetTimeEntryByID(id);
+
+ foreach (var project in ListProjects.Items)
+ {
+ if (((ListItem)project).Value == CurrentTimeEntry.ProjectID)
+ {
+ ListProjects.SelectedItem = project;
+ break;
+ }
+ }
+
+ foreach (var activity in ListActivities.Items)
+ {
+ if (((ListItem)activity).Value == CurrentTimeEntry.ActivityID)
+ {
+ ListActivities.SelectedItem = activity;
+ break;
+ }
+ }
+
+ var minutes = CurrentTimeEntry.Minutes;
+
+ if (TrackedTimeEntry != null && TrackedTimeEntry.ID == CurrentTimeEntry.ID)
+ minutes = TrackedTimeEntry.Minutes;
+
+ Time.Text = Helper.GetFormattedTimeText(minutes);
+ Note.Text = CurrentTimeEntry.Note;
+ BtnAccept.Text = MainLabels.ButtonSave;
+ TimeEntryDetailView.Text = MainLabels.GroupboxFormEditMode;
+ Time.Enabled = CurrentTimeEntry == null || TrackedTimeEntry == null || id != TrackedTimeEntry.ID;
+
+ EnableOrDisableTimeEntryDetailView();
+
+ }
+
+ private void EnableOrDisableTimeEntryDetailView()
+ {
+ ListProjects.Enabled = !CurrentTimeEntry.Locked;
+ ListActivities.Enabled = !CurrentTimeEntry.Locked;
+ Time.Enabled = !CurrentTimeEntry.Locked;
+ Note.Enabled = !CurrentTimeEntry.Locked;
+ BtnAccept.Enabled = !CurrentTimeEntry.Locked;
+ BtnCancel.Enabled = !CurrentTimeEntry.Locked;
+ Locked.Checked = CurrentTimeEntry.Locked;
+ }
+
+ private void BtnAccept_Click(object sender, EventArgs e)
+ {
+ Cursor = Cursors.WaitCursor;
+ CreateOrUpdateTimeEntry(CurrentTimeEntry != null);
+ Cursor = Cursors.Default;
+ }
+
+ private void BtnCancel_Click(object sender, EventArgs e)
+ {
+ ResetForm();
+ }
+
+ #endregion
+
+ #region Kalender
+
+ private void SelectDate(object sender, DateRangeEventArgs e)
+ {
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, e.Start);
+ SetWeekOfYear(e.Start);
+ }
+
+ private void SetWeekOfYear(DateTime date)
+ {
+ CultureInfo cultureInfo = CultureInfo.CurrentCulture;
+ WeekOfYear.Text = MainLabels.LabelCalendarWeek + " " + cultureInfo.Calendar.GetWeekOfYear(date, cultureInfo.DateTimeFormat.CalendarWeekRule, cultureInfo.DateTimeFormat.FirstDayOfWeek);
+ }
+
+ private void SetCalendarBoldedDays()
+ {
+ if(ActiveDates == null)
+ return;
+
+ var firstDate = new DateTime(Calendar.SelectionStart.Year, Calendar.SelectionStart.Month, 1);
+ if (CalendarCurrentSelectionStart != firstDate)
+ {
+ Calendar.BoldedDates = ActiveDates.ToArray();
+ CalendarCurrentSelectionStart = firstDate;
+ }
+ }
+
+ void Calendar_SizeChanged(object sender, EventArgs e)
+ {
+ int width = ((MonthCalendar) sender).Size.Width;
+ if(width > 164)
+ {
+ Width = 600;
+ groupBox1.Width = 223;
+ groupBox2.Width = 580;
+ }
+ }
+
+ #endregion
+
+ #region Zeiteinträge
+
+ void TimeEntriesBackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
+ {
+ try
+ {
+ if(!e.Cancelled)
+ LoadTimeEntries();
+ if (!e.Cancelled)
+ SetCalendarBoldedDays();
+ }
+ catch (TargetInvocationException ex)
+ {}
+ }
+
+ void TimeEntriesBackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
+ {
+
+ if(TimeEntriesBackgroundWorker.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ var selectedDate = (DateTime) e.Argument;
+ var firstDate = new DateTime(selectedDate.Year, selectedDate.Month, 1);
+
+ if (CalendarCurrentSelectionStart != firstDate && AuthenticatedUser != null)
+ {
+ var lastDate = firstDate.AddMonths(1).AddDays(-1);
+ ActiveDates = TimeEntryService.GetTimeEntryDatesByRange(firstDate, lastDate, AuthenticatedUser.ID);
+ }
+
+ TimeEntries = TimeEntryService.GetTimeEntriesByDate(selectedDate);
+
+ if (AppSettings.SortTimeEntriesDescending)
+ TimeEntries = TimeEntries.OrderByDescending(entry => entry.ID).ToList();
+
+ }
+
+ private void LoadTimeEntries()
+ {
+
+ if (TimeEntries == null)
+ return;
+
+ ListTimeEntries.SmallImageList = new ImageList();
+
+ ListViewItem selected = new ListViewItem();
+ selected.ImageKey = "-1";
+
+ if (ListTimeEntries.SelectedItems.Count > 0)
+ selected = ListTimeEntries.SelectedItems[0];
+
+ ListTimeEntries.Items.Clear();
+ RefreshListTimeEntriesGroupLabel();
+
+ foreach (var entry in TimeEntries)
+ {
+
+ var text = GetTimeEntryDisplayText(TrackedTimeEntry != null && TrackedTimeEntry.ID == entry.ID ? TrackedTimeEntry : entry);
+ ListViewItem item = new ListViewItem(text, entry.ID.ToString());
+ item.ToolTipText = text;
+ item.Selected = item.ImageKey == selected.ImageKey;
+
+ if (TrackedTimeEntry != null && TrackedTimeEntry.ID == entry.ID)
+ {
+ item.ForeColor = Color.FromArgb(255, 102, 51);
+ item.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold);
+ ListTimeEntries.SmallImageList.Images.Add(item.ImageKey, Properties.Resources.mite_desk_icon_16x16_1);
+ }
+ else
+ {
+ ListTimeEntries.SmallImageList.Images.Add(item.ImageKey, GetIdleIcon(entry.ID));
+ }
+
+ ListTimeEntries.Items.Add(item);
+ }
+ }
+
+ private void RefreshListTimeEntriesGroupLabel()
+ {
+
+ if (TimeEntries == null)
+ return;
+
+ if (TimeEntries.Count == 0)
+ {
+ groupBox2.Text = MainLabels.GroupboxTimeEntriesTitle + " " + string.Format("{0:d}", Calendar.SelectionStart);
+ }
+ else
+ {
+ int minutes = 0;
+ foreach (var timeEntry in TimeEntries)
+ minutes += timeEntry.Minutes;
+ groupBox2.Text = MainLabels.GroupboxTimeEntriesTitle + " " + string.Format("{0:d}", Calendar.SelectionStart) + " (" + TimeEntries.Count + ", " + MainLabels.TimeTotal + " " + Helper.GetFormattedTimeText(minutes) + ")";
+ }
+ }
+
+ private void RefreshTimeEntries()
+ {
+ for (int i = 0; i < ListTimeEntries.Items.Count; i++)
+ {
+ var item = ListTimeEntries.Items[i];
+ if (TrackedTimeEntry != null && item.ImageKey == TrackedTimeEntry.ID.ToString())
+ {
+ var text = GetTimeEntryDisplayText(TrackedTimeEntry);
+ if (item.ForeColor != Color.FromArgb(255, 102, 51))
+ {
+ item.ForeColor = Color.FromArgb(255, 102, 51);
+ item.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold);
+ item.Text = text;
+ item.ToolTipText = item.Text;
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_1;
+ }
+ else if(item.Text != text)
+ {
+ item.Text = text;
+ }
+ }
+ else
+ {
+ if (item.ForeColor == Color.FromArgb(255, 102, 51))
+ {
+ item.ForeColor = Color.Black;
+ item.Font = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Regular);
+ }
+ ListTimeEntries.SmallImageList.Images[i] = GetIdleIcon(int.Parse(item.ImageKey));
+ }
+ }
+ }
+
+ private Bitmap GetIdleIcon(int timeEntryID)
+ {
+ if (TimeEntries != null)
+ {
+ var entry = TimeEntries.SingleOrDefault(e => e.ID == timeEntryID);
+ if(entry != null && entry.Locked)
+ return Properties.Resources.Locked;
+ }
+ return Properties.Resources.mite_desk_icon_16x16_1;
+ }
+
+ void TimeEntries_MouseClick(object sender, MouseEventArgs e)
+ {
+ // In den ersten 20 Pixeln ist der Cursor auf dem Stoppuhr-Icon
+ if(e.X <= 20 && e.Button != MouseButtons.Right && TimeEntries != null && ListTimeEntries.SelectedItems != null && ListTimeEntries.SelectedItems.Count > 0)
+ {
+ var entry = TimeEntries.SingleOrDefault(t => t.ID == int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ if (entry != null && !entry.Locked)
+ HandleStopwatch(entry.ID);
+ }
+ }
+
+ private static string GetTimeEntryDisplayText(TimeEntry entry)
+ {
+ return GetTimeEntryDisplayText(entry, 0);
+ }
+
+ private static string GetTimeEntryDisplayText(TimeEntry entry, int maxLength)
+ {
+
+ var text = string.Format(" {0} / {1} / {2} / {3}{4}",
+ Helper.GetFormattedTimeText(entry.Minutes),
+ entry.CustomerName, entry.ProjectName, entry.ActivityName,
+ entry.Note.Trim().Length > 0 ? " (" + entry.Note + ")" : string.Empty);
+
+ if (maxLength == 0 || text.Length <= maxLength)
+ return text;
+
+ return text.Substring(0, maxLength - 4) + " ...";
+
+ }
+
+ private void TimeEntries_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (ListTimeEntries.SelectedItems.Count > 0)
+ {
+ Cursor = Cursors.WaitCursor;
+ LoadSingleTimeEntryInForm(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ Cursor = Cursors.Default;
+ }
+ }
+
+ void ActiveTimeEntryClockTimer_Tick(object sender, EventArgs e)
+ {
+
+ if (ActiveTimeEntryClockTimerActiveFrame == 8)
+ ActiveTimeEntryClockTimerActiveFrame = 0;
+
+ ActiveTimeEntryClockTimerActiveFrame++;
+
+ for (int i = 0; i < ListTimeEntries.Items.Count; i++)
+ {
+ if (TrackedTimeEntry != null && ListTimeEntries.Items[i].ImageKey == TrackedTimeEntry.ID.ToString())
+ {
+ switch (ActiveTimeEntryClockTimerActiveFrame)
+ {
+ case 1:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_1;
+ break;
+ case 2:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_2;
+ break;
+ case 3:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_3;
+ break;
+ case 4:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_4;
+ break;
+ case 5:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_5;
+ break;
+ case 6:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_6;
+ break;
+ case 7:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_7;
+ break;
+ case 8:
+ ListTimeEntries.SmallImageList.Images[i] = Properties.Resources.mite_desk_icon_16x16_8;
+ break;
+ }
+ ListTimeEntries.RedrawItems(i, i, false);
+ break;
+ }
+
+ }
+
+ }
+
+ #region Kontextmenü
+
+ private void TimeEntryContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+
+ TimeEntry entry = null;
+
+ if (ListTimeEntries.SelectedItems.Count > 0 && TimeEntries != null)
+ entry = TimeEntries.SingleOrDefault(t => t.ID == int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+
+ if(entry == null)
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ TimeEntryContextMenuStartStopwatchItem.Visible = !entry.Locked;
+ TimeEntryContextMenuStopStopwatchItem.Visible = !entry.Locked;
+
+ toolStripSeparator8.Visible = !entry.Locked;
+ TimeEntryContextMenuDeleteItem.Visible = !entry.Locked;
+ TimeEntryContextMenuLock.Visible = !entry.Locked && (AuthenticatedUser.Role == UserRole.Admin || AuthenticatedUser.Role == UserRole.Owner);
+ TimeEntryContextMenuUnlock.Visible = entry.Locked;
+
+ toolStripSeparator9.Visible = !entry.Locked && (AuthenticatedUser.Role == UserRole.Admin || AuthenticatedUser.Role == UserRole.Owner);
+
+ if (entry.Locked)
+ return;
+
+ if(TrackedTimeEntry != null && TrackedTimeEntry.ID == entry.ID)
+ {
+ TimeEntryContextMenuStartStopwatchItem.Visible = false;
+ TimeEntryContextMenuStopStopwatchItem.Visible = true;
+ }
+ else
+ {
+ TimeEntryContextMenuStartStopwatchItem.Visible = true;
+ TimeEntryContextMenuStopStopwatchItem.Visible = false;
+ }
+
+ }
+
+ private void TimeEntryContextMenuStartStopwatchItem_Click(object sender, EventArgs e)
+ {
+ HandleStopwatch(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ }
+
+ private void TimeEntryContextMenuStopStopwatchItem_Click(object sender, EventArgs e)
+ {
+ HandleStopwatch(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ }
+
+ private void TimeEntryContextMenuDeleteItem_Click(object sender, EventArgs e)
+ {
+ if (TrackedTimeEntry != null)
+ HandleStopwatch(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ DeleteTimeEntry(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ }
+
+ private void alsNichtabgeschlossenMarkierenToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ Locked.Checked = false;
+ CreateOrUpdateTimeEntry(true);
+ }
+
+ private void alsAbgeschlossenMarkierenToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if(TrackedTimeEntry != null)
+ HandleStopwatch(int.Parse(ListTimeEntries.SelectedItems[0].ImageKey));
+ Locked.Checked = true;
+ CreateOrUpdateTimeEntry(true);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Formular-Helfer
+
+ private void ResetForm()
+ {
+ ListTimeEntries.SelectedItems.Clear();
+ Note.Text = null;
+ Time.Text = "00:00";
+ Locked.Checked = false;
+ BtnAccept.Text = MainLabels.ButtonCreate;
+ TimeEntryDetailView.Text = MainLabels.GroupboxFormCreateMode;
+ CurrentTimeEntry = null;
+ ErrorProvider.Clear();
+ RefreshStopwatchStatus();
+ ListProjects.Enabled = true;
+ ListActivities.Enabled = true;
+ Time.Enabled = true;
+ Note.Enabled = true;
+ BtnAccept.Enabled = true;
+ BtnCancel.Enabled = true;
+ Locked.Checked = false;
+ }
+
+ private void DisplayValidationMessages(IDictionary errors)
+ {
+ ErrorProvider.Clear();
+ if (errors.ContainsKey("Time"))
+ ErrorProvider.SetError(Time, errors["Time"]);
+ }
+
+ #endregion
+
+ #region Fehlerbehandlung
+
+ public void NotifyAboutNetworkErrorAndDisableForm(MiteConnectorException exception)
+ {
+ EnableOrDisableForm(false);
+ ToolStripConnectionStatus.Text += " - " + MainLabels.ConnectionFailed;
+ }
+
+ public void EnableOrDisableForm(bool enabled)
+ {
+
+ Stopwatch.Enabled = enabled;
+ Cursor = Cursors.Default;
+
+ Calendar.Enabled = enabled;
+ ListProjects.Enabled = enabled;
+ ListActivities.Enabled = enabled;
+ Time.Enabled = enabled;
+ Note.Enabled = enabled;
+ ListTimeEntries.Enabled = enabled;
+ MainMenuItemCreateNewTimeEntry.Enabled = enabled;
+ MainMenuItemRefreshActivitiesAndProjects.Enabled = enabled;
+ MainMenuCustomersItem.Enabled = enabled;
+ MainMenuProjectsItem.Enabled = enabled;
+ MainMenuActivitiesItem.Enabled = enabled;
+ BtnAccept.Enabled = enabled;
+ BtnCancel.Enabled = enabled;
+
+ if (enabled)
+ {
+ DisplayAuthenticatedUserInTitleBar();
+ ToolStripConnectionStatus.Text = MainLabels.Connected;
+ ToolStripMenuItemDisconnectFromServer.Visible = true;
+ ToolStripMenuItemConnectToServer.Visible = false;
+ ToolStripConnectionStatus.Image = Properties.Resources.Connected;
+ }
+ else
+ {
+ Text = "mite.desk " + Helper.CurrentVersion + " - " + MainLabels.Disconnected;
+ ToolStripConnectionStatus.Text = MainLabels.Disconnected;
+ ToolStripMenuItemDisconnectFromServer.Visible = false;
+ ToolStripMenuItemConnectToServer.Visible = true;
+ ToolStripConnectionStatus.Image = Properties.Resources.Disconnected;
+ StopwatchStatus.Visible = false;
+ if (NotificationClockTimer != null && NotificationClockTimer.Enabled)
+ NotificationClockTimer.Stop();
+ if (ActiveTimeEntryClockTimer != null)
+ ActiveTimeEntryClockTimer.Stop();
+ }
+ }
+
+ #endregion
+
+ #region Online- und Offlinemodus
+
+ private void ConnectToServer(object sender, EventArgs e)
+ {
+ try
+ {
+ ObjectFactory.GetInstance().GetAuthenticatedUser();
+ InitializeForm(false);
+ }
+ catch (MiteConnectorException ex)
+ {
+ NotifyAboutNetworkErrorAndDisableForm(ex);
+ MessageBox.Show(MainLabels.MsgBoxConnectionErrorText, MainLabels.MsgBoxConnectionErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+
+ }
+
+ private void DisconnectFromServer(object sender, EventArgs e)
+ {
+ EnableOrDisableForm(false);
+ }
+
+ #endregion
+
+ #region Stoppuhr
+
+ private void HandleStopwatch(int timeEntryID)
+ {
+ Cursor = Cursors.WaitCursor;
+ Stopwatch.Enabled = false;
+
+ int stoppedTimeEntryID = StopStopwatch();
+ if (stoppedTimeEntryID != timeEntryID)
+ StartStopwatch(timeEntryID);
+ RefreshStopwatchStatus();
+ RefreshTimeEntries();
+ RefreshListTimeEntriesGroupLabel();
+
+ Stopwatch.Enabled = true;
+ Cursor = Cursors.Default;
+ }
+
+ private void StartStopwatch(int timeEntryID)
+ {
+ TimeEntryService.StartStopwatch(timeEntryID);
+ TrackedTimeEntry = TimeEntryService.GetTimeEntryCurrentlyTrackedByStopwatch();
+ if (NotifyIcon.Visible)
+ {
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+ NotifyIcon.Text = GetTimeEntryDisplayText(TrackedTimeEntry, 63);
+ NotificationClockTimer.Start();
+ }
+ }
+
+ private int StopStopwatch()
+ {
+ int trackedTimeEntryID = TrackedTimeEntry != null ? TrackedTimeEntry.ID : 0;
+ if (trackedTimeEntryID != 0)
+ {
+ TimeEntryService.StopStopwatch(trackedTimeEntryID);
+ TrackedTimeEntry = null;
+ Time.Enabled = CurrentTimeEntry == null || !CurrentTimeEntry.Locked;
+ if (NotifyIcon.Visible)
+ {
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+ NotifyIcon.Text = MainLabels.StopwatchNotStarted;
+ NotificationClockTimer.Stop();
+ }
+ }
+ return trackedTimeEntryID;
+ }
+
+ void StopwatchStatus_MouseLeave(object sender, EventArgs e)
+ {
+ Cursor = Cursors.Default;
+ }
+
+ void StopwatchStatus_MouseMove(object sender, MouseEventArgs e)
+ {
+ Cursor = e.X >= 355 ? Cursors.Hand : Cursors.Default;
+ }
+
+ private void Stopwatch_Tick(object sender, EventArgs e)
+ {
+
+ bool wasTracking = TrackedTimeEntry != null;
+ TrackedTimeEntry = TimeEntryService.GetTimeEntryCurrentlyTrackedByStopwatch();
+
+ bool isTracking = TrackedTimeEntry != null;
+ bool statusHasChanged = wasTracking != isTracking;
+
+ if (statusHasChanged)
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, Calendar.SelectionStart);
+
+ RefreshStopwatchStatus();
+ RefreshTimeEntries();
+
+ if (WindowState == FormWindowState.Minimized)
+ RefreshTaskbarNotificationInfo(false);
+
+ }
+
+ private void RefreshStopwatchStatus()
+ {
+ if (TrackedTimeEntry != null)
+ {
+ StopwatchStatus.Text = string.Format(MainLabels.Stopwatch + ": {0}", Helper.GetFormattedTimeText(TrackedTimeEntry.Minutes));
+ StopwatchStatus.Visible = true;
+ ActiveTimeEntryClockTimer.Enabled = true;
+ if(NotifyIcon.Visible)
+ {
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+ NotifyIcon.Text = GetTimeEntryDisplayText(TrackedTimeEntry, 63);
+ if (!NotificationClockTimer.Enabled)
+ NotificationClockTimer.Start();
+ }
+ else
+ {
+ if (TimeEntries != null)
+ {
+ var timeEntry = TimeEntries.SingleOrDefault(t => t.ID == TrackedTimeEntry.ID);
+ if (timeEntry != null)
+ timeEntry.Minutes = TrackedTimeEntry.Minutes;
+ }
+ RefreshListTimeEntriesGroupLabel();
+ }
+ if (CurrentTimeEntry != null && CurrentTimeEntry.ID == TrackedTimeEntry.ID)
+ {
+ Time.Text = Helper.GetFormattedTimeText(TrackedTimeEntry.Minutes);
+ Time.Enabled = false;
+ }
+ else if(CurrentTimeEntry == null || !CurrentTimeEntry.Locked)
+ {
+ Time.Enabled = true;
+ }
+ }
+ else
+ {
+ Time.Enabled = CurrentTimeEntry == null || !CurrentTimeEntry.Locked;
+ StopwatchStatus.Visible = false;
+ ActiveTimeEntryClockTimer.Enabled = false;
+ if(NotifyIcon.Visible)
+ {
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+ NotifyIcon.Text = MainLabels.StopwatchNotStarted;
+ NotificationClockTimer.Stop();
+ }
+ }
+ }
+
+ private void StopwatchStatus_Click(object sender, EventArgs e)
+ {
+ Calendar.SelectionStart = TrackedTimeEntry.Date;
+ Helper.StartBackgroundWorker(TimeEntriesBackgroundWorker, TrackedTimeEntry.Date);
+ SetWeekOfYear(TrackedTimeEntry.Date);
+ }
+
+ #endregion
+
+ #region Minimierung Taskbar
+
+ private const int SizeMinimized = 1;
+ private const int WmSize = 5;
+ private const int SwRestore = 9;
+
+ protected override void WndProc(ref Message m)
+ {
+ if (m.Msg == WmSize && (int)m.WParam == SizeMinimized)
+ {
+ RefreshTaskbarNotificationInfo(true);
+ }
+ else if(m.Msg == SingleInstance.WM_SHOWFIRSTINSTANCE)
+ {
+ if(!Visible)
+ ReOpenMainForm();
+ Activate();
+ }
+ base.WndProc(ref m);
+ }
+
+ void RefreshTaskbarNotificationInfo(bool initialize)
+ {
+
+ Visible = false;
+ WindowState = FormWindowState.Minimized;
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+
+ // Nur wenn nicht im offline-Modus
+ if (Stopwatch.Enabled && TrackedTimeEntry != null)
+ {
+ NotifyIcon.Text = GetTimeEntryDisplayText(TrackedTimeEntry, 63);
+ NotificationIconNumber = 0;
+ NotificationClockTimer.Start();
+ }
+ else
+ {
+ NotifyIcon.Text = MainLabels.StopwatchNotStarted;
+ }
+
+ if (!initialize)
+ return;
+
+ NotifyIcon.Visible = true;
+ NotifyIcon.MouseClick += NotifyIcon_MouseClick;
+
+ }
+
+ private void ReOpenMainForm()
+ {
+ if (NotificationClockTimer != null && NotificationClockTimer.Enabled)
+ NotificationClockTimer.Stop();
+ Visible = true;
+ ShowInTaskbar = true;
+ NotifyIcon.Visible = false;
+ WinApi.ShowWindow(Handle, SwRestore);
+ ListProjects.Focus();
+ }
+
+ void NotifyIcon_MouseClick(object sender, MouseEventArgs e)
+ {
+ if(e.Button != MouseButtons.Left || e.Clicks > 1)
+ return;
+ ReOpenMainForm();
+ }
+
+ private void NotifyContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ TimeEntry entry = null;
+ if (TimeEntries != null)
+ entry = TimeEntries.SingleOrDefault(t => t.ID == LastTrackedTimeEntryID);
+ NotifyContextMenuStartStopwatchItem.Visible = NotificationClockTimer != null && !NotificationClockTimer.Enabled;
+ NotifyContextMenuStartStopwatchItem.Enabled = entry != null && !entry.Locked;
+ NotifyContextMenuStopStopwatchItem.Visible = NotificationClockTimer != null && NotificationClockTimer.Enabled;
+ }
+
+ private void NotifyContextMenuStartStopwatchItem_Click(object sender, EventArgs e)
+ {
+ HandleStopwatch(LastTrackedTimeEntryID);
+ }
+
+ private void NotifyContextMenuStopStopwatchItem_Click(object sender, EventArgs e)
+ {
+ HandleStopwatch(TrackedTimeEntry.ID);
+ }
+
+ private void NotifyContextMenuOpenMiteDeskItem_Click(object sender, EventArgs e)
+ {
+ ReOpenMainForm();
+ }
+
+ private void NotifyContextMenuExitApplicationItem_Click(object sender, EventArgs e)
+ {
+ if(HandleClosing())
+ Application.Exit();
+ }
+
+ #region Stoppuhr in Taskbar
+
+ private int NotificationIconNumber;
+
+ void NotificationClockTimer_Tick(object sender, EventArgs e)
+ {
+
+ if(WindowState != FormWindowState.Minimized)
+ {
+ NotificationClockTimer.Stop();
+ return;
+ }
+
+ if (NotificationIconNumber == 8)
+ NotificationIconNumber = 0;
+
+ NotificationIconNumber++;
+
+ // bad, bad, bad ... :(
+ switch(NotificationIconNumber)
+ {
+ case 1:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_1;
+ break;
+ case 2:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_2;
+ break;
+ case 3:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_3;
+ break;
+ case 4:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_4;
+ break;
+ case 5:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_5;
+ break;
+ case 6:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_6;
+ break;
+ case 7:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_7;
+ break;
+ case 8:
+ NotifyIcon.Icon = Properties.Resources.mitedesk_clock_8;
+ break;
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Schließen/Minimieren
+
+ protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
+ {
+
+ if (AppSettings.MinimizeByClosing)
+ {
+ RefreshTaskbarNotificationInfo(true);
+ e.Cancel = true;
+ return;
+ }
+
+ if (!HandleClosing())
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ base.OnClosing(e);
+
+ }
+
+ private bool HandleClosing()
+ {
+
+ if (AppSettings.StopStopwatchByClosing)
+ {
+ StopStopwatch();
+ }
+
+ else if (AppSettings.AskForStoppingStopwatchByClosing && TrackedTimeEntry != null)
+ {
+ var result = MessageBox.Show(MainLabels.AskForStoppingStopwatch, MainLabels.Stopwatch, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
+ if (result == DialogResult.Yes)
+ {
+ StopStopwatch();
+ }
+ else if (result == DialogResult.Cancel)
+ {
+ return false;
+ }
+ }
+
+ return true;
+
+ }
+
+ #endregion
+
+
+ }
+
+}
diff --git a/App/MiteDesk.WinForms/Main.resx b/App/MiteDesk.WinForms/Main.resx
new file mode 100644
index 0000000..f156ccf
--- /dev/null
+++ b/App/MiteDesk.WinForms/Main.resx
@@ -0,0 +1,1161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 140, 17
+
+
+ 16, 16
+
+
+ True
+
+
+ 255, 17
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGOSURBVDhPzVK9S0JxFH2puSQhqYOZpU/ylSmYiUpvyBBb
+ pEKEviAzRzGHoKHNLfoHIseIdg0SopZoDBIKJfpAa7KGIKhcitN9YqJ9UQTRgQOXe+47/O65j/m/SCQS
+ eGWl9TMIHxbuAKPR+IcGcxoNTnkeWb8fG7EYLm6fygatUimSDgdyPh9SVitkYvHHpk0iEXbsdiAaxUM4
+ jPXVNZjIIOXxAKEQSsQhpfLrF8nI5MpmA8bHcBmJYisQACYmAbcbEZXqe+skF1jcD/LA1CSeR0bx3M9j
+ WaeDiGHeG9Se65Un6WEczEfx6HSi5HTh2GaFh7KJx+N1c1WDPKUtUEhdYDbRi4LPiyKtckMs2vqwMj2L
+ k+tSdbZ6HaGopYvjcOblkLdYsNfDYdvUiQLV52YzBtq0dbNlg1qIaccltRoZEo+IQZ0MQV6MtEmLHNeF
+ fYMBGonk8yAXFQocsiwyrB4zcnl1UEV3323vQJYMNrVayOlSFakeLSToGxvRSWx4k3gzaSz1u+mnEupK
+ +7dgmBcvoP5m2FVw5gAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAK8SURBVDhPfdNrSNNRGMfxo/mmsKigrKAbVOCLQMhRlJWm
+ dmNEvsguU7Oy0swYomBS5i1aF0S7aTdnZumc2ijXZiVkY6botgSjZVpp2bxjjuqN8e0/MdTIfnDeHB4+
+ 53keOGJ83v34zpOBajLfP2RnjQGlNYdzTR/JaxhgtGTyFDuM5HQk8aDvCuouFSn2UEJeejP/TibTL/b8
+ H8lqySfWtpHcztNU/zTyaKiC7PYM9phXMq9QhUhz4JYeSkrp838jPuW+7K9fxdnWA+R33eRGZxpFPbXs
+ Nb9ltroGt0uJiHSBR4ICk8k0EVFoHXhe0LHp6VIiJeS4zR9l0x4Sm7/iZwCP3EZElkCcFrjFzcR3l4SN
+ j/c5O+4nbSwpXoTv4wVsMC5mvbGOlTpYcfsb2+9bia/UodSUMjfOmxUhMRO7WJZsRcTYcE+pZOq1MGYW
+ eDEtX8bC7F4eWrvRWPrRtQ1z/7WTW6Z2FMl5qNXqMUCWKgG7qxFHLYh4uzTrCcRFwdrsaFIf2Clp7MPY
+ MoRlEMy9UPX5FxnXtGNAalU3Ili6CDEgFDWIQ+WIJEGAKmEEyHnaSUmTk8d2JzmGL6SXdRASfgKtdhRx
+ AfPDDbj5FSKCShFbK5gaPYspoWHIwu6S9aSDQssQaZo2tI291HX+4HD8mYl7cCELw6vxCtQwZ/MNlu9L
+ wNPvLjPW5SNT6MnSO0jTtnMs/R5qo5VXXcOUVdWPAa64kNUHCvA5UkfQkWfskHayLrIWWagO2ZZYAoO3
+ 4e/vj0qlosT8iZs1DgwGaezxcSGuAp+tB/EJimBNwA7ku6KIiE6kSN/Ai+Z+zG1OHrUMc768GblcPhEY
+ nyrzGyqaBtF/AI3NSbFVOtJ/uKxvJfWyZqSjqKioyYECUzdXXzqJPnV9pPU/x/WqUqkc6XS0dPK4iv/M
+ PXr1V4T4DTto6F1/z57KAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAK8SURBVDhPfdNrSNNRGMfxo/mmsKigrKAbVOCLQMhRlJWm
+ dmNEvsguU7Oy0swYomBS5i1aF0S7aTdnZumc2ijXZiVkY6botgSjZVpp2bxjjuqN8e0/MdTIfnDeHB4+
+ 53keOGJ83v34zpOBajLfP2RnjQGlNYdzTR/JaxhgtGTyFDuM5HQk8aDvCuouFSn2UEJeejP/TibTL/b8
+ H8lqySfWtpHcztNU/zTyaKiC7PYM9phXMq9QhUhz4JYeSkrp838jPuW+7K9fxdnWA+R33eRGZxpFPbXs
+ Nb9ltroGt0uJiHSBR4ICk8k0EVFoHXhe0LHp6VIiJeS4zR9l0x4Sm7/iZwCP3EZElkCcFrjFzcR3l4SN
+ j/c5O+4nbSwpXoTv4wVsMC5mvbGOlTpYcfsb2+9bia/UodSUMjfOmxUhMRO7WJZsRcTYcE+pZOq1MGYW
+ eDEtX8bC7F4eWrvRWPrRtQ1z/7WTW6Z2FMl5qNXqMUCWKgG7qxFHLYh4uzTrCcRFwdrsaFIf2Clp7MPY
+ MoRlEMy9UPX5FxnXtGNAalU3Ili6CDEgFDWIQ+WIJEGAKmEEyHnaSUmTk8d2JzmGL6SXdRASfgKtdhRx
+ AfPDDbj5FSKCShFbK5gaPYspoWHIwu6S9aSDQssQaZo2tI291HX+4HD8mYl7cCELw6vxCtQwZ/MNlu9L
+ wNPvLjPW5SNT6MnSO0jTtnMs/R5qo5VXXcOUVdWPAa64kNUHCvA5UkfQkWfskHayLrIWWagO2ZZYAoO3
+ 4e/vj0qlosT8iZs1DgwGaezxcSGuAp+tB/EJimBNwA7ku6KIiE6kSN/Ai+Z+zG1OHrUMc768GblcPhEY
+ nyrzGyqaBtF/AI3NSbFVOtJ/uKxvJfWyZqSjqKioyYECUzdXXzqJPnV9pPU/x/WqUqkc6XS0dPK4iv/M
+ PXr1V4T4DTto6F1/z57KAAAAAElFTkSuQmCC
+
+
+
+ 588, 17
+
+
+
+ AAABAAcAQEAAAAEAIAB8GQAAdgAAAICAAAABACAAzD0AAPIZAAAAAAAAAQAgABxEAAC+VwAAEBAAAAEA
+ IABoBAAA2psAABgYAAABACAAiAkAAEKgAAAgIAAAAQAgAKgQAADKqQAAMDAAAAEAIACoJQAAcroAAIlQ
+ TkcNChoKAAAADUlIRFIAAABAAAAAQAgGAAAAqmlx3gAAGUNJREFUeJy9W2eYXNV5fs+907Y3bdGudrUr
+ CRVU0UqAQIDoHRkCxI6AYBODbeKSxzY8iCQPJnlw7MRx/jjVCTbFBTDGGIyDTReIDhKiSIBAEmq70q52
+ Z8vM7Nx78n7nlrmzjRUlRzpz586cOef73vP1c1fhY7SBKzrMVWsNKPmvpEGVViitlO1mBuvguPOg3eX8
+ ejGHzmdv5rB6jk7KUG0mgMuXHCfq4t1e9rf4+WtQ1suwra1Wquyg0m5eDw14a8mrLMkJpJXf9t5H5sH+
+ SIxf3oH1y2rgGr61YduyYwol5RZcp1HnMqcgl7lWaX0dv/iSlSo51yqvOsqqqZ9hT5teZTc0x9iV3TgD
+ vIdV26jsmvqYVVlTpUrKZqhYfBmnPBWue6Fy8+cgl12k8yNxWFafKikfUq4jGCgPDIUbScv6JTW4ZfOh
+ Tx8AYV52W9a2uIOwbYV4Ig7HWYCR3DX85jtk4GoycywZbIq1dKTs6TOVXddIySinXMRAxoCRESCX867C
+ kG3DSpWCvxNQtF3fLKCkCEgTEV4BJ38B1ziDazSSjB4kEr0E32VXnjTgI4GgDptx11uM3JP5uA1nZD6F
+ 4PO8v1Clylrs2gabOw2CAmSHlZs+BD3QB50Zgh4hw46j4InxWFJkYtvWir9VBEOVV0FVVFNZSjQZh9vb
+ Daeny9GZwd0Uv1/zJ7eShrdIg8N7Ty0sb+ry26emFlMCINR11yygKIoi+Q1c8QqK6lVWaXmHVd9sWVV1
+ 0E5eCaG67wD08JDs7pRBHrdZBKSEYFRNgwBLCdJu30E43Xtc2oT3CeaPaW9uI3ZdlCwBQfumYUq24UOJ
+ i4q8MVrKjtMgHc/P1qtE8ngynrBrG2nCsso5sJeMHwTyI0Vz6/DlMJoaQ5xGjGaAIFu0G1xbOwf3wz2w
+ J8e1n+a3t2hlPa20MxKCMAVJmBQAb+eVsbyckMJllXPuzyvL+iZ1dbo9vY2QWMrt3mPEk3o6MdM+QdKN
+ BriR741K+aqlImMnAoNSINJA8EUstbN3p3b7e/by7Q8okbfyswGu4SofhckkYUIARjPP13oOvlHFYn9u
+ NbSUUtctt68HTtduGrNMOJcu4py/p31zc9p0Ld21OEawpDHkjpomEuPmuY5LPNkTXNDvyi6eTxUo1kik
+ YDe0UCpqxTa4btfuIZ3P/5Sjb+HKXVMBYVwvMHB5Own0rInP/AxO8wOVTK6zadWtsirL2bcTsvM0QGbP
+ ooyLbXaJSb5fI58mw4k6qLbFiK04DYmT1yJ59qVInvEnSJ51CZKnfQaJE89G/LgzYM/vhGpo5ywpOH1Z
+ 5HszcLOe1VW2MF8EhBKJ0+k+Y1yphopeJq6HB5bR0LaT5uc5Jh0wsX5J1bgeYgwAovMUcW/nETL/zypV
+ stZumRUXt+fufg863Stz+4GMDkXbpd0b6dNwVDXsxauRvOgqlKy7FqkL1iGx6hTEFiyD3Tob9vQZUNOa
+ qM9NfN9qPovNX4rEyhOQOOkcJI47HVYHHUzeQn5fD9z0sLANFYuIrUFBK4iHGR6koaxTVkWNRRDmIZ/v
+ IO0bOTYtpFnkaf2S6jEgjAFAApzA4PG1wdv51Fq7uT0mW+vsoShxQW/X/R0XxrNk/BAZt+sQP2ktSv/i
+ OqTWXoY4mbKqKQEi7hH5zY3ksfODPTjU14+yslLiaheYEmNXXYvYnIUE4jTElh3LNWIY2bmXQAzxe081
+ gtlM+Ekp0ENpWqlKglAtIMyhhMzgt09x3BDjJrP8LZsmASDQey9EVRUcf5NKJNbZzTPjEnk5e3eQ8qzy
+ AkAduvM8BS0/nDAiXvrlGynil8Bu4g7Hfab9HvgnOis8+sTTuPX2X+KZ515EMpVER3ubF9oqFV4NcwJG
+ /XTEO1cjvmgF3EP9yL/3gcQTtBER4gUFUYnBAYJQpdgJQnoux5WRl6epPjkhe/3S6iIQQgDS1HvL13sN
+ K87lv8ht+Su7sTWlKPbOPjI/kg113Ug9DdwINUGXNiF1xTeQWvcVWM3tMNFehPGgGSfNPsLo76577sPb
+ 77yLgYE0aXSw6pgV/voo/CYKhGXTDBOIFSdA0QOMbN0Kt4/MJhHxEgSPcYeoA6VAMZiyKBVHclFybL1k
+ IkfOdwPtwXd9VQgBkHja2DDLRDlcRX2flr6WhsVy9u9iVJcpZj5PYSDz1szFKPnqzYgffzojtpSJj6NM
+ j9ckiNzf3Y3NmzaTJAdrTlqNRUfONzuvJvqt8riUKDF2xELYRyxC/p234e7r8kCwtL+sgEBJyGYkZqAJ
+ 524MDy4ixS8zY9kp4idrBFJge7vfEawh4t3IeX5olVcstqrrLbdnPzUoDS/fKzAvO28duQolX78ZNnXV
+ eA3LKuzYRNz7TM7uaMeC+fNw0onHY/VxxyLuq8vk0AVqRL4apiO2cAXy72+Hs+sDgqAisQTnEdfq5AnC
+ NIV8tpx5RytJf5hrDwoP65fWGCkwAPz1UbVmem1kV3/JisWvsKc1xShKykR2UZ1nZDsiArXgGJR87TvQ
+ zOi6e3o5fw6pZGIMA9H7aGwTo9Gb3tRoejwWK5KaiUAoCibFP1fS0yxcDufdrXB274adVKE6eIYx69kQ
+ 5hQMm1u06/ZSl54TVRA5v2VTL+z0Ze1mYiVy6eojGev/AwOLesSTyj24z8TyOmLwxNKrlgVIfe1mqOaZ
+ eHLji/jFrx7AS5tfR1lpKRob6j1R9omcdD+jIv8hY0f90ANEfl9eaSQwv+UVhsUHYKeKgKTpIwhllUSL
+ fiM71EEeHyGv3YwajRTYkd2nTXW/ZSVSZ1o10yzd3yPuztd7rzmDHJGsR+rLfwt73lJkciO4/6E/Yg/1
+ cGBwCO++vxNVlRVoaqwPGft4mdAU8WAkaDGWyL/4jGSgxjuE9sBkzNy08mrGC8NVTNZytNKPSYxqEtob
+ FleJheXuuwtI9M1WZW21QY6iLzlFqPdUqZGhGBKXXI34mvNoPZgWEtQdu3bjgz37jHXPZnPYvmMXqg0I
+ DUXu7NPjXnm2u6HZ1BVGNr3IDNktsgcSakt6DSnaZIaaSezDDPa6hWbbWH8rZlMtrrYSyfOoV7bk8OLy
+ ggjP+HqGtdaCY5G8/BveZDR44raamxqwv+sADtIOyHAPhJ0EoRKNIgn4fwDBQwLWjA44216Du/cDowph
+ oOQHbVYZQ5tsppxS0K2s2AbReXv9slpKidtAGr/DAc0iDXrgkOyol9woL8pzdQUSn/82w9N5XtXBZ6qk
+ JIWOtla6tYPFIIg6VFESjE0ICfnUmtFUJkdWRRXyzz/BtbjrcYS2iEES3XSpR0YuU00bcD9twaC9fjmT
+ PNc5RdnWNaqiKi56zwF+1QZ+pEf0jlqD+NoraFUTYwKcUoLQPrMVXVEQ6BXee3+XAaGxYaw6fFJgjKkr
+ 1TXC3f4W3F3bPSkogK/MxqVKpDpFt6CfVXZ8m33D0jopcFyrEslVKlnCULKf2uCqYHJt3GkK8c/9JYOe
+ uYVQdRQjpaUl6Jg5Y3wQKss9w/gJMu6pp/bKVF5t1AODnpwpO5znHmMM5JhIJ/RIHEv1pXCMcEC+lxbg
+ D/b6xVUNBOZ6ftFkUBoeUiiy/LxpXYD4xV+U2pzR/TFM+ICUlkwAwo5dxjuEkgBMHPF9GNPwy/BBkyQo
+ k/VqkAE5VTVwNm2E7u0yAVIYJksQmJCwUfx5Li51RZspYid14RorVVai6SGQzxUocz3XZ598IazOEwuR
+ 2jjE+14ntAkGhN5RIAQ2IYj5RwE4EcPRey8ad5kU9WL4+afRfcet6H72aVSuONpLvqSRSd21G/qNlyNq
+ 4F8lp4hR6HOZFOd7hPKC5dzVCvMtkxQfY++VIS/iJVALVwYsIsz/J2l1tTW4+DNn4577HsJbb78jtUr0
+ pwdw3wMPmwmWL1tEL1owpJPOFzKtjTvL79yBgWeewsENj6N33z6o9lloOvt8MGuNIgqLNLsP3k4eGAgl
+ PMqlwqFkk0VahGfXWW7fuLTmGurNUaY8lRtWUWLE+uvqZsQuuJLyXT5G/8dtUe9Addjf3YOeUZJQV1dj
+ XGQwftxwOTTCGm66H5lXXsDBn92GHbffin3btgILl6DliqvQ/tl1qF6wkJ48FsYEppEf99k/QGX6mdtG
+ oeF/MeT5EUu57j6b4eD1zERmGLFkrl8ghM5hmG/amXmdcqExLjrK/BR0uERsQptnEwQE44EYPQ4PZ7Bk
+ 4XyvCBIwaoyUDrvO5xnf70L/w7/D3v/5d+x88H4coiRVnnU+2r9wDWaceQ7KW9tgJxJFtPj20NDrvroB
+ qnu3HMKZL0KPIJstxtNxMgLA3xCtKrN+fqQAoZa6Hm+Wrqb+r4nsztRCXBVKgmcYuw0Ifeazma0tWHzk
+ PKpjkI17UmByjsEBZF57FT133YGdt/0Yeza/CmfWXDRddiU61l2J+s6VSFXXeHYk4loLXtsHUcp62zYB
+ 773uZYreEZ63Fu0A8rQj2XyOcoN686kcT41uglpFTShaDndlYGAQCaIuIj6VeF+GiE245MJz8cLLm00x
+ ZMXyJUhznq1vbzdj5h8xC9VVlRjesgldt/03DjLPz9fVo+b0czFv9UmomDmTGxoPFxqtJgKcSJVkpOXl
+ ZaF9kRwhegil84THEZCZ4xAABkPVYgSToeiNYt5QX1FlFsg7Dv742FN4csMzqK2txecuvRAtzdMnE4IC
+ COw11VU4/eTVZloB8ad33oW3tr7jATB3Nq687E+RS6fRX12Hxq+uRd2yo5CUnR4vWwwY9293Mxf5+d2/
+ Rk9PD0484TicdtIJ5vDKlZBdisdDIu7aSL33w+ANykUCLPF3kh6Ou33iUrhgX38/HnuSbqf7APYx9n/p
+ lc1ont5UPHaSpiN99+692LzpNWaTOfPd5s1bmFCdiHnHrkbNMccVucnA7kzkJ+Tzl17ZhDfe2maAefTx
+ DThy7hxUUhJitDcpyLmET2I0YPJaMmYubsH4FAMAk2HJp0mKfW1NtQEgEY+ZHfUOTSZ3ZWM+5bhkMkHX
+ mMcgrbu0RHW1KaYU9BQTAhrUFV1KpNQS81TLVCppiio5qldlRZk5fc7TZdpORK31qKvfGAjRCAaeKCh8
+ +E2QU/M6gbnL6ChiaGudgUpGdMesXI4VnctoO+NTCm3NzpOovr5+DA0NGTcYI8F79+xBGUPo8849C8uX
+ LzNGMTBuAaOGSTIm+p3LZJjSSx9Ghu9z2Sy/y5vNkN7S1IjVq47mRlUZuuJvv4IYu+fTRgHg2cWsSl/W
+ PshFS7Sx+zpywmMxCaKunPsFqEu/XuRjlV93+tCYQHbKZ0LE9MHfP2J27JwzT8VKApjuTxsmKyoqzFwC
+ kmu641/dEAjoidUgqFkYRo2Ye9Jcet+/IfnEvb6EF9FlYiJ+1qN6L2h7h6Fwh8+QCjMWSYPlyG7F6chf
+ 9Z3wYCPws0pZhcUj6AZuyIipiCKZf3XTFtz724fQ3582w46Y1U6jdylVKV6QOFWY46M07SOkgt0m0OV3
+ /D3imzYYA1hEZKCwWr+jes5qe4R8r/H1uUhS5AQm3zoH6Wu+B7esCkUO70MIFoIcx8WmLW/gwf99lJZ/
+ wPsZRfzozqVYe84Z4WnQh9WCJ1lmTFO+qVUD/aj8z+sR28VQPB9RAU9atK8Cj9vXzalaxbedQTwWjflN
+ 3YMeIrvgWLiVNdGvJ6U0ZP71N/E7Mp/2mZca3BFzOnDmqWuM7ocJyifVQvVlotu1CyUb72conPEe7CjW
+ geDysH397KpWvj3TnALroHDgjzMHBXnkW2ZjpOWIqdHAORzq8OYtZP7hR03AI80wP7sDF3Dna2n1P3Hm
+ owSQs+SbzyL52gZIwAPtS4BvSvwTc0n1fkIAKsUVMthXJTCHJgWyzGmszf1kLCBSIKlkNBwetbK/vsaW
+ N7ZS7B8Zw/z5Z5/OIKram/fT4d47p2fGV/rUrxDb9z4MmzpCcXi8BUlO/sW+bnZlhuScxZsWhOYvYB/m
+ FNbODSI7txOuhMVF7I4FYDiTxQNkvvtAj2FSmJ8jOy/Mi3tSn2hdKGwFxdWI7d+B8id+CUWXi7yOqEZR
+ 20IUfsQUD3JItpEzrAxNg68EBiwiaA30IvX600g3zDRSUJRaBexHAghz0gNv52fT4p9/1mnGT4c0qqma
+ tKm3cH2qn9AqNDPWKo7PCg5LrhvZD4kN0KYCrNVa0pvwnogpSIEMFZ7t4UPIHrECbkk5JtpBmVWOvCTQ
+ UT7zp5x4nGFefVo6H12cBjvWsw8Vj/wUVn8fs73i3fefexCsqJv6+6TxbQFA9qOP5J3KnZkR2VoVlJKk
+ 2c4gdDyJXPuiQl1gHI6kjF5ZUY65c2ZhdkcbSlIpfGoGL1zUiz0Ut7zsmfuQ2voc3GFJgDzmi3InL1J6
+ ha8/JIND6sCprfIhrZv6Jun8O/Eg8O1fML/R5TIOqa1DzyXXI9e2wPhIHRGUyBKjbsaJHT4xxoNptcnw
+ EjvfRO3d34PqOQh30CkunuogQIAkNwz/9Q/Is2Nf11HlV2NwgC9n86Y2EjoH5UTjS21kYacPItOxjJ4h
+ NSXiPv3TEI8vK92L6od/jPi+9+BK+ht9DC9g37Ns75Hxm8jzAWPKDpze5oWKtF3sN3Hkt7wYEEUhmry1
+ Si1Y5XGkjz4PfWvWGZWAGlXhPVz68TExklr/SBZVj9+JiucfgDswYgDQUe7DG50nH//ENzexM13kXfcp
+ raEgU2Tm8XoP0Zkf+AIVkQKpHNgV1JCKEvSdtA7pTgqMHfdswmEq+ejnCQ/bRmjf5zsjqHjpIVQ9cSeQ
+ HoaTdszuBzzrwu6LMXiL7y6mSm8NSDDLHji1zWRM/Cf6/xX277Ib6xWcBHh0KnPSEqukPaisxKE1l2Fw
+ ySnQYaJ0GFz4yZI0K1oin0JTfsIlT4GUbX4U1Y/fAdXfj3y/4xm+gu6HRXV2eZrzBvZ/lZNCeZRn2iM7
+ PYpFCkIbqXUdB9zKd2eJakV2p2Dx5CHPKoLANLZ/1UXoX86hiZLIkAmYCZMyjb37u7DxuZfM3apjOjG9
+ sQGhzk2ERcgYmc8No/Ll36Ny471Q6TTyfY4X9UXSvlDKJKHR6vfmMV+lDsIvENQ/uquw1IGTW4P5LQ48
+ hl/cwfdtMII/Dgy0EgICylIYWHQyDh17EfKV0+AXCibi3zSpCfzi7l/jlU2vmfujli7GZy+50BRJJuM/
+ iPNj/QdQ/ey9KN/yGDCYMcxLwTO6SMT5iZjtpHu+jDw8x/eukDftsV3Fa3UTAFOUcAQsxJX8DQDwPfaK
+ CP/FGxTz1MEqjSHbPBe9qy7GcBvjBDs4QS5mJ3BLAsBPbrsTL7zgScDKlZ248op1BQCKAPTFRkTeyaFk
+ 5xbUbLwHyT3baOzyntjniwGO8C+vUoS4nmTcSp5GlO09BVs/GgADwppW+H8HI6pQxo/+lsRcy2v0abzi
+ FzEL5Ra7DbesAgPzViG95DRkp800hxNFACifHxLw/vs78NsHf2c+P//cc9DePtM/Qh8dKWvztFfywA5U
+ bP4jyrduhDWYhjPgsLuBFyxmvqD3Wa71I15vlqfDjDmk7tc/viscPEbaBASpEJtM2NV1HPGPfPtZeG4y
+ WhAoAkJOX2yRhpQFp7wGg7M6MTB3FbKNs+Amy8bJHWDOCKTJI3JjtEae6MgOIrl/O8q3bUTZ9pdgS3yf
+ ceFw17Uf5hYzHl7M9Lz8grffVpY6KNZQjWJ+fABObPEeljYWWllEsBGe77xIaC2qF4yukMijgiWWkQgr
+ yTmSKUpCGzItC5CZPhe5mmY4JVVwGURpE0kWiCDasHIZ5hx9SPTuQWrvNqR2v8mdp6XOZjzGB10vxHUR
+ adFgP8REkL2Xb7/Fnd8vwULAU/2TuycHIADBuDWjDiEIt3DwpfDVoTjAHVUpEiAIgF2qvPN5wqYZL0gi
+ 5ZRWI19KEFJlcGNeNGmNZLjbA4gN9cMePAQrM0B9H4Ee0SahcYa099h8lHE9zovn80U27iKi6w3zWphX
+ RiZGMz8hAB4IM7wZvXBBQKjl4Ov4/ov8wEsJ1ThAjJ7djvzxg5xKS4xp+z+M5BDeQ5ja1O/ksebgjyyK
+ C5oTcu9bAgzw8l98I5leD/xng6XVP/nBuHxOGn10nVAAwftzBRpGjT/jpAQCMxGYwYhKTFrgDJi2JgAg
+ KF9PUi7Qo0QehV/sIJ3f5/Vn5nFYr7xlBjQ8NT7zAUmTtrEg0PlpvYKTr+fHJyP0EEVAfOIJcNGRTTHj
+ WfbHSN8tXPJFZWpAU2MemGIe0rXaq5ZFSufiJuURU5GGq3mVimnhrHvUGh+1/qeLE4bwY/8qQe/bHPMf
+ vP7cE3n5ScC8RsOGsTo/uh0WZV2rZ0TPAwUEYXo27y/n9RJ4ahH7kPknBGQChkd/JmHPDva7Of52Xt+V
+ P5Xwfu7R1rBh8l0vImbKI/0mIATEBpxo+XsWYBZv1/IqfSF72TjzT3W98XZdSsyvs/+G6/2G1+1cL++v
+ XxD5w2D+cAga04w0uP5fdBWAkLxBVKOTH53Gqxy6zGGXg4BAMqYqAcKcFGzlIYKN/O4PvL7M3qPk7+vg
+ b7lsBH384TIetI9lqAq2wQRNxUdrnnoI43P48VLeL+FV6g1yECP1dXGlSX+4GDI5PpJa/S6O3cqxm3nd
+ BA+AQ76YB3Mbd6H8PxSeiq5P1P4P8t+8rwDuyu0IAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAA
+ AIAAAACACAYAAADDPmHLAAA9k0lEQVR4nO19B5gd1X3v/8zcu7039V4AgSQkhJAACQkhioUNBBscwAaX
+ OHbynPKc2ID9Sr7k2S9+Thy/lJcvX2wS24mNbWywwVRTRRdN9KaC+u5qe7/3zrzf739m7p27e3f33tUu
+ CJIjzc6ddubM+fdyzjHyPijdn1ggKc8X1+DA8I9vjO7Txfi+V4xdLX6XY79MjJyMO3g8xxdZYsQ0iT2O
+ 6WbEST/t618PWxIHCTzf4Yt/GM+/jnOHcLkd97yMa6/guBf7dmOcwfST+sMPdnjK2CuVP9g9dZ0yScV9
+ rxswVum9dqFcv6JK+9NxxNiiewHAS9DHTb6YVTi8FDddjStfwrXfxXYlbjsPx2djOwXHM3BPNbYibDFs
+ jrGoZDetE+f0muE9eKmZgW05tvW4vAHnt+H8FTj+CN61AucWAyeLfUUYPwGESAZNM6JYIPLVlTXy1VV1
+ cuOKavn6zo73uDdzl+MOAXpA7devrJUbVtQIycgxIazQsb5UYLcY5z+C/afQ2zfg6qfw+2L0++k4nolb
+ q/FIiXFjromB0ONxcUrLjSmvEqeiWkxVnTiVNeLUNopT0yBONY7LKnGtRgyvF5eKlJSKicX5Wt9YzAPz
+ 8UvQhmq+A+9ajYvnolVABnMpzpPjTMe+H7AfxDlyEUUH3/eVG3x1ZbXcuLLuuEOE4wYBej65QG5YaYFO
+ iDuOpXdSOk4uEFK5yBdx6svYLgfFnYF9E3q5zMRc18SLDQBsAFTjNEw3btNs486YZ2Iz5ht32mxxG2Ya
+ l+frphkA395XXW+3Wvyua8S1Jnu9Hvc1zhS3cRZ+47iqzgA5DJDDAKnIfoiSLvZlbAMRAm0+D3u2cRUE
+ EkVNN87143qS36NP4NtuPLUWyFArX3/h+ECE9xwBCPgbl9eGMjTkzg4oh9iwAb+/iLM3onOvANBPxe8a
+ 47hxEy8yTmU1AWXc6XOMO2uBBXTdNFGglleCmZcYcACj2MTaSY0eRL2XCrZksHnBZkW68nE3Zp9FHazL
+ qaw1LjlG/XRRpMAxOYuQQ/kelRCwDKnBiWVEBqHIgO6BGhP4tA5UORioHdqUG1cAEU597xEh9l69uBuA
+ V+7IP6FcF98FxU/DifNI5Th/RqDIQRKACxcViVMOSqyuVzZuyKrdmIWYil5P/BQAmxgUf3AAGzjyEHQ1
+ bH5yCCoeYJECwFNe0IpwH+iDrmPrA/s3sSKRomIx3CAWTDEYkQOkcF0xpZBEpdA165p81ucP9Buvu0P8
+ zqPi9XTy/aVAqMVo10LUejm+7Gl85U/xvvtw7gg+N0WEx6f7XRB5RPmK7783CuO7jgDdn5gPajHoH8vq
+ VcRD1AMRZuDyJThzNTroZKE2T0qMgQrLQIF1TSqvFRiuNltZsZ8YssDu68HWJV5/DwECYCctlQMpFNPy
+ LFl3Kl4BORwwSuoTQDintFJMWQW2Sh4btsWUQ4cor/T9xhl4d5/xOtvEa28xfm+XkVSyHjVdiJo2oO6X
+ 8IJ/R6tvQ8WHUL1HroP/fs81IAgIisof7JnE3h6/mPFvmbxCdk+i861KFyh2fgP2VOI+Q+0av0vZ6aA8
+ yOc6ymBSvVKlUjqpfAhA7+1Cr3WI193JTgdVBwB/NwoUQ3HBJUrKrGJJbgQl04BDKcKQrYHbkBt4bUcE
+ COGDE/mW3fkD+Ps89jehpjvwTS3Ku7ygW5x3lxu8KwhA7CaX9b2A3eM/vrccnGAjzn/eWFlfroKguMRR
+ aocsJ6Wp/Qdm4ZN9s0PBZv3udqV6BfrxUMgFICJMZa1aFooMQFifUo2QBXdSRGhrZru9ABF68ecREMQ/
+ gvIfxlf2WqGAx8gVQSgVP5x6RJhyJbBHZb3FM+NY9QoffiLO3Ijj63FmBQBfjA50VaGbswjAn25lLh5U
+ ltp6SFIHd4vXvB/Ah9IEtq+s/XgpbEvCciWvo9W2EQgLLgERESdSQ2cBclTXiuoyiQEH3AoXzGJ0yFbU
+ MBu9A2ibNvSJbyWWgZJYM+VK4pQiAG16lfWOdbSAA4BXCp0038SJrdgqQCmOWzvNUcA3zIDdTsB7Kj+9
+ 5n2SOrBL/PYWESh0xxXQRyts49CAIgGRgQopFEejukwREKGq1vocyB8GBynSykAMK/HkRooHcIA9QIIh
+ W5VvLYUp9B1MCQKQ5dPe9QPgA5v5niUA+P/E9kdQe2fDNIuZihonNnuRcabNsg6YEPCH3wHF71FWr5Qk
+ +StxLH4BSl8hZZj7ebxWqIhSrgCxRaSgDyEwLS0i0IxMDBlJDrGXGlH7JhAHXdd0QXc4xlrH7EuaylOB
+ CJOOAKT6lFjvF8xvUL3AGDcfwiVQvVyA3yUmXuw402ab2MwFqkGrQghWnzpMit9tWaiXn3yfKmDnW/JC
+ Cpimfi/0gK42IPSQOPFiI0SEknJFBAGHEJiSxktBi5Tl2NZia0Hf7QU3ABP1lfd9beXkI8GkKoEq71OB
+ M8U1luWLXIeP+GP01DRDo6+i2nGnzxVQvzWzkgnjtTdLCnJeqM3nAdCCgO4HVYabl3neD4wGE5CBApMu
+ AWufhA7ovEteyMB7YD3Q0+jUNNK6sbofLJoUOB8UXQtv3z+C/vsb3P0v4Jjt6FdPDSd3cq2ESUOA7mvm
+ 2w62ETva9XOg891AmS+U9W7MCV2sdLCogtfbLSnIeUvxY8v3vIDuB2Z/Esp3Ap3K2F7SAlqBTSvEN6HX
+ MSNZTLizTlt6ZogUusXs5sTpkzBqpuXTa+Mig+PCaqgWt2lOwAXx4qFB9Md+Wgt0MBEJetDGm4ER30B9
+ +0QRw76/8od7xm9EHmVSECAL+MBRwGoZaP3P0AcXMromRSUO3bRObRPZnVJ96ijMIlI9ZONYZTzAU88g
+ kD2Y2d6gpAGvTr7RHo0XqWMnq9BxlBjKfb+GIzOI4AB/nWJjkcMZuwvHRQTqA1B+3fpplhtAXChHPLKf
+ fUNuMIQuuAvI+z/wrldwnDJikXgykOCYdYBu2vgW+PxS9up6UAm1/C3Y4lJe6bizFwrdt+rH6e81quAd
+ PRwoeLnLWIBXoNOzC8s52YU+40bpQfgpWzfWFieFzZgjsRVrJX7aWXZbfZYUbfqQFG3+sBSfvVWKztoq
+ 8TOxrVonsRNWSOyUNeIuXiZO00xq79YPQU/g0JDNFsDOA856fb4iHTmLCRFkDGCPei1QFH0qiRq7AHKW
+ VogpLacr2xgqiCIwF81y9Mlb+H1QgvSDG6ETfOMYdYJjQoAI5ZugrrPQ0L+Ghr9WtfyqWic2a4F16JDl
+ d7UZ2vPS0zWqrB8V8L4FvNdvgZ7o5G+bvqENYEgX1kR87TkS33ChlPzWtVL60U9LycVXSvE526Ro3SYp
+ Ou1siZ+6TuInLJfYgqUSmx9s+M1zvFa0ar0iSvG6c6X43G2KKDGcc/AdTuM09UKqUjeU0HeT66T66JIO
+ dZ9MaCJXyYkI/OaBfiBVl3V9F5dY3wG+yU/AVBwapJUwG0+eirtfQx37JY0ENceEBBNGgBzA34iGfQvy
+ c6XGz2saGY4VoUPHSxnvaLN4h94ZleX7QULNyAuiiiU7OdmOrSegdL4WHeTOXyJFWz4iJR/7rJRe+TkA
+ bJsUrzlLYnMW2tgBKIlUpVQc7XwzbEufN3qvPoNnWUds9gIpWgkucvpGKd54EbjEaWLqm2yQaQDfQ2Qg
+ XpAzDOSDCEZyMgT1dnapP5ihZw1+EQlSSSPgBnisCc+tRl/RTNwn5tiRYEIIoA4esX0lGcon8FcQ+A6B
+ P32OlbXU8psPiNdycFTXbU6qjwK+A/seq9CpD75hOtj4Nin5+O9KyRW/I0VnniexeYvB8is1ASRwPoQK
+ ac4t9E7aYgJg5dqC5vBjUbepqBKKNOUkEB+xE1coh2MAiFTsJzwrIgbHR4Sc3MCjydit2izMRJqLigTQ
+ UYAEfXyA/gLGTF7Ftl+MHJOJWDACUObTmxmQLJ9fT7YfUr4mW0Dh0+BNcsh4R/YxMpbTi5eT6oMQMVl9
+ Igp41OfMXSTFH7lGyq77Iyk+7xJl3055eYS6M+RshtlwfuaFMuznyBJgdnAQ4RwZ+5CZQk5ZOTjNIqtb
+ gDuYmnpFBL+nO4MIQ+oMswqj5EKEHNyAZuFAr/oMTGmF0fA0xWiUE1jv4cvYDhAajuvIDcsL5wQFIQDZ
+ Pl/kMZ4OUw+9Cm3JfBPa6Vra+E51g+M0BcCH7Eod2is+nR85ensE1ftWqFGuJjs8yPlAvrsxC/hLPyGl
+ 1/0xqH2LuA1NNmXLcTKUyhKl3JEvTO+GoO2/uWuPPPP8i/L27r2ShEyvqqwQl6w/DethdQyvO3LMkLBT
+ 16CiIX7aBii8dUB6xgS6FBEoGmiamrj1M+RChBHcgEjAfAa01SktAxIU2TwE5QT9fB5mgyxCl+0ADFqh
+ H1kkWFFdEBIUhAD0S3spYrS184ECfwm4n4tj16mqd9KUT+DTqdHdKbnkek7g41wKWn0Ccp6Uo2wcplHx
+ R66Sss/+qQLeAYWpZm6c3EAep/AdA4NDcs/9j8hPf3G7PL/zZXnltTdk58uvwsryZd6cWRJjwkehdZsM
+ VzBVNRI/ebVyBb+4WLzD0Nf6AUiaqQM2MczE80QCFuY6QG9St3HM6iUUqzyPMkuMPxtNfxyPdgM2vgOz
+ tJAAUt4IoOae+vaZxuDX4i/t0o/S1FPvHoFPmZ8Yyh/4IdUnM1QvKespi63dJGWfv15ZPRM4JTTJJgD4
+ 8L1888uvvS4//skvpKO9QxKJBPoyIf19ffLOvv0yf/4cmdbUqPdP6D0hV6B4qK6V+PLTJXbSqeJ1dUIH
+ os8DNj6jwTQdi3Jzg5zv1YymhEWCuM1DAFIYEpowX9IXKAnyGOAxQM7BdLN8uUBeCNATyH2fppxnikGA
+ n8XLfh+NLZPScgB/jqZO+arwHbRBnDyBT2pPtnlq0imAp8+Wkqt+T0qv/oK4cxeHKV9ZFF8oaPzg3Z7n
+ yYMPb5dnn9upgFcEQMemkkkQab/U19XIySeekFYIJ/Ie28BADwHSqmm6ej04Q62k9sME7u0F8Hzd1LOY
+ QzfIjQQDmu4G4DOyqMEzpqKZVIIa71Lc0Qul+Vk8m6IouBH6QD5KYV4IwNx2T338bLJcCCPvz9HKegZ1
+ QPmGFIveNX7rYc2LG1fmB8Any0+2e8yqV9Hhnrpeyr5woxSdfb5NuxoucydagneTzT/3/E55CSw/CvwU
+ rBMPnXvC4kWyYvnJOkDAHOs7g+e1BgArtvQUcZecIl7zIfFbD1klcdBjzATEkycSgO3T8hMVB1CKYSb6
+ /b2iuQUiJ8NUeRUPvk1cJ8F+/YX2cZs4LgLQ5FOW5ajBsQS98y007gRgt8P0a+bS00jShMj2I6No+372
+ b0ZKe6jlMxMXTS+vkPj5l0np574isQUn2Pw7x5kc4IfPayq3kR5Q4FNP7ZB+mGwEfIquV5heJZDXH7ro
+ fJk3d47V9R1n3GrHfWewN0FuoTttpsRWnAGg9Yt3YI/6D2guappMUXh7hNONNA80E0r9FOAEov4NCP3+
+ XrJnmEOyELdsx6uOEmb55BKMiQAZk49Zz0zmcP47Kr9QvXw19cytZzNFY/j066dG5uTlAn6yG5TfSURB
+ J0NjLv7tz0vJlZ+DrG8ITDpn8nPVgs6sq62Vzs5O2b17dxoJSkuKZeuWzXLB1i1SBKoyE2D/eb2f9VZU
+ qLUgQLjUrtdB1YOqF2hCfFHUhJURv7UE1oFmK8dt1rKah0P9BBQtgwrc8whE9CDjFOOZhmMiwNfSrF/H
+ 0l2JCv/Iyv0Kx62friYa2JLxWg7kDKTkBH4nXbkW+KZxhpR++ktSfOFHwfLLR3jrJhsI7Mx4PCYnnXSC
+ zJ41EzK/VpaddKJcvO0i2fahC6SivBxqiDPp747qBrSeGQ2lSDBQblNvvggroU/FASOVDDKFbY22O6sw
+ zxCKoUMuQH2A+hfgYGgdGCiFIu/gqRfzEQWjIgCpnxFaR1m/nATg/yVaMsfEYg5H2FCuEfM8BnUoh4Z/
+ dC623x0BPpSj0s/dIEUbLxJRqgtZ7mju08kp7ExS+cIF82XN6tVy+prVsnjhAhBkcRr4U13086AgxuYv
+ QT/MltQbQAImjAx5NncuH06g4xuSNAutPgCxyeRTKDp8mqLgIXRpKxOlxwoa5USA7qvno0I7isX3/Aq8
+ /HpUdoGy/uoGwyibioWuo9bRM6yMAL5YmU/gE9COAv96ia/fYsOyOZw36aNjlf9ZDbN/QgWP4tMJdI1s
+ z9/kvXLUEuoFDDI1zZTUq88pIali6OTJCcB1VR9g3ID+F/q3rbu4TjQsr6IgQS5wwynV8o0XRyJBTgQg
+ xgRwYx7veWgns3croe07bl2THSgx0GuY5jw8Fz9L2Q9+M3RqZb5RtldM4J+5NQ18KmItR9tkz9590tnV
+ DWoswvfEMx88WTLZSE5vXnYcYDJeNF47MlYGYwzOrHki0H9Srzxro4IwER2aiHHres7AfaTb2E9AFJAb
+ 00kEpVBDyCkVBajU7MQtb6kLBA/m4gIjEIDUr69ydGRrI/Z/ztRtA6XfqW3SMKV4YP1tRyTwRg0r0Wwb
+ G7dPtAfaPjhH8TV/oCFW0aANEHZoSLY/sUN+duuv5ckdz8tzO1+Wve8ckAbI5+qqqhEwmSz4mMj2XpR0
+ MlLICWYv1FHJqdee19wDIoFb7NhgUoQr5dIHqHwbuotdaz35/QygCLBCagDD+8Dp+qyDqGYEFxiBADQd
+ gpxO6v9XAAE+x+EaprzKoTODTWAKl6ZxDf+oKOtXjQ//21Pic3xsUYkUXXqtFH/4arWLFftx3/M7X5Fb
+ b79HOjo6YZcn8e0JaWltk3cOHJLp0xqltqYmIM73ClRTX0zgPXTnLlLlznvzZXRcSn0FRILhySYj+sKO
+ QaByaZSrUhlMcP4KmYFO3g02Q06gA06Gm4VZCKDU70vg7pWZQIG/wMsWmXgMJl+TCSN8fnvzCJNvBOsn
+ /LtsmhYx0wXLL77mizoGnx/LW4aA6fc/9Cgofn+W35C/e7p7ZL8iQYPU1FRLOIvDB7nQw+fMW6p5E/6B
+ PTbBlimKJeOLAiIBuAAHsKoH0jqI/CJGDgGQu41ruplQM5wLZCEAEwuU1YD7AOuuASJco77+8mrHVNDd
+ TIdPW06tfzjrT/VbxY/szVm8TEo+/1WbZhVx8BABdjz3ohxpbs1ZW09Pr+w/eNhygurqSE9NgZ1+vBRw
+ R3feIklSKew4aqOI0Aec+HiiIPDWlUAhBBKAQI0MaXYKB6fuA0E/o/bcMF0gGwGW19A1SeqfQdkPFXA+
+ x8lzMgWtdGjAWFdvtrdvOOsPgzsq9+no+dSXxF12mpo+w1nZvgMHZe++AzmTQkYgQSgOMhV8IBAhK4bA
+ b+JgU2ypnU/aaCCQQLnAeKIgBS5QVGrHKoZcwPfpvq/HS+4EbHsY0MvJAULlT2xm/KVAgGt1vpwKyH4m
+ I5D6u9vsEK3RPiRg/UzS9IaMavnxi66Qoos+rkrfcPcqP6AcbOvtPXult7cvZxLvqEjwARUHYSKLC1PZ
+ Awfw3n7FzmfgjRQFORVC9g0dRLTUvDQXqBGbRqa6QFQMpCFCu5/Ur4M5HPNR4WhdjmljEgILo1HjOHwI
+ Lk2SHLDJgs6SUyS+7SqbF5gDYDwze/YM+fBFW6Whvm5UoDKIcwAIcMttd8pbu/egP7z3fETQlBb2Q0mZ
+ xD98jZiFJ/KE9qnqUxEyyck1+/s0fKzVEHYcdURYOuZywpYwDnw8WpQDdJH6PQ1KcFjEBuiAXwQHKDOl
+ 5Q6zbTWjt6djFLMvbIwolqqnL2nTsuNQ+tyTT7NevlFCrDwm8OvqamTf/oPS1z9K0qhkOMG0pgZwgg+m
+ ThAFqQ4YKSoWb+cTYhIJzYp2S0LfRXDPCMeAZwe2FJVYLpDUsYeUzHWo+0ncv4vK5Q0BF1AEoOOHmr+X
+ 9Io1zu84G7A5TlVN2qzwuzrGlP2h4kenjyZErN0sxTD7qNSkWf9wQAXH/IiG+nqNx+eDBAfSSBDRCcIY
+ fAGdfVyX4HvcxumS2vu6+Af3gLWiB0KFcMxYQcoOtg0SaHTGFEACPdiDOh4wrkONUZVBRQBGjKzjRxY4
+ joG6bho4QweoWG0v9TFz3N4oJaT+VFeg+NU0SNF1/1WcOYskHBse/ajsB+0HOBNBAjURhymGud7zfi5x
+ wK2iSlLPbLccOB8uQF2AiiAHoTJ1kyLBS/KuanT5HRADbX6gDLpdgfLHcDn+XQZEuEJNv7JKR8fwMdGj
+ tzOH3Z+D+vsD6j/rAolfcIWdaMnJM7Qb2PmFIIFVDC0ShG7eDxDoM1yN2cb73hZ/35t2fKObBxcgfEpK
+ LQFmlMEynH6NeTG8hWLAJftnsABco8KxaV6rdEKDiiqdXk0HcpADjFZCzb87oP6qWolf9UVxOBxsFLmf
+ q4rwI7jVQycoFAlCcfBBEQVZ6h0dcGDp3jOPWAWPXKDUjOsiNrFine5Ok2h1gg2fQ/e6IcnvwekhtTZC
+ 9o+Li7D/CrYaKBAOEw9Zr9/XO/qgSQny+gbtMC3V/FdtgOn3cTvFWo4o33iFdzsRJHhn/wHpzwcJAsUw
+ 7d//IIkBfCmnxUu9+ZIIdQFae+QAsQzgc1pQQe6B9gXdw6kku6wKsL4DcD5KMZCxB4w5C/dNU5BR7rAb
+ yfZzDOVKs/8w2qdWh1GW467fKkLtdaI0GHCBmOvIshOXymUXXwCxUDumiXiQJuIv75K3d+3VSaVt/sH7
+ yEwM2ztqm/HtsKq0b0tK9Nj2uWQcsLmeJexUdBubPWTxZBphHd7ifnVVLSNPpRADnKZtLScxMmXllv0z
+ oDAwuuNHX8y8BM53xaFW85ZI/PLP6UDNtOwvlBLDD0nrBHWauZM3J5jWqLGDNGsMbzpeOMJYCbM5rKTo
+ nsPSUs9BGeRMaaTeYjtR6ahigJ5fhonVFyBWiVTPoDniJfz7nLhJukHsn3PuctauRp3Dhp4ksn9q/mMN
+ 4eY/OigoIRjS3HypuDD/7OCNicvi3DpBYUig4uA40wmyQB91nzPvv7c3mH8w4503Wc/gV3GZnSntjRf0
+ WDPoIspgLi6pJjjHa6gYGLLpZDZU/DPAu5sIYKAUrAbBXyeceJnynw8wu4Tj07wxbH8qfxyXzykLKqol
+ 9jFQ//S5aeqdjBKaiPUQA/W1E0OC48ptHLB6neyjs1OGXnhWun9+s7T/4mYZ6u+XkiUnZGdEh4/xT3De
+ 2/FgWi9TLjCWNcBzRYEnlgGiZIK82kET7gcCvKMIgNpp/m0zzC/ijNhkGcw5G8P21xalAvZPGTP/JIlv
+ u1pdmJOJAPoBEiiGDeAEtVQMD+atGNa814phGCBRwNtkztTBAzJw/z3S+YObpPW2n0rLzuel5cAB6enr
+ l8aNmwDUErHNzQ1M71lYAxxwS2tgPDHAgKxyAMfOcq6I48dx/mWcetL9yknVpSbmXIXnTtdZtTWc6BgO
+ SgySCnJ/l1jljxk/ms9w9kXinr7JpotNduw+wuKibuN8kIBDvbJ0gilFAj+Lz/sB8HVii54uSbzykvTc
+ +lM5+sPvScsD90nrvj3S2tMvncaV1MzZMv0jl0ndySvSIjRnWyHTPc6d+NZONQNNkDo2qlNIU3tiomsn
+ 8DfNSN+nd26vl/B+4964vIaTDnCljRk6j11R4GbijWNOxWqHcOvkS5wz98KrxMxdmrH9J7Gj/YjHsFAk
+ OBAgQW1tdXZq2SS1L/fcBgHgEwnI7CMysP0B6fz3f5Wjt/xYWp57RlqPHpW2oaT0lJZL0SkrZfYVV8mJ
+ n/6cNK4+XdyioiyEH1EoBrrbxYMyaJgVTOIrHsccZOIofQksgR6gSODLre6Np9ZOx0OfB4+t0mlN40V2
+ 9gSaEGPN3OWLtf15S3W9xC79jMawJ536h5WJIkFoHUzJoA99WYbVe329knjzden91c+l7Qffk9Z775SW
+ XbuktbtHOmB5DzU0Se2558vi6z4ri6+8WhpPXSXF1TWAkzummEqjGijae+xuMdTRjA0Tj+0PMNYry0vB
+ LOpGE/bkZveGk6s3G9d8DA+WQFvUuW11WkKN/GVjd1biR9JOlqQe5IUnS+zcyzTvb6oRIP1BigS1ah3k
+ gwSHmltl4fy5UlFeNokuY1/Coe20t1NHW2Xg8e3SdfMPpPXmH0rL009Ka3OzHB0cku6iUnFOOElmX36l
+ LAW1zzv/Iqmav0BipTZYlkvxG/370ffPPSI+E3NROI7AuGMrgjqMTDXIlHIObX3Kf8q9YUUNkz84b6/L
+ pEK1/3XRhdG9f/rRwQRJKofWnCPOmk3pkT3vhtadiSKCE0AxZGbRmEgA6isH8BcumDs2tYxRbLZbxGlD
+ pxM09+Set6Xv17dZar/rdml54zVp7eqWdlwfqGuQ6rM3ycJPfkqWXnWtNK1ZKyX1DTqQI2rnF9QS9LO3
+ 5zUxb79sD+MBAoyhCOoIIp5nLIGmva/jBl5yv7qy7hI8eLbG7Mn+qS0SQ8aw/1lo++t6WWiMs3aLOMvW
+ TIn8H7UYUxASEGAVleWy7MQlElOFaGwESAN7WB0q2zlLWGe7DD79uHTf8iM5+u/fl5bHH5XWQ4ekrX9Q
+ uuh1W7hEZlxyuVL7/G0fkZrFSyReViYmnONguJOnkG9nUu2eV8V/5WkO2gxyBkdHALXTOIzPcawJmlTi
+ JrU+796wsvZTuH+5mhLxYmsxBcOOxip2jjxjZ9I6/woxM+e/e8CPlCydYAwkoBm5eME8RQCnkHam3d6+
+ mnDJd/ZK/313Svu/3SQtt98qLS+/JK0dndKW9GSgulbKzzhTFlx9rSy95jqZsf4sKWtqEjdMh5tAbGRE
+ c8I9vYEwB1URdH07nGyMqi0CuLaGRML6eXzZTSuAAaCZygFiwVCUcLmVMfqEU574wdBu54LfFsORwu8B
+ AmgZhgRMJw+RIPQBVFVWyqaN6zWRRMIrw5o6woBSNp8Sr6tLhl54Tnp+fjOo/SZpfuRBmHD75Sjs9g4X
+ JvXcBdJ00cWyBNS+8JLfkroTl0kc/aLrC01wOptxC72Hj99l5wzgK4oCU9DP8SEswYSXPscbDCQ4XY1J
+ DfiHyQunG9uD1qGvXG78efl9L3gRbcyyiuxr6R9+lhoZdcZMdpdoUzSAtESKQHH3PrBdDh1p1rVYaqqr
+ 5Kx1a2TxwvkKVN47BBHHQSgsRUVxiccDM4nt821AyWs+rEpdz6MPSQ/keg8QoRfEwaSnVGW1VCxbLnM2
+ bpJpp58hpQ2NSunBRxYM9IL7jAE31SNCcPmZMEr0TkKVcyVzLkMvCbGdMn7K8xXmvl/D+HCtViIWBdJe
+ q/Fa6we+atqXbmbe3ailwDF/vaASjvih3C0vKwWQ3MwHT6ZJxrrwbs70tXTxApkxvUmaW1rB7ZLS2FAv
+ tTVV+u4kKGD33n2y47mdcuiw1aJnTJ8ma1atkAXz59hJonCOVN/8t9+Szh1PSTcUvd6UJ4OcDWzmXKlf
+ u15mnbNZapacIEWVlQEzGQZ0388LCYbrGuP1WRjpVO+eE8tUEqF85vwp0HWybH/kvMl+gCO+NKofKXPB
+ yzR+zFZHrjdMV/MvHcAJGkkW/PiTO+TRJ56WDnRmTVWVrD/jNDlz3elSRtMn6JxJDdoqQvnKdqurKqWq
+ qjLdXvVcgxs88/xOuf3O+6StvUNCWnt71x555dXX5eKLzlNEcMEuPXCI5oMHpaW3TxLQc8qXniQLQO0z
+ 1p0pZdOmWYdNRuvKakNWV+XZdPZZHxDtMfTX408+k+6zs9Bf689YI6WlJdnilYRXUSVy9JCl2WQAlmTg
+ nMtvcZViioDItNn+sP04he0JI03hPHxsA7D40Seekp/f9mv9KJajR9vk4OHDeu28zRvTlPZulubmVvn1
+ XffJ4SNH7KxhmSisnuO1ubNnqdPIraqWGb/z+1L85htStfREyPWTQO1VwezgY7D4CeQh6CJj6JeHH31C
+ brv9rrT+wj4jlyKibtpwpnUUsd1AZM5p5HOhqqDrOaOqRL4nq/5c77S7umGraOfZ+Ohtw2b1UJu7t1e2
+ P/aUzrwVFQkD+DBi+Bmnr4ZctmndU4kEYd0hMbz59i45ePCQDAUp1ln3ArC8xnumT2tS+dq47izdsm+c
+ NBeS3Qf6RndPj/YN+yjaZySgRx59UlYsXwZxUKaTWpE7+V3dUorvSAePvdz1j9OAkmzqj5g84z4capxU
+ RtxoNfiY7l7p6Owc0Qged3Z2S1dXj7I3Le+W1YB2kaJ6OU1b0OnRQvaaGBrSe0IPX2g3T6SNhfKBLgC0
+ s7NrZJ/h/W3t7XLkcLPMCOcw9C0A/CBqWPC7I/DLXjWhUPbFSnq7dRJDHfIdlIryUpW/HZ1dIx4pxzVe
+ z7uxk1GC76JC5cOs4xRx4cSRLKFTiJYA78kqowA/73aP0afh3IVU/OJg76UlJTpBxvDCuYvKSkqC91qN
+ z9ClGw7TC4lxAiWqvuePAKFxrW1JjXh7RUWFrF2zSkf9Dg5mQsqcm+f001ZJZWXlxFqbbxkl7WrJ4oVq
+ DRwAq49ygdCZ1NRYr/f4MoaXcIIyPtzstHReMD9hKn1M59Tyk0+Uo6D20DxlKUafnUr2D6LJMhCD/IKc
+ wM+nicE97o0rav+bMTp6IzPsMA8RYNPA8EQdrIB1F4hNJJW0U4ZylGZMZ3e3zsPDtO1zNqyXczedDY02
+ YwVMpgDIsnR8Sy1RtZaIyfe+/tobMLV603MEEgB0FF126Ydl1aqV2t6JOLRCrsJEVQI4oRNeDMkQiGBg
+ gFu/DGHPc8lEUifdts/4XB1bpjU2qhnbBX2AlgiHxK9bu1rWQWfitDmh0Uxz3Qz2SfHT94jptjOAFdJa
+ K9V0INBAjAoozri2k/w8B3FEEK/1oE0yKI9cRudVVlbIhy7YArNvrXY2FRg6ZNQPP8lyfzi6EqD9AwPS
+ DlOPdn9tbY1GAWlPbzl3s049c8+9v5E9e/bo/fPnz5fzt26RNWtOy6t9UYr2AgomMFNEpuBYl7WRkbrG
+ WIVtPPecM2XN6hVqCZTB9GM/xuhsS0PG1qsu4L6R4qLA0hZDC2FBmmLFCvFyB0EiH64lKgJSdrGlqDzV
+ PWUqOpMhW24SOZ9V57F+wrD2EQB73tknd97zgOwKRhJPh/K0BabnqStOUUo688x1Sun9gYlKjlRWWqaW
+ QOjHCB0uyrYVoF4a0LoPOEcuhXJkw8a7nOlXImAdRzrVSPpc9B4TvovzAHE+gDzfkbM9viRi+N1mlH79
+ gAHkH5MOEcCDImjyxPS03C2wzfnUS0C9+dbbcvPPbtMcgfBd3RBDdPxUVpSrjGfh1LDFHHlLYEKWDgxo
+ yrT+tsD20wCWgE2PD8iJlvx7I/S2OF1tYqh8T6wjQzug2XRcNu8hYP4GdaE5YqJjOW30SmQEmgWOBw0G
+ lVSI//n/JWb1pikPBo1cZ8BPu0cpz996e7fcfMttGgzyhmUzUcnatPFM2QaxpCNmvQwZ+OlPe1dskokX
+ bZ6n+yLI//KffUdMwg4Vy9Pzx75KO47x5y7TdtHc76FDruMFY/OlsiFoRu7Tjj9FEEeGtn1aEhddGyCA
+ M+ZEy9HJnoYDaURjPdvWNKiC+/3I79CM2rV3n/zq1/fKgUOHR2XJ1KY/esk2FQNhW3K/eMxmvYfFT2v/
+ pff8UEqwMadfEWD04O2wGjIIgO0m03bh3D/DzxuZCeLbpZHyI2HC2LXYMLjmPOm9/A/FL7LDlsarIqPO
+ HEsJsm3xPbv3viO/uus+OXS4eVTgU7PfdPZ6OX/zBl32JteKHcd9CWBnoHSX3/IdKd5xn+WCqfw5gGQQ
+ gArf190vL6paiM44DydsdCNCFuP2jxMAOxaXwRUb7FQweT14bMWKZSufGdkbD/hqlkIR3LxxvVQFk0+K
+ 5I3qx0eJ2LOmv1tKt98mDifsYskb+BKluj70183ulxdXc+TlpeiMssA8zK9bjPWf68xVAMbQsvXiVdZm
+ 3zCpJdNy1fax7ckT+EwSuWjrZlkwb26QlDNcrr0fip8mXrflgJQ+/itwgv6QlgupxYpwDhMX+Wf3K4tr
+ eO5ywwmG/bBL8gtk6wTfNJ2AAMlZSyQ5c1Hw6NSwV0v5fpryb787P+B/6Pxz5cSli9MOnvcV5YclwgGK
+ XtshxS9tt1lbBcj/0JwxVrE6gJ74W4oAzgzIdX5pHwVp8/l1kS677tiUFFL/0JLVmcGNkxU1S8PWzwb+
+ Xb+xGT/jAn+zAt9Ne/fyRvHjrASiOzkkJU/fKbF9r2VOFyICJPx2/1l03Y/cP11clTLiLMeZdZKJi+Qp
+ BsJ0ZM2hkcFlXCqtVEaaDhMtw9g+sJ1OnryBv9UCP1T6CtBujrMS+iBgqXd3StkjP8XeuoBtKCZfH0z0
+ yPzSN/6d7vWLa6gNzkSfbMVZZgeZQhh4OEuFAWYm5i2TVMMsyeTF5VvLeA22ThlS/h1335838E9Yuiiy
+ GOT7lfIl46PA//juF6V0x93iaNq+rxlAEzCn+vHMv6KvnoUOUG0832O//BZ6p0LThU2eRhL1ANdOQSNM
+ OCyvkaFFK61yEHUmTbgEfi8A+3Bzi/zyznvzk/lp4GcHdY6rYeL5lmiORiohpU/dKfE9L1rPK1n/2Nn7
+ mWpCFwAzP33/KJTob6M/DrtfWaSrfqVwYStAOdfebgoQA2L9AShOYkAGl64VT7OETYYTTLCE386AzvbH
+ n5ZXX38rL23/xCWLNENY3tdsP1ICDuC2N0v5Qz8Wp8dO85pO+My7Dqvm488L6I1/Ru/0AgGqqBYmQSvL
+ cMMZktYD8icXE676MjQgyaY5kpy+KBv4E+572+r+gUHZ/uQOae/ozP3+NPA3yQlLPiBsnyWN69bbV/zq
+ Y1L6wgPB2D5cTEgB7D8jT9Edv8CfO7BPuV9eWEU/OTiCXwmMuBB9VhQGhfIWA45VBjVLBdvg0jXix4si
+ PT8xCKQ5AD6Ya/y2tY9EgDTwz9uUk+2/rylfMuzf6e+WiodulljzO/YccWDs0XvRWvzA+ct9D/78A2D+
+ ErkpEKDaptRDiUfHXYzbMkNn8uACaX2P1h9ud/u6JDFjsVUGw0jSMcHAV/u9r3dAp5WPxg9C4F8I4JPt
+ v6/t/Fwlrfz5UvTWc1L+xK9U2VZzPuGHcaE86smKdO0BrL8Nom0nL4ASWKVMAfcAAQRiwKySEHJ5igHD
+ zKRY4BVkogLODSxalVkR7BiRgLyIcwEwyYPJpiyxmCszZ0yT8zdv1IEg7387f1hJA9/TqXoqYfrFD75l
+ z+lInwnFUljhbYD1z9BXCUZ/3C8vqA4UQ2UqRbhwgejEwrlGPYxeTJQLQElJzFwkyfqZkg38QqGSSZTg
+ cK/5c+fInFkzZe7smXLKSSfImWeskVlAAscZvuT7BwL6oetTine9IBWP3SomMZCmfr8Q71+m0m4c/Q32
+ L9qILmD1zV1dcv3iGgUTFIEeUNtWXJwRZEPn7RXUWcpDLgA25Qz1gwustpMds0yQJDNYbmy2DFj+zBnT
+ ddoXZtGaYV6L9zvo0yUAPtO+qu7/ocQO75KQ+r3Rp24arSo/COG/QvPPNU4XQ/b19+6z4wq+vLBSfBsi
+ 6EeHzhbrFQzoWfI3oE0gCvDf7WmXVM00WATzI5mGExAFI/jc8BMfMOhH5L4BmZe+9IiU77gTolUnddDl
+ 5PL2/ftZRjM5/A9w8g7AU7UHEn+6y1rPm8Md1wpcB8L/Ca7MsDlC2db0mIXzHHKOSUUCB2JgsbRd/iUo
+ hMSpKDP5IEBqKkqE9dPub90vdbf8lZX9ZLGw+3UIWL7ZP2HKlE32PIQDzgT/BC813LdP70mPLPrKohrN
+ NQACdOGmU4Tr0Vv9K1D084sQqlkYTFZAi4AZQkNzTsqMHnrfa2dTXELWDxFa+dgvpOSNpyQctKvT8ReW
+ +WN/2u3XgO2/AI66qvg3d1llOo0A9AcECJigg0CsMhik+AS+wXyKF3iCA3jH2w6pMpggF4hW8Z+IkF2i
+ Ll8PrP/1J6Vy+8/Uuabg5Kovhch+P+tXJ+r93+j0F2nxE6Jk/yxpBOAJ5QK2HAWAqAcskLQxnycXMBmF
+ UBEhmZBY+yEZmnWCeBU18p+iIFeJav2exI/skZr7bpJYxxHruE0F1O+LjNSJctU2gvofxfYd0HAfqT9k
+ /yxZEGg9d44EacZ0pP82tr/FcVXBuoDYyQud8mB6FNeV/hPXS/sFn1Mk8I2TefV/dByIRDzpjaOfv/bu
+ f5LS1x63U70zDN7rFaT5D5P9JPUvYvtRcCwN92cQIGvhyG/u7gp1ARZOn7FWhnOBPEWB2qlO4BtAhbGO
+ Zq1hcOYSqw/8pzjIDtAD+BzuVfnkrVK+88FA648uxpFvlSOofzu2v8bWq9T/m31Z94/o+dYtc0IEcFHb
+ 5QDOP4gdp2JzvfP1Dop9wq2wc9nq1GYlFdKx6WrpOXWrneFCnP/kANrXnk7LV/H8vVLz4L+JGeix07on
+ fLv8br4uX60vjQDUHDtw/HuA2S2iep2MQIARq4crF1hYE7btICB0grqI/YxFkLd3MEhXckJYA6uLD++G
+ GKiVRL1VCv0Mc/mPgwzD2D5HV5W/sl1qHvqROH2dVolKkfX7ar3n7/L1w6Avu5V5s7/E0d+BZvt1FrVh
+ wGfJ2eXUBYL4AeeVP8sx5vs4mCNSOBKwOEXAtEqTnu8+VTtN2s77tPQvXhPMMBIZSDKV4sDPVo2jJeut
+ 71IbFNDU+N/aIXX3fU/c9iOBFeBJqjtYiKPQiv00698HDPgkPuVROnn5SVHZH5ZRv/TolrnMwTOe55Ua
+ riZizB+LjRE4BXkHg+JwTWMqhY51EhEJ2jd/UvoWn44L8SCYMHUdnwXw0XLootlDU9YSSdv6zPApe+tp
+ qX3g+wHwbdw/RaWvALkf1Bl+FVn/II6+je3rjuP0c/b/+t+8k/OxUb+zZfMc5SGgfsYIFsAMuAl3nylW
+ FzAFx9ycAAnKHFsDKD9VUScdGz4uvcs2iM+YgRk2pGwyEcLPDDHj+HyuJcDFplhmzpwus7EVFQVDxqbg
+ 3dnHno7pK3/lEal55Mfi9rQFKd4cc+llZmEv4AWhISl2xM9j+PMpwG43Ez04LrLxgZHUzzLmV7aeO1fj
+ 75xIGvVcAu7/93iiMdQHCkYCWoTlRhyuSBdwAq+8WrrWXCzdqy4Ur7gi4C+TG9kLQc9uIvC3P/6UPLnj
+ eenrs2RWVlYqZ6w5Vc5ev1aRIDN5xWQggZ/9m4s9DfZI5XN3SdWO28Xp7UxTvtcXLsBVUP1htN8PEj5a
+ 8IfrP96GKynmSDTcn5v6Wcb8wmZwAWIPRQHew0S/r6Hi/yKBKEhXkndPBS7iUmsdpJGgqFR6TzlHOtZe
+ JqmqRqscmsm1EEIaefW1N3QEMZerjxbOJH7l5ZfISScuDb5pMl8uVtljBk5Xi9Q89Qspf+khjZim2X6P
+ XX01HQzK65uybgxZ/99h/xf4gB6yfnLxplGon2Xcr2zZNCfwKTBc7M0DQvwjfp4rQbQwqCTvaGEaCUoC
+ JAjHFUAP6J9zsnScdYUM0FfAWTAnSSSEcwKSm91x593ymwceCmbwyDSLNvKWzefItosuCDKLjgEJcrB8
+ Zk2XHHxTah79iZTue1nlv9UDAuCnl2fInwNE7uSeXqP7AfDPO8bZy2tsfeODowOfJa8vbN08VwdjMkCF
+ btsIgv9/6J1FYteeKQwJIm/mShexyggSoOOTNdOlE+Kg5+RN4pVUBIGFY6NGVYt19hBPbvvVHXLPffen
+ p3CxTbGz5J9/3rlyyYe32YEk+bO1MV5sXbsO7PqKlx+UarD9WMfhcMkWBX6S2v5AoWw/Anyd/NhwpOzb
+ +J4voNUPo+EpBuEaHhid9Yclr29s3hSIAk6PIqliR5xPoIO+LhxPKEHqWDqBpLBioHfFKp0ggmg3DjPv
+ W7BKOldfLIMzgGduXNIxhGPiAr688MKL8t2b/jU9X6C2AXWWl5fLZz51raxcuVyicxhM4EXpcK76PQ69
+ LdXP3i5lu5+zgZ1wxpEhAt/T1K4JvMK6TzKTPbTh542Azg8ccQeJwMr6x6F+lry/smXTbEkTjPiVqP/6
+ QB9QlS6sakKE41px4JY6GRsDGJyEPtC9bKP0YEvUzAh8BqM0ewyAhYC2cxj3y623/koefPBB6e2zegAn
+ sNq0aZNceumHs2cwGwsJcpqSAV1Co493HJKKVx6WSmwxyH0JdADV9Ps96+HLO60r67URhV/lPod5/x2a
+ ymhft14wZP3786pvhCdwtPJ/9nTJl+dViafvNEPYvwJYz0QnnSQB2MJ7C87LZb8N2T4yQRSRtbhDfVJy
+ 6A0p3f+Kmk2p8hoojCUZYBuRPOc1C28XNxaThQsXyIwZM3S62kULF8qWLefKxo12+jqnQC5j0szYhnFj
+ nc1S+dIDUvfYzVLx1lPi0q0bUn3SrrKuHr7hM3jnUfxsrGMNQwD+T1HjN9Brbb4d1iWND+UHfNv+Aksr
+ lUL6qTnHcEoW4O93mEcoRKbovMMF9GKW0Rej1xBCptRaCWGmrwcxMFQ/W3qXrpfexWskUT1d/HAlrLE+
+ JWxG2lEWHtp5hVhcN5NUakZ5bmTJECJzIOOdh6X8rR1S/sbjUnR0vzgpO2rDLjphl9gj8P3kiBryLFlu
+ TAKfk8Lfi19/iJ7fbXCOeX4NebD9aCkYAZo3zlItmXPiOT4XK5Hl6Ly/wqWzxXKU6IrkBdUfhSUVRLfC
+ UR1BESHQAXxYB4mqeumft1J6F6yWwemLJVVSGREPo3/a8A6P6gBjPzns6YDNuwPdUnz4LSnf/ayU7n1B
+ 4l1HYSolAz5tAU/OlurxshS9Agk/GuBhUeBj247TX0JbX/SMn+JoKFo5TQ8fKKjqCWk6LRtnQ81MiuOp
+ BOGfFejFb6OyM31r3R+bcz98gtFELmRa7thFkRxJcwSNKRSXyVDdbJiPp0j/rBPAIebCcqgUL1Y0odeO
+ WegVZbYzgF509B0pPfA6zLmXpKhtP9SuvrTi5wdy3kvYOH6q38949QqGfPDizOOcl41TQjyG03TN7xQu
+ g+AAGf2YND6cP+sPy4R7qfUciIKUigLWwaDRGYFlsF4CcRDxrB8bNKgkkiOUG7s2Tjg3UaBt+OpMKpFk
+ Rb0MNi7ANk8G6+dAcZyu3kWuauIx/OzkqfKQuyUTms1EgMc7j0jx0X1S3LIX226J9RwVBxq90XmK+EAg
+ 471Au+8NTLsJKHnZJTKkx09T/uPU+PHdT7KlHNJhoPU3PFQY6w/LMQGGSJDSVSi1GoqDFfj9LYmIg4hM
+ PXaSdALRAK5AhKD/IDMuIFM9l7Lz4sUwJ0slUdEgyco6SZbXSqq0CuICCBEvAWKUZVcNKiZQCXCy9lhv
+ u8S62yTe06LmmwMl1GQtpOUHcA+cOQO+UrsCvsAZO3IWPwL8KNsX/09MQPkUM2T9EwU+yzEDpfns2UBB
+ D9TgYO+7aNNyVPsXgAu9hSrBs194DCIhcsyFbrhyNhEivXKmMoXhsYToc0aRQ5NTTDY3YA4+HTRWho/W
+ kMDG53/G64cswFNcQS3XSN0JsHx/pNYZaPtyP65+DZ/2ovFNKuzzpu2Fs/1omRRB2bKRkcOUBHaZi8bO
+ R19/DWC5HCdLadFlv3QSBXSQgUwkcIoDZGBGshO8JZqAmu9bo7QXuJFVoUvagRmapjVkjyeF2tOvHQZ8
+ X6meS3Tfgiskqj308vGCAwRufHjilB+WSQNEGgnUAw2dIOVNM677Bzj6jHBlstBXkDbhpyD4H+qHDCPE
+ 7Wqa+tsN/QsZJBj+9mgmncryZGblLSp0Oh4vGJY/MWVu7OJn26k2rCvSjh/f9VOp/ws5f0TPmckDPsuk
+ AqF5w2ydyMkSHseeCqec4WiUP8EpzkKmmQDRt075YG6T2SxqRo4DvpRe8yLo9jQDmCJgR4ufbd+LbYFu
+ u6AGfAvd8xM0tQe/deJcLu3c9Mixsf1omfTOp07AxRKonDmuC70pVWQc50yc+ApetkEyekFUP5xaJDhO
+ S/bQvTTVc/TfI7j4l77nPYY+HEIf6q30Yh6rzB9epqTjiQQsfuYdMBP92fjBRIVP4rg+PJ/VmP8giDAM
+ 8CyhY/goLn0fP/4eXbE/PB92ymQDn2VKO5yIwAUcghWziQSw5GUrDv4Ql9dIDm6gjfqAIkIOwKepHtsO
+ 3PAdnLgXn9+rLJ9rCbnulAA+LFPe0YoE/BHkF4rlBpyN7DM4vBp7ziUTkcyRxn1AEGEUwIfAP4DL/4b9
+ d/G5DOB7no3xa6dMJfBZ3pUOTosE2w86A5nnpUrAFE7D8RdEp6iTYODgBwcRxgA8L7Tj7934/U8g9mcc
+ xx0IF3MIP3eqgc/yrnZsFBEUqD7dGVKNRmwRay7SnVwp73NEGBPwvs+YPd2438WJ3zgcuRu4l95NwIfl
+ PelQFQt0Idv1aTgnAZfobBC7bsE1OHk6GlYtoyACy/GGDDmArqclQ/Ecov00fv8Qh/fhC1ptxj2Lp/Mc
+ vZuAD8t71omhgihWQdRF7BhJxFaHRnHB3o9h24grXC81FmnrcYMMYwA93CdxSwv2D2P7KU48auwiXZ6v
+ DJCJip6G15seLSyMO1nlPacijSWEy9ZH/bZMQzeGs5Rsw3aBYRKqCMVD1HTM2f6pQohRAK6XIr/5Md24
+ 9W3sKePvwIMvM007c1+oDB27L/9Yy3uOAGEJEcG3OaZpCIJHxnFhOs6cjsPzsWekcYaMRIawTApS5Ans
+ sCjQsR3CY6T2e7HfgZcehuWTCB/Shbn4hccB4MNy3CBAWBQRwtlAbagX4kGHvJArlIhR4K8Q43Be43W4
+ Y7FYfSG9UEEU1qHlMcHm+Dnq0p/CKdch1/GDszc+gUZTsduJK4fQgAFOxeIbjRymvb30hxwvgA/LcYcA
+ 0dKyYU46b8+Y7Pmr0aVxAKRa6GF0nOW4wkUvKDIWiE1XLw02N3y+kHdHOIBG5IKNa8vvxvYyLr4IRH0R
+ Fe9H1Z0mMnNvkIKuzzPfsPGRyQncTEU5rhEgWg6vm27XI1Q4kjCHpRlYRbGSk16LHcq+GDfNx342zs3A
+ byIFFUoOa+PvkmGv4NgcApiTsbQAgm141yH83o/n94il9H2oh6yeWxgb1GL1GDvlKpenn/10y+R2wBSV
+ /w8xfH7lm1om3QAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKoZgAAQ+NJ
+ REFUeJztnQecVNX59587ZTtld+kI7C5IEVBAjYXiAvYCYhKlF8VEjTFgmi0RkjeWJJZo/mqiRrCgMdZY
+ MZZFEU2MirHQYSnS2YXtu9Pe5zkzs8zOPXfmzsy5ZWbO18/1LnNn7pyZOc/vPOc5zzlHAUna0zivYlHo
+ z+/g0Sf09xA88iKeVoBHjs5bNuPRGvHvejy2hv7ejcd/8NhTuHzr35MqsMQ2KFYXQKIPNPLL8DQKj9Pg
+ qHF3tbRQRzmMRwseG/D4CI+1UhzSAykANiTUop+LxyA8euJRZG2JkqYBj314fInHKhSFey0ujyQKKQAW
+ g8Y+AE9X4TERgi27XVp1oyBvgTyF9/B4CEVhu8XlyWqkAFhAqIWfB0GDz7e4OFZD8QYShOXSQzAfp9UF
+ yAbQ4MfdPKr413j8BY8/QNC974WHW9R7OIo6g1JQBI4u3cDZrTc4uuK5Vz9wHVPBzuHDNWAIuAcOZ+fI
+ I/z86EPJK2DX6KC/FbcbFJcbAm2t8QulD/oO6Ls4F7+bJXhchccwPKpv+6J2n6g3kfCRAmAQ5NpjJX4Q
+ j2UQdPHHQLAvn7TXRUbu6FQMzh59g4bdpyxozOXDwNm7DJw90Wi79UJjLQ0eRV2CRht5uPiao3pe6Gi/
+ Fx50b/Ye+F5MOPpWgKOkB3tcKejE7q04HamKA31H9F1djd/dz/AYiccmKQbGIAVAICGjv4taevznLXiM
+ BP1Dbx1gBtcz1GofUw7uIaPQ8Aag8fdh16i1V/Kw9+BwCP0MiRXSwcrAPA8qL5aNyugaMDgoRJ2LwUFl
+ dDoh0NKczDvQd0ffIYnBtXgMweMLFIMjYj9I9iIFQADUp8eK+ST++Rs42tLrB1tOZ3EPZkBkPO7Bo5jx
+ O7pgy1uIrn1ugRHFNhTFncvK7qDP1bMf+1zMkyhEr8SBguBBL8HvT+SW9CXQd0vf9Rw8OqMQvG9M6bMH
+ KQBJEmrtl4UM/3w8ShJ5PRmHs88AdOGPA3fFceDs3ocZPGvVMxT6bI7OXdlndfUbGOw65ARzlQKtCXkI
+ 9F1Pwu/+FjzG4PGx9AqSQ44CJAgF9PC0DI+BCb2QWvnSnszInSW98N8u4WXzHznEzuRuB1qbgn97vRBo
+ rOO/wOtpLxsPhbyPUDnJCwmLE30G4WA5fTV72WfwHdp3tGz62YLHdYXLt74uvnCZixQAnYSG7m6FRMbp
+ Q0bvLEHDL+0ppBxkIEEDb243eP+RGiH3ThRHl5LQGT2X3PxgCy9IHPwoAr6afcmIAeUZLJVDivqQAhAH
+ NPxH8DQHEgjmOXscE2ztS5I3+gBWemq5ybj9eKa/E3STLYOJAfX/6UCRSFUUfPt3gT8sBvqhL2sFCsHC
+ lN48w5ECoEHjXDR8hSXr6PLVqdK7+tBQ3DGoAIm798EWPWTsoXMmwYKZhZ2Cgc2SHprDkTHxYTdh3y7w
+ 7q5ORAyxDwTLCx+XQsBDCkAUaPj34bdyNeg0fBqTp8PROaEYIIMMntzcQF1txhl8PJgg0DAhegjOJDwl
+ fx1+d7u3s+9PJyQEf0QhuDHhN8tgpACEQMNfhN+Gvj4+tl6u3gPAgYZPLb9u0K331exn7qwfjT6JQFdm
+ gt8nyxkooXhJD82gJA/mOe3/Frx7tuv9Pg+jECxFIZAxApACQIY/Dr+Ff0AwHTUmZOzBZJy++t18im7X
+ osEzw9+fYmmzA+oisAzD4p76R0uoe4BC4EMh0Nk9OIhCMA2FYHUqZU13slYA0PBpFt5y/AbOiPdcZvj9
+ BrHxa72QsfsOfCuNPkVYfgSNopBnoBPfgd3g27lZnxAEYBX+fx4KQVbOSsxKAQgF+C6HOJ+fGf4xA3Ub
+ PlU4qnx+PNIlYp8u0G/hwN+Bfgu93S4mBLu26PktAvjf37IxUJhVAsDcfYBX8FPH7OcnavgsILVnB/hr
+ ZWtvBiy9uHd/3YFXEgLv9vWsOxaTAMshuCibugVZIwBo/FX4aSdArM+M/U1XrwGscunp4wdbmK2ytbeI
+ oFBX6BNqihGgSHv3bo8nBOQNvIUicK6octqZjBcANPzL8FM+BnEW3qBK5Ow7ECtVXqynsYpEEWf/wT3S
+ 8G0CE4Je/YNCEE+46ffbvoGJdxyaUQgWoBBk9NqGGS0AoVY/ZpCPhp+cNK8dzzFhhr8DfHt3sL8lNgSN
+ n4TApcODo2FY7/aNEGiqj33PAKxCEagUV0h7kZECoKuvjxWEFrSg+fYxIcPfS4a/Uxp+usCEoB/7feNB
+ v6v3262xf9sMjg1knACg8d+On+qXEOOzOYq7g6v/4Ljuvq7KIbEt9PuSd0dLpMUi0NoC3h0bwV97IObT
+ 8L87My2TMGMEIDSu/w5+Iu1putgy0Nx7Wt8uFv56dA93bEL3sEFwKSVWQEJAy6bRcmqx8B8+CJ6t38Tz
+ Bmja8eRMyRvICAFonMOy+d7CQzPQR62+GytBrL4hawl2borXEkjSFOb59Ts2tueHxu/Zti52HQiwAOHZ
+ hU+kf5cg7QUAjX8ROOBu0Pos1Nfvfyw4S2Nn+np3bwPf7mrxBbSYgDcAfk6KvL+l43Jcjjz12oION36p
+ rrSvIh2h+EDPY8DVpzzm03yH9jIvMIY3QF2CX6Mn8P+El9FE0vrXjRflp8Uq3YNGtC87xcNffxi81etZ
+ 65+O+JoDzMiDB34eT/BM/xYJCYHiIlEInoP/VsCZn55ViHULyoZit0A7TkxdQA/VjVhdwTQfJUjLXw9b
+ /QFY8pj9fTY3v3eZ9k0ouo8tPi02kQ4EsMH2N/vB3xYIGb14I0+WsDiQGDhy8Mh3gGLhYsWJQIu3UF2J
+ 1TX07twcu55QXCAAk7FLkHZxgbQTgJDxr9Ps71Ogr2xIzEBfsNXfAIE2+7b6ZNxk6P6WQHsrn06EvQNH
+ XvBs564EeYguqjMxvAEWIMQ6o9klCMYFhqWbCNj3V+GAxn8Z9vdpFV6uXDOXH39IJV97Ve6gmn9rVBFT
+ wtfoBx8ZfGP6GXw8mCAU4kGCUGhP94BtuNJvkOb1QHMDE4EYXQIv+GE2ikDaZA+mjQCEjP9p0CgzLbrp
+ OmagpitHP563eiM72wVy65nRNwXY2UiUHn0gZ9zZup7btvotCOyPmyqbEiQCzoKgGNipu0CNh2vgcdpx
+ o1Aqsf/wIa1boNsGP0AReETzCYGguCuK9eZnfQl0gMb/CBr/FVrX2cw9WqRDA1ph1rtri20Serz1Yo3e
+ XXkBOEq6g3vcOezfrsHD2dlRUAiOZNbeiyDgx7I2BJcr8278mp09q1eCv+YAeKpeS+neYcJi4OpkEyWg
+ kSOsU7FWcqaFR+jQxA+PoghwpxdLAUiAeMbPdpzRWlOO1HrXVrYEl9WQS+85gsaExh9Iwe5zL5nPDN3R
+ ozc4u/fC/rW1uwb5mpvAd2Av+PfvYcLQ+sKypO9FnoATRcDdxWGLmAHVK9qDUcurpHpF8wk00RABKQA6
+ iWn8FOw7diS6bIXcyxTg825dhy5/o5FFjAu19nRQMC9RyG3PvWgWuE85A4VukOXGrhcSBe/2zeD59ypo
+ feWppLoTFDwkj8Bqr4Dql6timGaXgOqXZ9OX2t4lRwSkAOgglvGzH4Vy+TWM399wBLzb1lnm8rO+PRo9
+ tfiJBvPInc+dMhvcw0enjcHHw9dQD571/4PWfz6ZcLeBPAHyCMgzsCxWQF0CSiUu6sK9TCJA9U1zVMkP
+ T6MIzGx/vhSA2DTMqXgJf+ypvGtk9O5BI9mOszxoDT6WwWUBZPjeIz48EnPzyejzZl4N7oFYydyp9dnt
+ jt/jAc+WddCy4sGExICM34VC4OritEwIKKNUc21Cnw88m7/U9DixPrxc9MTWi9nfUgC0QeN/RInR8rsH
+ ahs/y+O3YBHOZAzfOeIkyL9uSVYYvRYkBm3r1kLLQ7eD76v/6nqN1UJAAkDzCbiQCGyJKQKPoggslAKg
+ QXzjH8E3fgr27dxs+h55yRh+3vW3Q97E88HZWf8Wg9mAr+4wtLz3OrTcrW+2rZVCwERAK3uQicBXMUWg
+ 8PEtLCYgBSCCWMbvKOoMrgFDNY2fpnCaHeyjwJ6nVl8f3zn8JMi74nrIHXO6LX50O0OtY+tna6D5/qXg
+ 37Yh7vNZjKDY/GAha5AqjtMUAVqE1N/A3+0pLAJ2qAvWlwB0GH/FcP4LLTB+Ssv11Pp0RfXJ8Atu+APk
+ 9I+/Mo1ETduOrdB0x8/B93X87gGNGriLnaZOToonAp6tX8ftDhhcxLhYLgANsysuU5zwDO+akhf+gtUt
+ f6ClEb9g8yL95OJ7DvlYyx8PafhiSUQIqFtAQmBWt4DqKOWiKDm56otMBL5hdZVHwAfTi560Nm3YUgEI
+ GT83vddOxk8Ze20HfHH7+c7hJ4YMX3tRIqs5WFML/3z9bdiweSscwr+J0pJiGDKoAqacfyZ0K4mzOKqF
+ tO3YEhKCT2M+j4w/p7vTvDkHbKWpYazOqogtAgEUgRlWioBlAoDGPwB/qI1Ygpzoa0peAbjLtYy/CTzb
+ vmFfrNGQwZPhx0vZpYSdoruetLXhE2+9+wE8/dzLMZ8z43tT4exJ400qUXK0blkPjTcsiJtgRAJAQmCK
+ N4B1leos1V0VJALbvmF1V0UAvFjPBqEIWDKL0BIBCBk/d0qvXYxfb6tfeNcKyD3xNFDsNKOFw5tvr4Kn
+ nn1R13NnXToNzj0z7paJlhLAH6blo/eg6cbLYz7PVG8gngjQEGFbq/paAJrx4wyzQgSsEYA5FZvxh1E3
+ l+wLHMb9AoPGv85w42d9/drg0F4s3JfMh8JrbkmLMfztO3bBTUtuT+g1ty25EQb0P8agEonD19oKTQ/d
+ Bp44cxBMiw1QHR44ghsTiFWHsd5tKXpiq/ZcZIMwXQCw9X8T+/3n8K65Bw7XVM+2TV8Ybvy02k7rXl/M
+ oT1y9wvTwN2P5A/3PgD//eyLhF5z0pgT4OeLrjGoROKhbkFTnG4BDRnm9nKyVYuMhHmxZfxhayYCW77m
+ vi7gg5XoBZi6JZmpAoDGvwiN/x7eNWffcv4qPjSmSuuy8fpPAmHj+odiu/w5V/wMCuf8yPbufjTfm6k5
+ mTImz614VHBJjIW6BQ1//QN4Vjyg+Rz66dylTsPzBkgEXBoiQKsL+b7dxn0dfoRfoSdg2kKjpgkAGv84
+ NP73ee9Ju7hwp/SyhIoNhhs/9fVjDe+xIN+fXwB3j9grC9uRbdU7YPEvf5XUa++587dQXtZfcImMp5WG
+ DX82O6Y3QAJAsQEjYSIwYAhfBGhjWf7+hKRjF6IIvG5o4UKYIgD108u7otu1mxf0o1bfSWmVHHyU3lt/
+ 2LByUWvfutvLXH8t3NOor39zWvT1eXz59Tq48dfJNSi3/+YWGDl8mOASmQPNM2i46ybwvvkPzedQVyC3
+ j8vQuEBS9TsAzVgn+3R6ZptxlT+EKQKgFfQLKuRg/JbUCklr9PuPaC67lDJ6+vsFdz0FeSeONawMZnHe
+ 1MuSet0bL6fN0naaNK95B5pv0u4CmREXoLkDzp6cPSj9vuAGpRwPFxundegFHGdYoUIYLgDo+t+Orv8N
+ qgvoFrn6D0ERUC/uS4Zv5CYdzPix5dfq75PL3+nh18HVJTMm7Fz145/Clq38PqcWAyvK4aH77zKoRObi
+ qTkIDVdN0ewSkAdAnoCRIkBegKNLqerxQEszeHds4I8M+OCOoieN3YvQUAFomFl+vOJW1vLeh9bx4y2w
+ QNs1Gzmf39sQHN/XwnXGBVB4y70pr6VnJz5c8zH8eultCb3mN7feBGNPP9WgEpkPGy68/XrwrtJeg4Bi
+ Aq4i4/oDtJ6AUtBJ9TgtYOOjNSvVBAJemFD0lHFbkMXeRD1FFKeyCnjG36033/g9bcHdeA0invHnLr4N
+ 8i+annZR/niQIZ926snwwYcf6Xr++LGnZZTxE87cXCi69X5ofGIoeB7jezbhumGUCFDddleop7STLQSw
+ m8BZy4Kq4it4Niw/2zAPQGu8X8nNDw6PREP9IdqRt7XZkPLEM/68Wx+A/MrzDXlvO9DQ0AC/u+OP8MHq
+ D2M+b/y4sXDzDT+DoiLtvRXSnaaVL0DrHddrXjfSE9Cs/0hwizp1/ceuwCrsClQaUh4jbtowq+IyxcWZ
+ 4edwsh1YFLcq/R98e3cYtqAHZfZ5DmsP8xUufyetEntS4bU3VsIjf1sGe/bs7fB47969YOHl8+GC87g5
+ WhkHTSxqnDdZ87q7azBz0AgcXUrA2Us9vMo8YNp9yM+JB3hhOnYFhEdlDRGAxrkVTbwhP/rQjs4lquf7
+ 62qYABhBLONnWX33Pw/uHr0NeW87s3HjJmhoDM5Q692rFxOAbIOJwDUXY4Wt5143UgQStoUANBc+vlX4
+ KrHCBUDL9ad+Dm88lFwe784tXNVLlVhuP4v0L3s7Y1belSRHW81BaLpae4TAsO4AecO0jgDPG6Yh8IYj
+ qseN6AoIFQB0/ceh66/O9nPQJJ+h3PF+o/r9PjL+g9rGX/S3f0njlzBoH4OGy8/SFoFuTnAaIAIsHtCf
+ s8Con6YPr9fqCowXOSog9lMFI5bcVF9uss+B3dL4JZZDdYHqBNUNHlSXqE6Jhuo+d9cqtBVmMzyCNiYM
+ YR4Atv73Yev/4+jHHYWdwdl7gOr5bDMFA4b8wkk+PFifXxq/RAPmCVx2qmZMwKhkIVffCu4mN7T3oL9R
+ vbAoegH3oxdwnYj3FuIBoPEPwH7/j9R3d4KjO0dV0bXx7d8l4q073haNv22vNH5JclDdKFj2LkChOlmH
+ oLoVa95IsjBb4Lj7zp7HcD1nsjWyORHvLUTOGmZXVGGhVEvIsISfrur0R9/BPbG2V04KNrFnj1czt7/g
+ 6Y/A3V1fpHvnt3tg7ZfftP97yKByGDxILvCZLbTt3gnNcydwr7G5A73FTyAiOyF7iYbshOwlmoAP/l30
+ 5NaUs7VSFoBQ4O8D1Y1p/74+5arnM9d/d2J56Xog49dS5/y/vaNrhd6Nm7fCshXPwaEa9SSs0pKucOm0
+ C2HUSMPnZ0hsAC0w0vLD87jX2CzC3uKTaF3HDAIlV70JqXfXZgi0qvcdFBEQTF0A5lTsQTVUNa005Mfr
+ 17DtlL2eVN+2A22HtIM0ub/6P8g7I36G35r/fAbL0fjjMfmM05kQSDKf5rdegLbf/5R7jUYFckrF5giQ
+ 8dMcmWio0eRNjkOvd2/RE1tTSmJJSQCw9V+Erb9qhR9Hp67Y9++rer6/9gAeYvfuYxH/Q/yIf85Pfgf5
+ F83kXouE3P0HH31S93ue9p0xMH/m93Q/X5K+ND5xP3iX3829RgIgenjQUdwDj+6qx/0HvuWuHYBewGL0
+ Au5N9v1S82MccKv6MWfoA3R0xwPY6os2fnL5KdOPh3P8+bqMn3j2xVcTet+P0FsgpAhkPgWzr4XGrevB
+ 94F6gR6qewp2B0SODNBUeKVTF1CiZqM6SnuBn0YnooOFQRtMWgCSLnn9zPI7HG7ll9GPk/Hz1vbz7dvF
+ pvqK4mjQT32NjfUvf0/XKj6Jtv6RSE8gO/Bh/7txwZncRCH0gIUHBSlrljd6RmsJkhcdTcAD9xetSG5Y
+ MGkBaJxT0Yrq0zGPEVXL1U+9sjGteEJjmiJh/f5GjYj/c5+CS+fuu6+++Q68uvLdpMtx2sljYN7M7yb9
+ ekl6QIuKNE8/hXuN1hekDUpFQrkzqhWy/X62C7bKCwiAt/DxrUktYJGUADTMKn9EcSmqdZZoGEPhzPP3
+ 0mIHAgN/tEGnVo5/7v0vQu6Q43Xf69kXX4N331+TUnmkCGQHLZ99CG03zOVeY5uPCNyYVMnJ48+docVD
+ eMOC3sCjRU9tS3iz0aRkS3Eq81QPYuvPM35/Xa1Q4w9v0snDNWVuQsZPFOSrh10S5aNPaATh+ZTvI7E3
+ eWPGgvMsvtDHW1I+UQJtLczYo2E2xlmtimuTOkg4CEitP/oNqtc5ab2zQJRLji6L/7C6z5IKWl809fvz
+ r0l8+etSQZthkggQ0hPIbPIW/Q6avvhIFQ8IN0wilxr3YZ/fVdhZ9TjZmu9Qx/UcyCbJNhP1AhL2ABSH
+ Mkf1oFbrX1/LREAU5PrTwSPvnmexbIk7NCeMPE6IF0BITyDzcbrdkHPbMu61WPUzKWjkrL5W9bBILyAh
+ D6BhZvkiVeAPQq0/cFr/OnEr/DCFrfFxoxbuH/8W3N2Ty4cg45804fSUAoGRSE8g88ntPxC8l/0QfM/+
+ RXWN6qhD4KgARf5pQh1ENW6aXgDaaNGKbbqHBROKWjTMLj+AKtNxjI8i/5xgBS3vJXJd/7YaftQ/OOS3
+ KqnWP5K7/+8R2LhZXIqyDAxmNn6fDxrnV3KHBp2FCuSUiOsK0HLitIxYNF7KDoyKr2FDebjoia26+7W6
+ rQaVZZzK+IGUSF0w1vpzXJdk8bcGNIf88u5KzvWP5qrLZ0O/vuKWBpPdgczG4XRCzu+Wca9RXaU6Kwot
+ W+LZHnoeXclW9d5bfxfAAcvUjzlAyStUBf9E9/1pq26eq+KcuxhcPXpHdz6SIh+7Aot/tJB5Aru+VQ+z
+ JAOJAJVNegKZCS0k67loLgReeVx1jepsTg9BXgDaUqChDpSoacpsjwFKDIq2taCt6tpqXFcXABVlgOJW
+ qqMfJ7eEt7AhW+hDkAD4Gv3Yr1LfS+neh83yE71nX3NzC9z9wKPCRIA49eTRMG+GFIFMxNvcBC2zxgJw
+ slzdJQ7sDggKBlBXm7OwDsXZVKtpB1heQFnRim1xs+/0eQAKP9fYQQoU1fqzdF9Bxs8Cf6ikPJlyLb7d
+ kA07yRO4/porhIrAx598zs5SBDIPV34BuH5xF3iX/kB1jequI98hJiCIff1AY51qZyGyQZUAKBC22Wnx
+ bquraNj3V81/dZA7wnY4CXQ4fAIj/2yKL2/Mf9gYyBl1mrD3iSYsAscIjAmQCCx/WsYEMpHc71QC0Ca3
+ 0fhB6FqCwdmAHe2NbNDBWcGIZ7M84gpA/YzyhbzEHyW/k6ostNEhePlLciUKtf5ejS/Pja2/iMBfLKQI
+ SPRCddG9+A7uNarDojIEaeMQZmNRdsdsUVWo4JBgvHvG7QLwd/alKVC5+N5RwT9O6mKyaLX+jovmQE4/
+ c3bxkd0BiV5yBo8E79hzIfDhmx0vhLwAV2cxDZYfu9iO6FWD0BZpfwESiA444FqIM1U4Zqmw9R+gOBSV
+ tbGNPaNUiFp+3j7nyRCr9c+ZJWQxVN1IT0CiB0VRwP2Dm7nXhHoBTQ1BLzvaC+DsOky2SzYc636xPQAF
+ fsULwAWX+uIE/wTBWv8AqIJ/jgvngLNLsZBhv0TIoyFCFIF7DPAE5kpPIGOgLeY84zheQECsF0C2pnTq
+ ON2d2WR04l0wGEgTZDTnB8QsESrIBarHCopUaYmEn5RJAKz1b9To+5vc+keSHxIB0Z7A49ITyChcV2p4
+ AY3ivACurbGcHPWS9zwb7nBd6wK5Do4czth/cXfVG5Hrz1upJBnIXaIkCtX7Yuuff416BTKzoTwBkZ4A
+ QXkC0hPIHJp+d63aC0BcXRzC9hl0lPZkawZEomWH/rZAWaen+TkB2qUJug5RzyaVoU1/O3ZAAs1iWn9C
+ a9jEddFsYe+RCtITkMTDPXcx93GRQ4IsFhBlh8w2eaNjPFsOoZmrePMJxY+j+9BBYqjlV3LVyxSpEhGS
+ xNfkx4Mz4WfoaMj7vjrRwircLhecNGokfLNhM9TVixG/Xbv3wqGaWjhhxDAh95NYB62K7VmNHgAnQ4/W
+ EHS4Bawc5PeBI7+Ioo8dH6fJQeoFeAbe9r/D3HFKrgdQd1n58YpTUU3w57b+rWIi/wTP+AnXIv4Yq5Uw
+ T+Dqy8V7As+8IOx+EmugEQHnj37DvaZVxxOG5gcw2+N4AdHlQVsmm+bdhisAihPU0TYF3f+cfH7yjwAC
+ vkBwZ59g5LL9oOm+7r5lQt5DNFIEJFrkDBsV3GMwqj5THae6LgJuUhDZKCf3mGvToCUAvOg/p/WnDcpE
+ be/tbeB/KY7vX2V41l8qSBGQ8HA4XeCYfi33mlZdTxRmewFaH1OHF6AxGsDNA+Bt9cUijtETfwS1/oSv
+ WSP4N3Gq6eP+iUJ5AotQBO598G/C8wTmTL9EyP0k5uOcPA38f7td9TjVdXcXQTkBra2q/QTJVmk7sQ6P
+ cWyaUJWifnr5LdzknxzVSmDCWn8K/nEn/Zx+btps550fEgHRnsAT0hNIW9xdigFGj1df8IfqvAB4Nsiz
+ VbJpZttRqCf5OEE1IK24c4N3iPYAODuWJoOvRSP4NyfuXAZbkS89AUkUjsuuAf/nqs2zWZ13CmjbmA1G
+ r8aNtko2G/C0dnw0aNv/r0P5VHd0KEOiH+JtWSzK+EkNA60BNpoRfbj6qrcXtzvSE5BEQsFAXt2mOs/z
+ ehMm4FdPAgINL4Bj2x08AHQRBmBfQR1BoCWIo1v/KHVJFl8r/1tQZi6ydfAvFtITSD8CDfXQ+vwz0LL2
+ E/BilcwZVwmdv69vc9lYUDAwcP5sUF5X7z9Jdd+ZL6COt7WqlwlnXnvH+Tlk22TjnZ45mhXY8d0VuEp1
+ cxr+46xBTjuXiMCv4f47x50r5P5WIT2B9MD3xafQeOdS2H/RRDjw2ENw6NP/woFPP4Ft994JB197Wch7
+ uM65lPu4Vt1PFJ4tMpvlLUUUZeMdMgFvPqH4j4pD6RAtVHJyVTnHlIUUEDH5xw/cvH8i58pbWEJFOnM0
+ Y3CT0IzBGpkxmBLU2re98gLU/fZmOPKPFVC/aT00+fzQ5PdDc+jc5AtAc90R6H3B1NTfsKgz+J59QF0O
+ L4oDrRmYajXH8jrY/BxOVqAvaoEeP7hv+/LwI+F/RnkAinolUVpoADqONPo5fY6kyt3GV8B0dv+jafcE
+ +nBHYZLi4/+ulZ5AEvi3bITG3y+FAzOmwP4//xFqv90FR9Dfr/P62FEfOoePRp+YSL2TbGgSv+umZQOJ
+ 4vd4VHZKtqvCoQyP/GeHGIDihKLo5yu07l90lFHQZp/tmX/R7zlmnO3H/hOB8gR+giLwJ4oJ7N4b/wU6
+ IBGg70jGBGJDrb13zSpofO5paN60AdqwLnv8AXZuC52P/tvPHvOEro2cPkdYPXSccREE3lOLNtmAI0+A
+ p0sxuSiDJ9tVjQ9E2Xh7M1s/Q2P9MNb/j8r/F+UBaAQAXeWZ597mh0RApCfwb+kJaOLftweaH7gbDmJr
+ v+/2JVC7YT3U+YKt/RFfx5b+SPvffqjH5xSMPgkmPLwc+k06U1h5nENH88upYQOJErTJKB+AE7sjIm09
+ 0s9WR914LgR5A9H9iiSgfOgAb5dv/KKMWO7bDkgRMB7PW69C3fVXwb7pF8GBZ5+CI0eOtBv5kZCRtx9h
+ IcBzS34h9JsxBy567R0499EnoM/JpwgtFy0fHuimDgiTDQiZG6BlkzwbjrD19i6A4lDvJKJwhv+Euf8a
+ EVDlwvlC7m9X8g3oDpAIENnaHaDWvm3lq1D/jxXQii5/pIvv4bj2kdeKBg+FEbPmwgBs7XM7qbfiFsqF
+ 8wCWqWe2ki3QfoIpQ15AVKuvODjdgAhbP+oBOJQ+qhs61csFBAQJQIAJlqI6HGWc9dUzDOkJiMH74Sqo
+ //XPYR8F9f72EBypO9LBta+LcO2plT8Scv+pte95wVQ4+5kXYcqzL8HgqZcYb/yI84TTgVfnA2JW0kdP
+ gnMjF2e6j6L0bL/c/hgnAUihcUSjPAAPPwDo7NVfyP3tjvQEkoMN4WFr3/Dc09CydzenZferAn3hv3N6
+ 9YERs+fBsVOnmWLw0Th69QM/p84zWxABeQBRQ/ZcDyAiEMg8gLrLyvmrhjrV6hHw8TruiRHs93AuZHD/
+ n4dRnsBzL78h7H52wffFZ9Bw51LYN2US7Lv/j1C7e1eHIF5kIC/aA+h54VSofHg5fO/Nd5kAWGH8hKug
+ MEYcIPX7B3hb8nFsmAjbPLuqKKBeLYTX/yf8AgTAq6F4oydk1PCfHmiI8DoUgfsEegJVH3wExw4sg+PT
+ PFmIDeGRm7/sr5qtvSd6OC+itR+ELf3wCIO3Rd06eRLAG0+pHiabUJwpxgGoC8CzWRKBqO5B2OaD8uBQ
+ C0AwESfa/RfTWdFyeZTBJ/A/QIaTn5cL1121AO576DFhIvA8egHHDx8q5F5mQwk7zc8/A42rq6C1Hl3+
+ gJ/r0nui3H661nviZBg4ZRqUTYwYwrNRnVJGjeUKANmEI1dAIJAMPSp2R7as8jAcEQKAb1uhLqlDZf/c
+ IEMSBDTCCI6K9G6xUoG6AyJFoKb2MLuPyO6F0dAQXuPzT0PTpo0dWvujrTw/mq8UdoLBs+bCsWj4nfr2
+ tfpjxEQpG8b1RLRsIlEC6KFTv78D0f+GozYf8gAU9b5C7Tv/Rt5d0OQFv0YAsEi1DmlWIVoENm3ZZnsB
+ CFDCDhp9w5uvQluotecO2XGCfCUnngwjp1wCg6fG3QXbNji6FIOPU/eZTYiAYnSuqHtxRvPCNs+CgNjY
+ d42+rrAFQKDjEoAiRgAC/IAHBUcyJf8/FcIiIMJwaRMTu0Kt/ZHrr4K9M6bAgX+saE/YCSfpdAzs+dqT
+ dlryi6D/9Dkw5bV34LxHn0gr4ydcuXkQKFBl3B9d2i9VfJx9Azmtbdjmgx4Ar+thkAeg2f+n4IiEIcoT
+ KC1R6bqlUGvfsvJVaMLWvnnPbu1AXodWP+gRUMLOmFnzYMCkyZZF8UUROP50UD5+S/U4iwPkpBYHCOB3
+ p0TbLX+zEIar7lKNIUCDRgBoCjD3Ix53Uur3ziBEiMCxA+2xohJF8ptp7H51VVSGXlS2XpQAQFEn6FM5
+ GY7D/n23oZkTH1KGjOYKgJAVgshGdTbUZPsOdAXU/ghv7FBU/18r77kwvVXdCFLpDtAwYEmxdR4AW2Hn
+ hWfg0MypsPeWn8GB99/jZ+n5Oubo09/+Hr1gxE9vgGmvvw0Tfnt7Rhk/4RjAz3YVMidAy05DgUDqatDm
+ JN46P6Ugb3ahtzCSf5+oGwlIAGL3JZXjTQHuW2GPcVqbQXkCPw55At/q9ARIOC6Zcp4l3ycl7LSsfAXq
+ 0c3n5d4HW31Oth6eB1w0DQZOubjDRJxMrBP+LqXg4AYCxdyfjdaFI//4vQa8XvA3obC2+qLfY5QLHDBQ
+ dQcDV+LRzHiKXnVI0k7YE3jq2Rfhf1+tj/v8S6acC31NjP5Ta+9Zswoalj3cnrDDM3K10ftZwg4N3w23
+ MEPPbBwoADxEZAMysLEOeMjoPdjae2KpaFd+niAvCcgvaMaCxnCHs6izrRI27AYlCy2cOx3e+FcVVK3+
+ mBvhJ7f/kotCxm/Cd8nm3D/+MDR+UMVm4Wm19urx/AD0rgwn7Ew+esMs+f2VgiK+TaYwFEgte8ATYIff
+ 0xj/BSFc2Nirk4Da1xSKeEjQb6OlcnIIUB/nnVUJleNOhc1bqzsEBynrT0+rTwlCNF9g05bqdhEhD4PE
+ 45STRumOG1A0v+b3v2kP5EVm6/FbfT/bK2/IzLlsMk6nPvZO2DEShzsHeGaQqAfgDxk8O5LrPmAXQAFV
+ ElBwMc5oi88OdU4HyGBHosGPTCDVl4z9uZdfR+P/nHt94+Yt8NrKd1AERsP3pp7P3iMWe+77I7R6fXGX
+ 1aLHSsecDCPR6AdPSa8xe6NwYGOXjLffsZUPiDDJrkrDrPJaxaV0kH22EUhU+mCA1h5PMRWYFM5To/7o
+ gVPPgZyf3Zvw/Q4ePAQv/PN1+PTz/0FTc3CLpIL8fDhx9PHYDz4funXj97WyDdqb4MFHn2Ctvx7IC7j6
+ ijkxlzT/fPzoDpNvooVAKSyCsikXw/BZ89K+tTeinrUsngLOnZtUj7tLnDRdt52wsVOqsKhdhSNYpV8A
+ aCegFPMA6IPwlgH3nzMLcheqti2LyZv/eg+e+vvzMZ8zDX8c+oGymUM1tfCbO+5JOCuQPIBf37AYSkuK
+ udc/nXsp1GxYpxrPLzp2KAybPRcGTEz/hB2CDP9FPGIx67LvwrlnTUzovs03zwTXRrU35upEGbhKcBtx
+ rVmz4lhFQUDOvl9g64CMHuMnwj9cNovAo8ufhoYG/UGhMPQaeu0vFl/DvX7sLb+BT5bcDHXr12Hfvgj6
+ oMEfNzOzEnb0GD8RrouJiICj9wDsd6kFwEdbhyum2V6ZS3Eqthh/0/uRd+zcpcv4w9APOHTIsTAMj2xj
+ /cbN8M36DUm/nl67Du8xdLB6u4hOg4fCpBXq38G+zUZirNuwSZfxh6E6SV2CeN0Bj8cD3jYPOGoPpFpE
+ EQxwcfNyWQzQnkHAF17W/6OEWYkeQzYKwAerP8JeW2rdNroHTwAyHaozifLkM8/Domt/0OExMnhPWxt4
+ 6ew5OpmusKUp5TKKgJ8HwDDA4AXccv0GdeAkHp+t/V/qb5yGbNu2A3ze1ASA7pGNJFNnqG5qGXxCmNjW
+ 8gXAoAKwoAbP4xh2oq7Xk/sfjsImCrl02eYFbKuutsU90o11STQyBNXNdevWQ9/e8fMxfMcMAtcmdQyA
+ TM/MHTE1PADeTEBBicop0NiUnPFnKz5B8zck+mluakm5ATWzsx2jC2Ai6/4LcHr87cCHpdAXHXBMX1uP
+ bBgBrQew/8DBlO7Ro3u3rPveWF1JkkEVZbqe59y1Oen3EIlGF4Dzg7M1Aq33AsaMOj7h/ln/fsdAQYFq
+ 24OMhz733r37Ur5HpkMzX71eL/bdPeg1Bc/kxn+7J7F1GEYcN8SgEhqHqR6A4lLUq5VAYn2ec86sTFgA
+ 6DXZyHdOGgMfffzvlO+RSRw19jbwYhfJh3/zukoTxp4CTz/3ckL3nnD6KbR1rq7nkh3w6r3ZvpZ+D0BA
+ 0ZTwbkiqC/rvTmP64/GL/mCNvopNY7Pj2A+TfUyadAa89M9XYeu26qReX1Fexu6Rrt8dDYGSsXtDRk5n
+ vcOiJ485Ab76ZgN8+U386dfh5+t1/xlatmDyl+3ihR3ZYiAGrgmQKjMv+y47xxMBMv6F82ebUSTbsui6
+ a+BHP74+6demCzTkFjZ4X8joVYvaJMj0700BeA7iigAZ/8UXnpPSe3XAzGHAgC/Qgq55x2xAs4M+LYlF
+ 96k/v3DBbOYNrHy7ig0PRtKttITNA6CWP9upqCiHxYuuhYf+8ojulOCiokK46ocL2WvtRrgVDxp6Yq16
+ ouTn5sGCWZfCJ599ASvfXaWaTEVxAnL7SQAYCZiN0tQgsKRJU01dAJolEpUObK4AON5/EeCa3yX8OjJw
+ Og4eqmEHQcZPh+QoZ581mRnzrbf+Fvbuix0U7NWzJyxd+isYNFC9TISZUCAuEPC3G3rY6K2ADJwOEoDa
+ w0fYY8Vdu6S05qLzW1uMAmzXDgIaoQGp7n2mQTYaPRO9g4fa/z00TpITGfRTTz4GK1f+C1Z/uAZWr17T
+ 4fq4cafDuLGnwznnnGVIeXlQvzxs2OSuU2DO7/fbNn+huLgLO8LoDfglhOkxAG4hNDL2UoRGErXu68dK
+ 4ODtZS7pwPrQJBWa6BNJfn4+G+0458yJMYc8ycCtMHIfGrY/IhBnVWtuB5TmBnPT/WKg1M8o3+vIUXpG
+ PawOAgY464QlgaeWr+7+h1aDqzN/7rkkyIuvvAEvvRJ762/yhH5yzZXQv595i3BQAI62pg635JFniRrX
+ 5i+g8/0/4V4TtjCoPlYp9dPLqxy5yhmqS7xRAAHBQe8R1dLEwcfvegPcvfunfP9M5ZHHnoTVH/1H13NL
+ UQR++6tfCkl+Yq23D1tvv4+15mTYPk/QsJOe7JLl5Hz5IRQ9erP6gsa2eQay1NwYAEELovMSCvfvApAC
+ wCUR4ycOHaqBFX9/no2UaMFa6JAh07CZH1U50rhFDKNJ+AQDgFp9AHO/cxcqzha/J3CGgoapdFgFzJiC
+ 0PvwgieB2v2GvF+6k6jxh6HXTLvoPLa0F2vBQ4E1adjWw2IA9uCwy9fofwL/uLzDwyhO2C1oFymHS2H7
+ CNMChdSCKxF+A/UUKMVXNxqrfzu2fQ1QeXFixc9QwoGzx554Btb8+79J32fzlq0wsHyAwJJJRKA5BGi+
+ Lq9Vas8fUIl/JL78SQyYIERpgoNEQwktbczbHjy/CHwPvM+9n8PpBCdvj3MLCRupFlr9Y9YCR02t5j33
+ mef/Cf/9PLWFTM6eNIEdEntRctMUrhfAVv01d77dRGamKALmaU8Mj6Hmtn8yIRCNy+UK7XVwFDu7wiKM
+ n5h6/tkw/vTvCCiRRBRk+CQAPNiCOSZWyeLXtyvmD7zH+ICub7eAZ+AJwt8yHOxKB555QYzxE3169bTL
+ Uo6SEFTHNbHgt3KF3ngV/l89FGgUGuseUd+ozQABSBf+LtD48/PyoAL7/9L+7UXM/r+5PxbZfHsmoL4t
+ Ywwm+OVkZ5X9+wuvCDN+4qyJ4yFbv0s7Y5M5AASz+XBMfq2Z7xwIpxpHHe6tX5hZDNsg2vhHDBsi+/42
+ hdVxTt23IB7FbD4sANVmvrPi534H4KrZa6cxUlMQbfx9eveESy+5UNj9JOKgus3qOHDqv/mr7VXT/1gX
+ IGCyAJDYaQ3q5Wz5AlpHjDWzOJZhhPFfdfls1v+X2A+q21r4ze+tVdP/2kNxNeeZOBSIOHPUuQJE0/jv
+ QsPU9FmJJlnI+D8VuGEJRfx/KI3f1hS9/AAUfMDZ1g4tz9dmrgKUvLGdWd/RYcAA6xOMMqsAlBCkcNyA
+ WCqZKUjjz0606jabHGeu/bfH/I56AOcOeAlPU80qAWUgONz8hKBDNz0JvuL4u6ukI0Hj/1LY/YLGP0sa
+ v81x1u6F0tv4k7P8HtoK3NTivFzy5naWdx+ZmW/qSECslEf3lszcy08af/YSs06bHwBst/VIAagyswSx
+ 3J7crz80syimII0/u9Gs0wFL9tupCv/RwQfHboCpPRFHTvQU5CA0H2D/0pfMLIqhPPuieOP/wQJp/OlE
+ j1sv1pgAhA6A2QHAN7e323305FxzE4J8/A9OX1Tu12u419INafwSqsta+S1aNmAgHWw8ejIQ5QebOhKg
+ tTBK7jeroXX4aWYVxRCeffFVA4x/Jhp/Lsg03/SB6rJWPbfA/V8V+Y9oD6DKvHJAzDXQ8tLcAzDO+GXL
+ n25o1WVW983X8arIf3SMAZwzgHY6qDWzNGw4MJcvj3WX/hyaTzzbzOIIgbL7/vHSa8LuJ40/fcn/9C3o
+ /OwfuNf8raYP/xHFJSu3t0/+U1lezTn9PwcTuwFUAmcBf52w1uFj4fDcJaYVRQTNLS1wxz0PQEtLq5D7
+ SeNPb7o+vkRzBMDX5Dc9Aahk5Y7RkQ/wBOBePPEXLTcIRx6NBvC9gAO/pKSgntxrdoQy/ES1/mT8V86X
+ xp+uOGv3Qfc7+ck/FPzzt5ju//8JBWBR5AO8prfKnLIchfWFuFOk0IX67C2zi5MSX6/fKOQ+0vjTH1Z3
+ Neq1yev/h6mKfoDb7KIXYLo0OQsd3NJQ63/gF0+YXZyk+euyFbC1ekdK9wga/wxp/GlO99/PYV6ACpr8
+ 02h++B9bf5WFaSzSDS8bXBYVbEFEDvQF5n/2L5NLYx3S+DMDqrNc4wftum4wXJvW2ByUuQqmTQwiKBvK
+ pTE5qODTt6B5jHkbWqZC7149kvYApPFnDlRntXbLYFN/LR7+C8PvApzdvwxP2wwsDBfqBigaPsmhhX+A
+ 1gr7Lxi6Z+8+uO8vjyX8ut4U7Z83A/Kk8ac9uVu/gNJHfs69Rok/Vrj/SHnJWzuqox/kmlvoiebODkQC
+ bfy1AukoevdJs4uTFGTIY04YmfBrpPFnDqyuagX/TM77D7GWZ/yE5p5e6AXQcME9RpVIC2eRthdw4NoH
+ wNN7oLkFSgLKAfjr8hXoDcTf75C6DD+YNxONP9eEkkmMxr1nC3T/M39FK9b6N1jS+i9GAbiXd0ErCEhY
+ Mh2P7T+oQeGa9JghSMZMRl1RFnu347GnngTX/XCBNP4MIlYdjVW3DUazUJob7t255cjhXw7sQllDQw0p
+ kgakkg6N9QJJXZvGnG3I9mGioe3IThw1kokAbUtGgb3irl3YcdzQY2HGd6fACSOGWV1MiUAo6l/8/B/5
+ F2nor9ma6D+2/g9pXYy3NZipy4QxAsERAa35AV3xCz64kJ9bbUfKUQDKNTwBOZ8vs+iqZfwQmvNvzQ8e
+ 022Oua/3obP6mz45iEGbhHTiJwYRB6/4A7SWH29umSSSGORu+x90e5Qf+SfD99Sbnvcfprj0Xzs0d/6K
+ KQAEisAyPM0TWSI9OPMUNkeABwUC91/zgMklkki06fHANayLyoNy/n3m5/0Ty9H458d6gh4BqMTTe4IK
+ pB/yAjo7NUtYe8lPoWn0meaWSSLhUPD521D8wl38i9T61/msav0nogBUxXpCXAEgUAQoKahMQIESwpnn
+ 0PQC/HmFsO+ny9lZIrEKR0sj9LxrHjvzCLb+lgz9VaPxl8d7kl4BsCQnIJ4X0HD6xXD4vB+aWyaJJIKu
+ b/wFirSG/qxt/RejAHDH/iOJlQcQybLUypIkbOhEWz3pi6fgi0RiBVT3NI0fQnXXuqGeZXqepMsDIA6d
+ aU0wkHB1cWguGOLpVQH7rv4/k0skkQD0fPBH4N67lXuNFvzwHrHE9SeWl74dO/gXJl4eQCTkTlgiAL6m
+ ALg68QWAfoDOVU9CXeUsk0slyWY6Vz2lafwE1VkLiev6h9HtARDoBdBoQGWipREBzRTUSg4i9l39Z+YN
+ SCRGQ4bf88FrNa/TYp8WzfgjqrD1n6j3yYl4AMRSsEgAaAFFR452QLDkxbth/4I75aiAxFAo2k91TZNA
+ aLFP61iayJMT8gAI9AIsGRIkaI4AzRbUonH0WVBz8WITSyTJNkpeugcKP9deoYpm+5m91VcE1dj6xx36
+ iyQZAZiPp8RXvBCEq7NDc1tx4tDUxdA4Kj1WD5KkF4Vr/wWlL2uPhtM23946S1v/BSgAyxJ5QcICQFjp
+ BdBaAe6u2l0B6gLsn3cntMl4gEQgOdjv77H8l5oJP2zM/7DPiq2+wiTc+hPJCcBka70A6gqQJ6AFGf/+
+ eXfIeIBECGT0PZbfwERAC2r5LXT9iQWl7yTW+hNJCQCBImCZF0C4irTThImGUWey7oBEkirk9hetfVvz
+ OqX7eq1Z6SdMNRp/wq0/kegoQCQUbbTMC/A2+sHtdoKisaQJ/WDerj3hyBkzzS2YJKPosmpFTOOnDT68
+ 1g35hUko8h9J0h4AYbUXoLgUcHfVXjeAIC+g4QQ5a1CSOEVfvB0z6Bfs9/utWuc/TNKtP5GqAFSCFVOF
+ I6BugKuTdjyAzRqcc4cMCkoSgvr7PZ+4QTvoh3jr/Vbs7xfNRBSAqmRfnJIAECgClmUHhiEBiBUPCIrA
+ 7VIEJLoIGv+NMY2f9fvrLXf9q9D4dWf98UhdACZZs4lINO4SB+sSaEEisOfK+1hcQCLRwnV4H/R++LqY
+ xk8uv6fGcuMnykvf5a/3r5eUBYBAEViCp1tF3CtpaO2AEu2gIEEewF70BOTwoIQHGX0vbPljDfdR0M9T
+ Y9kc/0iWovEvSfUmogSAFg8lL6CriPslCwsKFscOCkoRkPDQY/ws6FdredCPoEU+qfXXXOxTL0IEgDg4
+ ydrkoDCUJMREIAZtPaUISI7Sbvz7Yhg/BI3f4mSfMAu6vZt40g8PYQJAoAhYHhAknPmxMwUJEoH9378Z
+ vF16mFQqiR1xHdkPPf7xu7jGT5l+Fm3sEU0VGn9Kgb9IRAtAGZ4+B4u7AoQeESAPYO/s25gYSLIPMvpe
+ T94UM+BH2Mj4yeUf3S3FwF8kQgWAOGiHgGAIvSKwJ4tE4PCROnjv/TWwfuMWaGltZY/l5ebC0MEDYeKE
+ 06Frl84Wl9AcyPh7p5fxE0u7CQj8RSJcAIiDE/uTFzDKiHsnCgmAszD2xyQROHTmldBw/GSTSmUN76z6
+ EN7FIxaTzhgLk/HIZIr+9w6Uvv1wXOP3NVo+vTeStd3e2zFa9E2NEgAy/s+NuHcy6BEB4vD4GVA7PjPn
+ Drz93vt4fKDruWdOHI/HBINLZA3FH6yArh88Hfd5NjN+YjQKwFrRNzVEAAgUgSVgk64AwboDXeOvgk5e
+ wKHJV2bUCMGWbdXw4CPLE3rN1QvnwcDyMkPKYwXU2pe+8zBr/ePhPWwrt59Yisa/xIgbGyYABIqALUYF
+ wpAIuHWIABsm/O5NGTNC8OjyFfDVN+sSes2I44bBFfMywxuiSH+v52+LG+knPPYz/io0fmFR/2iMFoAy
+ sMmoQBi9IsBWFrrgJ9A4+FQTSmUs1/30xqRed99dtwsuifkUbvwYerz2p7j9fcKGxh+M+r8nLuofjaEC
+ QKAIXIynF41+n0QIJwspOvZFOnLyRXDwzCuNL5RBbNq0Be69/8GkXrvox1fDsccOFFwi8+j29sPQ5ZNX
+ 4j6PlvGyUZJPJNPQ+LW3HhKA4QJAoAhQhuB8M95LL7SwKJtAFGPuQJhW7BIcOP86dk43Nm7cDHfd++ek
+ XvvTRdfC4MGDBJfIeHLR1e/++n3sHI9gbr+fLehpM5ah8S8w+k3MEYDKftQFoHiALYYG20EPIKebM+Yq
+ w5HUjpsBNXikGwt/8KOkXvfIX9Nvy7WS1U9D8er4UX6CjL7tICqArYL9DIr2T+xWtTPlXP94mCIABIpA
+ GdgsHhCGugPOAn37pDb3HwGHJi+E1h5JL8JiOnf8/m5Yv2FjQq8ZOmQw3PCL6w0qkXhy92+D0ncegfwd
+ X+l6Pm3eQW6/DQn2+6t2VpvxZqYJAIEiYLt4QBgSALYJqc79kmvGTofDJ08Bf679hwvXrd8At9/++4Re
+ c+ONv4BhQ4cYVCJxOFoboesn/4SSD5/R9Xzq79OmnRbv3hOLaWj8hvb7IzFVAAgUgSVgo/yASFhcoFR7
+ J+JoPF16wMHJV0DjsfYfKXjoL4/A++/rSwSaMGE8XPXDhQaXKHUKN30M3d55FNxH9ut6Pu3Y6zlky/5+
+ mKVo/EvMfEPTBYBAESAv4GIr3jsutPFIFwfbjFQv1C2oOX0GO9uVxsYmWP7441BV9X7M51VWToB5c+dC
+ YWGBSSVLHHLzS9Y8rdvdJ2izTg9t123bhh9eQuOfZvabWiUA9gwKRuDMxy5BsVN3l4CoHzGJdQ08Nk4g
+ qqpaBa+++hps21bd4fHy8jK48MILUADOsKJYuqCWnlz9Tl+9q/s1zOWv9YGv2b6WDyYG/aKxRACIkAhQ
+ ULDMqjLEg1YYorgAiUEi1I+YiB6BvYVg//79eBxgf/fo0R0P+5aVGf4aMvzEFqAmo6f+vg1W8IlFNQSD
+ fqYbP2GZABAHz+hHHgD9qrYbGYiEeQMliXkDRF0aCIGdCRt+5wQNn7X6NbZv9Qky+ondVu0UPslHL5YK
+ AIEiUAkW7y2gi9CmpInEBsI09xsBh8Zexs6S+OTv/ApKP/w7OycK6+sftuXYPg8y/iorC2C5ABAoAvPB
+ BusJ6oFtRIJCQOnEiUKeQM1pl0HDsaekxfChmdBwXtGmf0PJR3/XHdWPhNJ4vWj4NtioQy8L0PiXWV0I
+ WwgAkU4iQJAnkGiQMJK64ROhEYWgYdApYguWZhRt/jcUouF3/jo5J7A9yGf9/nyJsKC0ascyRbHe/Kwv
+ QQTpJgLULaBdiZydkhcC8goaB34H6kZMSqvswlSgrL3OX70LhVv+k1RrT5Dh++p9wd150sr2g8ZPf0gB
+ 4HAg3UQAIeN3ohC4UhACwtO5B3oE34HmfsMzzjOglj5/59d4RqOvS87oCdbio+H70PAD6WX4xILu6PYH
+ AsFuihQADQ5M6Ge72YN6aBeCzqkJQZjmY4JC0NqjDJrSLIBYsPMrbOmrg4a/6+uU78cMvy5tDZ9Y1v39
+ nWx2nxQAHaAIzIc08wTCkPHTOoSuotj7FSZKEwoCdRPCZ/IY7EDugW3MlS9AQyf3vkCAwYdh+/DRyrwN
+ aWv4xAI0/mXhf0gB0Ek6i0AYEgESg2RGDfRAYkBCQMuXtXQvY6MLLSgOokcZKEqfh8bNzgeq2TJb5MqL
+ NPZIWFQfDd/bkL5WH6KD8RNSABIgE0SAYPsW0urERfpnHKYKEwMUhTCtOoSBDJxa8TBGGTgPFthDg6cW
+ 3+bZe3pRGT8hBSBBMkUEwpBX4CxQdK9BkOnQ1FxfUyATWvtIuMZvN9JCAAgUgUoIriVg67ThRGBBw4Ls
+ FIOw0dM5jfv2PCi9dxoaf5XVBdFD2ggAgSJAcwdIBMosLopwSAwceSExyFOEBg/tALn0vpYAM3p/S8YZ
+ fZhqCBq/Zbn9iZJ2tezAePtPJRYBBQ0d+Qo701Lm6SYIzOCbAyyYR7vsZEifPhZsSm/3D6yZ1Zcs6VWr
+ QoREgGIC9lxUxABIABy5JAhBT8HhBtuIAhm33wOsZfe34bk1Kww+ElrCa0G6GT9hjxqUJCgEtLTYEqvL
+ YRXUbVDIU3CThxAUBCYUBohD2MjpHDyCq+oGsIXPUHdeL0vQ8JdaXYhkSWsBIFAEyAsgbyBjgoMiCYpC
+ 1GPOoCcRCbXctGZeJGTkWdaSJwK19tTqm7aApxGkvQAQKAJlEAwOZnRcQGIbqL8/DY2/2uqCpEpGCAAR
+ igvcA2k4h0CSVizDY3E69vd5ZIwAhJFdAolBZITLH03GCQAR6hKQCFRaWxJJhlAFQeOvtrgcwslIAQiT
+ 7aMEEiGkdZQ/HhktAASKAAUGyRuQAUJJIlCgj1r9tMnqS4aMF4AwIW9gEcjYgCQ21Ne/N5Nb/UiyRgAI
+ GRuQxKEKMrSvr0VWCUAYFIJ5eLoXpDcgCUKt/iI0/OVWF8RssmsOaojQD01L8C6xuCgS61mCR3k2Gj+R
+ lR5AJLJbkLXQeP7ibHL3eWS9AIRBIaiEYCahHC3IbCiqT4ZfZXVB7IAUgChC8YElkIGLjmQ51RAc089K
+ V18LKQAaSCHIGKpBGr4mUgDiIIUgbakGafhxkQKgk1CMgJKJKq0tiSQOVXgslX18fUgBSJBQavFPQE47
+ thvL8PhTpqfuikYKQJKE1h+g7gGlF5dZW5qspRqCCV3LM2V+vtlIARBAqHtAYjDf2pJkDcsgaPRVFpcj
+ 7ZECIJCQVzAVgqsVZ82KxSbxUuh4Wbb24pACYBChDEMSg/kgk4uShfrzy0C6+IYhBcAEQmJwBgS9gkqQ
+ k5C0ICOvgmBLvyrb03TNQAqABaAgRIpBtnsH1MpX4fESGvwqi8uSdUgBsJhQ3IAEoRKCYlBpZXlMoAqO
+ Gv0q6dpbixQAGxLyECohOLw4CtLXS1gbOqrxqJItvP2QApAmhBKQBsBRQSDPodLKMkVQBcH+e9jgt8uE
+ nPRACkAGEPIYiLAwRP9NlIH+hKXq0BEmbNwd/pYtevrz/wGA0nIwAAAA5R34QQAAAABJRU5ErkJggigA
+ AAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIl/1ICJf
+ 9Y8iX/XPIl/1/yJf9f8iX/XPIl/1jyJf9SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIl/1jyJf
+ 9f8iX/X/Il/1/zBp9v8wafb/Il/1/yJf9f8iX/X/Il/1j////wD///8AAAAAAAAAAAAAAAAAIl/1zyJf
+ 9f8+c/b/rcP7//L2/v////////////L2/v+tw/v/PnP2/yJf9f8iX/XP////AAAAAAAAAAAAIl/1kCJf
+ 9f9Mfff/8vb+//////////////////////////////////L2/v9Mfff/Il/1/yJf9ZAAAAAAIl/1ICJf
+ 9f8+c/b/8vb+///////l5eX/////////////////////////////////8vb+/z5z9v8iX/X/Il/1ICJf
+ 9aAiX/X/rcP7///////l5eX/Pz8//39/f/////////////////////////////////+tw/v/Il/1/yJf
+ 9aAiX/XPIl/1//L2/v///////////39/f/8zMzP/f39/////////////////////////////8vb+/yJf
+ 9f8iX/XPIl/1/zBp9v//////////////////////f39//0FBQf9/f3//////////////////////////
+ //8wafb/Il/1/yJf9f8wafb//////////////////////39/f/8zMzP/f39/////////////////////
+ ////////MGn2/yJf9f8iX/XQIl/1//L2/v///////////39/f/8zMzP/f39/////////////////////
+ ////////8vb+/yJf9f8iX/XQIl/1oCJf9f+tw/v//////39/f/8zMzP/f39/////////////////////
+ /////////////63D+/8iX/X/Il/1oCJf9SAiX/X/PnP2//L2/v9/f3//f39/////////////////////
+ //////////////L2/v8+c/b/Il/1/yJf9SAAAAAAIl/1kCJf9f9Mfff/8vb+////////////////////
+ //////////////L2/v9Mfff/Il/1/yJf9ZAAAAAAAAAAAAAAAAAiX/XQIl/1/z5z9v+tw/v/8vb+////
+ ////////8vb+/63D+/8+c/b/Il/1/yJf9dD///8AAAAAAAAAAAAAAAAAAAAAACJf9ZAiX/X/Il/1/yJf
+ 9f8wafb/MGn2/yJf9f8iX/X/Il/1/yJf9ZD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAIl/1ICJf
+ 9ZAiX/XQIl/1/yJf9f8iX/XQIl/1kCJf9SAAAAAAAAAAAAAAAAAAAAAA8A///+AH///AA///gAH//wAA
+ //8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//gAH//8AD///gB///8A///ygAAAAYAAAAMAAAAAEA
+ IAAAAAAAYAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHDzqABw86QAbPOkAHDzqARw96gIcPOoKGzvqPBw8
+ 6okcPOrIHDzq7Bw86vocPOr6HDzq7Bw86sgcPOqJGzvqOxw86gocPOoCHDzqARs86QAcPekAHDzqAAAA
+ AAAcP+sAHD/rABw+6gAcPeoBHD3qBBw86jQcPOqfHDzq6Bw86vwdPOn9Hj3q/h496v4dPOn+Hj3q/h08
+ 6f0cPOn8HDzq6Bw86p8cPOo0HD3qBBw96gEcPuoAHD/rABw/6wAdQOsAHD7qABw+6gEcPeoJHDzqZBw8
+ 6t0cPOr7HT3q/R4/6/weQuv9IEnt/iNN7P0iTOz9IEnt/h5C6/0dPur8HT3q/Rw86vscPOrdHDzqZBw9
+ 6gkcPuoBHD7qAB1A6wAcP+sAHD/rARw+6wkcPep3HD7q7h0+6/seQOv8Ikns/jxl6v1oieP9i6Lc/pmr
+ 1/2Zq9f9i6Lc/miJ4/08Zer9Ikns/h5A6/wdPuv7HD7q7hw96nccPusJHD/rARw/6wAcQOsAHEDrBBw/
+ 62QcP+vuHUDr+x9D7P0yXOz9fJfg/rrC1P7NztD+z8/P/5SSkP6UkpD+z8/P/83O0P66wtT+fJfg/jJc
+ 7P0fQ+z9HUDr+xw/6+4cP+tkHEDrBBxA6wAdQuwBHUHrMx1B690eQev7H0Ts/T1l6/6isdv9z9DS/tHS
+ 0v7R0tH+0tLS/7CurP6vrqv+0tLS/9LS0f7R0tL+z9DS/qKx2/09Zev9H0Ts/R5B6/sdQevdHUHrMx1C
+ 7AEdQ+wKHULrnx5D7PsfROz9NF3s/qWz3P7S09T909TU/tTU0/3U1NL91tXU/tXV0/3V1NP91tXU/tXV
+ 0/3U1NP909TU/tLT1P2ls9z9NF3s/h9E7P0eQ+z7HULrnx1D7AodROw8HUTs6B5E7PwjTO39g5ri/tPU
+ 1v7V1tb+1tbV/87Ny/7U1NL+19fV/9fW1f7W1tT+2NfW/9fX1f7X1tX+19fW/9XW1v7T1Nb+g5ri/iNM
+ 7f0eROz8HUTs6B1E7DwdRe2JHkbt/B9H7f1BZ+v9xcrb/tfX2P7Y2Nf+zMvJ/oJ8dv6opaD+1dXU/tnY
+ 1/7Z2Nf+2tnY/tnZ1/7Z2Nf+2tnY/tnY2P7X2Nj+xcrb/kFn6/0fR+39Hkbs/B1F7YkeR+3IH0jt/iBK
+ 7v11j+b919ja/tna2v7b2tn919bV/p2ZlP1vaGD9qaWh/tfX1v3a2dj929va/tva2v3b2tn93Nva/tva
+ 2v3Z2tr919ja/nWP5f0gSu79H0jt/h5H7cgfT+/tIFDv/iRT7/2ktOj+5OXk/+Xl5P/l5eT+5eXj/97e
+ 3P6jn5n+eHFp/8vJxv7e3dz+3t3d/93d3P7d3Nz+3t3c/93d3P7c3Nz+29zc/52t4v4jTu79H0nt/h5J
+ 7uwjX/T8Il/z/ipf8f2/yu3+uriz/tfV0v7z8/D+8/Pw/vLy8P7s6+j+0c/L/qKfmv6mo6D+7e3r/u7t
+ 6/7r6+r+6Ojn/uXl5P7Ix8X+rquo/q653/4nUu39IEvu/h9L7vslYfT8I2D0/itf8f3Byu39q6ej/s/N
+ yf709PL99PTy/vT08f3x8O394eDc/qGdl/2jn5r9wMLg/sXH4v3r6+799PTy/vT08v3OzMj9qqai/rrE
+ 6P0pV+/9IFDw/h9O7/snY/TvJWH0/idc8v21wvL+8/Ty//T18//29vP+9fXz//Ly7/7Bvbj+kIh//9za
+ 1v7w8O7+4OHv/7C04v6Yndr+sbTf/97f6/7y8vL+8vPy/7TB8v4mXPL9JF/0/iZe8+4oZPTMKGT1/iJc
+ 8/2OpPH99PX0/vX19P729vT+8/Px/sK9uP6Ee3L+tK+p/vHw7v729vT+9/f1/vb29f7s7fP+xsnq/p6j
+ 3v65vOP+8vP0/oyi8f0iW/P9KGT1/ihj9MwnY/SNLWf1/CNe9P1TePH96Ov2/vb29v709PL9wr65/oR8
+ cv20r6n98fHv/vj49v34+Pb9+Pj3/vf39v339/b9+fn3/vX19v3s7fT95+r2/lN38f0jXvT9LWf1/Cdi
+ 9I0jX/Q+MGr16SZi9fwpXfL9qLfz/vP09f7Cv7v+hHxz/7Wwqv7y8vD++Pj3//n59/74+Pf++vr5//n5
+ +P75+fj++fn4//f39/729/f+qLf0/ild8v0mYvX8MGr16SNf9D4iXvQLLWf1ojBq9fsjXvT9RWzw/svR
+ 7v6dl5L+tbCs/vPz8f75+fj++vr5/vr6+v76+vn++/v6/vr6+f76+vn++fn5/vf4+f7S2ff9RW3x/iNe
+ 9P0wavX7LWf1oyJe9AsybPYBJGD0NjRt9t8rZvX7JF3z/VZ48f7Kz+v99PT1/vn5+v35+vr9+/v7/trZ
+ 2P3a2dj9+/v7/vr6+v35+vr9+Pn6/tXb+P1XePH9JF3z/Stm9fs0bfbfJGD0NjJs9gErZvUAKmT1BCpl
+ 9Wc4cfbvKmT1+yRd8/1IbvH9r7z1/u7x+/75+vv++vr7/7Gtq/6xrar++vr7//n6+/7v8fv+sL32/khu
+ 8f0kXfP9KmX1+zhx9u8pZfVoKmT1BCtm9QAjYPQALWf1ASZi9AotZ/V6O3P37y5o9fsjXvP8K13y/lx8
+ 8v2crfb9xs74/tHX9P7R1/T+xs74/pyt9v1cfPL9K13y/iNe9PwuaPX7O3P37y1n9XomYvQKLWf1ASRg
+ 9AA3b/YAIV30AC9p9QEnY/QKLGb1aDxz9985cfb7KWX1/SNe9PwjW/P9K13y/jJh8f0yYPH9K13y/iNb
+ 8/0jXvT8KWX1/Tlx9vs8c/ffLGb1aCdj9AovafUBIV30ADZv9gAhXvMAQXj3ACFe9AAwavYBLmj1BCdi
+ 9DY1bvajP3b36j119/w1bvb9Lmj2/itm9f4rZfX+Lmj2/jVu9v09dff8P3b36jVu9qInYvQ2Lmj1BDBq
+ 9gEhXvQAQXj3ACFe8wAAAAAAIV70ADx09wAiX/QAL2n1AUB39wIjYPQLJmL0PjJr9o07c/fLQHb370F4
+ 9/xBd/f8P3b37jtz98sya/aNJmL0PyNg9As/d/cCL2n1ASJf9AA7c/cAIV70AAAAAADwAA//4AAH/8AA
+ A/+AAAH/gAAB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+ AP8AAAD/gAAB/4AAAf/AAAP/4AAH//AAD/8oAAAAIAAAAEAAAAABACAAAAAAAIAQAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAABIqrwAMKtQAFjflABQwzAETLNMDEzHbFBY14z8XN+V0FzfmrBg4
+ 5tQZOObtGDjn+Bg55/gZOObtGDjm1Bc45qwXN+V0FjXjPxMx2xQULNMDFDDMARY35QAMKtQAEiqvAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARKssAEjHbABQz1QARKssEFTDdEhY15EMXN+WLFzflxxg4
+ 5ugYOOb3GDjn+xk55/sZOef8GTnn/Bk55/sZOef7GDnm9xg45ugXN+XHFzflixY15EMUMd0SESrLBBQz
+ 1QASMdsAESrLAAAAAAAAAAAAAAAAAAAAAAAAAAAAEy65ABM03gAVNNYBDizPBxU14S8XN+aFFzjm0xg4
+ 5u8ZOeb3GTnn+hk55/saO+f7Gjvn/Bo75/waO+f8Gjvm/Bo75/sZOeb7GTnm+hk55vcYOObvGDjm0xc3
+ 5YUVNeEvDizPBxU01gETNN4AEy65AAAAAAAAAAAAAAAAABE04wAOM9MAFDPbABIx2wsWNuRBFzjlrBg4
+ 5ukYOef3GTrn+ho75/ocPej7HkLo/CFI6fwlT+n8J1Ho/SdR6PwlT+n8IUjp/B5C6PwcPef7Gjvn+hk6
+ 5/oZOef3GDjm6Rc45awWNuRBEjHbCxQz2wAOM9MAETTjAAAAAAAYPecAFC/RABU10gATM9sKFjjkUhc5
+ 5sAYOubwGTrn+Bk75/ocP+j8IUnp/DJc5/xPdeP8aonf/H6X2vyIndb9h53X/H+X2v1qid/8T3Xj/DJc
+ 5/whSen8HD/o/Bk75/oZOuf4GDrm8Bc55sAWOORSEzPbChU10gAUL9AAGD3nABc62wATNuEADzTTBhY4
+ 5EEXOubAGTrn8xk75/kaPej7H0Xo+zFb6PxfgeD8kaTX/LK60PzAxM39w8TH/aamp/2mpqf9w8TH/cDE
+ zfyxutD9kaTX/F+B4PwxW+j8H0Xo+xo96PsZO+f5GTrn8xc65sAWOORBDzTTBhM24QAXOtsAFzvlABMy
+ 2QMWOeMvGDvnrBg85/AZPej5Gz/o+yFJ6fxJb+X8jKDa/LvB0fzIys79y8zM/MvLzP2/v779f3t4/X97
+ eP3Av779y8vM/cvMzP3Iys78u8HR/Iyg2vxJb+X8IUnp/Bs/6PsZPej5GDzn8Bg75qwWOeMvEzLZAxc7
+ 5QAXO+ABFTjeEhc85YQZPejpGT3o+Rs/6fsiS+n8TXHk/J+u1vzHydD9zc3P/c7Ozv3Pz879zs7N/cvK
+ yf2ysK39srCt/cvKyf3Ozs39z8/O/c7Ozv3Nzc/9x8nQ/aCu1vxNceT8Ikvp/Bs/6fsZPej5GT3n6Rc8
+ 5YQVON4SFzvgARYy0wMXPeVDGD7n0hk/6PcaQOj7IEjp+0tv5fyisNf8yczR/M/P0f3Pz9D80NDP/dDQ
+ 0P3Q0M/90NDP/c7Ozf3Ozs390NDP/dHRz/3R0dD90dHQ/dDR0P3Pz9H9yczR/KKw1/xLb+X8IEjp+xpA
+ 6PsZP+j3GD7n0hc95UMWMtMDFjnhFBg+54sZP+jvGkDp+R1D6fs0W+f8kqTb/MrM0/3Q0dH90dHR/dHQ
+ 0P3Qz87+0dDP/dLS0P7S0tD90tLQ/tLR0P3T09H+09PR/dPS0f7S0tH90tLR/dLS0v3Q0dL9yszT/ZKk
+ 2/w0W+f8HUPp+xpA6PkZP+jvGD7nixY54RQYPuU/GUDoyBpB6PcbQun7Ikzp+2eE4fzCxtX80tHT/NPT
+ 0vzS0tH9xMPA/bGtqv3GxMH90tHQ/dPT0v3U1NL91NTT/dTU0/3U1NP91NTT/dTU0/3U1NP91NTT/dTU
+ 0/3S0dT8wsbV/GeE4fwiTOn7G0Lp+xpB6PcZQOjIGD7lPxlB53QaQenoGkLp+RxF6fw3Xuj8nKvc/NDR
+ 1f3U1NT91NTT/dHR0P6rqKP9eHFq/pSPiv3Dwb/+0tLR/dXU0/7V1dT91dXU/tXV1P3W1tT+1tbU/dXV
+ 1P7V1dT91dXU/dTU1f3Q0dX9nKvc/Dde6PwcRen8GkLp+RlB6egZQed0GkPprBtE6fcbROr7H0nq/Fp6
+ 5Py/xdn91NXW/dbW1v3W1tX91dTT/cG/vf2Jg339bWZf/Y6KhP3Ew8D91dTT/dbW1f3X19b919fW/dfX
+ 1v3X19b919fW/dfX1v3W1tb91tbW/dTV1v2/xdn9Wnrk/B9J6fwbROn7GkTp9xlD6awbRurVHEbq+xxH
+ 6vslT+r8e5Lj/NHT2v3Y2Nj92trZ/dra2f3a2tj+19bV/b+9uv6Gf3n9b2dg/puXkv3Ozsz+1tbV/dnY
+ 1/7Z2Nj92djX/tjY1/3Y2Nf+2NjX/djX1/7Y19f91tbX/c/R2P16keH8JE7p/BxG6fsbRer7GkTq1RxS
+ 7vAdU+38HlTt+ytb7PyesOn94uPj/d/f3f3o5+X96unn/enp5/3p6eb95OTh/cvKxv2Yk439npmT/cTD
+ wP3Pzcv9397d/eDf3v3f3t393d3c/dzc2/3b2tn92tnY/djX1v3R0ND909PW/ZKk4P0pUun8HEjq+xtG
+ 6vwbRuruHlrv+x5b7/wfWu/8MGDs/a686v3JyMb9pqOe/dfW0v3u7uv97+/s/u/v7P3v7+z+7Ovp/d3b
+ 2P7IxsH9j4uG/pGNif3W1dT+6Ojo/erq6f7p6ej96Ojm/ubl4/3i4d/+ysnG/Z2Zlf27urn9nqzf/SxV
+ 6f0dSer8G0fr/BtH6/kgXO/7IVzv/B9b7/wwYO39r73r/cG/vv2Yk4/90tHM/e/v7P3x8e798fHu/fDv
+ 7v3u7uz95uTi/c/MyP2OiYP9j4mE/cTEzf27vtz909Xj/enp6/3u7uz97e3s/ezs6v3Qzsv9mJON/b27
+ uf2mtOT9Lljq/R5M6/wcSuv8G0nr+SFd8PIiXvD8IFvw+y5f7vyot+395ebm/d7c2/3s7On98fHv/fHx
+ 7/7x8e797+7s/t/d2v20sKr+tbGr/c3Kxv7V09D92Nnl/qSo2v2Tl9T+qKvY/czO4/7k5Or96+zt/urq
+ 6f3d3Nr95ebm/ae27f0tXe38Hlfu+x9V7vweUu7vI17w2SRg8PsgXPD7KV3u/JGl7fzq6+/97+/v/fHx
+ 7/3x8fD98fHv/fDv7f3e3Nn9pqCZ/YR7cv2ppJ395OPg/e/v7P3w8O/96Ont/dfY6v2ztuH9lZrY/Zqd
+ 1v22ud392tvn/ezs7f3q6+79j6Tt/Chc7vwfXO/7JF/w+yJd8NgjXvCwJ2Lw9yBd8fsjW+/8bovt/N/i
+ 8P3w8fH98vLx/fLy8P3w7+3+393a/aqln/6CeXD9mpOL/tfV0f3w8O7+8vLw/fPz8f7y8vH98fHx/u/v
+ 8f3e4O3+vcDl/aCk3P2prd394eLs/d3h8P1tiu38I1vv/CBd8PsnYvD3I17wsCFc73gqZPDqI17x+SBb
+ 7/xGbe38vsnw/O/v8v3y8vH98fHv/eDe2/2moJr9gnpx/Z2Ykf3X1NH97+/t/fPz8v309PP99PTz/fT0
+ 8/3z8/P98/Pz/fLy8v3v8PL96erw/ePl7/3r7PH9vcfw/EVt7fwgW+/8I17w+Spk8OohXO94HVnsQilj
+ 8MooYvH3IFvw+ylc7fuGnO785Ofy/PHx8P3h4N39q6ag/YN6cf2ak4z+19XR/fHw7/709PP99fTz/vX1
+ 9P319fT+9fX0/fX19P719fT99fX0/fT09P3z8/P98vLz/eXo8vyGm+78KVvt+yBb8PsoYvH3KWPwyh1Z
+ 7EIZVOUVJF/vji5m8fAjX/H5IFnv+0Rq7fy7xfD85ebo/aynov2DenH9n5mS/djW0v3x8O/99PTz/fX1
+ 9f319fT99fX0/fb29f329vX99vb1/fb29f329vX99fX1/fT09P3v8PP9u8bx/ERr7fwgWe/7I1/x+S5m
+ 8fAkX++OGVTlFRxN0wQhXO1GLWfx1Ctl8vchXPD7J1vu+2mE7fzDyOX8op2c/J+Zk/3Z19T98vLx/fX1
+ 9f329vX+9vb1/fT08/709PP99vb2/vb29f329vb99vb1/fb29f319fX98PH0/M/W8vxphe78J1vu+yFc
+ 8PsrZfL3Lmfx1SFc7UYcTNMEJ1/rAR5X6BMmYfCIMWry6ydi8fkgW/D7K1zt/G2H7PzCx+H84uLk/fLy
+ 8v319fX99vf2/fb29v309PP93Nza/dzc2v309PP99vb2/ff39v329vb99fb2/fHy9f3R1/P8b4ju/Ctc
+ 7vwgW/D7J2Lx+TFq8usnYe+IHlfmEydf6wEhW+0AHFDkBB5Z7TErZfGvMmvy8SVg8fkhW+/7LFzt/GyF
+ 7fzAyfL86uz1/PT09v329vf89vb2/eno5/2gnZn9oJ2Z/eno5/329vb99vb3/fT19/zq7Pb8wcrz/G2H
+ 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
+ AAAZPeEAGDnhABY53wcZPehKGj3pyxo96fcaPun7Gz7q/Bs/6vwcP+r9HUbr/SdY7f1Od+j9kqfa/sHF
+ 0f7Lzc/+zs7P/s/Pzv7Pz87+zs/N/s7Ny/6ioZ7+V1JN/ldSTf6ioZ7+zs3L/s7Pzf7Pz87+zs/O/s7O
+ z/7Lzc/+wcXR/pKn2v5Od+j9J1jt/R1G6/0cP+r9Gz/q/Bs+6vwaPun7Gj3p9xo96MsZPedKFjnfBxg4
+ 4QAZPeEAAAAAAAAAAAAJN9UAFzfOAho95SkaPumvGz7q9Bo+6fsbP+r8HD/r/BxA6/0eR+v9KFjt/WOF
+ 5P2suNb+y8zR/s/P0P7P0ND+0NDQ/tDQz/7Q0M/+0NDP/s/Pzv61s7H+enVw/np1cP61s7H+z8/O/tDQ
+ z/7Q0M/+0NDP/tDQ0P7P0ND+z8/Q/svM0f6suNb+Y4Xk/ShY7f0eR+v9HEDq/Rw/6/0bP+r8Gj7p+xs+
+ 6fQaPumvGj3lKRc3zgIJN9UAAAAAABY2wgAZPuMAFjfeDBk/6HobP+nsGz/q+hs/6vwcQOr8HEHr/B5H
+ 6/0pWOz9Z4fj/ba+1f3Nz9H90dHR/dHR0f3R0dD90tLR/dHR0P3R0dD90dHQ/dHRz/3Ozsz9v768/b++
+ vP3Ozsz90dHP/dHR0P3R0dD90tLQ/dLS0f3R0dD90dHR/dHR0f3Nz9H9tr7V/WeH4/0pWOz9Hkfr/RxB
+ 6/0cQOr8Gz/q/Bs/6fobP+nsGT/oehY33gwZPuMAFjbCABMv1AAQNsoBGj7nOhpA6dIbQOr5G0Dq/BtB
+ 6vwcQer9HkXs/SlX7f1mh+T+uMDW/c/Q0v7S0tL+0tLS/tLS0f7S0tH+0tLS/tLS0f7S0tH+0tLR/tLS
+ 0f7S0tD+0dHQ/tHR0P7S0tD+09PR/tLS0f7S0tH+09PR/tLS0v7S0tH+09PR/tLS0v7S0tL+z9DS/rjA
+ 1v5mh+T+KVft/R5F7P0cQer9G0Hq/BtA6vwbQOr5GkDp0hk+5zoQNsoBEy/UABY4xwAXPuMMGkDqiRpB
+ 6vIbQer6G0Hq/BxC6/0dQ+v9I0/s/VN45/2yvNj+z9DT/dPT0/7T09L+09PS/tPT0v7T09L+09PS/tPT
+ 0v7T09L+09PS/tPT0v7T09L+09PS/tPT0v7T09L+1NTS/tPT0v7T09L+1NTT/tPT0/7T09L+1NTT/tPT
+ 0/7T09P+09PT/s/Q0/6yvNj+U3jn/SNP7P0dQ+v9HELr/RtB6vwbQer6GkHq8hpA6okXPuMMFjjHABQy
+ 1QIaQOg2G0HqyBtB6vgbQev7HELr/BxC6/0fSev9NmDq/Zus3P7P0NX+1NPU/dTU1P7U1NP+1NTT/tTU
+ 0v7U09L+1NPR/tTU0v7V1NL+1dTT/tXV0/7V1dP+1dXT/tXV0/7V1dP+1dXU/tXV0/7V1dP+1dXU/tXV
+ 0/7V1dP+1dXU/tXU0/7U1NP+1NTU/tTT1P7P0NX+m6zc/jZg6v0fSev9HELr/RxC6/wbQev7G0Hq+BtB
+ 6sgaQOg2FDLVAhY93AwbQul2G0Lq6xtC6vobQ+v8HEPr/R1F6/0kUuz9cIzj/cjM1v7U09X+1dXV/dXV
+ 1P7V1dT+1dXT/tPT0f7HxsT+xMK//tHQzv7V1dP+1dXU/tXV1P7W1tT+1tbV/tXV1P7W1tX+1dXU/tXV
+ 1P7W1tX+1dXU/tXV1P7W1tX+1dXU/tXV1P7W1tX+1dXU/tXV1f7U09X+yMzW/nCM4/4kUuz9HUXr/RxD
+ 6v0bQ+v8G0Lq+htC6usbQul2Fj3cDBlC5iIbQ+qvG0Pr+BtD6/scROv8HETr/R5K7P09Z+r9qbXc/dPT
+ 1v7W1db+1tbV/dbW1f7W1tX+1dXU/sTDwP6Mh4L+gHpz/q2qpv7Rz87+1dXU/tbW1f7W1tX+19fV/tbW
+ 1f7X19b+19fV/tbW1f7X19b+19fV/tbW1f7X19b+19fV/tbW1f7X19b+1tbV/tbW1v7W1db+09PW/qm1
+ 3P49Z+r9Hkrs/RxE6/0cROv8G0Pr+xtD6/gbQ+qvGULmIhpD6kUbROvZHETr+hxE7PwcRev8HUbs/SNR
+ 7P1riOX+x8zZ/dXW1/7X19f+19fW/dfX1v7X19b+1dXU/ru5tv50bWX+ZV1U/nZvaP6sqKT+0M/O/tbW
+ 1f7X19X+19fW/tjY1v7Y2Nf+2NjW/tjY1v7Y2Nf+2NjW/tjY1v7Y2Nf+2NjW/tjY1v7Y2Nf+2NfW/tfX
+ 1v7X19f+1dbX/sfM2f5riOX+I1Hs/R1G7P0cRev8HETr/BtE6/obROvZGkPqRRtE63UcRevyHEXr+xxF
+ 6/wcRuz9Hknr/TRe6v6bq9/+1NXZ/djY2P7Y2Nf+2NjX/djY1/7Y2Nf+2NfW/s7Ny/6alpH+bGVd/mNc
+ U/5xamT+p6Sg/tHQzv7Y19b+2NjX/tjY1/7Y2Nf+2dnY/tnZ2P7Y2Nf+2dnY/tnZ2P7Y2Nf+2dnY/tnZ
+ 2P7Y2Nf+2dnY/tjY2P7Y2Nf+2NjY/tTV2f6bq9/+NF7q/h5J6/0cRuv9HEXr/BtF6/scRevyG0TrdRxF
+ 66QdRuz7HUbs/B1G7P0dR+z9H0vs/Ulu6f67w9z+19jZ/dnZ2f7Z2dj+2tnZ/drZ2P7Z2dj+2dnY/tjX
+ 1/7My8n+mZSP/mlhWf5jW1L+cmtk/q2qpv7U09H+2dnY/tnZ2P7Z2dj+2trZ/tra2f7Z2dj+2trZ/tra
+ 2f7Z2dj+2trZ/tra2f7Z2dj+2dnZ/tnZ2f7Z2dj+2dnZ/tfY2f67w9z+SW7o/h9L7P0dR+v9HUbr/RxG
+ 7PwcRuz7G0XrpBxH7ModR+z8HUfs/B1I7f0eSOz9IU7t/WKA5v7P0t3+2trb/dva2/7b29r+3Nzb/dzc
+ 2/7c3Nr+3Nza/tva2v7a2dj+zMvJ/paRi/5pYlr+ZFxU/nt0bf67urf+2NjX/tnZ2P7a2tn+29rZ/tva
+ 2v7b2tn+29ra/tva2v7a2tn+29ra/tva2v7a2tn+29ra/tra2f7a2dn+2tnZ/tjZ2v7O0dv+YYDm/iFN
+ 7P0dR+z9HUfs/RxG7PwcR+z8HEbsyRxQ7+geUu/8HlLv/B5U7/0fVe/9JVXu/YWd6/7m5+j+6eno/enp
+ 5/7r6uj+7Ovp/ezr6f7r6+j+6+vp/uvq6P7q6uf+5+bk/tjX1P6inpj+cmtj/nZvZ/63tLD+2trZ/tzb
+ 2f7f3t3+4N/e/t7e3P7e3dz+3d3b/tzc2v7d29r+3dza/tzc2v7c29r+3Nva/tzb2v7b2tn+2trZ/tnZ
+ 2v7X2Nv+e5Lk/iRP7P0dSev9HUjs/RxH7PwcR+z8HEfs5R9b8fkgXPH9H1zx/R9b8f0gW/D9KFju/pyv
+ 7f7u7u7+5OTh/dHPy/7i4N3+8PDt/fHx7v7x8e7+8vLv/vHx7v7y8u7+8fHu/u/v7P7i4t7+urey/rez
+ rv7OzMj+q6ml/quopf7a2db+7Ovp/uvq6f7q6uj+6Ojm/uXl5P7k4+L+4uHg/uDf3v7e3t3+3dzb/tzb
+ 2v7Ozcz+wL68/tHQ0P7Z2tz+jJ/j/iZR7P4eSuz9HUns/RxI7P0cSO39HEjs9CBc8f0iXvH9IF3x/R9c
+ 8f0gW/H9Klnu/qa37f7r6+r+r6un/X14cP6koJr+5eXh/fHx7v7y8u/+8vLv/vLy7/7y8u/+8vLv/vHx
+ 7/7x8e7+7Ovo/uXk4f6npJ/+YVtV/mFbVf6opaH+6enn/u/v7f7w8O7+8PDu/vDw7f7v7+3+7u7s/u3s
+ 6v7r6uj+5ubl/tnY1v6dmJP+enRt/qShnf7X19j+labi/idS7P4eS+z9Hknt/R1J7f0dSe39HEnt/CFd
+ 8v0kYPL9IV3y/R9c8v0hXPH9Kljv/qm47v7p6ej+oJyX/W9oYf6WkYv+4uHd/fHx7/7y8vD+8/Pw/vPz
+ 8P7y8vH+8vLw/vLy8P7x8e/+7+/r/ufm4v6jnpn+aGBZ/mhgWf6jn5r+29vh/tLT5P7k5er+7+/u/vDw
+ 7/7x8e/+8fHv/vHx7/7x8e/+8PDt/uHg3P6VkIr+b2hg/p2ZlP7e3t7+m6vl/ihS7P4fTOz9Hkrt/R1K
+ 7f0dS+39HUrt/CFd8vkmYfL9Il7y/SBc8v0hXPH9KFfv/qKy7v7v8O/+1tXT/bSxrf7Rzsv+7+/s/fPz
+ 8f7z8/H+9PTx/vPz8f7z8/H+8vLx/vLy8P7t7ev+2dfU/tXTz/7OzMj+oZyW/qGblv7S0M3+wsXi/nR6
+ zP6Ijc7+t7rb/uHh6f7v8PD+8PHw/vHx8P7x8fD+8vLw/u7u7P7Rzsv+tLGt/tbV0/7u7u7+nq/t/ihV
+ 7f4fVe/9HlLv/R5P7/0eTe79HUvt9CFd8uooY/P9Il/z/CBd8v0gXPH9J1fv/ZSn7v7w8PH+8PHv/e/u
+ 7P7y8e/+8/Px/fPz8f7z8/L+9PTy/vT08f7z8/H+8vLw/uzr6f7Fwr3+k4yE/pSNhf7OzMf+5eTi/ufm
+ 4/7w8O7+5ufv/ru+5f6Lkdn+bHPO/nl+y/6oq9f+1dbm/uvr7v7w8PD+8vLx/vLy8f7x8e/+7+7s/vDx
+ 7/7v8PH+kqXu/idW7v0gW/H9H1rx/SFb8vwkXPH9H1Xw5iFd8s8pZPP8JGDz/CBd8v0gXPL9JVfv/XmS
+ 7v7s7fL+8vLx/fPz8f709PL+9PTy/fT08v709PL+9PTy/vT08f7z8/D+7Ovo/sG9t/6Hf3b+eXBm/od/
+ df7KyML+8PDu/vLy8P709PH+9PTy/vHx8f7r7PD+1tfs/qSo4f51fNP+bHLK/pCU0f6+wN/+3t/q/u/v
+ 8P7z8/H+8/Px/vLy8f7r7fH+d5Du/iRX7/0gXPH9H1zy/SRg8vwpZPL8IV3yzyFd8qopZPP7J2Pz/CBd
+ 8v0gXPL9Iljw/Vx67v7e4vL+8vLy/fT08v709PP+9PTz/fT08/709PL+9PTy/vTz8f7u7ev+xcK9/od/
+ dv53bWP+fXRr/rGrpf7p6OX+9PTx/vT08v709PP+9fXy/vT08v709PL+8/Py/vHx8v7h4u/+uLzn/oSK
+ 2P5qcM3+eoDN/qyv2v7g4ev+8/Py/vLy8v7d4fH+Wnnu/iJY8P0gXPH9IF3y/Sdj8/wpZPP7IVzyqiBc
+ 8XspZPP0K2bz+yFd8/wgXPL9IVrx/UBl7v6/yvH+8vLz/fT08/719fT+9fXz/fX18/719fP+9PTy/u3s
+ 6v7Gwr7+i4N7/nhuZP59dGr+q6af/uXk4f709PL+9fXz/vX18/719fT+9vb0/vX19P719fP+9fX0/vX1
+ 8/7z8/P+8fLz/uTm8f7KzOv+n6Th/n6F1v67v+P+8PDy/vHx8/6+yfH+QGXt/iFa8f0gXPL9IV7z/Cxm
+ 8/spZPP0IFzxex9a8EkmYvPcMGnz+iJe8/wgXfL8IVzx/StY7v2Noe/+6uzz/fT09P719fT+9fX0/fX1
+ 9P719fL+7ezr/sG9uP6Hf3b+eG9l/oB3b/6wq6X+5uTh/vPz8f719fT+9fX0/vb29f729vT+9vb1/vb2
+ 9f729vT+9vb1/vb29f719fT+9fX1/vPz9P7y8vP+7/D0/ufo8v7s7fL+8/P0/uns8/6MoO/+Klju/SFc
+ 8f0gXfL8Il7z/DBp8/omYvPcH1rwSR5Y7SUjX/KzMWrz+Shj8/sgXfL8IFzy/SFW7/1Xde790tnz/fPz
+ 9P719fX+9vb0/fX19P7v7+3+xsO+/od/dv53bWP+fXRq/rCspf7o5uT+9PTz/vb29P729vX+9vb1/vf3
+ 9f739/b+9/f2/vf39v739/X+9/f2/vf39v739/X+9vb2/vb29f729vX+9fX1/vX19f719fT+8/P0/tHY
+ 8/5WdO79IVbv/SBc8v0gXfL8KGPz+zFq8/kjX/KzHljtJR9W4w0fXPF6LWfz7TBq9PohXvP8IF3y/SBa
+ 8P0tV+39nKzx/e3v9P719fX+9vb0/e/u7P7Hw77+jIR7/nhuZP59dGv+rKeg/ufl4/719fP+9vb1/vf3
+ 9f739/b+9/f2/vf39v74+Pf+9/f3/vf39/74+Pf+9/f3/vf39/74+Pf+9/f2/vf39v739/b+9/f2/vb2
+ 9f719fX+7e/0/pur8f4tV+39IFrw/SBd8v0hXvP8MGr0+i1n8+0fXPF7H1jjDRxZ2wIeW+85JmHyyzZu
+ 9PkoY/P7IF3y/CBb8f0hVe/9TW3u/c7V9P7z9PX+8/Lx/cXCvv6If3f+eG9l/oF4b/6yrKb+5+bj/vb1
+ 8/739/X+9/f2/vj49v74+Pf+9/f3/vf39/74+Pf+9/f3/vf39/74+Pf+9/f3/vf39/74+Pf+9/f3/vf3
+ 9/739/b+9/f2/vf39v7z9PX+zdT0/k1s7f0hVe/9IFvx/SBd8vwoY/P7Nm70+SZh8sseW+85HFrbAh9W
+ 3wEbW+cOIV3xjjJr9PMzbPT6I1/z/CBc8v0gW/H9KFTu/X6S8P3j5vT+6unp/ZmSi/54bmT+fnVr/rKs
+ pv7q6Ob+9vb1/vf39/739/f++Pj3/vj49/74+Pj+9/f3/vf39/74+Pj++Pj3/vj4+P75+fj++Pj4/vj4
+ +P75+fj++Pj4/vj49/739/f+9/f3/vX19v7k5/X+fZLw/ShU7v0gW/H9IFzy/SNf8/wzbPT6Mmr08yFd
+ 8Y4bW+cOH1bfASBc8AAbWdMCH13vPShk89U5cfT5K2b0/CFe8/wgXPL9IVnw/Tdc7f2aqfD+4OLt/aun
+ pP6Kgnr+sKul/ujn5f739vX++Pj3/vj4+P74+Pj++Pj4/vj4+P74+Pj+9/f2/vf39v74+Pj++Pj4/vj4
+ +P75+fj++Pj4/vj4+P75+fj++Pj4/vj4+P74+Pf+9fb3/ujr9v6aqfH+N1zt/SFZ8P0gXPL9IV7z/Ctm
+ 9Pw5cPT5KWTz1iBd7z0bWdMCIFzwAB1PygAkXusAH1rnDSJe8X8xavTuOXH1+iZi8/wgXfL8IFzx/CJX
+ 8P07Xuz9navx/d7g6v7h4N/+7+7t/vf39v74+Pf++fn4/vn5+P75+fj++fn4/vn5+P739/f+7e3s/u3t
+ 7P739/f++fn4/vn5+P75+fj++fn4/vn5+P75+fj++fn4/vj5+P729/f+6ev3/p2s8v06Xu39IVfw/SBc
+ 8f0gXfL8JmLz/Dpx9foxavTuIl7xgB9a6A0kXusAHU/KACFd8gATX90AIFTXAyBa7iwkYPO0OHD19TZu
+ 9PsjX/P8IF3y/CBb8f0hVe/9PF7s/Z6s8f3n6fX+9vb3/vj5+P75+fj++fn4/vr6+f75+fn++fn5/vn5
+ 9/7j4+H+op+c/qKfnP7j4+H++fn3/vn5+f75+fn++vr5/vr6+P75+fn++Pn4/vf3+P7n6vf+nqzy/Tte
+ 7f0hVe/9H1vx/SBd8v0jX/P8Nm70+zlw9fUkYPK0IFrtLCBU1wMTX90AIV3yAAAAAAAlXusAHljpAB1V
+ 6QcgW/FOKWTzzj519fcybPT7I1/z/CFc8vwgW/H9Ilfv/Tpd7f2FlvD91dv2/vLz+f74+Pn++fn5/vr6
+ +f76+vn++vr5/vf39v7GxMH+b2lj/m9pY/7GxMH+9/f2/vr6+f76+vn++vr5/vn5+f74+Pn+8vP5/tXa
+ 9v6El/H9Ol3s/SJX7/0gW/H9IFzy/CNf8/wzbPT7PnX19ylk8s4gW/BOHVXnBx9Y6gAlXusAAAAAAAAA
+ AAAAAAAAIVHMABtQ1AEdWucLI13yYi1o891Ad/X5NG30+yNf8/wgXfL9IFzy/CFY8P0pU+39VXHu/ai0
+ 9P3d4fj+8/T6/vj5+v75+fr++fn6/vn4+f7g397+oZyX/qGcl/7g397++fj5/vn5+v75+fr++Pn6/vL0
+ +v7d4fj+qLT0/VRw7v0pVO39IVjw/SBc8v0gXfL9I1/z/DRt9PtBd/X5LWfz3SNd8WIdWucLG1DUASFR
+ zAAAAAAAAAAAAAAAAAAAAAAAH1fqAB5X6wAfU9YBI1nsESNe8XsvafTjQnj1+TVu9PskX/P8IF3y/CBc
+ 8v0gWvH9IlTv/TJY7f1je+/9n6zz/tHX9/7t7/n+9vf6/vj5+v73+Pn+7e3t/u3t7f73+Pn++Pn6/vb3
+ +v7t7/n+0df3/p+s8/5je+/9Mljt/SFU7/0gW/H9IFzy/SBd8vwkX/P8NW70+0J49fkvafTjI17xeyNZ
+ 7BEfU9UBHlboAB9X6gAAAAAAAAAAAAAAAAAAAAAAAAAAABhIxAAbWugAHlHhAiFb7BsjX/F6MGnz3UN6
+ 9vc7cvX6KGPz/CFe8/wgXfL8IFvy/SFZ8f0jVe79MFjt/Uxp7v1uhPD+kqHy/q+79f7Ayfb+yM/2/sjP
+ 9v7Ayfb+sLv1/pKh8v5uhPD+TGnu/TBY7f0jVe79IVnx/SBb8v0gXfL8IV7z/Chj8/w7cvX6Q3r29zBp
+ 890jX/F6IVvsGx5R4QIbWucAGEjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdRq0AIVntAB9T
+ 4wIjWegRI17xYixn889Ad/b1RHr2+jFr9PskYPP8IV3z/CBd8/0hXPL9IVzx/SJZ8f0kVu/9JlTu/StU
+ 7f0uVu39M1ft/TNX7f0uVu39K1Tt/SZU7v0kVu/9Ilnx/SFc8f0hXPL9IF3z/SFd8/wkYfP8MWv0+0R6
+ 9vpAd/b1LGfzzyNe8WMiWOgSH1PjAiFZ7QAdRq0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAHEnVACFd8QAbSdcCHVvnCyBc8E8nYvO0OXH17Uh99vlBd/X6L2n0+yNf8/whXfP8IV3y/SFd
+ 8/0iXfL9Il3y/SJc8v0iW/L9Ilvy/SJb8v0iW/L9Ilzy/SJd8v0iXfL9IV3z/SFd8v0hXfP8I1/z/C9p
+ 9PtBd/X6SH32+Tlx9e0nYvO0IFzwTx1b5wsbSdcCIV3xABxJ1QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAHVTmABtJ1wAgWOkAHFTWARxX5gggW+4tJGDxgDBp89VAdvXySn/2+EN5
+ 9vozbPT7J2Pz/CNf8/wiXvP9IV7z/SFd8/0hXfP9IV7z/SFe8v0hXfP9IV3y/SFe8/0iXvP9I1/z/Cdj
+ 8/wzbPT7Q3n2+kp/9/hAdvXyL2nz1iRg8YAgW+4tHFfmCBxU1gEgV+kAG0nXAB1U5gAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARMrwAGlrrAB9Z6gEiV9wDIVvmDSFe
+ 8T0kYPKNLWf0yz519u1Kf/b4S4D3+kR69vo8dPX8NG71/C9p9fwtZ/X8LGb1/Sxm9f0tZ/X8L2n0/DRu
+ 9fw8dPX8RHr2+kuA9/pKf/b4PnX27S1n9MskYPKOIF7xPSFb5g0iV9wDH1nqARpa6wARMrwAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkWwABpZ
+ 7QAgXfIAH07BASNdzQIiXOkOH13wOSFf8nsoY/O0M2z03D519fRGfPb7S4D2/E2B9/xNgff8ToL3/U6C
+ 9/1Ngff8TYH3/EuA9vxGfPb7PnX29DNs9NwoY/OzIV/yex9d8DkhWukOI1zNAh9OwQEgXfIAGlntABJF
+ sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAwkgwAaR8UAHFfpACBd8gAfU9ABIV/eAyJb5w0gXO4mIV7xSSNf8nsmYfKqKWTzzyxn
+ 8+ouaPT5MGr0/DBq9PwuaPT4LGfz6Spk888mYfKqIl/yeyBe8EkgXu4lIlvkDSFf3gMfU9ABIF3yABtX
+ 6QAaR8UADCSDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AAAf/////+AAAAf/
+ ////gAAAAf////8AAAAA/////gAAAAB////8AAAAAD////gAAAAAH///8AAAAAAP///gAAAAAAf//+AA
+ AAAAB///wAAAAAAD///AAAAAAAP//4AAAAAAAf//gAAAAAAB//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
+ //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA
+ AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA
+ //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//+AAAAAAAH//8AAAAAAA///wAAAAAAD///gAAAAAAf//+AA
+ AAAAB///8AAAAAAP///4AAAAAB////wAAAAAP////gAAAAB/////AAAAAP////+AAAAB/////+AAAAf/
+ ////+AAAH////w==
+
+
+
+ 371, 17
+
+
+ 480, 17
+
+
+ 769, 19
+
+
+ 17, 56
+
+
+ 240, 56
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/MiteDesk.WinForms.csproj b/App/MiteDesk.WinForms/MiteDesk.WinForms.csproj
new file mode 100644
index 0000000..eb442ac
--- /dev/null
+++ b/App/MiteDesk.WinForms/MiteDesk.WinForms.csproj
@@ -0,0 +1,343 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}
+ WinExe
+ Properties
+ SixtyNineDegrees.MiteDesk.WinForms
+ mite.desk
+ v3.5
+ 512
+ D6A9395B773CD057B51D8A60BAF73F15E7B078BE
+ WinMite.WinForms_TemporaryKey.pfx
+ true
+ false
+ false
+ true
+ SixtyNineDegrees.MiteDesk.WinForms.Program
+ false
+
+
+ mite.desk.ico
+
+
+ 3.5
+
+ C:\Temp\WinMiteDeploy\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 2
+ 0.9.0.%2a
+ false
+ true
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+ False
+ ..\..\Library\Shared\StructureMap\StructureMap.dll
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+ Form
+
+
+ Activities.cs
+
+
+
+ Form
+
+
+ Customers.cs
+
+
+ Form
+
+
+ DebugConsole.cs
+
+
+ True
+ True
+ ActivitiesLabels.resx
+
+
+ True
+ True
+ CustomersLabels.resx
+
+
+ True
+ True
+ DebugConsoleLabels.resx
+
+
+ True
+ True
+ FeedbackLabels.resx
+
+
+ True
+ True
+ MainLabels.resx
+
+
+ True
+ True
+ ProjectsLabels.resx
+
+
+ True
+ True
+ SettingsLabels.resx
+
+
+ True
+ True
+ UpdateCheckLabels.resx
+
+
+ Form
+
+
+ LoginHelp.cs
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+ Form
+
+
+ Main.cs
+
+
+
+ Form
+
+
+ Projects.cs
+
+
+
+ Activities.cs
+
+
+ Customers.cs
+
+
+ DebugConsole.cs
+
+
+
+ ResXFileCodeGenerator
+ ActivitiesLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ CustomersLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ DebugConsoleLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ FeedbackLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ MainLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ ProjectsLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ SettingsLabels.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ UpdateCheckLabels.Designer.cs
+
+
+ LoginHelp.cs
+
+
+ Main.cs
+
+
+ Projects.cs
+
+
+ ResXFileCodeGenerator
+ Designer
+ Resources.Designer.cs
+
+
+ Settings.cs
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+ Form
+
+
+ Settings.cs
+
+
+
+
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}
+ MiteDesk.Core.Data
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}
+ MiteDesk.Core.Services
+
+
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}
+ MiteDesk.Tools.Connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Program.cs b/App/MiteDesk.WinForms/Program.cs
new file mode 100644
index 0000000..b878527
--- /dev/null
+++ b/App/MiteDesk.WinForms/Program.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+
+ static class Program
+ {
+
+ private static Main MainForm;
+
+ [STAThread]
+ static void Main()
+ {
+
+ if (!SingleInstance.Start())
+ {
+ SingleInstance.ShowFirstInstance();
+ return;
+ }
+
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Bootstrapper.Initialize();
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ Application.ThreadException += Application_ThreadException;
+ Application.ApplicationExit += Application_ApplicationExit;
+ MainForm = new Main();
+ try
+ {
+ MainForm.Initialize();
+ }
+ catch(MiteConnectorException e)
+ {
+ HandleException(e);
+ }
+ Application.Run(MainForm);
+
+ }
+
+ static void Application_ApplicationExit(object sender, EventArgs e)
+ {
+ SingleInstance.Stop();
+ }
+
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ HandleException((Exception)e.ExceptionObject);
+ }
+
+ static void Application_ThreadException(object sender,ThreadExceptionEventArgs e)
+ {
+ HandleException(e.Exception);
+ }
+
+ private static void HandleException(Exception e)
+ {
+ if (e is MiteConnectorException)
+ {
+ MainForm.NotifyAboutNetworkErrorAndDisableForm(e as MiteConnectorException);
+ }
+ else
+ {
+ new DebugConsole(e).ShowDialog();
+ }
+ }
+
+ }
+
+ static public class WinApi
+ {
+ [DllImport("user32")]
+ public static extern int RegisterWindowMessage(string message);
+
+ public static int RegisterWindowMessage(string format, params object[] args)
+ {
+ string message = String.Format(format, args);
+ return RegisterWindowMessage(message);
+ }
+
+ public const int HWND_BROADCAST = 0xffff;
+ public const int SW_SHOWNORMAL = 1;
+
+ [DllImport("user32.dll")]
+ public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
+
+ [DllImport("User32.dll")]
+ public static extern int ShowWindow(IntPtr hWnd, int swCommand);
+
+ }
+
+ static public class ProgramInfo
+ {
+ static public string AssemblyGuid
+ {
+ get
+ {
+ object[] attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(GuidAttribute), false);
+ if (attributes.Length == 0)
+ {
+ return String.Empty;
+ }
+ return ((GuidAttribute)attributes[0]).Value;
+ }
+ }
+ }
+
+ static public class SingleInstance
+ {
+
+ public static readonly int WM_SHOWFIRSTINSTANCE = WinApi.RegisterWindowMessage("WM_SHOWFIRSTINSTANCE|{0}", ProgramInfo.AssemblyGuid);
+ static Mutex mutex;
+
+ static public bool Start()
+ {
+ bool onlyInstance;
+ string mutexName = String.Format("Local\\{0}", ProgramInfo.AssemblyGuid);
+ mutex = new Mutex(true, mutexName, out onlyInstance);
+ return onlyInstance;
+ }
+
+ static public void ShowFirstInstance()
+ {
+ WinApi.PostMessage((IntPtr)WinApi.HWND_BROADCAST, WM_SHOWFIRSTINSTANCE, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ static public void Stop()
+ {
+ mutex.ReleaseMutex();
+ }
+
+ }
+
+}
diff --git a/App/MiteDesk.WinForms/Projects.Designer.cs b/App/MiteDesk.WinForms/Projects.Designer.cs
new file mode 100644
index 0000000..c3a6cc3
--- /dev/null
+++ b/App/MiteDesk.WinForms/Projects.Designer.cs
@@ -0,0 +1,360 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class Projects
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.TabCustomers = new System.Windows.Forms.TabControl();
+ this.ActiveProjectsTabPage = new System.Windows.Forms.TabPage();
+ this.ActiveProjectsTree = new System.Windows.Forms.TreeView();
+ this.TreeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.ArchivedCustomersTabPage = new System.Windows.Forms.TabPage();
+ this.ArchivedProjectsTree = new System.Windows.Forms.TreeView();
+ this.FormGroup = new System.Windows.Forms.GroupBox();
+ this.BtnOpenCustomers = new System.Windows.Forms.Button();
+ this.ListBudgetType = new System.Windows.Forms.ComboBox();
+ this.BoxBudget = new System.Windows.Forms.TextBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.ListCustomers = new System.Windows.Forms.ComboBox();
+ this.CheckBoxArchived = new System.Windows.Forms.CheckBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.BoxNote = new System.Windows.Forms.TextBox();
+ this.BoxName = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.BtnNewProject = new System.Windows.Forms.Button();
+ this.BtnCancel = new System.Windows.Forms.Button();
+ this.BtnSave = new System.Windows.Forms.Button();
+ this.ErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+ this.TreeDataBackgroundWorker = new System.ComponentModel.BackgroundWorker();
+ this.TabCustomers.SuspendLayout();
+ this.ActiveProjectsTabPage.SuspendLayout();
+ this.TreeContextMenu.SuspendLayout();
+ this.ArchivedCustomersTabPage.SuspendLayout();
+ this.FormGroup.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).BeginInit();
+ this.SuspendLayout();
+ //
+ // TabCustomers
+ //
+ this.TabCustomers.Controls.Add(this.ActiveProjectsTabPage);
+ this.TabCustomers.Controls.Add(this.ArchivedCustomersTabPage);
+ this.TabCustomers.Location = new System.Drawing.Point(9, 7);
+ this.TabCustomers.Name = "TabCustomers";
+ this.TabCustomers.SelectedIndex = 0;
+ this.TabCustomers.Size = new System.Drawing.Size(189, 277);
+ this.TabCustomers.TabIndex = 10;
+ //
+ // ActiveProjectsTabPage
+ //
+ this.ActiveProjectsTabPage.Controls.Add(this.ActiveProjectsTree);
+ this.ActiveProjectsTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ActiveProjectsTabPage.Name = "ActiveProjectsTabPage";
+ this.ActiveProjectsTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ActiveProjectsTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ActiveProjectsTabPage.TabIndex = 0;
+ this.ActiveProjectsTabPage.Text = "Aktive";
+ this.ActiveProjectsTabPage.UseVisualStyleBackColor = true;
+ //
+ // ActiveProjectsTree
+ //
+ this.ActiveProjectsTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ActiveProjectsTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ActiveProjectsTree.FullRowSelect = true;
+ this.ActiveProjectsTree.HideSelection = false;
+ this.ActiveProjectsTree.Location = new System.Drawing.Point(3, 3);
+ this.ActiveProjectsTree.Name = "ActiveProjectsTree";
+ this.ActiveProjectsTree.ShowLines = false;
+ this.ActiveProjectsTree.ShowPlusMinus = false;
+ this.ActiveProjectsTree.ShowRootLines = false;
+ this.ActiveProjectsTree.Size = new System.Drawing.Size(175, 245);
+ this.ActiveProjectsTree.TabIndex = 2;
+ //
+ // TreeContextMenu
+ //
+ this.TreeContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.DeleteToolStripMenuItem});
+ this.TreeContextMenu.Name = "TreeContextMenu";
+ this.TreeContextMenu.Size = new System.Drawing.Size(114, 26);
+ //
+ // DeleteToolStripMenuItem
+ //
+ this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem";
+ this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
+ this.DeleteToolStripMenuItem.Text = "Löschen";
+ this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click_1);
+ //
+ // ArchivedCustomersTabPage
+ //
+ this.ArchivedCustomersTabPage.Controls.Add(this.ArchivedProjectsTree);
+ this.ArchivedCustomersTabPage.Location = new System.Drawing.Point(4, 22);
+ this.ArchivedCustomersTabPage.Name = "ArchivedCustomersTabPage";
+ this.ArchivedCustomersTabPage.Padding = new System.Windows.Forms.Padding(3);
+ this.ArchivedCustomersTabPage.Size = new System.Drawing.Size(181, 251);
+ this.ArchivedCustomersTabPage.TabIndex = 1;
+ this.ArchivedCustomersTabPage.Text = "Archivierte";
+ this.ArchivedCustomersTabPage.UseVisualStyleBackColor = true;
+ //
+ // ArchivedProjectsTree
+ //
+ this.ArchivedProjectsTree.ContextMenuStrip = this.TreeContextMenu;
+ this.ArchivedProjectsTree.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ArchivedProjectsTree.FullRowSelect = true;
+ this.ArchivedProjectsTree.HideSelection = false;
+ this.ArchivedProjectsTree.Location = new System.Drawing.Point(3, 3);
+ this.ArchivedProjectsTree.Name = "ArchivedProjectsTree";
+ this.ArchivedProjectsTree.ShowLines = false;
+ this.ArchivedProjectsTree.ShowPlusMinus = false;
+ this.ArchivedProjectsTree.ShowRootLines = false;
+ this.ArchivedProjectsTree.Size = new System.Drawing.Size(175, 245);
+ this.ArchivedProjectsTree.TabIndex = 1;
+ //
+ // FormGroup
+ //
+ this.FormGroup.Controls.Add(this.BtnOpenCustomers);
+ this.FormGroup.Controls.Add(this.ListBudgetType);
+ this.FormGroup.Controls.Add(this.BoxBudget);
+ this.FormGroup.Controls.Add(this.label4);
+ this.FormGroup.Controls.Add(this.label3);
+ this.FormGroup.Controls.Add(this.ListCustomers);
+ this.FormGroup.Controls.Add(this.CheckBoxArchived);
+ this.FormGroup.Controls.Add(this.label2);
+ this.FormGroup.Controls.Add(this.BoxNote);
+ this.FormGroup.Controls.Add(this.BoxName);
+ this.FormGroup.Controls.Add(this.label1);
+ this.FormGroup.Enabled = false;
+ this.FormGroup.Location = new System.Drawing.Point(215, 8);
+ this.FormGroup.Name = "FormGroup";
+ this.FormGroup.Size = new System.Drawing.Size(313, 276);
+ this.FormGroup.TabIndex = 11;
+ this.FormGroup.TabStop = false;
+ //
+ // BtnOpenCustomers
+ //
+ this.BtnOpenCustomers.Location = new System.Drawing.Point(209, 174);
+ this.BtnOpenCustomers.Name = "BtnOpenCustomers";
+ this.BtnOpenCustomers.Size = new System.Drawing.Size(77, 21);
+ this.BtnOpenCustomers.TabIndex = 9;
+ this.BtnOpenCustomers.Text = "Kunden ...";
+ this.BtnOpenCustomers.UseVisualStyleBackColor = true;
+ this.BtnOpenCustomers.Click += new System.EventHandler(this.BtnOpenCustomers_Click);
+ //
+ // ListBudgetType
+ //
+ this.ListBudgetType.FormattingEnabled = true;
+ this.ListBudgetType.Location = new System.Drawing.Point(116, 215);
+ this.ListBudgetType.Name = "ListBudgetType";
+ this.ListBudgetType.Size = new System.Drawing.Size(87, 21);
+ this.ListBudgetType.TabIndex = 7;
+ this.ListBudgetType.SelectedIndexChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // BoxBudget
+ //
+ this.BoxBudget.Location = new System.Drawing.Point(10, 216);
+ this.BoxBudget.Name = "BoxBudget";
+ this.BoxBudget.Size = new System.Drawing.Size(100, 20);
+ this.BoxBudget.TabIndex = 6;
+ this.BoxBudget.Text = "0:00";
+ this.BoxBudget.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(7, 199);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(41, 13);
+ this.label4.TabIndex = 8;
+ this.label4.Text = "Budget";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(7, 158);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(38, 13);
+ this.label3.TabIndex = 7;
+ this.label3.Text = "Kunde";
+ //
+ // ListCustomers
+ //
+ this.ListCustomers.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
+ this.ListCustomers.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
+ this.ListCustomers.DisplayMember = "Text";
+ this.ListCustomers.FormattingEnabled = true;
+ this.ListCustomers.Location = new System.Drawing.Point(10, 174);
+ this.ListCustomers.Name = "ListCustomers";
+ this.ListCustomers.Size = new System.Drawing.Size(193, 21);
+ this.ListCustomers.TabIndex = 5;
+ this.ListCustomers.ValueMember = "Value";
+ this.ListCustomers.SelectedIndexChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // CheckBoxArchived
+ //
+ this.CheckBoxArchived.AutoSize = true;
+ this.CheckBoxArchived.Location = new System.Drawing.Point(10, 242);
+ this.CheckBoxArchived.Name = "CheckBoxArchived";
+ this.CheckBoxArchived.Size = new System.Drawing.Size(70, 17);
+ this.CheckBoxArchived.TabIndex = 8;
+ this.CheckBoxArchived.Text = "Archiviert";
+ this.CheckBoxArchived.UseVisualStyleBackColor = true;
+ this.CheckBoxArchived.CheckedChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(7, 63);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(61, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Bemerkung";
+ //
+ // BoxNote
+ //
+ this.BoxNote.Location = new System.Drawing.Point(10, 79);
+ this.BoxNote.Multiline = true;
+ this.BoxNote.Name = "BoxNote";
+ this.BoxNote.Size = new System.Drawing.Size(276, 75);
+ this.BoxNote.TabIndex = 4;
+ this.BoxNote.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // BoxName
+ //
+ this.BoxName.Location = new System.Drawing.Point(10, 37);
+ this.BoxName.Name = "BoxName";
+ this.BoxName.Size = new System.Drawing.Size(276, 20);
+ this.BoxName.TabIndex = 3;
+ this.BoxName.TextChanged += new System.EventHandler(this.EnableBtnSave);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(7, 20);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(35, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Name";
+ //
+ // BtnNewProject
+ //
+ this.BtnNewProject.Location = new System.Drawing.Point(10, 294);
+ this.BtnNewProject.Name = "BtnNewProject";
+ this.BtnNewProject.Size = new System.Drawing.Size(87, 23);
+ this.BtnNewProject.TabIndex = 12;
+ this.BtnNewProject.Text = "Neues Projekt";
+ this.BtnNewProject.UseVisualStyleBackColor = true;
+ this.BtnNewProject.Click += new System.EventHandler(this.BtnNewProject_Click);
+ //
+ // BtnCancel
+ //
+ this.BtnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.BtnCancel.Location = new System.Drawing.Point(445, 294);
+ this.BtnCancel.Name = "BtnCancel";
+ this.BtnCancel.Size = new System.Drawing.Size(83, 23);
+ this.BtnCancel.TabIndex = 10;
+ this.BtnCancel.Text = "Schließen";
+ this.BtnCancel.UseVisualStyleBackColor = true;
+ this.BtnCancel.Click += new System.EventHandler(this.BtnCancel_Click_1);
+ //
+ // BtnSave
+ //
+ this.BtnSave.Enabled = false;
+ this.BtnSave.Location = new System.Drawing.Point(356, 295);
+ this.BtnSave.Name = "BtnSave";
+ this.BtnSave.Size = new System.Drawing.Size(83, 23);
+ this.BtnSave.TabIndex = 9;
+ this.BtnSave.Text = "Übernehmen";
+ this.BtnSave.UseVisualStyleBackColor = true;
+ this.BtnSave.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // ErrorProvider
+ //
+ this.ErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+ this.ErrorProvider.ContainerControl = this;
+ //
+ // Projects
+ //
+ this.AcceptButton = this.BtnSave;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.BtnCancel;
+ this.ClientSize = new System.Drawing.Size(537, 330);
+ this.Controls.Add(this.TabCustomers);
+ this.Controls.Add(this.FormGroup);
+ this.Controls.Add(this.BtnNewProject);
+ this.Controls.Add(this.BtnCancel);
+ this.Controls.Add(this.BtnSave);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MaximumSize = new System.Drawing.Size(543, 355);
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(543, 355);
+ this.Name = "Projects";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Projekte";
+ this.TabCustomers.ResumeLayout(false);
+ this.ActiveProjectsTabPage.ResumeLayout(false);
+ this.TreeContextMenu.ResumeLayout(false);
+ this.ArchivedCustomersTabPage.ResumeLayout(false);
+ this.FormGroup.ResumeLayout(false);
+ this.FormGroup.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TabControl TabCustomers;
+ private System.Windows.Forms.TabPage ActiveProjectsTabPage;
+ private System.Windows.Forms.TreeView ActiveProjectsTree;
+ private System.Windows.Forms.TabPage ArchivedCustomersTabPage;
+ private System.Windows.Forms.TreeView ArchivedProjectsTree;
+ private System.Windows.Forms.GroupBox FormGroup;
+ private System.Windows.Forms.CheckBox CheckBoxArchived;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox BoxNote;
+ private System.Windows.Forms.TextBox BoxName;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Button BtnNewProject;
+ private System.Windows.Forms.Button BtnCancel;
+ private System.Windows.Forms.Button BtnSave;
+ private System.Windows.Forms.ContextMenuStrip TreeContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
+ private System.Windows.Forms.ErrorProvider ErrorProvider;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.ComboBox ListCustomers;
+ private System.Windows.Forms.ComboBox ListBudgetType;
+ private System.Windows.Forms.TextBox BoxBudget;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Button BtnOpenCustomers;
+ public System.ComponentModel.BackgroundWorker TreeDataBackgroundWorker;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Projects.cs b/App/MiteDesk.WinForms/Projects.cs
new file mode 100644
index 0000000..51d62d0
--- /dev/null
+++ b/App/MiteDesk.WinForms/Projects.cs
@@ -0,0 +1,345 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+using StructureMap;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class Projects : Form
+ {
+
+ #region Setup
+
+ public Projects()
+ {
+ InitializeComponent();
+ LocalizeForm();
+ ProjectService = ObjectFactory.GetInstance();
+
+ TreeDataBackgroundWorker.DoWork += TreeDataBackgroundWorker_DoWork;
+ TreeDataBackgroundWorker.RunWorkerCompleted += TreeDataBackgroundWorker_RunWorkerCompleted;
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+
+ ActiveProjectsTree.NodeMouseClick += Tree_NodeMouseClick;
+ ArchivedProjectsTree.NodeMouseClick += Tree_NodeMouseClick;
+
+ ListCustomers.TextUpdate += Helper.ValidateTextEnteredInComboBox;
+ PrepareFormForNewProject();
+ }
+
+ private IList ActiveProjects;
+ private IList ArchivedProjects;
+ private IList ActiveCustomers;
+ private IList ArchivedCustomers;
+ private readonly IProjectService ProjectService;
+
+ private Project CurrentProject;
+ private bool CreateNewProject;
+
+ #endregion
+
+ #region Lokalisierung
+
+ private void LocalizeForm()
+ {
+ Text = ProjectsLabels.FormTitle;
+ ActiveProjectsTabPage.Text = ProjectsLabels.TabActiveTitle;
+ ArchivedCustomersTabPage.Text = ProjectsLabels.TabArchivedTitle;
+ BtnNewProject.Text = ProjectsLabels.ButtonNewActivity;
+ BtnSave.Text = ProjectsLabels.ButtonApply;
+ BtnCancel.Text = ProjectsLabels.ButtonCancel;
+ label1.Text = ProjectsLabels.LabelName;
+ label2.Text = ProjectsLabels.LabelNote;
+ label3.Text = ProjectsLabels.LabelCustomer;
+ label4.Text = ProjectsLabels.LabelBudget;
+ BtnOpenCustomers.Text = ProjectsLabels.ButtonCustomers;
+ CheckBoxArchived.Text = ProjectsLabels.LabelArchived;
+ DeleteToolStripMenuItem.Text = ProjectsLabels.ButtonDelete;
+ ListBudgetType.Items.Add(ProjectsLabels.BudgetHours);
+ ListBudgetType.Items.Add(ProjectsLabels.BudgetEuro);
+ }
+
+ #endregion
+
+ #region Treeviews befüllen
+
+ void TreeDataBackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
+ {
+ if (TreeDataBackgroundWorker.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ ActiveProjects = ProjectService.GetAllActiveProjects();
+ ArchivedProjects = ProjectService.GetAllArchivedProjects();
+
+ var customerService = ObjectFactory.GetInstance();
+ ActiveCustomers = customerService.GetAllActiveCustomers();
+ ArchivedCustomers = customerService.GetAllArchivedCustomers();
+
+ }
+
+ void TreeDataBackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
+ {
+
+ if (ActiveProjects == null || ArchivedProjects == null || ActiveCustomers == null || e.Cancelled)
+ return;
+
+ FillTree(ActiveProjectsTree, ActiveProjects);
+ FillTree(ArchivedProjectsTree, ArchivedProjects);
+
+ ListItem selected = ListCustomers.SelectedItem != null ? (ListItem) ListCustomers.SelectedItem : null;
+ ListCustomers.Items.Clear();
+ ListCustomers.Items.Add(new ListItem {Value = 0, Text = string.Empty});
+
+ foreach (var customer in ActiveCustomers)
+ {
+ ListCustomers.Items.Add(new ListItem {Value = customer.ID, Text = customer.Name});
+ if (selected != null && selected.Value == customer.ID)
+ ListCustomers.SelectedItem = ListCustomers.Items[ListCustomers.Items.Count - 1];
+ }
+
+ foreach (var customer in ArchivedCustomers)
+ {
+ ListCustomers.Items.Add(new ListItem { Value = customer.ID, Text = customer.Name + " (" + ProjectsLabels.LabelArchived + ")"});
+ if (selected != null && selected.Value == customer.ID)
+ ListCustomers.SelectedItem = ListCustomers.Items[ListCustomers.Items.Count - 1];
+ }
+
+ }
+
+ void FillTree(TreeView tree, IList projects)
+ {
+
+ tree.Nodes.Clear();
+
+ var customers = new Dictionary();
+
+ foreach (var project in projects)
+ {
+ if (!customers.ContainsKey(project.CustomerID))
+ customers.Add(project.CustomerID, project.CustomerName);
+ }
+
+ customers.OrderBy(c => c.Value).ToDictionary(c => c.Key, c => c.Value);
+
+ foreach (var customer in customers)
+ {
+ foreach (var project in projects.Where(p => p.CustomerID == customer.Key))
+ {
+ tree.Nodes.Add(project.ID.ToString(), !string.IsNullOrEmpty(customer.Value) ? customer.Value + ": " + project.Name : project.Name);
+ }
+ }
+
+ }
+
+ #endregion
+
+ #region Projekt darstellen
+
+ private void LoadSingleProjectInForm(int projectID)
+ {
+
+ FormGroup.Text = ProjectsLabels.GroupBoxTitleEditMode;
+ CreateNewProject = false;
+ CheckBoxArchived.Visible = true;
+ CurrentProject = ProjectService.GetProjectByID(projectID);
+ BoxName.Text = CurrentProject.Name;
+ BoxNote.Text = CurrentProject.Note;
+ CheckBoxArchived.Checked = CurrentProject.Archived;
+
+ ListBudgetType.SelectedIndex = CurrentProject.BudgetType == "minutes" ? 0 : 1;
+
+ foreach (var customerItem in ListCustomers.Items)
+ {
+ if (((ListItem)customerItem).Value == CurrentProject.CustomerID)
+ {
+ ListCustomers.SelectedItem = customerItem;
+ break;
+ }
+ }
+
+ if (CurrentProject.Budget == 0)
+ {
+ BoxBudget.Text = CurrentProject.BudgetType == "minutes" ? "0:00" : "0,00";
+ }
+ else
+ {
+ if(CurrentProject.BudgetType == "minutes")
+ {
+ BoxBudget.Text = Helper.GetFormattedTimeText(CurrentProject.Budget);
+ }
+ else
+ {
+ if (CurrentProject.Budget % 100 == 0)
+ {
+ BoxBudget.Text = (CurrentProject.Budget / 100).ToString();
+ }
+ else
+ {
+ BoxBudget.Text = (CurrentProject.Budget / 100) + "," +
+ (CurrentProject.Budget % 100).ToString().PadRight(2, '0');
+ }
+
+ if (BoxBudget.Text == "0")
+ BoxBudget.Text = "0,00";
+ else if (BoxBudget.Text.IndexOf(',') < 0)
+ BoxBudget.Text = BoxBudget.Text + ",00";
+ }
+ }
+
+ BtnSave.Enabled = false;
+ FormGroup.Enabled = true;
+ BoxName.Focus();
+ }
+
+ private void BtnOpenCustomers_Click(object sender, EventArgs e)
+ {
+ new Customers().ShowDialog(this);
+ }
+
+ #endregion
+
+ #region Formular zurücksetzen
+
+ private void PrepareFormForNewProject()
+ {
+ ResetForm();
+ FormGroup.Text = ProjectsLabels.GroupBoxTitleCreateMode;
+ FormGroup.Enabled = true;
+ CreateNewProject = true;
+ CheckBoxArchived.Visible = false;
+ BoxName.Focus();
+ }
+
+ private void ResetForm()
+ {
+ FormGroup.Enabled = false;
+ FormGroup.Text = null;
+ CheckBoxArchived.Visible = true;
+ CurrentProject = null;
+ CreateNewProject = false;
+ ActiveProjectsTree.SelectedNode = null;
+ ArchivedProjectsTree.SelectedNode = null;
+ ListCustomers.SelectedItem = null;
+ ListBudgetType.SelectedItem = null;
+ BoxName.Text = null;
+ BoxNote.Text = null;
+ BoxBudget.Text = "0:00";
+ CheckBoxArchived.Checked = false;
+ BtnSave.Enabled = false;
+ ErrorProvider.Clear();
+ }
+
+ #endregion
+
+ #region Projekt erstellen/aktualisieren
+
+ private void BtnSave_Click(object sender, EventArgs e)
+ {
+
+ Cursor = Cursors.WaitCursor;
+
+ var project = CurrentProject ?? new Project();
+ project.Name = BoxName.Text;
+ project.Note = BoxNote.Text;
+ project.Archived = CheckBoxArchived.Checked;
+ project.BudgetType = ListBudgetType.SelectedIndex == 0 ? "minutes" : "cents";
+ project.CustomerID = ListCustomers.SelectedItem != null ? ((ListItem) ListCustomers.SelectedItem).Value : 0;
+
+ var result = CurrentProject != null
+ ? ProjectService.UpdateProject(project, BoxBudget.Text)
+ : ProjectService.CreateProject(project, BoxBudget.Text);
+
+ ErrorProvider.Clear();
+
+ if(result.Count == 0)
+ {
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ if (CreateNewProject)
+ PrepareFormForNewProject();
+ else
+ BtnSave.Enabled = false;
+ Cursor = Cursors.Default;
+ return;
+ }
+
+ if (result.ContainsKey("Name"))
+ ErrorProvider.SetError(BoxName, result["Name"]);
+
+ Cursor = Cursors.Default;
+
+ }
+
+ #endregion
+
+ #region Projekt löschen
+
+ private void DeleteProject(int projectID)
+ {
+
+ var timeEntries = ObjectFactory.GetInstance().GetTimeEntriesByProjectID(projectID);
+
+ if (timeEntries.Count > 0)
+ {
+ MessageBox.Show(ProjectsLabels.MsgBoxDeleteErrorText, ProjectsLabels.MsgBoxDeleteErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+
+ var question = MessageBox.Show(ProjectsLabels.MsgBoxDeleteQuestionText, ProjectsLabels.MsgBoxDeleteQuestionTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+ if (question == DialogResult.Yes)
+ {
+ ProjectService.DeleteProject(projectID);
+ ResetForm();
+ Helper.StartBackgroundWorker(TreeDataBackgroundWorker, null);
+ }
+ }
+
+ #endregion
+
+ #region Event-Handler
+
+ private void BtnNewProject_Click(object sender, EventArgs e)
+ {
+ PrepareFormForNewProject();
+ }
+
+ private void BtnCancel_Click_1(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
+ {
+ e.Node.TreeView.SelectedNode = e.Node;
+ LoadSingleProjectInForm(int.Parse(e.Node.Name));
+ }
+
+ private void DeleteToolStripMenuItem_Click_1(object sender, EventArgs e)
+ {
+ if (ActiveProjectsTabPage.Visible)
+ DeleteProject(int.Parse(ActiveProjectsTree.SelectedNode.Name));
+ else
+ DeleteProject(int.Parse(ArchivedProjectsTree.SelectedNode.Name));
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ Helper.StartBackgroundWorker(((Main)Owner).InitializationBackgroundWorker, null);
+ base.OnClosed(e);
+ }
+
+ private void EnableBtnSave(object sender, EventArgs e)
+ {
+ if (FormGroup.Enabled)
+ BtnSave.Enabled = true;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/App/MiteDesk.WinForms/Projects.resx b/App/MiteDesk.WinForms/Projects.resx
new file mode 100644
index 0000000..42ba458
--- /dev/null
+++ b/App/MiteDesk.WinForms/Projects.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 475, 17
+
+
+ 624, 17
+
+
+ 747, 17
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Properties/AssemblyInfo.cs b/App/MiteDesk.WinForms/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..09a1d89
--- /dev/null
+++ b/App/MiteDesk.WinForms/Properties/AssemblyInfo.cs
@@ -0,0 +1,16 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Resources;
+
+[assembly: AssemblyTitle("mite.desk")]
+[assembly: AssemblyDescription("mite.desk")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("698529cc-b794-49f9-ac63-6d7fe9ae3f24")]
+
+[assembly: AssemblyVersion("1.3.0")]
+[assembly: AssemblyFileVersion("1.3.0")]
+[assembly: NeutralResourcesLanguageAttribute("de-DE")]
diff --git a/App/MiteDesk.WinForms/Properties/Resources.Designer.cs b/App/MiteDesk.WinForms/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..c3d80b7
--- /dev/null
+++ b/App/MiteDesk.WinForms/Properties/Resources.Designer.cs
@@ -0,0 +1,231 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.WinForms.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ internal static System.Drawing.Bitmap Connected {
+ get {
+ object obj = ResourceManager.GetObject("Connected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap Disconnected {
+ get {
+ object obj = ResourceManager.GetObject("Disconnected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap faviconico {
+ get {
+ object obj = ResourceManager.GetObject("faviconico", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap hilfe {
+ get {
+ object obj = ResourceManager.GetObject("hilfe", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap Locked {
+ get {
+ object obj = ResourceManager.GetObject("Locked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap loginhelp {
+ get {
+ object obj = ResourceManager.GetObject("loginhelp", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap logo {
+ get {
+ object obj = ResourceManager.GetObject("logo", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mini_clock_animated_15x15 {
+ get {
+ object obj = ResourceManager.GetObject("mini_clock_animated_15x15", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_1 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_1", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_2 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_2", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_3 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_3", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_4 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_4", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_5 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_5", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_6 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_6", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_7 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_7", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Bitmap mite_desk_icon_16x16_8 {
+ get {
+ object obj = ResourceManager.GetObject("mite_desk_icon_16x16_8", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_1 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_1", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_2 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_2", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_3 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_3", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_4 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_4", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_5 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_5", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_6 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_6", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_7 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_7", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+
+ internal static System.Drawing.Icon mitedesk_clock_8 {
+ get {
+ object obj = ResourceManager.GetObject("mitedesk_clock_8", resourceCulture);
+ return ((System.Drawing.Icon)(obj));
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Properties/Resources.resx b/App/MiteDesk.WinForms/Properties/Resources.resx
new file mode 100644
index 0000000..361cb6b
--- /dev/null
+++ b/App/MiteDesk.WinForms/Properties/Resources.resx
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+
+ ..\Resources\mitedesk_clock_5.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\logo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_8.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\favicon.ico.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\connected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_1.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_7.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_3.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mini_clock_animated_15x15.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_6.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_6.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_7.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_1.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_5.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\loginhelp.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_4.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_4.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_8.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\disconnected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mite.desk_icon_16x16_3.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\mitedesk_clock_2.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\hilfe.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\Locked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Properties/Settings.Designer.cs b/App/MiteDesk.WinForms/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..108fb03
--- /dev/null
+++ b/App/MiteDesk.WinForms/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.WinForms.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/App/MiteDesk.WinForms/Properties/Settings.settings b/App/MiteDesk.WinForms/Properties/Settings.settings
new file mode 100644
index 0000000..8e615f2
--- /dev/null
+++ b/App/MiteDesk.WinForms/Properties/Settings.settings
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Resources/Locked.png b/App/MiteDesk.WinForms/Resources/Locked.png
new file mode 100644
index 0000000..6eaba3c
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/Locked.png differ
diff --git a/App/MiteDesk.WinForms/Resources/Thumbs.db b/App/MiteDesk.WinForms/Resources/Thumbs.db
new file mode 100644
index 0000000..357d69a
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/Thumbs.db differ
diff --git a/App/MiteDesk.WinForms/Resources/connected.png b/App/MiteDesk.WinForms/Resources/connected.png
new file mode 100644
index 0000000..45a2f10
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/connected.png differ
diff --git a/App/MiteDesk.WinForms/Resources/disconnected.png b/App/MiteDesk.WinForms/Resources/disconnected.png
new file mode 100644
index 0000000..967d674
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/disconnected.png differ
diff --git a/App/MiteDesk.WinForms/Resources/favicon.ico.png b/App/MiteDesk.WinForms/Resources/favicon.ico.png
new file mode 100644
index 0000000..7ba63ef
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/favicon.ico.png differ
diff --git a/App/MiteDesk.WinForms/Resources/hilfe.png b/App/MiteDesk.WinForms/Resources/hilfe.png
new file mode 100644
index 0000000..a724b0b
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/hilfe.png differ
diff --git a/App/MiteDesk.WinForms/Resources/loginhelp.png b/App/MiteDesk.WinForms/Resources/loginhelp.png
new file mode 100644
index 0000000..2de252b
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/loginhelp.png differ
diff --git a/App/MiteDesk.WinForms/Resources/logo.png b/App/MiteDesk.WinForms/Resources/logo.png
new file mode 100644
index 0000000..bea2e7c
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/logo.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mini_clock_animated_15x15.gif b/App/MiteDesk.WinForms/Resources/mini_clock_animated_15x15.gif
new file mode 100644
index 0000000..3f8b97e
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mini_clock_animated_15x15.gif differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_1.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_1.png
new file mode 100644
index 0000000..52a51c4
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_1.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_2.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_2.png
new file mode 100644
index 0000000..ebac7eb
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_2.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_3.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_3.png
new file mode 100644
index 0000000..59755d6
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_3.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_4.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_4.png
new file mode 100644
index 0000000..4922672
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_4.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_5.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_5.png
new file mode 100644
index 0000000..852e2e3
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_5.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_6.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_6.png
new file mode 100644
index 0000000..70c861f
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_6.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_7.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_7.png
new file mode 100644
index 0000000..94cdc70
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_7.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_8.png b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_8.png
new file mode 100644
index 0000000..6280eff
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mite.desk_icon_16x16_8.png differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_1.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_1.ico
new file mode 100644
index 0000000..4f9743a
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_1.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_2.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_2.ico
new file mode 100644
index 0000000..2059edb
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_2.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_3.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_3.ico
new file mode 100644
index 0000000..b3fedcf
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_3.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_4.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_4.ico
new file mode 100644
index 0000000..8e376ab
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_4.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_5.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_5.ico
new file mode 100644
index 0000000..0cee071
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_5.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_6.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_6.ico
new file mode 100644
index 0000000..ff25fca
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_6.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_7.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_7.ico
new file mode 100644
index 0000000..b715ebb
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_7.ico differ
diff --git a/App/MiteDesk.WinForms/Resources/mitedesk_clock_8.ico b/App/MiteDesk.WinForms/Resources/mitedesk_clock_8.ico
new file mode 100644
index 0000000..bf277ba
Binary files /dev/null and b/App/MiteDesk.WinForms/Resources/mitedesk_clock_8.ico differ
diff --git a/App/MiteDesk.WinForms/Settings.Designer.cs b/App/MiteDesk.WinForms/Settings.Designer.cs
new file mode 100644
index 0000000..1071dbf
--- /dev/null
+++ b/App/MiteDesk.WinForms/Settings.Designer.cs
@@ -0,0 +1,733 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ partial class Settings
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.ButtonCancel = new System.Windows.Forms.Button();
+ this.ButtonOK = new System.Windows.Forms.Button();
+ this.CheckConnectionButton = new System.Windows.Forms.Button();
+ this.ErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+ this.checkBox1 = new System.Windows.Forms.CheckBox();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.label8 = new System.Windows.Forms.Label();
+ this.ExtendedTab = new System.Windows.Forms.TabPage();
+ this.groupBox5 = new System.Windows.Forms.GroupBox();
+ this.MinimizeByClosing = new System.Windows.Forms.CheckBox();
+ this.StopStopwatchByClosing = new System.Windows.Forms.CheckBox();
+ this.AskForStoppingStopwatchByClosing = new System.Windows.Forms.CheckBox();
+ this.groupBox2 = new System.Windows.Forms.GroupBox();
+ this.EnableAutostart = new System.Windows.Forms.CheckBox();
+ this.StartMinimized = new System.Windows.Forms.CheckBox();
+ this.groupBox8 = new System.Windows.Forms.GroupBox();
+ this.SortDescending = new System.Windows.Forms.CheckBox();
+ this.LanguageTab = new System.Windows.Forms.TabPage();
+ this.groupBox6 = new System.Windows.Forms.GroupBox();
+ this.ListLanguages = new System.Windows.Forms.ComboBox();
+ this.NetworkTab = new System.Windows.Forms.TabPage();
+ this.groupBox7 = new System.Windows.Forms.GroupBox();
+ this.label9 = new System.Windows.Forms.Label();
+ this.ProxyServer = new System.Windows.Forms.TextBox();
+ this.label10 = new System.Windows.Forms.Label();
+ this.ProxyPort = new System.Windows.Forms.NumericUpDown();
+ this.BoxUseProxyServer = new System.Windows.Forms.CheckBox();
+ this.LblProxyPassword = new System.Windows.Forms.Label();
+ this.LblProxyUser = new System.Windows.Forms.Label();
+ this.ProxyPassword = new System.Windows.Forms.TextBox();
+ this.ProxyUser = new System.Windows.Forms.TextBox();
+ this.checkBox2 = new System.Windows.Forms.CheckBox();
+ this.AccountTab = new System.Windows.Forms.TabPage();
+ this.GroupBoxAuthenticateByAPIKey = new System.Windows.Forms.GroupBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.APIKey = new System.Windows.Forms.TextBox();
+ this.GroupBoxAuthenticateByEmailAndPassword = new System.Windows.Forms.GroupBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.Password = new System.Windows.Forms.TextBox();
+ this.Email = new System.Windows.Forms.TextBox();
+ this.CheckBoxShowPasswordInClearText = new System.Windows.Forms.CheckBox();
+ this.groupBox1 = new System.Windows.Forms.GroupBox();
+ this.AccountName = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.AuthenticateByEmailAndPassword = new System.Windows.Forms.RadioButton();
+ this.AuthenticateByAPIKey = new System.Windows.Forms.RadioButton();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.label11 = new System.Windows.Forms.Label();
+ this.label12 = new System.Windows.Forms.Label();
+ this.TabContainer = new System.Windows.Forms.TabControl();
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).BeginInit();
+ this.ExtendedTab.SuspendLayout();
+ this.groupBox5.SuspendLayout();
+ this.groupBox2.SuspendLayout();
+ this.groupBox8.SuspendLayout();
+ this.LanguageTab.SuspendLayout();
+ this.groupBox6.SuspendLayout();
+ this.NetworkTab.SuspendLayout();
+ this.groupBox7.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ProxyPort)).BeginInit();
+ this.AccountTab.SuspendLayout();
+ this.GroupBoxAuthenticateByAPIKey.SuspendLayout();
+ this.GroupBoxAuthenticateByEmailAndPassword.SuspendLayout();
+ this.groupBox1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.TabContainer.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // ButtonCancel
+ //
+ this.ButtonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.ButtonCancel.Location = new System.Drawing.Point(365, 324);
+ this.ButtonCancel.Name = "ButtonCancel";
+ this.ButtonCancel.Size = new System.Drawing.Size(75, 23);
+ this.ButtonCancel.TabIndex = 11;
+ this.ButtonCancel.Text = "Abbrechen";
+ this.ButtonCancel.UseVisualStyleBackColor = true;
+ this.ButtonCancel.Click += new System.EventHandler(this.ButtonCancel_Click);
+ //
+ // ButtonOK
+ //
+ this.ButtonOK.Location = new System.Drawing.Point(283, 324);
+ this.ButtonOK.Name = "ButtonOK";
+ this.ButtonOK.Size = new System.Drawing.Size(75, 23);
+ this.ButtonOK.TabIndex = 10;
+ this.ButtonOK.Text = "OK";
+ this.ButtonOK.UseVisualStyleBackColor = true;
+ this.ButtonOK.Click += new System.EventHandler(this.ButtonOK_Click);
+ //
+ // CheckConnectionButton
+ //
+ this.CheckConnectionButton.Location = new System.Drawing.Point(9, 324);
+ this.CheckConnectionButton.Name = "CheckConnectionButton";
+ this.CheckConnectionButton.Size = new System.Drawing.Size(107, 23);
+ this.CheckConnectionButton.TabIndex = 9;
+ this.CheckConnectionButton.Text = "Verbindung testen";
+ this.CheckConnectionButton.UseVisualStyleBackColor = true;
+ this.CheckConnectionButton.Click += new System.EventHandler(this.button1_Click);
+ //
+ // ErrorProvider
+ //
+ this.ErrorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+ this.ErrorProvider.ContainerControl = this;
+ //
+ // checkBox1
+ //
+ this.checkBox1.AutoSize = true;
+ this.checkBox1.Location = new System.Drawing.Point(10, 23);
+ this.checkBox1.Name = "checkBox1";
+ this.checkBox1.Size = new System.Drawing.Size(297, 17);
+ this.checkBox1.TabIndex = 8;
+ this.checkBox1.Text = "Sichere Verbindung mit SSL-Verschlüsselung verwenden.";
+ this.checkBox1.UseVisualStyleBackColor = true;
+ //
+ // textBox1
+ //
+ this.textBox1.Location = new System.Drawing.Point(111, 26);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(276, 20);
+ this.textBox1.TabIndex = 7;
+ //
+ // label8
+ //
+ this.label8.AutoSize = true;
+ this.label8.Location = new System.Drawing.Point(7, 29);
+ this.label8.Name = "label8";
+ this.label8.Size = new System.Drawing.Size(52, 13);
+ this.label8.TabIndex = 7;
+ this.label8.Text = "Schlüssel";
+ //
+ // ExtendedTab
+ //
+ this.ExtendedTab.Controls.Add(this.groupBox8);
+ this.ExtendedTab.Controls.Add(this.groupBox2);
+ this.ExtendedTab.Controls.Add(this.groupBox5);
+ this.ExtendedTab.Location = new System.Drawing.Point(4, 22);
+ this.ExtendedTab.Name = "ExtendedTab";
+ this.ExtendedTab.Padding = new System.Windows.Forms.Padding(3);
+ this.ExtendedTab.Size = new System.Drawing.Size(423, 279);
+ this.ExtendedTab.TabIndex = 2;
+ this.ExtendedTab.Text = "Erweitert";
+ this.ExtendedTab.UseVisualStyleBackColor = true;
+ //
+ // groupBox5
+ //
+ this.groupBox5.Controls.Add(this.AskForStoppingStopwatchByClosing);
+ this.groupBox5.Controls.Add(this.StopStopwatchByClosing);
+ this.groupBox5.Controls.Add(this.MinimizeByClosing);
+ this.groupBox5.Location = new System.Drawing.Point(8, 83);
+ this.groupBox5.Name = "groupBox5";
+ this.groupBox5.Size = new System.Drawing.Size(406, 96);
+ this.groupBox5.TabIndex = 10;
+ this.groupBox5.TabStop = false;
+ this.groupBox5.Text = "Beenden";
+ //
+ // MinimizeByClosing
+ //
+ this.MinimizeByClosing.AutoSize = true;
+ this.MinimizeByClosing.Location = new System.Drawing.Point(10, 23);
+ this.MinimizeByClosing.Name = "MinimizeByClosing";
+ this.MinimizeByClosing.Size = new System.Drawing.Size(376, 17);
+ this.MinimizeByClosing.TabIndex = 4;
+ this.MinimizeByClosing.Text = "mite.desk beim Schließen des Fensters nicht beenden, sondern minimieren";
+ this.MinimizeByClosing.UseVisualStyleBackColor = true;
+ //
+ // StopStopwatchByClosing
+ //
+ this.StopStopwatchByClosing.AutoSize = true;
+ this.StopStopwatchByClosing.Location = new System.Drawing.Point(10, 47);
+ this.StopStopwatchByClosing.Name = "StopStopwatchByClosing";
+ this.StopStopwatchByClosing.Size = new System.Drawing.Size(262, 17);
+ this.StopStopwatchByClosing.TabIndex = 5;
+ this.StopStopwatchByClosing.Text = "Beim Beenden die Stoppuhr automatisch anhalten";
+ this.StopStopwatchByClosing.UseVisualStyleBackColor = true;
+ this.StopStopwatchByClosing.CheckedChanged += new System.EventHandler(this.StopStopwatchByClosing_CheckedChanged);
+ //
+ // AskForStoppingStopwatchByClosing
+ //
+ this.AskForStoppingStopwatchByClosing.AutoSize = true;
+ this.AskForStoppingStopwatchByClosing.Location = new System.Drawing.Point(10, 71);
+ this.AskForStoppingStopwatchByClosing.Name = "AskForStoppingStopwatchByClosing";
+ this.AskForStoppingStopwatchByClosing.Size = new System.Drawing.Size(337, 17);
+ this.AskForStoppingStopwatchByClosing.TabIndex = 6;
+ this.AskForStoppingStopwatchByClosing.Text = "Vor dem Beenden fragen, ob die Stoppuhr angehalten werden soll";
+ this.AskForStoppingStopwatchByClosing.UseVisualStyleBackColor = true;
+ this.AskForStoppingStopwatchByClosing.CheckedChanged += new System.EventHandler(this.AskForStoppingStopwatchByClosing_CheckedChanged);
+ //
+ // groupBox2
+ //
+ this.groupBox2.Controls.Add(this.StartMinimized);
+ this.groupBox2.Controls.Add(this.EnableAutostart);
+ this.groupBox2.Location = new System.Drawing.Point(8, 6);
+ this.groupBox2.Name = "groupBox2";
+ this.groupBox2.Size = new System.Drawing.Size(406, 71);
+ this.groupBox2.TabIndex = 11;
+ this.groupBox2.TabStop = false;
+ this.groupBox2.Text = "Start";
+ //
+ // EnableAutostart
+ //
+ this.EnableAutostart.AutoSize = true;
+ this.EnableAutostart.Location = new System.Drawing.Point(10, 23);
+ this.EnableAutostart.Name = "EnableAutostart";
+ this.EnableAutostart.Size = new System.Drawing.Size(355, 17);
+ this.EnableAutostart.TabIndex = 1;
+ this.EnableAutostart.Text = "mite.desk bei der Windows-Anmeldung automatisch starten (Autostart)";
+ this.EnableAutostart.UseVisualStyleBackColor = true;
+ //
+ // StartMinimized
+ //
+ this.StartMinimized.AutoSize = true;
+ this.StartMinimized.Location = new System.Drawing.Point(10, 46);
+ this.StartMinimized.Name = "StartMinimized";
+ this.StartMinimized.Size = new System.Drawing.Size(102, 17);
+ this.StartMinimized.TabIndex = 2;
+ this.StartMinimized.Text = "Minimiert starten";
+ this.StartMinimized.UseVisualStyleBackColor = true;
+ //
+ // groupBox8
+ //
+ this.groupBox8.Controls.Add(this.SortDescending);
+ this.groupBox8.Location = new System.Drawing.Point(8, 185);
+ this.groupBox8.Name = "groupBox8";
+ this.groupBox8.Size = new System.Drawing.Size(406, 49);
+ this.groupBox8.TabIndex = 11;
+ this.groupBox8.TabStop = false;
+ this.groupBox8.Text = "Zeiteinträge";
+ //
+ // SortDescending
+ //
+ this.SortDescending.AutoSize = true;
+ this.SortDescending.Location = new System.Drawing.Point(10, 23);
+ this.SortDescending.Name = "SortDescending";
+ this.SortDescending.Size = new System.Drawing.Size(319, 17);
+ this.SortDescending.TabIndex = 4;
+ this.SortDescending.Text = "Einträge in umgekehrter Reihenfolge sortieren (neueste zuerst)";
+ this.SortDescending.UseVisualStyleBackColor = true;
+ //
+ // LanguageTab
+ //
+ this.LanguageTab.Controls.Add(this.groupBox6);
+ this.LanguageTab.Location = new System.Drawing.Point(4, 22);
+ this.LanguageTab.Name = "LanguageTab";
+ this.LanguageTab.Size = new System.Drawing.Size(423, 279);
+ this.LanguageTab.TabIndex = 3;
+ this.LanguageTab.Text = "Sprache";
+ this.LanguageTab.UseVisualStyleBackColor = true;
+ //
+ // groupBox6
+ //
+ this.groupBox6.Controls.Add(this.ListLanguages);
+ this.groupBox6.Location = new System.Drawing.Point(6, 6);
+ this.groupBox6.Name = "groupBox6";
+ this.groupBox6.Size = new System.Drawing.Size(406, 58);
+ this.groupBox6.TabIndex = 1;
+ this.groupBox6.TabStop = false;
+ this.groupBox6.Text = "Sprache";
+ //
+ // ListLanguages
+ //
+ this.ListLanguages.FormattingEnabled = true;
+ this.ListLanguages.Items.AddRange(new object[] {
+ "Deutsch",
+ "English"});
+ this.ListLanguages.Location = new System.Drawing.Point(10, 23);
+ this.ListLanguages.Name = "ListLanguages";
+ this.ListLanguages.Size = new System.Drawing.Size(383, 21);
+ this.ListLanguages.TabIndex = 0;
+ //
+ // NetworkTab
+ //
+ this.NetworkTab.Controls.Add(this.groupBox7);
+ this.NetworkTab.Location = new System.Drawing.Point(4, 22);
+ this.NetworkTab.Name = "NetworkTab";
+ this.NetworkTab.Padding = new System.Windows.Forms.Padding(3);
+ this.NetworkTab.Size = new System.Drawing.Size(423, 279);
+ this.NetworkTab.TabIndex = 1;
+ this.NetworkTab.Text = "Netzwerk";
+ this.NetworkTab.UseVisualStyleBackColor = true;
+ //
+ // groupBox7
+ //
+ this.groupBox7.Controls.Add(this.checkBox2);
+ this.groupBox7.Controls.Add(this.ProxyUser);
+ this.groupBox7.Controls.Add(this.ProxyPassword);
+ this.groupBox7.Controls.Add(this.LblProxyUser);
+ this.groupBox7.Controls.Add(this.LblProxyPassword);
+ this.groupBox7.Controls.Add(this.BoxUseProxyServer);
+ this.groupBox7.Controls.Add(this.ProxyPort);
+ this.groupBox7.Controls.Add(this.label10);
+ this.groupBox7.Controls.Add(this.ProxyServer);
+ this.groupBox7.Controls.Add(this.label9);
+ this.groupBox7.Location = new System.Drawing.Point(6, 6);
+ this.groupBox7.Name = "groupBox7";
+ this.groupBox7.Size = new System.Drawing.Size(406, 158);
+ this.groupBox7.TabIndex = 1;
+ this.groupBox7.TabStop = false;
+ this.groupBox7.Text = "Proxy";
+ //
+ // label9
+ //
+ this.label9.AutoSize = true;
+ this.label9.Location = new System.Drawing.Point(9, 49);
+ this.label9.Name = "label9";
+ this.label9.Size = new System.Drawing.Size(67, 13);
+ this.label9.TabIndex = 7;
+ this.label9.Text = "Proxy-Server";
+ //
+ // ProxyServer
+ //
+ this.ProxyServer.Location = new System.Drawing.Point(113, 46);
+ this.ProxyServer.Name = "ProxyServer";
+ this.ProxyServer.Size = new System.Drawing.Size(174, 20);
+ this.ProxyServer.TabIndex = 10;
+ //
+ // label10
+ //
+ this.label10.AutoSize = true;
+ this.label10.Location = new System.Drawing.Point(293, 49);
+ this.label10.Name = "label10";
+ this.label10.Size = new System.Drawing.Size(26, 13);
+ this.label10.TabIndex = 8;
+ this.label10.Text = "Port";
+ //
+ // ProxyPort
+ //
+ this.ProxyPort.Location = new System.Drawing.Point(325, 46);
+ this.ProxyPort.Maximum = new decimal(new int[] {
+ 65535,
+ 0,
+ 0,
+ 0});
+ this.ProxyPort.Name = "ProxyPort";
+ this.ProxyPort.Size = new System.Drawing.Size(64, 20);
+ this.ProxyPort.TabIndex = 11;
+ //
+ // BoxUseProxyServer
+ //
+ this.BoxUseProxyServer.AutoSize = true;
+ this.BoxUseProxyServer.Location = new System.Drawing.Point(10, 20);
+ this.BoxUseProxyServer.Name = "BoxUseProxyServer";
+ this.BoxUseProxyServer.Size = new System.Drawing.Size(142, 17);
+ this.BoxUseProxyServer.TabIndex = 9;
+ this.BoxUseProxyServer.Text = "Proxy-Server verwenden";
+ this.BoxUseProxyServer.UseVisualStyleBackColor = true;
+ this.BoxUseProxyServer.CheckedChanged += new System.EventHandler(this.BoxUseProxy_CheckedChanged);
+ //
+ // LblProxyPassword
+ //
+ this.LblProxyPassword.AutoSize = true;
+ this.LblProxyPassword.Location = new System.Drawing.Point(9, 107);
+ this.LblProxyPassword.Name = "LblProxyPassword";
+ this.LblProxyPassword.Size = new System.Drawing.Size(50, 13);
+ this.LblProxyPassword.TabIndex = 13;
+ this.LblProxyPassword.Text = "Passwort";
+ //
+ // LblProxyUser
+ //
+ this.LblProxyUser.AutoSize = true;
+ this.LblProxyUser.Location = new System.Drawing.Point(9, 77);
+ this.LblProxyUser.Name = "LblProxyUser";
+ this.LblProxyUser.Size = new System.Drawing.Size(55, 13);
+ this.LblProxyUser.TabIndex = 12;
+ this.LblProxyUser.Text = "Username";
+ //
+ // ProxyPassword
+ //
+ this.ProxyPassword.Location = new System.Drawing.Point(113, 104);
+ this.ProxyPassword.Name = "ProxyPassword";
+ this.ProxyPassword.Size = new System.Drawing.Size(276, 20);
+ this.ProxyPassword.TabIndex = 15;
+ this.ProxyPassword.UseSystemPasswordChar = true;
+ //
+ // ProxyUser
+ //
+ this.ProxyUser.Location = new System.Drawing.Point(113, 74);
+ this.ProxyUser.Name = "ProxyUser";
+ this.ProxyUser.Size = new System.Drawing.Size(276, 20);
+ this.ProxyUser.TabIndex = 14;
+ //
+ // checkBox2
+ //
+ this.checkBox2.AutoSize = true;
+ this.checkBox2.Location = new System.Drawing.Point(113, 130);
+ this.checkBox2.Name = "checkBox2";
+ this.checkBox2.Size = new System.Drawing.Size(115, 17);
+ this.checkBox2.TabIndex = 16;
+ this.checkBox2.Text = "Passwort anzeigen";
+ this.checkBox2.UseVisualStyleBackColor = true;
+ this.checkBox2.CheckedChanged += new System.EventHandler(this.checkBox2_CheckedChanged);
+ //
+ // AccountTab
+ //
+ this.AccountTab.Controls.Add(this.groupBox1);
+ this.AccountTab.Controls.Add(this.GroupBoxAuthenticateByEmailAndPassword);
+ this.AccountTab.Controls.Add(this.GroupBoxAuthenticateByAPIKey);
+ this.AccountTab.Location = new System.Drawing.Point(4, 22);
+ this.AccountTab.Name = "AccountTab";
+ this.AccountTab.Padding = new System.Windows.Forms.Padding(3);
+ this.AccountTab.Size = new System.Drawing.Size(423, 279);
+ this.AccountTab.TabIndex = 0;
+ this.AccountTab.Text = "Account";
+ this.AccountTab.UseVisualStyleBackColor = true;
+ //
+ // GroupBoxAuthenticateByAPIKey
+ //
+ this.GroupBoxAuthenticateByAPIKey.Controls.Add(this.APIKey);
+ this.GroupBoxAuthenticateByAPIKey.Controls.Add(this.label4);
+ this.GroupBoxAuthenticateByAPIKey.Location = new System.Drawing.Point(6, 207);
+ this.GroupBoxAuthenticateByAPIKey.Name = "GroupBoxAuthenticateByAPIKey";
+ this.GroupBoxAuthenticateByAPIKey.Size = new System.Drawing.Size(406, 61);
+ this.GroupBoxAuthenticateByAPIKey.TabIndex = 0;
+ this.GroupBoxAuthenticateByAPIKey.TabStop = false;
+ this.GroupBoxAuthenticateByAPIKey.Text = "Anmeldung per API-Schlüssel";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(7, 29);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(52, 13);
+ this.label4.TabIndex = 7;
+ this.label4.Text = "Schlüssel";
+ //
+ // APIKey
+ //
+ this.APIKey.Location = new System.Drawing.Point(111, 26);
+ this.APIKey.Name = "APIKey";
+ this.APIKey.Size = new System.Drawing.Size(276, 20);
+ this.APIKey.TabIndex = 7;
+ //
+ // GroupBoxAuthenticateByEmailAndPassword
+ //
+ this.GroupBoxAuthenticateByEmailAndPassword.Controls.Add(this.CheckBoxShowPasswordInClearText);
+ this.GroupBoxAuthenticateByEmailAndPassword.Controls.Add(this.Email);
+ this.GroupBoxAuthenticateByEmailAndPassword.Controls.Add(this.Password);
+ this.GroupBoxAuthenticateByEmailAndPassword.Controls.Add(this.label2);
+ this.GroupBoxAuthenticateByEmailAndPassword.Controls.Add(this.label3);
+ this.GroupBoxAuthenticateByEmailAndPassword.Location = new System.Drawing.Point(6, 91);
+ this.GroupBoxAuthenticateByEmailAndPassword.Name = "GroupBoxAuthenticateByEmailAndPassword";
+ this.GroupBoxAuthenticateByEmailAndPassword.Size = new System.Drawing.Size(406, 110);
+ this.GroupBoxAuthenticateByEmailAndPassword.TabIndex = 0;
+ this.GroupBoxAuthenticateByEmailAndPassword.TabStop = false;
+ this.GroupBoxAuthenticateByEmailAndPassword.Text = "Anmeldung per E-Mail/Passwort";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(7, 58);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(50, 13);
+ this.label3.TabIndex = 2;
+ this.label3.Text = "Passwort";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(7, 28);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(77, 13);
+ this.label2.TabIndex = 1;
+ this.label2.Text = "E-Mail-Adresse";
+ //
+ // Password
+ //
+ this.Password.Location = new System.Drawing.Point(111, 55);
+ this.Password.Name = "Password";
+ this.Password.Size = new System.Drawing.Size(276, 20);
+ this.Password.TabIndex = 5;
+ this.Password.UseSystemPasswordChar = true;
+ //
+ // Email
+ //
+ this.Email.Location = new System.Drawing.Point(111, 25);
+ this.Email.Name = "Email";
+ this.Email.Size = new System.Drawing.Size(276, 20);
+ this.Email.TabIndex = 4;
+ //
+ // CheckBoxShowPasswordInClearText
+ //
+ this.CheckBoxShowPasswordInClearText.AutoSize = true;
+ this.CheckBoxShowPasswordInClearText.Location = new System.Drawing.Point(111, 81);
+ this.CheckBoxShowPasswordInClearText.Name = "CheckBoxShowPasswordInClearText";
+ this.CheckBoxShowPasswordInClearText.Size = new System.Drawing.Size(115, 17);
+ this.CheckBoxShowPasswordInClearText.TabIndex = 6;
+ this.CheckBoxShowPasswordInClearText.Text = "Passwort anzeigen";
+ this.CheckBoxShowPasswordInClearText.UseVisualStyleBackColor = true;
+ this.CheckBoxShowPasswordInClearText.CheckedChanged += new System.EventHandler(this.CheckBoxShowPasswordInClearText_CheckedChanged_1);
+ //
+ // groupBox1
+ //
+ this.groupBox1.Controls.Add(this.label12);
+ this.groupBox1.Controls.Add(this.label11);
+ this.groupBox1.Controls.Add(this.pictureBox1);
+ this.groupBox1.Controls.Add(this.AuthenticateByAPIKey);
+ this.groupBox1.Controls.Add(this.AuthenticateByEmailAndPassword);
+ this.groupBox1.Controls.Add(this.label5);
+ this.groupBox1.Controls.Add(this.label1);
+ this.groupBox1.Controls.Add(this.AccountName);
+ this.groupBox1.Location = new System.Drawing.Point(6, 6);
+ this.groupBox1.Name = "groupBox1";
+ this.groupBox1.Size = new System.Drawing.Size(406, 79);
+ this.groupBox1.TabIndex = 0;
+ this.groupBox1.TabStop = false;
+ this.groupBox1.Text = "Account";
+ //
+ // AccountName
+ //
+ this.AccountName.Location = new System.Drawing.Point(152, 18);
+ this.AccountName.Name = "AccountName";
+ this.AccountName.Size = new System.Drawing.Size(173, 20);
+ this.AccountName.TabIndex = 1;
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(7, 22);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(33, 13);
+ this.label1.TabIndex = 4;
+ this.label1.Text = "Login";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(7, 51);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(71, 13);
+ this.label5.TabIndex = 5;
+ this.label5.Text = "Anmelden via";
+ //
+ // AuthenticateByEmailAndPassword
+ //
+ this.AuthenticateByEmailAndPassword.AutoSize = true;
+ this.AuthenticateByEmailAndPassword.Location = new System.Drawing.Point(111, 49);
+ this.AuthenticateByEmailAndPassword.Name = "AuthenticateByEmailAndPassword";
+ this.AuthenticateByEmailAndPassword.Size = new System.Drawing.Size(102, 17);
+ this.AuthenticateByEmailAndPassword.TabIndex = 2;
+ this.AuthenticateByEmailAndPassword.TabStop = true;
+ this.AuthenticateByEmailAndPassword.Text = "E-Mail/Passwort";
+ this.AuthenticateByEmailAndPassword.UseVisualStyleBackColor = true;
+ this.AuthenticateByEmailAndPassword.Click += new System.EventHandler(this.RadioAuthByEmailAndPassword_Click);
+ //
+ // AuthenticateByAPIKey
+ //
+ this.AuthenticateByAPIKey.AutoSize = true;
+ this.AuthenticateByAPIKey.Location = new System.Drawing.Point(235, 49);
+ this.AuthenticateByAPIKey.Name = "AuthenticateByAPIKey";
+ this.AuthenticateByAPIKey.Size = new System.Drawing.Size(90, 17);
+ this.AuthenticateByAPIKey.TabIndex = 3;
+ this.AuthenticateByAPIKey.TabStop = true;
+ this.AuthenticateByAPIKey.Text = "API-Schlüssel";
+ this.AuthenticateByAPIKey.UseVisualStyleBackColor = true;
+ this.AuthenticateByAPIKey.Click += new System.EventHandler(this.RadioAuthByAPIKey_Click);
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Cursor = System.Windows.Forms.Cursors.Hand;
+ this.pictureBox1.Image = global::SixtyNineDegrees.MiteDesk.WinForms.Properties.Resources.hilfe;
+ this.pictureBox1.Location = new System.Drawing.Point(41, 22);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(16, 16);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.pictureBox1.TabIndex = 10;
+ this.pictureBox1.TabStop = false;
+ this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click);
+ //
+ // label11
+ //
+ this.label11.AutoSize = true;
+ this.label11.Location = new System.Drawing.Point(108, 22);
+ this.label11.Name = "label11";
+ this.label11.Size = new System.Drawing.Size(43, 13);
+ this.label11.TabIndex = 11;
+ this.label11.Text = "https://";
+ //
+ // label12
+ //
+ this.label12.AutoSize = true;
+ this.label12.Location = new System.Drawing.Point(326, 22);
+ this.label12.Name = "label12";
+ this.label12.Size = new System.Drawing.Size(54, 13);
+ this.label12.TabIndex = 12;
+ this.label12.Text = ".mite.yo.lk";
+ //
+ // TabContainer
+ //
+ this.TabContainer.Controls.Add(this.AccountTab);
+ this.TabContainer.Controls.Add(this.NetworkTab);
+ this.TabContainer.Controls.Add(this.LanguageTab);
+ this.TabContainer.Controls.Add(this.ExtendedTab);
+ this.TabContainer.Location = new System.Drawing.Point(9, 10);
+ this.TabContainer.Name = "TabContainer";
+ this.TabContainer.SelectedIndex = 0;
+ this.TabContainer.Size = new System.Drawing.Size(431, 305);
+ this.TabContainer.TabIndex = 12;
+ //
+ // Settings
+ //
+ this.AcceptButton = this.ButtonOK;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.ButtonCancel;
+ this.ClientSize = new System.Drawing.Size(449, 356);
+ this.Controls.Add(this.TabContainer);
+ this.Controls.Add(this.CheckConnectionButton);
+ this.Controls.Add(this.ButtonOK);
+ this.Controls.Add(this.ButtonCancel);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "Settings";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Einstellungen";
+ ((System.ComponentModel.ISupportInitialize)(this.ErrorProvider)).EndInit();
+ this.ExtendedTab.ResumeLayout(false);
+ this.groupBox5.ResumeLayout(false);
+ this.groupBox5.PerformLayout();
+ this.groupBox2.ResumeLayout(false);
+ this.groupBox2.PerformLayout();
+ this.groupBox8.ResumeLayout(false);
+ this.groupBox8.PerformLayout();
+ this.LanguageTab.ResumeLayout(false);
+ this.groupBox6.ResumeLayout(false);
+ this.NetworkTab.ResumeLayout(false);
+ this.groupBox7.ResumeLayout(false);
+ this.groupBox7.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ProxyPort)).EndInit();
+ this.AccountTab.ResumeLayout(false);
+ this.GroupBoxAuthenticateByAPIKey.ResumeLayout(false);
+ this.GroupBoxAuthenticateByAPIKey.PerformLayout();
+ this.GroupBoxAuthenticateByEmailAndPassword.ResumeLayout(false);
+ this.GroupBoxAuthenticateByEmailAndPassword.PerformLayout();
+ this.groupBox1.ResumeLayout(false);
+ this.groupBox1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.TabContainer.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button ButtonCancel;
+ private System.Windows.Forms.Button ButtonOK;
+ private System.Windows.Forms.Button CheckConnectionButton;
+ private System.Windows.Forms.ErrorProvider ErrorProvider;
+ private System.Windows.Forms.CheckBox checkBox1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Label label8;
+ private System.Windows.Forms.TabControl TabContainer;
+ private System.Windows.Forms.TabPage AccountTab;
+ private System.Windows.Forms.GroupBox groupBox1;
+ private System.Windows.Forms.Label label12;
+ private System.Windows.Forms.Label label11;
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.RadioButton AuthenticateByAPIKey;
+ private System.Windows.Forms.RadioButton AuthenticateByEmailAndPassword;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox AccountName;
+ private System.Windows.Forms.GroupBox GroupBoxAuthenticateByEmailAndPassword;
+ private System.Windows.Forms.CheckBox CheckBoxShowPasswordInClearText;
+ private System.Windows.Forms.TextBox Email;
+ private System.Windows.Forms.TextBox Password;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.GroupBox GroupBoxAuthenticateByAPIKey;
+ private System.Windows.Forms.TextBox APIKey;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.TabPage NetworkTab;
+ private System.Windows.Forms.GroupBox groupBox7;
+ private System.Windows.Forms.CheckBox checkBox2;
+ private System.Windows.Forms.TextBox ProxyUser;
+ private System.Windows.Forms.TextBox ProxyPassword;
+ private System.Windows.Forms.Label LblProxyUser;
+ private System.Windows.Forms.Label LblProxyPassword;
+ private System.Windows.Forms.CheckBox BoxUseProxyServer;
+ private System.Windows.Forms.NumericUpDown ProxyPort;
+ private System.Windows.Forms.Label label10;
+ private System.Windows.Forms.TextBox ProxyServer;
+ private System.Windows.Forms.Label label9;
+ private System.Windows.Forms.TabPage LanguageTab;
+ private System.Windows.Forms.GroupBox groupBox6;
+ private System.Windows.Forms.ComboBox ListLanguages;
+ private System.Windows.Forms.TabPage ExtendedTab;
+ private System.Windows.Forms.GroupBox groupBox8;
+ private System.Windows.Forms.CheckBox SortDescending;
+ private System.Windows.Forms.GroupBox groupBox2;
+ private System.Windows.Forms.CheckBox StartMinimized;
+ private System.Windows.Forms.CheckBox EnableAutostart;
+ private System.Windows.Forms.GroupBox groupBox5;
+ private System.Windows.Forms.CheckBox AskForStoppingStopwatchByClosing;
+ private System.Windows.Forms.CheckBox StopStopwatchByClosing;
+ private System.Windows.Forms.CheckBox MinimizeByClosing;
+ }
+}
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Settings.cs b/App/MiteDesk.WinForms/Settings.cs
new file mode 100644
index 0000000..b1ba037
--- /dev/null
+++ b/App/MiteDesk.WinForms/Settings.cs
@@ -0,0 +1,309 @@
+using System;
+using System.Windows.Forms;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Core.Services;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+using SixtyNineDegrees.MiteDesk.WinForms.Localization;
+using StructureMap;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public partial class Settings : Form
+ {
+
+ public bool ReLocalize;
+ public AppSettings AppSettings;
+
+ public Settings(bool firstSetup)
+ {
+
+ ReLocalize = false;
+ FirstSetup = firstSetup;
+
+ InitializeComponent();
+ LocalizeForm();
+
+ Config = ObjectFactory.GetInstance();
+
+ TabContainer.SelectedIndexChanged += TabContainer_SelectedIndexChanged;
+
+ AppSettings = Config.GetAppSettings();
+ MinimizeByClosing.Checked = AppSettings.MinimizeByClosing;
+ EnableAutostart.Checked = AppSettings.Autostart;
+ AccountName.Text = AppSettings.AccountName;
+ StartMinimized.Checked = AppSettings.StartMinimized;
+ BoxUseProxyServer.Checked = AppSettings.UseProxy;
+ StopStopwatchByClosing.Checked = AppSettings.StopStopwatchByClosing;
+ AskForStoppingStopwatchByClosing.Checked = AppSettings.AskForStoppingStopwatchByClosing;
+ SortDescending.Checked = AppSettings.SortTimeEntriesDescending;
+
+ SetProxyPanel();
+ if (BoxUseProxyServer.Checked)
+ {
+ ProxyServer.Text = AppSettings.ProxyServer;
+ ProxyPort.Value = AppSettings.ProxyPort;
+ ProxyUser.Text = AppSettings.ProxyUser;
+ ProxyPassword.Text = AppSettings.ProxyPassword;
+ }
+
+ if (!string.IsNullOrEmpty(AppSettings.APIKey))
+ {
+ APIKey.Text = AppSettings.APIKey;
+ SetAuthentiactionByAPIKey();
+ }
+ else
+ {
+ SetAuthenticationByEmailAndPassword();
+ Email.Text = AppSettings.Email;
+ Password.Text = AppSettings.Password;
+ }
+
+ ListLanguages.SelectedIndex = AppSettings.Culture == "en-US" ? 1 : 0;
+
+ if (firstSetup)
+ ShowFirstSetupMessage();
+
+ }
+
+ void LocalizeForm()
+ {
+
+ #region Lokalisierung
+
+ Text = SettingsLabels.FormTitle;
+
+ AccountTab.Text = SettingsLabels.TabAccount;
+ LanguageTab.Text = SettingsLabels.TabLanguage;
+ ExtendedTab.Text = SettingsLabels.TabAdvanced;
+ NetworkTab.Text = SettingsLabels.TabNetwork;
+
+ CheckConnectionButton.Text = SettingsLabels.ButtonCheckConnection;
+ ButtonOK.Text = SettingsLabels.ButtonOK;
+ ButtonCancel.Text = SettingsLabels.ButtonCancel;
+
+ groupBox1.Text = SettingsLabels.AccountGroupboxTitle;
+ GroupBoxAuthenticateByEmailAndPassword.Text = SettingsLabels.LoginByAccountGroupboxTitle;
+ GroupBoxAuthenticateByAPIKey.Text = SettingsLabels.LoginByApiKeyGroupboxTitle;
+ groupBox6.Text = SettingsLabels.LanguageGroupboxTitle;
+ groupBox2.Text = SettingsLabels.StartGroupboxTitle;
+ groupBox5.Text = SettingsLabels.AdvancedGroupboxTitle;
+
+ label1.Text = SettingsLabels.AccountLabelAccountName;
+ label5.Text = SettingsLabels.AccountLabelConnectBy;
+ AuthenticateByEmailAndPassword.Text = SettingsLabels.AccountLabelConnectByEmailAndPassword;
+ AuthenticateByAPIKey.Text = SettingsLabels.AccountLabelConnectByApiKey;
+
+ label2.Text = SettingsLabels.LoginByAccountLabelEmail;
+ label3.Text = SettingsLabels.LoginByAccountLabelPassword;
+ CheckBoxShowPasswordInClearText.Text = SettingsLabels.LoginByAccountLabelShowPassword;
+ checkBox2.Text = SettingsLabels.LoginByAccountLabelShowPassword;
+ label4.Text = SettingsLabels.AccountLabelAPIKey;
+
+ EnableAutostart.Text = SettingsLabels.StartLabelAutostart;
+ StartMinimized.Text = SettingsLabels.StartLabelStartMinimized;
+ MinimizeByClosing.Text = SettingsLabels.AdvancedLabelMinimizeByClose;
+
+ BoxUseProxyServer.Text = SettingsLabels.ProxyServerLabel;
+ label9.Text = SettingsLabels.ProxyServer;
+
+ LblProxyPassword.Text = SettingsLabels.ProxyPassword;
+ LblProxyUser.Text = SettingsLabels.ProxyUser;
+
+ StopStopwatchByClosing.Text = SettingsLabels.StopStopwatchByClosing;
+ AskForStoppingStopwatchByClosing.Text = SettingsLabels.AskForStoppingStopwatchByClosing;
+
+ groupBox8.Text = SettingsLabels.TimeEntriesGroupboxTitle;
+ SortDescending.Text = SettingsLabels.SortDescending;
+
+ #endregion
+
+ }
+
+ void TabContainer_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ CheckConnectionButton.Visible = TabContainer.SelectedIndex <= 1;
+ }
+
+ private readonly bool FirstSetup;
+ private readonly IConfigurationService Config;
+
+ private void SetAuthentiactionByAPIKey()
+ {
+ ErrorProvider.Clear();
+ AuthenticateByAPIKey.Checked = true;
+ AuthenticateByEmailAndPassword.Checked = false;
+ GroupBoxAuthenticateByAPIKey.Enabled = true;
+ GroupBoxAuthenticateByEmailAndPassword.Enabled = false;
+ }
+
+ private void SetAuthenticationByEmailAndPassword()
+ {
+ ErrorProvider.Clear();
+ AuthenticateByAPIKey.Checked = false;
+ AuthenticateByEmailAndPassword.Checked = true;
+ GroupBoxAuthenticateByAPIKey.Enabled = false;
+ GroupBoxAuthenticateByEmailAndPassword.Enabled = true;
+ }
+
+ private void ButtonCancel_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ private void ButtonOK_Click(object sender, EventArgs e)
+ {
+ if(SaveFormData())
+ {
+ //if (!FirstSetup)
+ //{
+ Cursor = Cursors.WaitCursor;
+ ((Main)Owner).InitializeForm(false);
+ Cursor = Cursors.Default;
+ //}
+ Close();
+ }
+ }
+
+ private bool SaveFormData()
+ {
+
+ var settings = new AppSettings();
+ settings.AccountName = AccountName.Text;
+ settings.MinimizeByClosing = MinimizeByClosing.Checked;
+ settings.Autostart = EnableAutostart.Checked;
+ settings.StartMinimized = StartMinimized.Checked;
+ settings.UseProxy = BoxUseProxyServer.Checked;
+ settings.ProxyServer = ProxyServer.Text;
+ settings.ProxyPort = (int)ProxyPort.Value;
+ settings.ProxyPassword = ProxyPassword.Text;
+ settings.ProxyUser = ProxyUser.Text;
+ settings.AskForStoppingStopwatchByClosing = AskForStoppingStopwatchByClosing.Checked;
+ settings.StopStopwatchByClosing = StopStopwatchByClosing.Checked;
+ settings.SortTimeEntriesDescending = SortDescending.Checked;
+
+ settings.Culture = ListLanguages.SelectedIndex == 1 ? "en-US" : "de-DE";
+ ReLocalize = AppSettings.Culture != settings.Culture;
+
+ if (AuthenticateByAPIKey.Checked)
+ {
+ settings.AuthenticationType = AuthenticationType.APIKey;
+ settings.APIKey = APIKey.Text;
+ }
+ else
+ {
+ settings.AuthenticationType = AuthenticationType.EmailAndPassword;
+ settings.Email = Email.Text;
+ settings.Password = Password.Text;
+ }
+
+ var result = Config.UpdateAppSettings(settings);
+
+ if (result.Count == 0)
+ {
+ Helper.SetCulture(settings.Culture);
+ return true;
+ }
+
+ ErrorProvider.Clear();
+
+ if (result.ContainsKey("AccountName"))
+ ErrorProvider.SetError(AccountName, result["AccountName"]);
+
+ if (result.ContainsKey("Email"))
+ ErrorProvider.SetError(Email, result["Email"]);
+
+ if (result.ContainsKey("Password"))
+ ErrorProvider.SetError(Password, result["Password"]);
+
+ if (result.ContainsKey("APIKey"))
+ ErrorProvider.SetError(APIKey, result["APIKey"]);
+
+ return false;
+
+ }
+
+ private void RadioAuthByEmailAndPassword_Click(object sender, EventArgs e)
+ {
+ SetAuthenticationByEmailAndPassword();
+ }
+
+ private void RadioAuthByAPIKey_Click(object sender, EventArgs e)
+ {
+ SetAuthentiactionByAPIKey();
+ }
+
+ private void CheckBoxShowPasswordInClearText_CheckedChanged_1(object sender, EventArgs e)
+ {
+ Password.UseSystemPasswordChar = !CheckBoxShowPasswordInClearText.Checked;
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ if (SaveFormData())
+ {
+ Cursor = Cursors.WaitCursor;
+ try
+ {
+ var user = ObjectFactory.GetInstance().GetAuthenticatedUser();
+ MessageBox.Show(string.Format(SettingsLabels.MsgBoxConnectionTestSuccessText, user.Name, user.Email), SettingsLabels.MsgBoxConnectionTestSuccessTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch(MiteConnectorException ex)
+ {
+ ((Main)Owner).EnableOrDisableForm(false);
+ MessageBox.Show(string.Format(SettingsLabels.MsgBoxConnectionTestFailureText, ex.Message), SettingsLabels.MsgBoxConnectionTestFailureTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ Cursor = Cursors.Default;
+ }
+ }
+
+ private static void ShowFirstSetupMessage()
+ {
+ MessageBox.Show(SettingsLabels.MsgBoxFirstSetupMessageText, SettingsLabels.MsgBoxFirstSetupMessageTitle, MessageBoxButtons.OK);
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ ((Main)Owner).SetAppSettings();
+ if (ReLocalize)
+ ((Main)Owner).LocalizeForm();
+ base.OnClosed(e);
+ }
+
+ private void BoxUseProxy_CheckedChanged(object sender, EventArgs e)
+ {
+ SetProxyPanel();
+ }
+
+ private void SetProxyPanel()
+ {
+ ProxyServer.Enabled = BoxUseProxyServer.Checked;
+ ProxyPort.Enabled = BoxUseProxyServer.Checked;
+ ProxyUser.Enabled = BoxUseProxyServer.Checked;
+ ProxyPassword.Enabled = BoxUseProxyServer.Checked;
+ }
+
+ private void checkBox2_CheckedChanged(object sender, EventArgs e)
+ {
+ ProxyPassword.UseSystemPasswordChar = !checkBox2.Checked;
+ }
+
+ private void pictureBox1_Click(object sender, EventArgs e)
+ {
+ new LoginHelp().ShowDialog(this);
+ }
+
+ private void StopStopwatchByClosing_CheckedChanged(object sender, EventArgs e)
+ {
+ if (StopStopwatchByClosing.Checked)
+ AskForStoppingStopwatchByClosing.Checked = false;
+ }
+
+ private void AskForStoppingStopwatchByClosing_CheckedChanged(object sender, EventArgs e)
+ {
+ if (AskForStoppingStopwatchByClosing.Checked)
+ StopStopwatchByClosing.Checked = false;
+ }
+
+ }
+}
diff --git a/App/MiteDesk.WinForms/Settings.resx b/App/MiteDesk.WinForms/Settings.resx
new file mode 100644
index 0000000..c496b4e
--- /dev/null
+++ b/App/MiteDesk.WinForms/Settings.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/App/MiteDesk.WinForms/Stuff/Helper.cs b/App/MiteDesk.WinForms/Stuff/Helper.cs
new file mode 100644
index 0000000..6e1f52e
--- /dev/null
+++ b/App/MiteDesk.WinForms/Stuff/Helper.cs
@@ -0,0 +1,90 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public static class Helper
+ {
+
+ public static string CurrentVersion
+ {
+ get
+ {
+ return Assembly.GetExecutingAssembly().GetName().Version.Major + "." +
+ Assembly.GetExecutingAssembly().GetName().Version.Minor;
+ }
+ }
+
+ public static string CurrentBuild
+ {
+ get { return Assembly.GetExecutingAssembly().GetName().Version.Build.ToString(); }
+ }
+
+ public static void OpenBrowser(string url)
+ {
+ try
+ {
+ Process.Start(url);
+ }
+ catch
+ {
+ }
+ }
+
+ public static void ValidateTextEnteredInComboBox(object sender, EventArgs e)
+ {
+
+ var comboBox = (ComboBox)sender;
+
+ string text = comboBox.Text;
+
+ if (string.IsNullOrEmpty(text) || text.Length == 0)
+ return;
+
+ foreach (ListItem item in comboBox.Items)
+ {
+ if (item.Text.ToLower().StartsWith(text.ToLower()))
+ return;
+ }
+
+ comboBox.Text = text.Substring(0, text.Length - 1);
+ comboBox.Select(comboBox.Text.Length, 0);
+
+ }
+
+ public static string GetFormattedTimeText(int minutes)
+ {
+ return (minutes / 60).ToString().PadLeft(2, '0') + ":" + (minutes % 60).ToString().PadLeft(2, '0');
+ }
+
+ public static void StartBackgroundWorker(BackgroundWorker worker, object argument)
+ {
+
+ if(worker.IsBusy)
+ {
+ worker.CancelAsync();
+ while (worker.IsBusy)
+ Application.DoEvents();
+ }
+
+ if (argument != null)
+ worker.RunWorkerAsync(argument);
+ else
+ worker.RunWorkerAsync();
+
+ }
+
+ public static void SetCulture(string culture)
+ {
+ var ci = new System.Globalization.CultureInfo(culture, false);
+ Thread.CurrentThread.CurrentCulture = ci;
+ Thread.CurrentThread.CurrentUICulture = ci;
+ }
+
+ }
+
+}
diff --git a/App/MiteDesk.WinForms/Stuff/ListItem.cs b/App/MiteDesk.WinForms/Stuff/ListItem.cs
new file mode 100644
index 0000000..9f5c664
--- /dev/null
+++ b/App/MiteDesk.WinForms/Stuff/ListItem.cs
@@ -0,0 +1,8 @@
+namespace SixtyNineDegrees.MiteDesk.WinForms
+{
+ public class ListItem
+ {
+ public int Value { get; set; }
+ public string Text { get; set; }
+ }
+}
diff --git a/App/MiteDesk.WinForms/mite.desk.ico b/App/MiteDesk.WinForms/mite.desk.ico
new file mode 100644
index 0000000..ff25fca
Binary files /dev/null and b/App/MiteDesk.WinForms/mite.desk.ico differ
diff --git a/Core/MiteDesk.Core.Configuration/MiteDesk.Core.Configuration.csproj b/Core/MiteDesk.Core.Configuration/MiteDesk.Core.Configuration.csproj
new file mode 100644
index 0000000..8536b26
--- /dev/null
+++ b/Core/MiteDesk.Core.Configuration/MiteDesk.Core.Configuration.csproj
@@ -0,0 +1,59 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {DD1B5B7C-2272-4D57-A0CF-190193689373}
+ Library
+ Properties
+ MiteDesk.Core.Configuration
+ MiteDesk.Core.Configuration
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Configuration/Properties/AssemblyInfo.cs b/Core/MiteDesk.Core.Configuration/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1ecd41f
--- /dev/null
+++ b/Core/MiteDesk.Core.Configuration/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("MiteDesk.Core.Configuration")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MiteDesk.Core.Configuration")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("b198584e-c66a-45b8-b961-63ca6672ace0")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Core/MiteDesk.Core.Data/Contracts/IActivityRepository.cs b/Core/MiteDesk.Core.Data/Contracts/IActivityRepository.cs
new file mode 100644
index 0000000..4af502b
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Contracts/IActivityRepository.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public interface IActivityRepository
+ {
+ IList GetAllActiveActivities();
+ IList GetAllArchivedActivities();
+ Activity GetActivityByID(int activityID);
+ void DeleteActivity(int activityID);
+ void CreateActivity(Activity activity);
+ void UpdateActivity(Activity activity);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Contracts/ICustomerRepository.cs b/Core/MiteDesk.Core.Data/Contracts/ICustomerRepository.cs
new file mode 100644
index 0000000..6664676
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Contracts/ICustomerRepository.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public interface ICustomerRepository
+ {
+ IList GetAllActiveCustomers();
+ IList GetAllArchivedCustomers();
+ Customer GetCustomerByID(int customerID);
+ void DeleteCustomer(int customerID);
+ void CreateCustomer(Customer customer);
+ void UpdateCustomer(Customer customer);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Contracts/IProjectRepository.cs b/Core/MiteDesk.Core.Data/Contracts/IProjectRepository.cs
new file mode 100644
index 0000000..cae3f61
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Contracts/IProjectRepository.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public interface IProjectRepository
+ {
+ IList GetAllActiveProjects();
+ IList GetAllArchivedProjects();
+ IList GetProjectsByCustomer(int customerID);
+ Project GetProjectByID(int projectID);
+ void CreateProject(Project project);
+ void UpdateProject(Project project);
+ void DeleteProject(int projectID);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Contracts/ITimeEntryRepository.cs b/Core/MiteDesk.Core.Data/Contracts/ITimeEntryRepository.cs
new file mode 100644
index 0000000..4562e1d
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Contracts/ITimeEntryRepository.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public interface ITimeEntryRepository
+ {
+ void CreateTimeEntry(ref TimeEntry entry);
+ void DeleteTimeEntry(int timeEntryID);
+ void UpdateTimeEntry(TimeEntry entry);
+ void StartStopwatch(int timeEntryID);
+ void StopStopwatch(int timeEntryID);
+ IList GetTimeEntriesByDate(DateTime date);
+ IList GetTimeEntriesByActivityID(int activityID);
+ IList GetTimeEntriesByProjectID(int projectID);
+ IList GetTimeEntryDatesByRange(DateTime start, DateTime end, int userID);
+ TimeEntry GetTimeEntryByID(int timeEntryID);
+ TimeEntry GetTimeEntryCurrentlyTrackedByStopwatch();
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Contracts/IUserRepository.cs b/Core/MiteDesk.Core.Data/Contracts/IUserRepository.cs
new file mode 100644
index 0000000..a77de4e
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Contracts/IUserRepository.cs
@@ -0,0 +1,9 @@
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public interface IUserRepository
+ {
+ User GetAuthenticatedUser();
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Mite/MiteCustomers.cs b/Core/MiteDesk.Core.Data/Mite/MiteCustomers.cs
new file mode 100644
index 0000000..214b280
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Mite/MiteCustomers.cs
@@ -0,0 +1,97 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public class MiteCustomers : ICustomerRepository
+ {
+
+ public MiteCustomers(IConfigurationService configurationService)
+ {
+ ConfigurationService = configurationService;
+ }
+
+ private readonly IConfigurationService ConfigurationService;
+
+ private Connector Connector
+ {
+ get { return new Connector(ConfigurationService.GetAppSettings());}
+ }
+
+ public IList GetAllActiveCustomers()
+ {
+ var customersSource = Connector.HttpGet("customers.xml");
+ IEnumerable customers = from c in customersSource.Elements("customer")
+ select c;
+
+ var result = new List();
+ foreach (XElement c in customers)
+ {
+ result.Add(CreateCustomer(c));
+ }
+ return result;
+ }
+
+ public IList GetAllArchivedCustomers()
+ {
+ var customersSource = Connector.HttpGet("customers/archived.xml");
+ IEnumerable customers = from c in customersSource.Elements("customer")
+ select c;
+
+ var result = new List();
+ foreach (XElement c in customers)
+ {
+ result.Add(CreateCustomer(c));
+ }
+ return result;
+ }
+
+ public Customer GetCustomerByID(int customerID)
+ {
+ return CreateCustomer(Connector.HttpGet(string.Format("customers/{0}.xml", customerID)));
+ }
+
+ public void DeleteCustomer(int customerID)
+ {
+ Connector.HttpDelete("customers/" + customerID + ".xml");
+ }
+
+ public void CreateCustomer(Customer customer)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(customer.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(customer.Note));
+ xml.AppendFormat("{0}", customer.Archived ? "true" : "false");
+ xml.Append("");
+ Connector.HttpPost("customers.xml", xml.ToString());
+ }
+
+ public void UpdateCustomer(Customer customer)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(customer.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(customer.Note));
+ xml.AppendFormat("{0}", customer.Archived ? "true" : "false");
+ xml.Append("");
+ Connector.HttpPut("customers/" + customer.ID + ".xml", xml.ToString());
+ }
+
+ private Customer CreateCustomer(XElement source)
+ {
+ return new Customer
+ {
+ ID = source.Element(XName.Get("id")) != null ? int.Parse(source.Element(XName.Get("id")).Value) : 0,
+ Name = source.Element(XName.Get("name")) != null ? source.Element(XName.Get("name")).Value : string.Empty,
+ Note = source.Element(XName.Get("note")) != null ? source.Element(XName.Get("note")).Value : string.Empty,
+ Archived = source.Element(XName.Get("archived")) != null ? bool.Parse(source.Element(XName.Get("archived")).Value) : false
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Mite/MiteProjects.cs b/Core/MiteDesk.Core.Data/Mite/MiteProjects.cs
new file mode 100644
index 0000000..abf14f6
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Mite/MiteProjects.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public class MiteProjects : IProjectRepository
+ {
+
+ public MiteProjects(IConfigurationService configurationService)
+ {
+ ConfigurationService = configurationService;
+ }
+
+ private readonly IConfigurationService ConfigurationService;
+
+ private Connector Connector
+ {
+ get { return new Connector(ConfigurationService.GetAppSettings());}
+ }
+
+ public IList GetAllActiveProjects()
+ {
+ var projectsSource = Connector.HttpGet("projects.xml");
+ IEnumerable projects = from p in projectsSource.Elements("project")
+ select p;
+
+ var result = new List();
+ foreach (XElement p in projects)
+ {
+ result.Add(CreateProject(p));
+ }
+ return result;
+ }
+
+ public IList GetAllArchivedProjects()
+ {
+ var projectsSource = Connector.HttpGet("projects/archived.xml");
+ IEnumerable projects = from p in projectsSource.Elements("project")
+ select p;
+
+ var result = new List();
+ foreach (XElement p in projects)
+ {
+ result.Add(CreateProject(p));
+ }
+ return result;
+ }
+
+ public IList GetProjectsByCustomer(int customerID)
+ {
+ var projectsSource = Connector.HttpGet("projects.xml?customer-id=" + customerID);
+ IEnumerable projects = from p in projectsSource.Elements("project")
+ select p;
+
+ var result = new List();
+ foreach (XElement p in projects)
+ {
+ result.Add(CreateProject(p));
+ }
+ return result;
+ }
+
+ public Project GetProjectByID(int projectID)
+ {
+ return CreateProject(Connector.HttpGet(string.Format("projects/{0}.xml", projectID)));
+ }
+
+ public void CreateProject(Project project)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(project.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(project.Note));
+ xml.AppendFormat("{0}", project.Budget);
+ xml.AppendFormat("{0}", project.BudgetType);
+ xml.AppendFormat("{0}", project.Archived ? "true" : "false");
+ xml.AppendFormat("{0}", project.CustomerID);
+ xml.Append("");
+ Connector.HttpPost("projects.xml", xml.ToString());
+ }
+
+ public void UpdateProject(Project project)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(project.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(project.Note));
+ xml.AppendFormat("{0}", project.Budget);
+ xml.AppendFormat("{0}", project.BudgetType);
+ xml.AppendFormat("{0}", project.Archived ? "true" : "false");
+ xml.AppendFormat("{0}", project.CustomerID);
+ xml.Append("");
+ Connector.HttpPut("projects/" + project.ID + ".xml", xml.ToString());
+ }
+
+ public void DeleteProject(int projectID)
+ {
+ Connector.HttpDelete("projects/" + projectID + ".xml");
+ }
+
+ private Project CreateProject(XElement source)
+ {
+ return new Project
+ {
+ ID = source.Element(XName.Get("id")) != null ? int.Parse(source.Element(XName.Get("id")).Value) : 0,
+ Name = source.Element(XName.Get("name")) != null ? source.Element(XName.Get("name")).Value : string.Empty,
+ CustomerID = source.Element(XName.Get("customer-id")) != null && !string.IsNullOrEmpty(source.Element(XName.Get("customer-id")).Value) ? int.Parse(source.Element(XName.Get("customer-id")).Value) : 0,
+ CustomerName = source.Element(XName.Get("customer-name")) != null ? source.Element(XName.Get("customer-name")).Value : string.Empty,
+ Note = source.Element(XName.Get("note")) != null ? source.Element(XName.Get("note")).Value : string.Empty,
+ BudgetType = source.Element(XName.Get("budget-type")) != null ? source.Element(XName.Get("budget-type")).Value : string.Empty,
+ Budget = source.Element(XName.Get("budget")) != null ? int.Parse(source.Element(XName.Get("budget")).Value) : 0,
+ Archived = source.Element(XName.Get("archived")) != null ? bool.Parse(source.Element(XName.Get("archived")).Value) : false
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Mite/MiteServices.cs b/Core/MiteDesk.Core.Data/Mite/MiteServices.cs
new file mode 100644
index 0000000..bd0ee19
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Mite/MiteServices.cs
@@ -0,0 +1,103 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public class MiteServices : IActivityRepository
+ {
+
+ public MiteServices(IConfigurationService configurationService)
+ {
+ ConfigurationService = configurationService;
+ }
+
+ private readonly IConfigurationService ConfigurationService;
+
+ private Connector Connector
+ {
+ get { return new Connector(ConfigurationService.GetAppSettings());}
+ }
+
+ public IList GetAllActiveActivities()
+ {
+ var activitiesSource = Connector.HttpGet("services.xml");
+ IEnumerable activities = from c in activitiesSource.Elements("service")
+ select c;
+
+ var result = new List();
+ foreach (XElement a in activities)
+ {
+ result.Add(CreateActivity(a));
+ }
+ return result;
+ }
+
+ public IList GetAllArchivedActivities()
+ {
+ var activitiesSource = Connector.HttpGet("services/archived.xml");
+ IEnumerable activities = from c in activitiesSource.Elements("service")
+ select c;
+
+ var result = new List();
+ foreach (XElement a in activities)
+ {
+ result.Add(CreateActivity(a));
+ }
+ return result;
+ }
+
+ public Activity GetActivityByID(int activityID)
+ {
+ return CreateActivity(Connector.HttpGet(string.Format("services/{0}.xml", activityID)));
+ }
+
+ public void DeleteActivity(int activityID)
+ {
+ Connector.HttpDelete("services/" + activityID + ".xml");
+ }
+
+ public void CreateActivity(Activity activity)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(activity.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(activity.Note));
+ xml.AppendFormat("{0}", activity.HourlyRate > 0 ? activity.HourlyRate.ToString() : "");
+ xml.AppendFormat("{0}", activity.Archived ? "true" : "false");
+ xml.AppendFormat("{0}", activity.Billable ? "true" : "false");
+ xml.Append("");
+ Connector.HttpPost("services.xml", xml.ToString());
+ }
+
+ public void UpdateActivity(Activity activity)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(activity.Name));
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(activity.Note));
+ xml.AppendFormat("{0}", activity.HourlyRate > 0 ? activity.HourlyRate.ToString() : "");
+ xml.AppendFormat("{0}", activity.Archived ? "true" : "false");
+ xml.AppendFormat("{0}", activity.Billable ? "true" : "false");
+ xml.Append("");
+ Connector.HttpPut("services/" + activity.ID + ".xml", xml.ToString());
+ }
+
+ private Activity CreateActivity(XElement source)
+ {
+ return new Activity
+ {
+ ID = source.Element(XName.Get("id")) != null ? int.Parse(source.Element(XName.Get("id")).Value) : 0,
+ Name = source.Element(XName.Get("name")) != null ? source.Element(XName.Get("name")).Value : string.Empty,
+ Note = source.Element(XName.Get("note")) != null ? source.Element(XName.Get("note")).Value : string.Empty,
+ Archived = source.Element(XName.Get("archived")) != null ? bool.Parse(source.Element(XName.Get("archived")).Value) : false,
+ Billable = source.Element(XName.Get("billable")) != null ? bool.Parse(source.Element(XName.Get("billable")).Value) : false,
+ HourlyRate = source.Element(XName.Get("hourly-rate")) != null && !string.IsNullOrEmpty(source.Element(XName.Get("hourly-rate")).Value) ? int.Parse(source.Element(XName.Get("hourly-rate")).Value) : 0
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Mite/MiteTimeEntries.cs b/Core/MiteDesk.Core.Data/Mite/MiteTimeEntries.cs
new file mode 100644
index 0000000..20e7e81
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Mite/MiteTimeEntries.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public class MiteTimeEntries : ITimeEntryRepository
+ {
+
+ public MiteTimeEntries(IConfigurationService configurationService)
+ {
+ ConfigurationService = configurationService;
+ }
+
+ private readonly IConfigurationService ConfigurationService;
+
+ private Connector Connector
+ {
+ get { return new Connector(ConfigurationService.GetAppSettings());}
+ }
+
+ public void CreateTimeEntry(ref TimeEntry entry)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}-{1}-{2}", entry.Date.Year, entry.Date.Month, entry.Date.Day);
+ xml.AppendFormat("{0}", entry.Minutes);
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(entry.Note));
+ xml.AppendFormat("{0}", entry.ActivityID);
+ xml.AppendFormat("{0}", entry.ProjectID);
+ xml.AppendFormat("{0}", entry.Locked ? "1" : "0");
+ xml.Append("");
+ entry.ID = CreateEntry(Connector.HttpPost("time_entries.xml", xml.ToString())).ID;
+ }
+
+ public void DeleteTimeEntry(int timeEntryId)
+ {
+ Connector.HttpDelete("time_entries/" + timeEntryId + ".xml");
+ }
+
+ public void UpdateTimeEntry(TimeEntry entry)
+ {
+ var xml = new StringBuilder();
+ xml.Append("");
+ xml.AppendFormat("{0}-{1}-{2}", entry.Date.Year, entry.Date.Month, entry.Date.Day);
+ xml.AppendFormat("{0}", entry.Minutes);
+ xml.AppendFormat("{0}", System.Web.HttpUtility.HtmlEncode(entry.Note));
+ xml.AppendFormat("{0}", entry.ActivityID);
+ xml.AppendFormat("{0}", entry.ProjectID);
+ xml.AppendFormat("{0}", entry.Locked ? "1" : "0");
+ xml.Append("1");
+ xml.Append("");
+ Connector.HttpPut("time_entries/" + entry.ID + ".xml", xml.ToString());
+ }
+
+ public void StartStopwatch(int timeEntryID)
+ {
+ Connector.HttpPut("tracker/" + timeEntryID + ".xml", string.Empty);
+ }
+
+ public void StopStopwatch(int timeEntryID)
+ {
+ Connector.HttpDelete("tracker/" + timeEntryID + ".xml");
+ }
+
+ public IList GetTimeEntriesByDate(DateTime date)
+ {
+ var timeEntriesSource = Connector.HttpGet(string.Format("daily/{0}/{1}/{2}.xml", date.Year, date.Month, date.Day));
+ IEnumerable timeEntries = from c in timeEntriesSource.Elements("time-entry")
+ select c;
+
+ var result = new List();
+ foreach (XElement a in timeEntries)
+ {
+ result.Add(CreateEntry(a));
+ }
+ return result;
+ }
+
+ public IList GetTimeEntriesByActivityID(int activityID)
+ {
+ var timeEntriesSource = Connector.HttpGet("time_entries.xml?service-id=" + activityID);
+ IEnumerable timeEntries = from c in timeEntriesSource.Elements("time-entry")
+ select c;
+
+ var result = new List();
+ foreach (XElement a in timeEntries)
+ {
+ result.Add(CreateEntry(a));
+ }
+ return result;
+ }
+
+ public IList GetTimeEntriesByProjectID(int projectID)
+ {
+ var timeEntriesSource = Connector.HttpGet("time_entries.xml?project-id=" + projectID);
+ IEnumerable timeEntries = from c in timeEntriesSource.Elements("time-entry")
+ select c;
+
+ var result = new List();
+ foreach (XElement a in timeEntries)
+ {
+ result.Add(CreateEntry(a));
+ }
+ return result;
+ }
+
+ public IList GetTimeEntryDatesByRange(DateTime start, DateTime end, int userID)
+ {
+ var timeEntryGroupSource = Connector.HttpGet(string.Format("time_entries.xml?from={0:yyyy}-{0:MM}-{0:dd}&to={1:yyyy}-{1:MM}-{1:dd}&user-id={2}&group_by=day", start, end, userID));
+ IEnumerable timeEntryGroups = from c in timeEntryGroupSource.Elements("time-entry-group")
+ select c;
+ var result = new List();
+ foreach (XElement g in timeEntryGroups)
+ {
+ result.Add(DateTime.Parse(g.Element(XName.Get("day")).Value));
+ }
+ return result;
+ }
+
+ public TimeEntry GetTimeEntryByID(int timeEntryId)
+ {
+ return CreateEntry(Connector.HttpGet(string.Format("time_entries/{0}.xml", timeEntryId)));
+ }
+
+ public TimeEntry GetTimeEntryCurrentlyTrackedByStopwatch()
+ {
+ return CreateEntry(Connector.HttpGet("tracker.xml").Element(XName.Get("tracking-time-entry")));
+ }
+
+ private TimeEntry CreateEntry(XElement source)
+ {
+ if (source == null)
+ return null;
+
+ return new TimeEntry
+ {
+ ID = source.Element(XName.Get("id")) != null ? int.Parse(source.Element(XName.Get("id")).Value) : 0,
+ ActivityID = source.Element(XName.Get("service-id")) != null && !string.IsNullOrEmpty(source.Element(XName.Get("service-id")).Value) ? int.Parse(source.Element(XName.Get("service-id")).Value) : 0,
+ ProjectID = source.Element(XName.Get("project-id")) != null && !string.IsNullOrEmpty(source.Element(XName.Get("project-id")).Value) ? int.Parse(source.Element(XName.Get("project-id")).Value) : 0,
+ Date = source.Element(XName.Get("date-at")) != null ? DateTime.Parse(source.Element(XName.Get("date-at")).Value) : DateTime.MinValue,
+ Minutes = source.Element(XName.Get("minutes")) != null ? int.Parse(source.Element(XName.Get("minutes")).Value) : 0,
+ Note = source.Element(XName.Get("note")) != null ? source.Element(XName.Get("note")).Value : string.Empty,
+ CustomerName = source.Element(XName.Get("customer-name")) != null ? source.Element(XName.Get("customer-name")).Value : "-",
+ ProjectName = source.Element(XName.Get("project-name")) != null ? source.Element(XName.Get("project-name")).Value : "-",
+ ActivityName = source.Element(XName.Get("service-name")) != null ? source.Element(XName.Get("service-name")).Value : "-",
+ Locked = source.Element(XName.Get("locked")) != null ? bool.Parse(source.Element(XName.Get("locked")).Value) : false
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Mite/MiteUsers.cs b/Core/MiteDesk.Core.Data/Mite/MiteUsers.cs
new file mode 100644
index 0000000..f578506
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Mite/MiteUsers.cs
@@ -0,0 +1,57 @@
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data
+{
+ public class MiteUsers : IUserRepository
+ {
+
+ public MiteUsers(IConfigurationService configurationService)
+ {
+ ConfigurationService = configurationService;
+ }
+
+ private readonly IConfigurationService ConfigurationService;
+
+ private Connector Connector
+ {
+ get { return new Connector(ConfigurationService.GetAppSettings());}
+ }
+
+ public User GetAuthenticatedUser()
+ {
+ return CreateUser(Connector.HttpGet("myself.xml"));
+ }
+
+ private User CreateUser(XElement source)
+ {
+ return new User
+ {
+ ID = int.Parse(source.Element(XName.Get("id")).Value),
+ Name = source.Element(XName.Get("name")).Value,
+ Email = source.Element(XName.Get("email")).Value,
+ Role = GetRole(source.Element(XName.Get("role")).Value)
+ };
+ }
+
+ private UserRole GetRole(string text)
+ {
+ switch (text)
+ {
+ case "coworker":
+ return UserRole.CoWorker;
+ case "time_tracker":
+ return UserRole.TimeTracker;
+ case "admin":
+ return UserRole.Admin;
+ case "owner":
+ return UserRole.Owner;
+ default:
+ throw new UserRoleInvalidException();
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/MiteDesk.Core.Data.csproj b/Core/MiteDesk.Core.Data/MiteDesk.Core.Data.csproj
new file mode 100644
index 0000000..32743ce
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/MiteDesk.Core.Data.csproj
@@ -0,0 +1,131 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Data
+ mite.desk.core.data
+ v3.5
+ 512
+ true
+
+
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+
+ 3.5
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}
+ MiteDesk.Tools.Connector
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Data/Properties/AssemblyInfo.cs b/Core/MiteDesk.Core.Data/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f5e2dfc
--- /dev/null
+++ b/Core/MiteDesk.Core.Data/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("mite.desk.data")]
+[assembly: AssemblyDescription("mite.desk.data")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("fe66bff2-02ed-4173-a671-919cf2e54b1b")]
+
+[assembly: AssemblyVersion("1.2.17")]
+[assembly: AssemblyFileVersion("1.2.17")]
diff --git a/Core/MiteDesk.Core.Infrastructure/Configuration/ConfigurationService.cs b/Core/MiteDesk.Core.Infrastructure/Configuration/ConfigurationService.cs
new file mode 100644
index 0000000..cd185fb
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Configuration/ConfigurationService.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+ public class ConfigurationService : IConfigurationService
+ {
+
+ public ConfigurationService(IRegistryService registryService, IEncryptionService encryptionService, string applicationID, string executablePath)
+ {
+ RegistryService = registryService;
+ EncryptionService = encryptionService;
+ ApplicationID = applicationID;
+ ExecutablePath = executablePath;
+ }
+
+ private readonly IRegistryService RegistryService;
+ private readonly IEncryptionService EncryptionService;
+ private readonly string ApplicationID;
+ private readonly string ExecutablePath;
+
+ public AppSettings GetAppSettings()
+ {
+
+ var settings = new AppSettings();
+
+ if (!RegistryService.ApplicationRegistryKeyExists())
+ RegistryService.CreateApplicationRegistryKey();
+
+ settings.AccountName = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("C"), ApplicationID);
+ settings.Email = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("D"), ApplicationID);
+ settings.APIKey = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("E"), ApplicationID);
+ settings.Password = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("F"), ApplicationID);
+
+ settings.ProxyUser = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("R"), ApplicationID);
+ settings.ProxyPassword = EncryptionService.DecryptString(RegistryService.GetApplicationRegistryKeyValue("S"), ApplicationID);
+
+ settings.Culture = RegistryService.GetApplicationRegistryKeyValue("N");
+ if (string.IsNullOrEmpty(settings.Culture)) settings.Culture = "de-DE";
+
+ string autostartRegistryValue = RegistryService.GetApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk");
+ settings.Autostart = autostartRegistryValue != null && autostartRegistryValue == ExecutablePath;
+
+ bool minimizeByClosing;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("H"), out minimizeByClosing);
+ settings.MinimizeByClosing = minimizeByClosing;
+
+ bool startMinimized;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("I"), out startMinimized);
+ settings.StartMinimized = startMinimized;
+
+ DateTime lastUpdateCheck;
+ DateTime.TryParse(RegistryService.GetApplicationRegistryKeyValue("K"), out lastUpdateCheck);
+ settings.LastUpdateCheck = lastUpdateCheck;
+
+ int selectedProjectID;
+ int.TryParse(RegistryService.GetApplicationRegistryKeyValue("L"), out selectedProjectID);
+ settings.SelectedProjectID = selectedProjectID;
+
+ int activityID;
+ int.TryParse(RegistryService.GetApplicationRegistryKeyValue("M"), out activityID);
+ settings.SelectedActivityID = activityID;
+
+ bool useProxy;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("O"), out useProxy);
+ settings.UseProxy = useProxy;
+
+ bool stopStopwatchByClosing;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("T"), out stopStopwatchByClosing);
+ settings.StopStopwatchByClosing = stopStopwatchByClosing;
+
+ bool askForStoppingStopwatchByClosing;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("U"), out askForStoppingStopwatchByClosing);
+ settings.AskForStoppingStopwatchByClosing = askForStoppingStopwatchByClosing;
+
+ bool sortTimeEntriesDescending;
+ bool.TryParse(RegistryService.GetApplicationRegistryKeyValue("V"), out sortTimeEntriesDescending);
+ settings.SortTimeEntriesDescending = sortTimeEntriesDescending;
+
+ settings.ProxyServer = RegistryService.GetApplicationRegistryKeyValue("P");
+
+ int proxyPort;
+ int.TryParse(RegistryService.GetApplicationRegistryKeyValue("Q"), out proxyPort);
+ settings.ProxyPort = proxyPort;
+
+ return settings;
+
+ }
+
+ public Dictionary UpdateAppSettings(AppSettings settings)
+ {
+
+ Dictionary errors = new Dictionary();
+
+ if(string.IsNullOrEmpty(settings.AccountName) || settings.AccountName.Trim().Length == 0)
+ errors.Add("AccountName", Localization.Configuration.AccountNameEmpty);
+
+ if(settings.AuthenticationType == AuthenticationType.EmailAndPassword)
+ {
+ if (string.IsNullOrEmpty(settings.Email) || settings.Email.Trim().Length == 0)
+ errors.Add("Email", Localization.Configuration.EmailEmpty);
+ else if (!new Regex(@"^[\w\.-]+@[\w\.-]+\.[a-zA-Z]{2,6}$").Match(settings.Email).Success)
+ errors.Add("Email", Localization.Configuration.EmailFormat);
+
+ if (string.IsNullOrEmpty(settings.Password) || settings.Password.Trim().Length == 0)
+ errors.Add("Password", Localization.Configuration.PasswordEmpty);
+ }
+ else if(settings.AuthenticationType == AuthenticationType.APIKey)
+ {
+ if (string.IsNullOrEmpty(settings.APIKey) || settings.APIKey.Trim().Length == 0)
+ errors.Add("APIKey", Localization.Configuration.APIKeyEmpty);
+ }
+
+ if(errors.Count == 0)
+ {
+
+ RegistryService.SetApplicationRegistryKeyValue("C", EncryptionService.EncryptString(settings.AccountName, ApplicationID));
+ RegistryService.SetApplicationRegistryKeyValue("H", settings.MinimizeByClosing.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("I", settings.StartMinimized.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("L", settings.SelectedProjectID.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("M", settings.SelectedActivityID.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("N", settings.Culture);
+ RegistryService.SetApplicationRegistryKeyValue("O", settings.UseProxy.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("P", settings.ProxyServer);
+ RegistryService.SetApplicationRegistryKeyValue("Q", settings.ProxyPort.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("R", EncryptionService.EncryptString(settings.ProxyUser, ApplicationID));
+ RegistryService.SetApplicationRegistryKeyValue("S", EncryptionService.EncryptString(settings.ProxyPassword, ApplicationID));
+ RegistryService.SetApplicationRegistryKeyValue("T", settings.StopStopwatchByClosing.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("U", settings.AskForStoppingStopwatchByClosing.ToString());
+ RegistryService.SetApplicationRegistryKeyValue("V", settings.SortTimeEntriesDescending.ToString());
+
+ if (settings.LastUpdateCheck > DateTime.MinValue)
+ RegistryService.SetApplicationRegistryKeyValue("K", settings.LastUpdateCheck.ToShortDateString());
+
+ if(settings.AuthenticationType == AuthenticationType.EmailAndPassword)
+ {
+ RegistryService.SetApplicationRegistryKeyValue("D", EncryptionService.EncryptString(settings.Email, ApplicationID));
+ RegistryService.SetApplicationRegistryKeyValue("F", EncryptionService.EncryptString(settings.Password, ApplicationID));
+ RegistryService.SetApplicationRegistryKeyValue("E", string.Empty);
+ }
+ else if (settings.AuthenticationType == AuthenticationType.APIKey)
+ {
+ RegistryService.SetApplicationRegistryKeyValue("D", string.Empty);
+ RegistryService.SetApplicationRegistryKeyValue("F", string.Empty);
+ RegistryService.SetApplicationRegistryKeyValue("E", EncryptionService.EncryptString(settings.APIKey, ApplicationID));
+ }
+
+ if (settings.Autostart)
+ RegistryService.SetApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk", ExecutablePath);
+ else
+ RegistryService.DeleteApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk");
+
+ }
+
+ return errors;
+
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Configuration/IConfigurationService.cs b/Core/MiteDesk.Core.Infrastructure/Configuration/IConfigurationService.cs
new file mode 100644
index 0000000..3d69362
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Configuration/IConfigurationService.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+ public interface IConfigurationService
+ {
+ AppSettings GetAppSettings();
+ Dictionary UpdateAppSettings(AppSettings settings);
+ }
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Encryption/EncryptionService.cs b/Core/MiteDesk.Core.Infrastructure/Encryption/EncryptionService.cs
new file mode 100644
index 0000000..f31646d
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Encryption/EncryptionService.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+
+ public class EncryptionService : IEncryptionService
+ {
+
+ public string EncryptString(string clearText, string password)
+ {
+ if (string.IsNullOrEmpty(clearText))
+ return clearText;
+ byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
+ Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
+ byte[] encryptedData = EncryptString(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
+ return Convert.ToBase64String(encryptedData);
+ }
+
+ private static byte[] EncryptString(byte[] clearText, byte[] key, byte[] iv)
+ {
+ MemoryStream ms = new MemoryStream();
+ Rijndael alg = Rijndael.Create();
+ alg.Key = key;
+ alg.IV = iv;
+ using (CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write))
+ {
+ cs.Write(clearText, 0, clearText.Length);
+ }
+ byte[] encryptedData = ms.ToArray();
+ return encryptedData;
+ }
+
+ public string DecryptString(string cipherText, string password)
+ {
+ if (string.IsNullOrEmpty(cipherText))
+ return null;
+ byte[] cipherBytes = Convert.FromBase64String(cipherText);
+ Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
+ byte[] decryptedData = DecryptString(cipherBytes, pdb.GetBytes(32), pdb.GetBytes(16));
+ return Encoding.Unicode.GetString(decryptedData);
+ }
+
+ private static byte[] DecryptString(byte[] cipherData, byte[] key, byte[] iv)
+ {
+ MemoryStream ms = new MemoryStream();
+ Rijndael alg = Rijndael.Create();
+ alg.Key = key;
+ alg.IV = iv;
+ using (CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write))
+ {
+ cs.Write(cipherData, 0, cipherData.Length);
+ }
+ byte[] decryptedData = ms.ToArray();
+ return decryptedData;
+ }
+
+ }
+
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Encryption/IEncryptionService.cs b/Core/MiteDesk.Core.Infrastructure/Encryption/IEncryptionService.cs
new file mode 100644
index 0000000..24fd599
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Encryption/IEncryptionService.cs
@@ -0,0 +1,8 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+ public interface IEncryptionService
+ {
+ string EncryptString(string clearText, string password);
+ string DecryptString(string cipherText, string password);
+ }
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.Designer.cs b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.Designer.cs
new file mode 100644
index 0000000..2dd4d08
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.Designer.cs
@@ -0,0 +1,108 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Configuration {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Configuration() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.Core.Infrastructure.Localization.Configuration", typeof(Configuration).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Gib bitte den Account-Namen an..
+ ///
+ internal static string AccountNameEmpty {
+ get {
+ return ResourceManager.GetString("AccountNameEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bitte gib den API-Schlüssel an..
+ ///
+ internal static string APIKeyEmpty {
+ get {
+ return ResourceManager.GetString("APIKeyEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bitte gib E-Mail-Adresse an..
+ ///
+ internal static string EmailEmpty {
+ get {
+ return ResourceManager.GetString("EmailEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bitte gib eine korrekte E-Mail-Adresse an..
+ ///
+ internal static string EmailFormat {
+ get {
+ return ResourceManager.GetString("EmailFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bitte gib dein Passwort an..
+ ///
+ internal static string PasswordEmpty {
+ get {
+ return ResourceManager.GetString("PasswordEmpty", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.en.resx b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.en.resx
new file mode 100644
index 0000000..ff21dc7
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.en.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Please enter your account name
+
+
+ Please enter your API key
+
+
+ Please enter your email address
+
+
+ Please enter a correcty formatted email address
+
+
+ Please enter your password
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.resx b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.resx
new file mode 100644
index 0000000..4273def
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Localization/Configuration.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Gib bitte den Account-Namen an.
+
+
+ Bitte gib den API-Schlüssel an.
+
+
+ Bitte gib E-Mail-Adresse an.
+
+
+ Bitte gib eine korrekte E-Mail-Adresse an.
+
+
+ Bitte gib dein Passwort an.
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Infrastructure/MiteDesk.Core.Infrastructure.csproj b/Core/MiteDesk.Core.Infrastructure/MiteDesk.Core.Infrastructure.csproj
new file mode 100644
index 0000000..c6c74e4
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/MiteDesk.Core.Infrastructure.csproj
@@ -0,0 +1,123 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Infrastructure
+ mite.desk.core.infrastructure
+ v3.5
+ 512
+ true
+
+
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Configuration.resx
+
+
+
+
+
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+
+
+
+ ResXFileCodeGenerator
+ Configuration.Designer.cs
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Infrastructure/Properties/AssemblyInfo.cs b/Core/MiteDesk.Core.Infrastructure/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..adb4428
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("mite.desk.infrastructure")]
+[assembly: AssemblyDescription("mite.desk.infrastructure")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("cd8b1326-809b-4366-b893-47d5fb176b70")]
+
+[assembly: AssemblyVersion("1.2.17")]
+[assembly: AssemblyFileVersion("1.2.17")]
diff --git a/Core/MiteDesk.Core.Infrastructure/Registry/IRegistryService.cs b/Core/MiteDesk.Core.Infrastructure/Registry/IRegistryService.cs
new file mode 100644
index 0000000..ffd3325
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Registry/IRegistryService.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+ public interface IRegistryService
+ {
+ bool ApplicationRegistryKeyExists();
+ void CreateApplicationRegistryKey();
+ void SetApplicationRegistryKeyValue(string name, string value);
+ void SetApplicationRegistryKeyValue(string key, string name, string value);
+ void DeleteApplicationRegistryKeyValue(string key, string name);
+ string GetApplicationRegistryKeyValue(string key, string name);
+ string GetApplicationRegistryKeyValue(string name);
+ }
+}
diff --git a/Core/MiteDesk.Core.Infrastructure/Registry/RegistryService.cs b/Core/MiteDesk.Core.Infrastructure/Registry/RegistryService.cs
new file mode 100644
index 0000000..6982c36
--- /dev/null
+++ b/Core/MiteDesk.Core.Infrastructure/Registry/RegistryService.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using Microsoft.Win32;
+using System.Text;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure
+{
+ public class RegistryService : IRegistryService
+ {
+ private const string RegistryKey = "Software\\69 Grad\\mite.desk";
+
+ public bool ApplicationRegistryKeyExists()
+ {
+ return Registry.CurrentUser.OpenSubKey(RegistryKey) != null;
+ }
+
+ public void CreateApplicationRegistryKey()
+ {
+ Registry.CurrentUser.CreateSubKey(RegistryKey);
+ }
+
+ public void SetApplicationRegistryKeyValue(string key, string name, string value)
+ {
+ var subKey = Registry.CurrentUser.OpenSubKey(key, true);
+ if (subKey == null)
+ Registry.CurrentUser.CreateSubKey(key);
+ subKey.SetValue(name, value ?? string.Empty);
+ }
+
+ public void DeleteApplicationRegistryKeyValue(string key, string name)
+ {
+ var subKey = Registry.CurrentUser.OpenSubKey(key, true);
+ if (subKey != null && subKey.GetValue(name) != null)
+ subKey.DeleteValue(name);
+ }
+
+ public string GetApplicationRegistryKeyValue(string key, string name)
+ {
+ return (string)Registry.CurrentUser.OpenSubKey(key).GetValue(name);
+ }
+
+ public string GetApplicationRegistryKeyValue(string name)
+ {
+ return GetApplicationRegistryKeyValue(RegistryKey, name);
+ }
+
+ public void SetApplicationRegistryKeyValue(string name, string value)
+ {
+ SetApplicationRegistryKeyValue(RegistryKey, name, value);
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/Activity.cs b/Core/MiteDesk.Core.Model/Activity.cs
new file mode 100644
index 0000000..7491114
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/Activity.cs
@@ -0,0 +1,25 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class Activity
+ {
+
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public string Note { get; set; }
+ public int HourlyRate { get; set; }
+ public bool Billable { get; set; }
+ public bool Archived { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ var a = (Activity) obj;
+ return ID == a.ID &&
+ Name == a.Name &&
+ Note == a.Note &&
+ HourlyRate == a.HourlyRate &&
+ Billable == a.Billable &&
+ Archived == a.Archived;
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/AppSettings.cs b/Core/MiteDesk.Core.Model/AppSettings.cs
new file mode 100644
index 0000000..be9d72b
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/AppSettings.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+
+ public class AppSettings
+ {
+ public string Culture { get; set; }
+ public int SelectedProjectID { get; set; }
+ public int SelectedActivityID { get; set; }
+ public DateTime LastUpdateCheck { get; set; }
+ public bool StartMinimized { get; set; }
+ public AuthenticationType AuthenticationType { get; set; }
+ public string AccountName { get; set; }
+ public string Email { get; set; }
+ public string Password { get; set; }
+ public string APIKey { get; set; }
+ public bool MinimizeByClosing { get; set; }
+ public bool Autostart { get; set; }
+ public bool UseProxy { get; set; }
+ public int ProxyPort { get; set; }
+ public string ProxyServer { get; set; }
+ public string ProxyUser { get; set; }
+ public string ProxyPassword { get; set; }
+ public bool StopStopwatchByClosing { get; set; }
+ public bool AskForStoppingStopwatchByClosing { get; set; }
+ public bool SortTimeEntriesDescending { get; set; }
+ }
+
+ public enum AuthenticationType
+ {
+ EmailAndPassword = 0,
+ APIKey = 1
+ }
+
+}
diff --git a/Core/MiteDesk.Core.Model/Customer.cs b/Core/MiteDesk.Core.Model/Customer.cs
new file mode 100644
index 0000000..467d1dc
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/Customer.cs
@@ -0,0 +1,10 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class Customer
+ {
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public string Note { get; set; }
+ public bool Archived { get; set; }
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/MiteDesk.Core.Model.csproj b/Core/MiteDesk.Core.Model/MiteDesk.Core.Model.csproj
new file mode 100644
index 0000000..017607e
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/MiteDesk.Core.Model.csproj
@@ -0,0 +1,107 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Model
+ mite.desk.core.model
+ v3.5
+ 512
+ true
+
+
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Model/Project.cs b/Core/MiteDesk.Core.Model/Project.cs
new file mode 100644
index 0000000..a39730c
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/Project.cs
@@ -0,0 +1,26 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class Project
+ {
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public string Note { get; set; }
+ public string BudgetType { get; set; }
+ public int Budget { get; set; }
+ public bool Archived { get; set; }
+ public int CustomerID { get; set; }
+ public string CustomerName { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ var p = (Project)obj;
+ return ID == p.ID &&
+ Name == p.Name &&
+ Note == p.Note &&
+ Budget == p.Budget &&
+ BudgetType == p.BudgetType &&
+ Archived == p.Archived;
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/Properties/AssemblyInfo.cs b/Core/MiteDesk.Core.Model/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d0787bc
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("mite.desk.model")]
+[assembly: AssemblyDescription("mite.desk.model")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("a0d857f1-8fc9-4ffd-9f9d-89f099f5e212")]
+
+[assembly: AssemblyVersion("1.2.17")]
+[assembly: AssemblyFileVersion("1.2.17")]
diff --git a/Core/MiteDesk.Core.Model/TimeEntry.cs b/Core/MiteDesk.Core.Model/TimeEntry.cs
new file mode 100644
index 0000000..cf89d8c
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/TimeEntry.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class TimeEntry
+ {
+ public int ID { get; set; }
+ public DateTime Date { get; set; }
+ public int Minutes { get; set; }
+ public string Note { get; set; }
+ public int ProjectID { get; set; }
+ public int ActivityID { get; set; }
+ public string CustomerName { get; set; }
+ public string ProjectName { get; set; }
+ public string ActivityName { get; set; }
+ public bool Locked { get; set; }
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/User.cs b/Core/MiteDesk.Core.Model/User.cs
new file mode 100644
index 0000000..c8009ae
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/User.cs
@@ -0,0 +1,10 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class User
+ {
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public string Email { get; set; }
+ public UserRole Role { get; set; }
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/UserRole.cs b/Core/MiteDesk.Core.Model/UserRole.cs
new file mode 100644
index 0000000..5162282
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/UserRole.cs
@@ -0,0 +1,10 @@
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public enum UserRole
+ {
+ TimeTracker = 0,
+ CoWorker = 1,
+ Admin = 2,
+ Owner = 3
+ }
+}
diff --git a/Core/MiteDesk.Core.Model/UserRoleInvalidException.cs b/Core/MiteDesk.Core.Model/UserRoleInvalidException.cs
new file mode 100644
index 0000000..cbcfb34
--- /dev/null
+++ b/Core/MiteDesk.Core.Model/UserRoleInvalidException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Model
+{
+ public class UserRoleInvalidException : Exception
+ {
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Activities/ActivityService.cs b/Core/MiteDesk.Core.Services/Activities/ActivityService.cs
new file mode 100644
index 0000000..ecb4191
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Activities/ActivityService.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public class ActivityService : IActivityService
+ {
+
+ public ActivityService(IActivityRepository repository)
+ {
+ Repository = repository;
+ }
+
+ private readonly IActivityRepository Repository;
+
+ public IList GetAllActiveActivities()
+ {
+ return Repository.GetAllActiveActivities();
+ }
+
+ public IList GetAllArchivedActivities()
+ {
+ return Repository.GetAllArchivedActivities();
+ }
+
+ public Dictionary CreateActivity(Activity activity, string hourlyRate)
+ {
+ var errors = ValidateActivity(activity);
+ if (errors.Count == 0)
+ {
+ activity.HourlyRate = ParseHourlyRate(hourlyRate);
+ Repository.CreateActivity(activity);
+ }
+ return errors;
+ }
+
+ public Dictionary UpdateActivity(Activity activity, string hourlyRate)
+ {
+ if (activity.ID == 0)
+ throw new ArgumentException(Localization.Activities.IDException, "activity");
+
+ var errors = ValidateActivity(activity);
+ if (errors.Count == 0)
+ {
+ activity.HourlyRate = ParseHourlyRate(hourlyRate);
+ Repository.UpdateActivity(activity);
+ }
+
+ return errors;
+ }
+
+ private static Dictionary ValidateActivity(Activity activity)
+ {
+ var errors = new Dictionary();
+ if (string.IsNullOrEmpty(activity.Name) || activity.Name.Trim().Length == 0)
+ {
+ errors.Add("Name", Localization.Activities.NameEmpty);
+ }
+ return errors;
+ }
+
+ private static int ParseHourlyRate(string value)
+ {
+
+ int rate = 0;
+
+ if (string.IsNullOrEmpty(value) || value.Trim().Length == 0)
+ return rate;
+
+
+ if(value.IndexOf(',') > -1)
+ {
+
+ int first, second;
+
+ int.TryParse(value.Split(',')[0], out first);
+
+ if (value.Split(',')[1].Length <= 2)
+ {
+ int.TryParse(value.Split(',')[1], out second);
+ }
+ else
+ {
+ decimal tmp;
+ decimal.TryParse(value, out tmp);
+ tmp = Math.Round(tmp, 2);
+ int.TryParse(tmp.ToString().Split(',')[1], out second);
+ }
+
+ rate = (first*100) + second;
+
+ }
+ else
+ {
+ int.TryParse(value, out rate);
+ if(rate > 0)
+ {
+ rate = rate * 100;
+ }
+ }
+
+ return rate;
+
+ }
+
+ public Activity GetActivityByID(int activityID)
+ {
+ return Repository.GetActivityByID(activityID);
+ }
+
+ public void DeleteActivity(int activityID)
+ {
+ Repository.DeleteActivity(activityID);
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Activities/IActivityService.cs b/Core/MiteDesk.Core.Services/Activities/IActivityService.cs
new file mode 100644
index 0000000..5166c14
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Activities/IActivityService.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public interface IActivityService
+ {
+ IList GetAllActiveActivities();
+ IList GetAllArchivedActivities();
+ Dictionary CreateActivity(Activity activity, string hourlyRate);
+ Dictionary UpdateActivity(Activity activity, string hourlyRate);
+ Activity GetActivityByID(int activityID);
+ void DeleteActivity(int activityID);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Authentication/AuthenticationService.cs b/Core/MiteDesk.Core.Services/Authentication/AuthenticationService.cs
new file mode 100644
index 0000000..58eff72
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Authentication/AuthenticationService.cs
@@ -0,0 +1,21 @@
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public class AuthenticationService : IAuthenticationService
+ {
+
+ public AuthenticationService(IUserRepository userRepository)
+ {
+ UserRepository = userRepository;
+ }
+
+ private readonly IUserRepository UserRepository;
+
+ public User GetAuthenticatedUser()
+ {
+ return UserRepository.GetAuthenticatedUser();
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Authentication/IAuthenticationService.cs b/Core/MiteDesk.Core.Services/Authentication/IAuthenticationService.cs
new file mode 100644
index 0000000..eabf917
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Authentication/IAuthenticationService.cs
@@ -0,0 +1,9 @@
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public interface IAuthenticationService
+ {
+ User GetAuthenticatedUser();
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Customers/CustomerService.cs b/Core/MiteDesk.Core.Services/Customers/CustomerService.cs
new file mode 100644
index 0000000..0e35d6d
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Customers/CustomerService.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public class CustomerService : ICustomerService
+ {
+
+ public CustomerService(ICustomerRepository repository)
+ {
+ Repository = repository;
+ }
+
+ private readonly ICustomerRepository Repository;
+
+ public IList GetAllActiveCustomers()
+ {
+ return Repository.GetAllActiveCustomers();
+ }
+
+ public IList GetAllArchivedCustomers()
+ {
+ return Repository.GetAllArchivedCustomers();
+ }
+
+ public Dictionary CreateCustomer(Customer customer)
+ {
+ var errors = ValidateCustomer(customer);
+ if (errors.Count == 0)
+ Repository.CreateCustomer(customer);
+ return errors;
+ }
+
+ public Dictionary UpdateCustomer(Customer customer)
+ {
+ if (customer.ID == 0)
+ throw new ArgumentException(Localization.Customers.IDException, "customer");
+
+ var errors = ValidateCustomer(customer);
+ if (errors.Count == 0)
+ Repository.UpdateCustomer(customer);
+
+ return errors;
+ }
+
+ private static Dictionary ValidateCustomer(Customer customer)
+ {
+ var errors = new Dictionary();
+ if (string.IsNullOrEmpty(customer.Name) || customer.Name.Trim().Length == 0)
+ {
+ errors.Add("Name", Localization.Customers.NameEmpty);
+ }
+ return errors;
+ }
+
+ public Customer GetCustomerByID(int customerID)
+ {
+ return Repository.GetCustomerByID(customerID);
+ }
+
+ public void DeleteCustomer(int customerID)
+ {
+ Repository.DeleteCustomer(customerID);
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Customers/ICustomerService.cs b/Core/MiteDesk.Core.Services/Customers/ICustomerService.cs
new file mode 100644
index 0000000..b05b5f9
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Customers/ICustomerService.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public interface ICustomerService
+ {
+ IList GetAllActiveCustomers();
+ IList GetAllArchivedCustomers();
+ Dictionary CreateCustomer(Customer customer);
+ Dictionary UpdateCustomer(Customer customer);
+ Customer GetCustomerByID(int customerID);
+ void DeleteCustomer(int customerID);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Activities.Designer.cs b/Core/MiteDesk.Core.Services/Localization/Activities.Designer.cs
new file mode 100644
index 0000000..67fbd04
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Activities.Designer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Activities {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Activities() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.Core.Services.Localization.Activities", typeof(Activities).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die ID der Leistung darf nicht 0 sein.
+ ///
+ internal static string IDException {
+ get {
+ return ResourceManager.GetString("IDException", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Der angegebene Name ist ungültig..
+ ///
+ internal static string NameEmpty {
+ get {
+ return ResourceManager.GetString("NameEmpty", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Localization/Activities.en.resx b/Core/MiteDesk.Core.Services/Localization/Activities.en.resx
new file mode 100644
index 0000000..5344f20
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Activities.en.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ ID of service may not be 0.
+
+
+ Please enter a valid name
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Activities.resx b/Core/MiteDesk.Core.Services/Localization/Activities.resx
new file mode 100644
index 0000000..db393aa
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Activities.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Die ID der Leistung darf nicht 0 sein
+
+
+ Der angegebene Name ist ungültig.
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Customers.Designer.cs b/Core/MiteDesk.Core.Services/Localization/Customers.Designer.cs
new file mode 100644
index 0000000..040618c
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Customers.Designer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Customers {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Customers() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.Core.Services.Localization.Customers", typeof(Customers).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die ID des Kunden darf nicht 0 sein.
+ ///
+ internal static string IDException {
+ get {
+ return ResourceManager.GetString("IDException", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Der angegebene Name ist ungültig..
+ ///
+ internal static string NameEmpty {
+ get {
+ return ResourceManager.GetString("NameEmpty", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Localization/Customers.en.resx b/Core/MiteDesk.Core.Services/Localization/Customers.en.resx
new file mode 100644
index 0000000..06c7dcd
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Customers.en.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ ID of customer may not be 0.
+
+
+ Please enter a valid name
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Customers.resx b/Core/MiteDesk.Core.Services/Localization/Customers.resx
new file mode 100644
index 0000000..db6cab0
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Customers.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Die ID des Kunden darf nicht 0 sein
+
+
+ Der angegebene Name ist ungültig.
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Projects.Designer.cs b/Core/MiteDesk.Core.Services/Localization/Projects.Designer.cs
new file mode 100644
index 0000000..a4c77e6
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Projects.Designer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Projects {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Projects() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.Core.Services.Localization.Projects", typeof(Projects).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die ID des Projektes darf nicht 0 sein.
+ ///
+ internal static string IDException {
+ get {
+ return ResourceManager.GetString("IDException", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Der angegebene Name ist ungültig..
+ ///
+ internal static string NameEmpty {
+ get {
+ return ResourceManager.GetString("NameEmpty", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Localization/Projects.en.resx b/Core/MiteDesk.Core.Services/Localization/Projects.en.resx
new file mode 100644
index 0000000..c0a2883
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Projects.en.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ ID of project may not be 0.
+
+
+ Please enter a valid name
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/Projects.resx b/Core/MiteDesk.Core.Services/Localization/Projects.resx
new file mode 100644
index 0000000..c18b36d
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/Projects.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Die ID des Projektes darf nicht 0 sein
+
+
+ Der angegebene Name ist ungültig.
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/TimeEntries.Designer.cs b/Core/MiteDesk.Core.Services/Localization/TimeEntries.Designer.cs
new file mode 100644
index 0000000..0539d82
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/TimeEntries.Designer.cs
@@ -0,0 +1,99 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30128.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Localization {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // 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.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class TimeEntries {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal TimeEntries() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SixtyNineDegrees.MiteDesk.Core.Services.Localization.TimeEntries", typeof(TimeEntries).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Die ausgewählte Leistung konnte nicht gefunden werden..
+ ///
+ internal static string ActivityID {
+ get {
+ return ResourceManager.GetString("ActivityID", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Das angegebene Datum ist ungültig..
+ ///
+ internal static string Date {
+ get {
+ return ResourceManager.GetString("Date", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Das ausgewählte Projekt konnte nicht gefunden werden..
+ ///
+ internal static string ProjectID {
+ get {
+ return ResourceManager.GetString("ProjectID", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bitte gib eine korrekt formatierte Zeit an..
+ ///
+ internal static string Time {
+ get {
+ return ResourceManager.GetString("Time", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Localization/TimeEntries.en.resx b/Core/MiteDesk.Core.Services/Localization/TimeEntries.en.resx
new file mode 100644
index 0000000..660a934
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/TimeEntries.en.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ The service you selected could not be found
+
+
+ Please enter a valid date
+
+
+ The project you selected could not be found
+
+
+ Please enter a well formatted time
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Localization/TimeEntries.resx b/Core/MiteDesk.Core.Services/Localization/TimeEntries.resx
new file mode 100644
index 0000000..b9426de
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Localization/TimeEntries.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Die ausgewählte Leistung konnte nicht gefunden werden.
+
+
+ Das angegebene Datum ist ungültig.
+
+
+ Das ausgewählte Projekt konnte nicht gefunden werden.
+
+
+ Bitte gib eine korrekt formatierte Zeit an.
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/MiteDesk.Core.Services.csproj b/Core/MiteDesk.Core.Services/MiteDesk.Core.Services.csproj
new file mode 100644
index 0000000..b9b9c4e
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/MiteDesk.Core.Services.csproj
@@ -0,0 +1,166 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Services
+ mite.desk.core.services
+ v3.5
+ 512
+ true
+
+
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Activities.resx
+
+
+ True
+ True
+ Customers.resx
+
+
+ True
+ True
+ Projects.resx
+
+
+ True
+ True
+ TimeEntries.resx
+
+
+
+
+
+
+
+
+
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}
+ MiteDesk.Core.Data
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+
+
+
+ ResXFileCodeGenerator
+ Activities.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ Customers.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ Projects.Designer.cs
+
+
+
+ ResXFileCodeGenerator
+ TimeEntries.Designer.cs
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Projects/IProjectService.cs b/Core/MiteDesk.Core.Services/Projects/IProjectService.cs
new file mode 100644
index 0000000..146bdf9
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Projects/IProjectService.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public interface IProjectService
+ {
+ IList GetAllActiveProjects();
+ IList GetAllArchivedProjects();
+ IList GetProjectsByCustomer(int customerID);
+ Project GetProjectByID(int projectID);
+ Dictionary CreateProject(Project project, string budget);
+ Dictionary UpdateProject(Project project, string budget);
+ void DeleteProject(int projectID);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/Projects/ProjectService.cs b/Core/MiteDesk.Core.Services/Projects/ProjectService.cs
new file mode 100644
index 0000000..4686396
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Projects/ProjectService.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public class ProjectService : IProjectService
+ {
+
+ public ProjectService(IProjectRepository repository)
+ {
+ Repository = repository;
+ }
+
+ private readonly IProjectRepository Repository;
+
+ public IList GetAllActiveProjects()
+ {
+ return Repository.GetAllActiveProjects();
+ }
+
+ public IList GetProjectsByCustomer(int customerID)
+ {
+ return Repository.GetProjectsByCustomer(customerID);
+ }
+
+ public IList GetAllArchivedProjects()
+ {
+ return Repository.GetAllArchivedProjects();
+ }
+
+ public Project GetProjectByID(int projectID)
+ {
+ return Repository.GetProjectByID(projectID);
+ }
+
+ public Dictionary CreateProject(Project project, string budget)
+ {
+ var errors = ValidateProject(project);
+ if (errors.Count == 0)
+ {
+ project.Budget = ParseBudget(budget, project.BudgetType);
+ Repository.CreateProject(project);
+ }
+ return errors;
+ }
+
+ public Dictionary UpdateProject(Project project, string budget)
+ {
+ if (project.ID == 0)
+ throw new ArgumentException(Localization.Projects.IDException, "project");
+
+ var errors = ValidateProject(project);
+ if (errors.Count == 0)
+ {
+ project.Budget = ParseBudget(budget, project.BudgetType);
+ Repository.UpdateProject(project);
+ }
+
+ return errors;
+ }
+
+ private static Dictionary ValidateProject(Project project)
+ {
+ var errors = new Dictionary();
+ if (string.IsNullOrEmpty(project.Name) || project.Name.Trim().Length == 0)
+ {
+ errors.Add("Name", Localization.Projects.NameEmpty);
+ }
+ return errors;
+ }
+
+ public void DeleteProject(int projectID)
+ {
+ Repository.DeleteProject(projectID);
+ }
+
+ private static int ParseBudget(string value, string type)
+ {
+
+ // mal aufräumen ...
+
+ int budget = 0;
+
+ if(type == "minutes")
+ {
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ if (value.IndexOf(':') > 0)
+ {
+ string[] tmpTime = value.Split(':');
+ int hours, minutes;
+ if (int.TryParse(tmpTime[0], out hours) && int.TryParse(tmpTime[1], out minutes))
+ {
+ budget = 60*hours + minutes;
+ }
+ }
+ else
+ {
+ int.TryParse(value, out budget);
+ budget = budget*60;
+ }
+ }
+
+ return budget;
+
+ }
+
+ if (string.IsNullOrEmpty(value) || value.Trim().Length == 0)
+ return budget;
+
+
+ if (value.IndexOf(',') > -1)
+ {
+
+ int first, second;
+
+ int.TryParse(value.Split(',')[0], out first);
+
+ if (value.Split(',')[1].Length <= 2)
+ {
+ int.TryParse(value.Split(',')[1], out second);
+ }
+ else
+ {
+ decimal tmp;
+ decimal.TryParse(value, out tmp);
+ tmp = Math.Round(tmp, 2);
+ int.TryParse(tmp.ToString().Split(',')[1], out second);
+ }
+
+ budget = (first * 100) + second;
+
+ }
+ else
+ {
+ int.TryParse(value, out budget);
+ if (budget > 0)
+ {
+ budget = budget * 100;
+ }
+ }
+
+ return budget;
+
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Properties/AssemblyInfo.cs b/Core/MiteDesk.Core.Services/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c4c85b0
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("mite.desk.services")]
+[assembly: AssemblyDescription("mite.desk.services")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("f2048a59-65e3-4b83-ba99-66479ff3336c")]
+
+[assembly: AssemblyVersion("1.2.17")]
+[assembly: AssemblyFileVersion("1.2.17")]
diff --git a/Core/MiteDesk.Core.Services/TimeEntries/ITimeEntryService.cs b/Core/MiteDesk.Core.Services/TimeEntries/ITimeEntryService.cs
new file mode 100644
index 0000000..f9374fc
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/TimeEntries/ITimeEntryService.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public interface ITimeEntryService
+ {
+ Dictionary CreateTimeEntry(ref TimeEntry entry, string timeText);
+ Dictionary UpdateTimeEntry(TimeEntry entry, string timeText);
+ Dictionary ValidateTimeEntry(TimeEntry entry, string timeText);
+ IList GetTimeEntriesByDate(DateTime date);
+ IList GetTimeEntriesByActivityID(int activityID);
+ IList GetTimeEntriesByProjectID(int projectID);
+ IList GetTimeEntryDatesByRange(DateTime start, DateTime end, int userID);
+ TimeEntry GetTimeEntryByID(int timeEntryID);
+ TimeEntry GetTimeEntryCurrentlyTrackedByStopwatch();
+ void DeleteTimeEntry(int timeEntryID);
+ void StartStopwatch(int timeEntryID);
+ void StopStopwatch(int timeEntryID);
+ }
+}
\ No newline at end of file
diff --git a/Core/MiteDesk.Core.Services/TimeEntries/TimeEntryService.cs b/Core/MiteDesk.Core.Services/TimeEntries/TimeEntryService.cs
new file mode 100644
index 0000000..c5e15db
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/TimeEntries/TimeEntryService.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services
+{
+ public class TimeEntryService : ITimeEntryService
+ {
+
+ public TimeEntryService(ITimeEntryRepository repository, IProjectService projectService, IActivityService activityService)
+ {
+ Repository = repository;
+ ProjectService = projectService;
+ ActivityService = activityService;
+ }
+
+ private readonly ITimeEntryRepository Repository;
+ private readonly IProjectService ProjectService;
+ private readonly IActivityService ActivityService;
+
+ public Dictionary CreateTimeEntry(ref TimeEntry entry, string timeText)
+ {
+ Dictionary errors = ValidateTimeEntry(entry, timeText);
+ if(errors.Count == 0)
+ {
+ Repository.CreateTimeEntry(ref entry);
+ }
+ return errors;
+ }
+
+ public Dictionary UpdateTimeEntry(TimeEntry entry, string timeText)
+ {
+ Dictionary errors = ValidateTimeEntry(entry, timeText);
+ if (errors.Count == 0)
+ {
+ Repository.UpdateTimeEntry(entry);
+ }
+ return errors;
+
+ }
+
+ public Dictionary ValidateTimeEntry(TimeEntry entry, string timeText)
+ {
+ Dictionary errors = new Dictionary();
+
+ int projectID = entry.ProjectID;
+ int activityID = entry.ActivityID;
+
+ // Projekt verfügbar?
+ if (entry.ProjectID != 0 && !ProjectService.GetAllActiveProjects().Any(p => p.ID == projectID))
+ {
+ errors.Add("ProjectID", Localization.TimeEntries.ProjectID);
+ }
+
+ // Leistung verfügbar?
+ if (entry.ActivityID != 0 && !ActivityService.GetAllActiveActivities().Any(a => a.ID == activityID))
+ {
+ errors.Add("ActivityID", Localization.TimeEntries.ActivityID);
+ }
+
+ // Datum angegeben?
+ if(entry.Date == DateTime.MinValue)
+ {
+ errors.Add("Date", Localization.TimeEntries.Date);
+ }
+
+ // Zeit richtig formatiert?
+ bool timeWellFormatted = false;
+ if(!string.IsNullOrEmpty(timeText))
+ {
+ int time;
+ decimal decTime;
+ timeText = timeText.Replace(".", ",");
+ if (timeText.IndexOf(':') > 0)
+ {
+ string[] tmpTime = timeText.Split(':');
+ int hours, minutes;
+ if (int.TryParse(tmpTime[0], out hours) && int.TryParse(tmpTime[1], out minutes))
+ {
+ timeWellFormatted = true;
+ entry.Minutes = 60*hours + minutes;
+ }
+ }
+ else if (decimal.TryParse(timeText, out decTime))
+ {
+ timeWellFormatted = true;
+ entry.Minutes = (int)(decTime * 60);
+ }
+ else if(int.TryParse(timeText, out time))
+ {
+ timeWellFormatted = true;
+ entry.Minutes = time*60;
+ }
+ }
+ else
+ {
+ timeWellFormatted = true;
+ entry.Minutes = 0;
+ }
+
+ if(!timeWellFormatted)
+ {
+ errors.Add("Time", Localization.TimeEntries.Time);
+ }
+ return errors;
+
+ }
+
+ public IList GetTimeEntriesByDate(DateTime date)
+ {
+ return Repository.GetTimeEntriesByDate(date);
+ }
+
+ public IList GetTimeEntriesByActivityID(int activityID)
+ {
+ return Repository.GetTimeEntriesByActivityID(activityID);
+ }
+
+ public IList GetTimeEntriesByProjectID(int projectID)
+ {
+ return Repository.GetTimeEntriesByProjectID(projectID);
+ }
+
+ public IList GetTimeEntryDatesByRange(DateTime start, DateTime end, int userID)
+ {
+ return Repository.GetTimeEntryDatesByRange(start, end, userID);
+ }
+
+ public TimeEntry GetTimeEntryByID(int id)
+ {
+ return Repository.GetTimeEntryByID(id);
+ }
+
+ public TimeEntry GetTimeEntryCurrentlyTrackedByStopwatch()
+ {
+ return Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ }
+
+ public void DeleteTimeEntry(int id)
+ {
+ Repository.DeleteTimeEntry(id);
+ }
+
+ public void StartStopwatch(int timeEntryID)
+ {
+ Repository.StartStopwatch(timeEntryID);
+ }
+
+ public void StopStopwatch(int timeEntryID)
+ {
+ Repository.StopStopwatch(timeEntryID);
+ }
+
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Users/IUserService.cs b/Core/MiteDesk.Core.Services/Users/IUserService.cs
new file mode 100644
index 0000000..47e4a39
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Users/IUserService.cs
@@ -0,0 +1,16 @@
+/****************************************************************
+ * Copyright (c) 2009 69° media solutions - All rights reserved *
+ * 69 Grad OHG - Forsterstraße 100 - 90441 Nuernberg - Germany *
+ ***************************************************************/
+
+using System.Collections.Generic;
+using WinMite.Core.Model;
+
+namespace WinMite.Core.Services
+{
+ public interface IUserService
+ {
+ User GetUser();
+ Dictionary UpdateUser(User user);
+ }
+}
diff --git a/Core/MiteDesk.Core.Services/Users/UserService.cs b/Core/MiteDesk.Core.Services/Users/UserService.cs
new file mode 100644
index 0000000..106906a
--- /dev/null
+++ b/Core/MiteDesk.Core.Services/Users/UserService.cs
@@ -0,0 +1,58 @@
+/****************************************************************
+ * Copyright (c) 2009 69° media solutions - All rights reserved *
+ * 69 Grad OHG - Forsterstraße 100 - 90441 Nuernberg - Germany *
+ ***************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using WinMite.Core.Data;
+using WinMite.Core.Model;
+
+namespace WinMite.Core.Services
+{
+ public class UserService : IUserService
+ {
+
+ public UserService(IUserRepository repository)
+ {
+ Repository = repository;
+ }
+
+ private readonly IUserRepository Repository;
+
+ public User GetUser()
+ {
+ return Repository.GetUser();
+ }
+
+ public Dictionary UpdateUser(User user)
+ {
+
+ Dictionary errors = new Dictionary();
+
+ // Accountname angegeben?
+ if(string.IsNullOrEmpty(user.AccountName) || user.AccountName.Trim().Length == 0)
+ errors.Add("AccountName", "Bitte geben Sie den Account-Namen an.");
+
+ // E-Mail-Adresse okay?
+ if (string.IsNullOrEmpty(user.Email) || user.Email.Trim().Length == 0)
+ errors.Add("Email", "Bitte geben Sie Ihre E-Mail-Adresse an.");
+ else if (!new Regex(@"^[\w\.-]+@[\w\.-]+\.[a-zA-Z]{2,6}$").Match(user.Email).Success)
+ errors.Add("Email", "Bitte geben Sie eine korrekte E-Mail-Adresse an.");
+
+ // Passwort angegeben?
+ if (string.IsNullOrEmpty(user.Password) || user.Password.Trim().Length == 0)
+ errors.Add("Password", "Bitte geben Sie Ihr Passwort an.");
+
+ if(errors.Count == 0)
+ {
+ Repository.UpdateUser(user);
+ }
+
+ return errors;
+
+ }
+
+ }
+}
diff --git a/Deployment/MiteDesk.WinForms.Setup/MiteDesk.WinForms.Setup.vdproj b/Deployment/MiteDesk.WinForms.Setup/MiteDesk.WinForms.Setup.vdproj
new file mode 100644
index 0000000..67f0e8c
--- /dev/null
+++ b/Deployment/MiteDesk.WinForms.Setup/MiteDesk.WinForms.Setup.vdproj
@@ -0,0 +1,1235 @@
+"DeployProject"
+{
+"VSVersion" = "3:800"
+"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
+"IsWebType" = "8:FALSE"
+"ProjectName" = "8:MiteDesk.WinForms.Setup"
+"LanguageId" = "3:1031"
+"CodePage" = "3:1252"
+"UILanguageId" = "3:1031"
+"SccProjectName" = "8:"
+"SccLocalPath" = "8:"
+"SccAuxPath" = "8:"
+"SccProvider" = "8:"
+ "Hierarchy"
+ {
+ "Entry"
+ {
+ "MsmKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "OwnerKey" = "8:_A1D793DFCEAC4C2632C82E16A2294CBE"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "OwnerKey" = "8:_CE68243731A7F382932200AC685A832B"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "OwnerKey" = "8:_390D2894D6B8216C73514AD70EE9C970"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "OwnerKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_390D2894D6B8216C73514AD70EE9C970"
+ "OwnerKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_390D2894D6B8216C73514AD70EE9C970"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_4BA3E6D6E6F0507A83D364988B9EC467"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_665DDB4A7B834028B01E82C06ADCCC2A"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_7684FBF17F1A472588EF44035BEB78DE"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_A1D793DFCEAC4C2632C82E16A2294CBE"
+ "OwnerKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_A1D793DFCEAC4C2632C82E16A2294CBE"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_CE68243731A7F382932200AC685A832B"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "OwnerKey" = "8:_CE68243731A7F382932200AC685A832B"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_4BA3E6D6E6F0507A83D364988B9EC467"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_CE68243731A7F382932200AC685A832B"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_390D2894D6B8216C73514AD70EE9C970"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_A1D793DFCEAC4C2632C82E16A2294CBE"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_UNDEFINED"
+ "OwnerKey" = "8:_2D7003A1F920EF9EC3E2849B8E78110A"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ }
+ "Configurations"
+ {
+ "Debug"
+ {
+ "DisplayName" = "8:Debug"
+ "IsDebugOnly" = "11:TRUE"
+ "IsReleaseOnly" = "11:FALSE"
+ "OutputFilename" = "8:Debug\\mite.desk.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:3"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Net.Framework.3.5"
+ {
+ "Name" = "8:.NET Framework 3.5"
+ "ProductCode" = "8:Microsoft.Net.Framework.3.5"
+ }
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1"
+ {
+ "Name" = "8:Windows Installer 3.1"
+ "ProductCode" = "8:Microsoft.Windows.Installer.3.1"
+ }
+ }
+ }
+ }
+ "Release"
+ {
+ "DisplayName" = "8:Release"
+ "IsDebugOnly" = "11:FALSE"
+ "IsReleaseOnly" = "11:TRUE"
+ "OutputFilename" = "8:Release\\mite.desk.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:3"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Net.Framework.3.5"
+ {
+ "Name" = "8:.NET Framework 3.5"
+ "ProductCode" = "8:Microsoft.Net.Framework.3.5"
+ }
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1"
+ {
+ "Name" = "8:Windows Installer 3.1"
+ "ProductCode" = "8:Microsoft.Windows.Installer.3.1"
+ }
+ }
+ }
+ }
+ }
+ "Deployable"
+ {
+ "CustomAction"
+ {
+ }
+ "DefaultFeature"
+ {
+ "Name" = "8:DefaultFeature"
+ "Title" = "8:"
+ "Description" = "8:"
+ }
+ "ExternalPersistence"
+ {
+ "LaunchCondition"
+ {
+ "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_C366A84C997D46A1B3E07AA85ACA4C8A"
+ {
+ "Name" = "8:.NET Framework"
+ "Message" = "8:[VSDNETMSG]"
+ "FrameworkVersion" = "8:3.5.30729 "
+ "AllowLaterVersions" = "11:FALSE"
+ "InstallUrl" = "8:http://www.microsoft.com/downloads/details.aspx?FamilyId=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=de"
+ }
+ }
+ }
+ "File"
+ {
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_2D7003A1F920EF9EC3E2849B8E78110A"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:mite.desk.core.model, Version=1.2.17.0, Culture=neutral, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_2D7003A1F920EF9EC3E2849B8E78110A"
+ {
+ "Name" = "8:mite.desk.core.model.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:mite.desk.core.model.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_390D2894D6B8216C73514AD70EE9C970"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:mite.desk.tools.connector, Version=1.2.17.0, Culture=neutral, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_390D2894D6B8216C73514AD70EE9C970"
+ {
+ "Name" = "8:mite.desk.tools.connector.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:mite.desk.tools.connector.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_4BA3E6D6E6F0507A83D364988B9EC467"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:StructureMap, Version=2.5.3.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_4BA3E6D6E6F0507A83D364988B9EC467"
+ {
+ "Name" = "8:StructureMap.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:StructureMap.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_665DDB4A7B834028B01E82C06ADCCC2A"
+ {
+ "SourcePath" = "8:mite.desk.ico"
+ "TargetName" = "8:mite.desk.ico"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7684FBF17F1A472588EF44035BEB78DE"
+ {
+ "SourcePath" = "8:Setup_Splash.jpg"
+ "TargetName" = "8:Setup_Splash.jpg"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_A1D793DFCEAC4C2632C82E16A2294CBE"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:mite.desk.core.infrastructure, Version=1.2.17.0, Culture=neutral, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_A1D793DFCEAC4C2632C82E16A2294CBE"
+ {
+ "Name" = "8:mite.desk.core.infrastructure.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:mite.desk.core.infrastructure.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B2002D4BCE4648F5A834FA62822D3BF3"
+ {
+ "SourcePath" = "8:setup_titlebar.jpg"
+ "TargetName" = "8:setup_titlebar.jpg"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_CE68243731A7F382932200AC685A832B"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:mite.desk.core.services, Version=1.2.17.0, Culture=neutral, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_CE68243731A7F382932200AC685A832B"
+ {
+ "Name" = "8:mite.desk.core.services.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:mite.desk.core.services.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_FCBAAC4F50103C640B2F5DF5201DEC97"
+ {
+ "AssemblyRegister" = "3:1"
+ "AssemblyIsInGAC" = "11:FALSE"
+ "AssemblyAsmDisplayName" = "8:mite.desk.core.data, Version=1.2.17.0, Culture=neutral, processorArchitecture=MSIL"
+ "ScatterAssemblies"
+ {
+ "_FCBAAC4F50103C640B2F5DF5201DEC97"
+ {
+ "Name" = "8:mite.desk.core.data.dll"
+ "Attributes" = "3:512"
+ }
+ }
+ "SourcePath" = "8:mite.desk.core.data.dll"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:TRUE"
+ "IsolateTo" = "8:"
+ }
+ }
+ "FileType"
+ {
+ }
+ "Folder"
+ {
+ "{1525181F-901A-416C-8A58-119130FE478E}:_29C9412AA9BD49A6A833A48F59B6BD0D"
+ {
+ "Name" = "8:#1916"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:DesktopFolder"
+ "Folders"
+ {
+ }
+ }
+ "{1525181F-901A-416C-8A58-119130FE478E}:_3483506330BF40DA9E48247C5C7DA1ED"
+ {
+ "Name" = "8:#1928"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:StartupFolder"
+ "Folders"
+ {
+ }
+ }
+ "{3C67513D-01DD-4637-8A68-80971EB9504F}:_474D496400934C669E8E0D12487A84B1"
+ {
+ "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]"
+ "Name" = "8:#1925"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:TARGETDIR"
+ "Folders"
+ {
+ }
+ }
+ "{1525181F-901A-416C-8A58-119130FE478E}:_4757F6931EB44E119EFEE4ABF59151FE"
+ {
+ "Name" = "8:#1919"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:ProgramMenuFolder"
+ "Folders"
+ {
+ }
+ }
+ "{1525181F-901A-416C-8A58-119130FE478E}:_C8CAF572CADD4604A23AABF8060CA298"
+ {
+ "Name" = "8:#1915"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:AppDataFolder"
+ "Folders"
+ {
+ }
+ }
+ }
+ "LaunchCondition"
+ {
+ }
+ "Locator"
+ {
+ }
+ "MsiBootstrapper"
+ {
+ "LangId" = "3:1031"
+ "RequiresElevation" = "11:FALSE"
+ }
+ "Product"
+ {
+ "Name" = "8:Microsoft Visual Studio"
+ "ProductName" = "8:mite.desk"
+ "ProductCode" = "8:{64190F74-3531-4813-B09F-11685336F3B4}"
+ "PackageCode" = "8:{0EE72A52-F9B5-4919-AC4B-7D01F28AFF29}"
+ "UpgradeCode" = "8:{57BAD98D-AB91-48CD-8DBC-9FC1C8029282}"
+ "AspNetVersion" = "8:4.0.30319.0"
+ "RestartWWWService" = "11:FALSE"
+ "RemovePreviousVersions" = "11:TRUE"
+ "DetectNewerInstalledVersion" = "11:FALSE"
+ "InstallAllUsers" = "11:TRUE"
+ "ProductVersion" = "8:1.3.0"
+ "Manufacturer" = "8:69 Grad"
+ "ARPHELPTELEPHONE" = "8:"
+ "ARPHELPLINK" = "8:http://www.69grad.de"
+ "Title" = "8:mite.desk Setup"
+ "Subject" = "8:"
+ "ARPCONTACT" = "8:69 Grad"
+ "Keywords" = "8:"
+ "ARPCOMMENTS" = "8:"
+ "ARPURLINFOABOUT" = "8:http://www.69grad.de/"
+ "ARPPRODUCTICON" = "8:_665DDB4A7B834028B01E82C06ADCCC2A"
+ "ARPIconIndex" = "3:0"
+ "SearchPath" = "8:"
+ "UseSystemSearchPath" = "11:TRUE"
+ "TargetPlatform" = "3:0"
+ "PreBuildEvent" = "8:"
+ "PostBuildEvent" = "8:"
+ "RunPostBuildEvent" = "3:0"
+ }
+ "Registry"
+ {
+ "HKLM"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_8E067F3AD9E64DE39DF5CBCC53370867"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_28D63300C54D4E25B8F2D212C798732B"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCU"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_3D87F767BA6B44AD9872E8B2969A320F"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_28C07956704B4E3EB9D446DED2664AE2"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCR"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKU"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKPU"
+ {
+ "Keys"
+ {
+ }
+ }
+ }
+ "Sequences"
+ {
+ }
+ "Shortcut"
+ {
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_8460030AFF0842F49D59444AAEC77343"
+ {
+ "Name" = "8:mite.desk"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "Folder" = "8:_29C9412AA9BD49A6A833A48F59B6BD0D"
+ "WorkingFolder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Icon" = "8:_665DDB4A7B834028B01E82C06ADCCC2A"
+ "Feature" = "8:"
+ }
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_FD70069B358B4EA69E94BB0394385AF0"
+ {
+ "Name" = "8:mite.desk"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_04A8B693F44A4C2AA60FD814913E3D08"
+ "Folder" = "8:_4757F6931EB44E119EFEE4ABF59151FE"
+ "WorkingFolder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Icon" = "8:_665DDB4A7B834028B01E82C06ADCCC2A"
+ "Feature" = "8:"
+ }
+ }
+ "UserInterface"
+ {
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_0F21D88DE6754393B61444016DF4F692"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:1"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2F7CA84E87314D798E1B7157A142804A"
+ {
+ "Sequence" = "3:300"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7C2FFB9880C948F9A5485A0B9805B1EC"
+ {
+ "Sequence" = "3:110"
+ "DisplayName" = "8:Splash"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdSplashDlg.wid"
+ "Properties"
+ {
+ "SplashBitmap"
+ {
+ "Name" = "8:SplashBitmap"
+ "DisplayName" = "8:#1013"
+ "Description" = "8:#1113"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:0"
+ "Setting" = "3:2"
+ "Value" = "8:_7684FBF17F1A472588EF44035BEB78DE"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Sunken"
+ {
+ "Name" = "8:Sunken"
+ "DisplayName" = "8:#1007"
+ "Description" = "8:#1107"
+ "Type" = "3:5"
+ "ContextData" = "8:4;True=4;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:0"
+ "DefaultValue" = "3:4"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9F3099BC506C4419925266281880EE0E"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "InstallAllUsersVisible"
+ {
+ "Name" = "8:InstallAllUsersVisible"
+ "DisplayName" = "8:#1059"
+ "Description" = "8:#1159"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_188D95436D754802B81FDFCE432C1002"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:2"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8709E07B55EB4200B16F774B0915A908"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2C14386792EA4490873704E74E862AAC"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:1"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8984BDC4525A4276A3A7BCADB58B642D"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "UpdateText"
+ {
+ "Name" = "8:UpdateText"
+ "DisplayName" = "8:#1058"
+ "Description" = "8:#1158"
+ "Type" = "3:15"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:2"
+ "Value" = "8:"
+ "DefaultValue" = "8:#1258"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_368EFD2AEFFF4776B1EE63522E39E231"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:1"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F3B220FD1A504DE397B94DF9F8B45DB1"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_5CBE240E454949EDBE92A181CB2FD5AF"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:2"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_B5ACFF92442949F2A982D5A02C6AD40B"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_A78015CF23EA4386A15C22A109F048E4"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdUserInterface.wim"
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_DFA92D47F66F47B2B52DF87DC0CF022C"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:2"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_09D1D3227DA04BF08022F58F6453BC53"
+ {
+ "Sequence" = "3:120"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8F17CD27BB744D12AD09D893EC86E114"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Splash"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminSplashDlg.wid"
+ "Properties"
+ {
+ "SplashBitmap"
+ {
+ "Name" = "8:SplashBitmap"
+ "DisplayName" = "8:#1013"
+ "Description" = "8:#1113"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:0"
+ "Setting" = "3:2"
+ "Value" = "8:_7684FBF17F1A472588EF44035BEB78DE"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Sunken"
+ {
+ "Name" = "8:Sunken"
+ "DisplayName" = "8:#1007"
+ "Description" = "8:#1107"
+ "Type" = "3:5"
+ "ContextData" = "8:4;True=4;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:0"
+ "DefaultValue" = "3:4"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_FC03B617E08C4BDC8901447FFC480ED4"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:2"
+ "Value" = "8:_B2002D4BCE4648F5A834FA62822D3BF3"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_E9276C061A344212A4E18C0C3457474F"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdBasicDialogs.wim"
+ }
+ }
+ "MergeModule"
+ {
+ }
+ "ProjectOutput"
+ {
+ "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_04A8B693F44A4C2AA60FD814913E3D08"
+ {
+ "SourcePath" = "8:..\\..\\App\\MiteDesk.WinForms\\obj\\Release\\mite.desk.exe"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ "ProjectOutputGroupRegister" = "3:1"
+ "OutputConfiguration" = "8:"
+ "OutputGroupCanonicalName" = "8:Built"
+ "OutputProjectGuid" = "8:{352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}"
+ "ShowKeyOutput" = "11:TRUE"
+ "ExcludeFilters"
+ {
+ }
+ }
+ "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_BB09C5F62C6D4D7C9D3154FE02976466"
+ {
+ "SourcePath" = "8:"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ "ProjectOutputGroupRegister" = "3:1"
+ "OutputConfiguration" = "8:"
+ "OutputGroupCanonicalName" = "8:LocalizedResourceDlls"
+ "OutputProjectGuid" = "8:{352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}"
+ "ShowKeyOutput" = "11:TRUE"
+ "ExcludeFilters"
+ {
+ }
+ }
+ "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_C06EDB9458EB43E89A25EF1A758B6655"
+ {
+ "SourcePath" = "8:"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ "ProjectOutputGroupRegister" = "3:1"
+ "OutputConfiguration" = "8:"
+ "OutputGroupCanonicalName" = "8:LocalizedResourceDlls"
+ "OutputProjectGuid" = "8:{733C8DE9-36B5-4C9F-9701-FDD19B64B966}"
+ "ShowKeyOutput" = "11:TRUE"
+ "ExcludeFilters"
+ {
+ }
+ }
+ "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_C7ECF21159E04AABB6405AC9B0D57722"
+ {
+ "SourcePath" = "8:"
+ "TargetName" = "8:"
+ "Tag" = "8:"
+ "Folder" = "8:_474D496400934C669E8E0D12487A84B1"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ "ProjectOutputGroupRegister" = "3:1"
+ "OutputConfiguration" = "8:"
+ "OutputGroupCanonicalName" = "8:LocalizedResourceDlls"
+ "OutputProjectGuid" = "8:{B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}"
+ "ShowKeyOutput" = "11:TRUE"
+ "ExcludeFilters"
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/Deployment/MiteDesk.WinForms.Setup/Setup_Splash.jpg b/Deployment/MiteDesk.WinForms.Setup/Setup_Splash.jpg
new file mode 100644
index 0000000..159707d
Binary files /dev/null and b/Deployment/MiteDesk.WinForms.Setup/Setup_Splash.jpg differ
diff --git a/Deployment/MiteDesk.WinForms.Setup/mite.desk.ico b/Deployment/MiteDesk.WinForms.Setup/mite.desk.ico
new file mode 100644
index 0000000..ff25fca
Binary files /dev/null and b/Deployment/MiteDesk.WinForms.Setup/mite.desk.ico differ
diff --git a/Deployment/MiteDesk.WinForms.Setup/setup_titlebar.jpg b/Deployment/MiteDesk.WinForms.Setup/setup_titlebar.jpg
new file mode 100644
index 0000000..e76e04b
Binary files /dev/null and b/Deployment/MiteDesk.WinForms.Setup/setup_titlebar.jpg differ
diff --git a/Library/Shared/RhinoMocks/Rhino.Mocks.dll b/Library/Shared/RhinoMocks/Rhino.Mocks.dll
new file mode 100644
index 0000000..4b6904b
Binary files /dev/null and b/Library/Shared/RhinoMocks/Rhino.Mocks.dll differ
diff --git a/Library/Shared/RhinoMocks/Rhino.Mocks.xml b/Library/Shared/RhinoMocks/Rhino.Mocks.xml
new file mode 100644
index 0000000..ebb20c5
--- /dev/null
+++ b/Library/Shared/RhinoMocks/Rhino.Mocks.xml
@@ -0,0 +1,5226 @@
+
+
+
+ Rhino.Mocks.Partial
+
+
+
+
+ Interface for constraints
+
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ And operator for constraints
+
+
+
+
+ Not operator for constraints
+
+
+
+
+ Or operator for constraints
+
+
+
+
+ Allow overriding of || or &&
+
+
+
+
+
+
+ Allow overriding of || or &&
+
+
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Initializes a new constraint object.
+
+ The expected object, The actual object is passed in as a parameter to the method
+
+
+
+ Evaluate this constraint.
+
+ The actual object that was passed in the method call to the mock.
+ True when the constraint is met, else false.
+
+
+
+ Checks if the properties of the object
+ are the same as the properies of the object.
+
+ The expected object
+ The actual object
+ True when both objects have the same values, else False.
+
+
+
+
+
+
+
+
+ This is the real heart of the beast.
+
+
+
+ Used by CheckReferenceType to check all properties of the reference type.
+
+ The expected object
+ The actual object
+ True when both objects have the same values, else False.
+
+
+
+ Used by CheckReferenceType to check all fields of the reference type.
+
+ The expected object
+ The actual object
+ True when both objects have the same values, else False.
+
+
+
+ Checks the items of both collections
+
+ The expected collection
+
+ True if both collections contain the same items in the same order.
+
+
+
+ Builds a propertyname from the Stack _properties like 'Order.Product.Price'
+ to be used in the error message.
+
+ A nested property name.
+
+
+
+ Rhino.Mocks uses this property to generate an error message.
+
+
+ A message telling the tester why the constraint failed.
+
+
+
+
+ Constrain that the public field has a specified value
+
+
+
+
+ Constrain that the public field matches another constraint.
+
+
+
+
+ Creates a new instance.
+
+ Name of the public field.
+ Constraint to place on the public field value.
+
+
+
+ Creates a new instance, specifying a disambiguating
+ for the public field.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+ Constraint to place on the public field value.
+
+
+
+ Determines if the object passes the constraint.
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Creates a new instance.
+
+ Name of the public field.
+ Expected value.
+
+
+
+ Creates a new instance, specifying a disambiguating
+ for the public field.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+ Expected value.
+
+
+
+ Constrain that the property has a specified value
+
+
+
+
+ Constrain that the property matches another constraint.
+
+
+
+
+ Creates a new instance.
+
+ Name of the property.
+ Constraint to place on the property value.
+
+
+
+ Creates a new instance, specifying a disambiguating
+ for the property.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+ Constraint to place on the property value.
+
+
+
+ Determines if the object passes the constraint.
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Creates a new instance.
+
+ Name of the property.
+ Expected value.
+
+
+
+ Creates a new instance, specifying a disambiguating
+ for the property.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+ Expected value.
+
+
+
+ Constrain that the parameter must be of the specified type
+
+
+
+
+ Creates a new instance.
+
+ Type.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that determines whether an object is the same object as another.
+
+
+
+
+ Creates a new instance.
+
+ Obj.
+
+
+
+ Determines if the object passes the constraints.
+
+
+
+
+ Gets the message for this constraint.
+
+
+
+
+ Evaluate a parameter using constraints
+
+
+
+
+ Create new instance
+
+
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ A constraint based on lambda expression, we are using Expression{T}
+ because we want to be able to get good error reporting on that.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The expr.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constrain that the list contains the same items as the parameter list
+
+
+
+
+ Creates a new instance.
+
+ In list.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constrain that the parameter is one of the items in the list
+
+
+
+
+ Creates a new instance.
+
+ In list.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constrain that the object is inside the parameter list
+
+
+
+
+ Creates a new instance.
+
+ In list.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Applies another AbstractConstraint to the collection count.
+
+
+
+
+ Creates a new instance.
+
+ The constraint that should be applied to the collection count.
+
+
+
+ Determines if the parameter conforms to this constraint.
+
+
+
+
+ Gets the message for this constraint.
+
+
+
+
+ Applies another AbstractConstraint to a specific list element.
+
+
+
+
+ Creates a new instance.
+
+ The zero-based index of the list element.
+ The constraint that should be applied to the list element.
+
+
+
+ Determines if the parameter conforms to this constraint.
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Applies another AbstractConstraint to a specific generic keyed list element.
+
+
+
+
+ Creates a new instance.
+
+ The key of the list element.
+ The constraint that should be applied to the list element.
+
+
+
+ Determines if the parameter conforms to this constraint.
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constrains that all elements are in the parameter list
+
+
+
+
+ Initializes a new instance of the class.
+
+ The these.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Combines two constraints, constraint pass if either is fine.
+
+
+
+
+ Creates a new instance.
+
+ C1.
+ C2.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Negate a constraint
+
+
+
+
+ Creates a new instance.
+
+ C1.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Combines two constraints
+
+
+
+
+
+ Creates a new instance.
+
+ C1.
+ C2.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constrain the argument to validate according to regex pattern
+
+
+
+
+ Creates a new instance.
+
+ Pattern.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that evaluate whatever an argument contains the specified string.
+
+
+
+
+ Creates a new instance.
+
+ Inner string.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that evaluate whatever an argument ends with the specified string
+
+
+
+
+ Creates a new instance.
+
+ End.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that evaluate whatever an argument start with the specified string
+
+
+
+
+ Creates a new instance.
+
+ Start.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that evaluate whatever an object equals another
+
+
+
+
+ Creates a new instance.
+
+ Obj.
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that always returns true
+
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Constraint that evaluate whatever a comparable is greater than another
+
+
+
+
+ Creates a new instance.
+
+
+
+
+ determains if the object pass the constraints
+
+
+
+
+ Gets the message for this constraint
+
+
+
+
+
+ Central location for constraints
+
+
+
+
+ Evaluate a greater than constraint for .
+
+ The object the parameter should be greater than
+
+
+
+ Evaluate a less than constraint for .
+
+ The object the parameter should be less than
+
+
+
+ Evaluate a less than or equal constraint for .
+
+ The object the parameter should be less than or equal to
+
+
+
+ Evaluate a greater than or equal constraint for .
+
+ The object the parameter should be greater than or equal to
+
+
+
+ Evaluate an equal constraint for .
+
+ The object the parameter should equal to
+
+
+
+ Evaluate a not equal constraint for .
+
+ The object the parameter should not equal to
+
+
+
+ Evaluate a same as constraint.
+
+ The object the parameter should the same as.
+
+
+
+ Evaluate a not same as constraint.
+
+ The object the parameter should not be the same as.
+
+
+
+ A constraints that accept anything
+
+
+
+
+
+ A constraint that accept only nulls
+
+
+
+
+
+ A constraint that accept only non null values
+
+
+
+
+
+ A constraint that accept only value of the specified type
+
+
+
+
+ A constraint that accept only value of the specified type
+
+
+
+
+ Evaluate a parameter using a predicate
+
+ The predicate to use
+
+
+
+ Provides access to the constraintes defined in the class to be used in context
+ with the syntax.
+
+ The type of the argument
+
+
+
+ Evaluate a greater than constraint for .
+
+ The object the parameter should be greater than
+
+
+
+ Evaluate a less than constraint for .
+
+ The object the parameter should be less than
+
+
+
+ Evaluate a less than or equal constraint for .
+
+ The object the parameter should be less than or equal to
+
+
+
+ Evaluate a greater than or equal constraint for .
+
+ The object the parameter should be greater than or equal to
+
+
+
+ Evaluate an equal constraint for .
+
+ The object the parameter should equal to
+
+
+
+ Evaluate a not equal constraint for .
+
+ The object the parameter should not equal to
+
+
+
+ Evaluate a same as constraint.
+
+ The object the parameter should the same as.
+
+
+
+ Evaluate a not same as constraint.
+
+ The object the parameter should not be the same as.
+
+
+
+ Throws NotSupportedException. Don't use Equals to define constraints. Use Equal instead.
+
+
+
+
+
+
+ Serves as a hash function for a particular type.
+
+
+ A hash code for the current .
+
+
+
+
+ A constraints that accept anything
+
+
+
+
+
+ A constraint that accept only nulls
+
+
+
+
+
+ A constraint that accept only non null values
+
+
+
+
+
+ A constraint that accept only value of the specified type.
+ The check is performed on the type that has been defined
+ as the argument type.
+
+
+
+
+ Central location for constraints about lists and collections
+
+
+
+
+ Determines whether the specified obj is in the paramter.
+ The parameter must be IEnumerable.
+
+ Obj.
+
+
+
+
+ Determains whatever the parameter is in the collection.
+
+
+
+
+ Determains that the parameter collection is identical to the specified collection
+
+
+
+
+ Determines that the parameter collection has the specified number of elements.
+
+ The constraint that should be applied to the collection count.
+
+
+
+ Determines that an element of the parameter collections conforms to another AbstractConstraint.
+
+ The zero-based index of the list element.
+ The constraint which should be applied to the list element.
+
+
+
+ Determines that an element of the parameter collections conforms to another AbstractConstraint.
+
+ The key of the element.
+ The constraint which should be applied to the element.
+
+
+
+ Determines that all elements of the specified collection are in the the parameter collection
+
+ The collection to compare against
+ The constraint which should be applied to the list parameter.
+
+
+
+ Provides access to the constraintes defined in the class to be used in context
+ with the syntax.
+
+
+
+
+ Determines whether the specified object is in the paramter.
+ The parameter must be IEnumerable.
+
+ Obj.
+
+
+
+
+ Determains whatever the parameter is in the collection.
+
+
+
+
+ Determains that the parameter collection is identical to the specified collection
+
+
+
+
+ Determines that the parameter collection has the specified number of elements.
+
+ The constraint that should be applied to the collection count.
+
+
+
+ Determines that an element of the parameter collections conforms to another AbstractConstraint.
+
+ The zero-based index of the list element.
+ The constraint which should be applied to the list element.
+
+
+
+ Determines that all elements of the specified collection are in the the parameter collection
+
+ The collection to compare against
+ The constraint which should be applied to the list parameter.
+
+
+
+ Throws NotSupportedException. Don't use Equals to define constraints. Use Equal instead.
+
+
+
+
+
+
+ Serves as a hash function for a particular type.
+
+
+ A hash code for the current .
+
+
+
+
+ Provides a dummy field to pass as out or ref argument.
+
+
+
+
+
+ Dummy field to satisfy the compiler. Used for out and ref arguments.
+
+
+
+
+ Central location for constraints for object's properties
+
+
+
+
+ Constrains the parameter to have property with the specified value
+
+ Name of the property.
+ Expected value.
+
+
+
+
+ Constrains the parameter to have property with the specified value.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+ Expected value.
+
+
+
+
+ Constrains the parameter to have a property satisfying a specified constraint.
+
+ Name of the property.
+ Constraint for the property.
+
+
+
+ Constrains the parameter to have a property satisfying a specified constraint.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+ Constraint for the property.
+
+
+
+ Determines whether the parameter has the specified property and that it is null.
+
+ Name of the property.
+
+
+
+
+ Determines whether the parameter has the specified property and that it is null.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+
+
+
+
+ Determines whether the parameter has the specified property and that it is not null.
+
+ Name of the property.
+
+
+
+
+ Determines whether the parameter has the specified property and that it is not null.
+
+ The type that declares the property, used to disambiguate between properties.
+ Name of the property.
+
+
+
+
+ constraints the parameter to have the exact same property values as the expected object.
+
+ An object, of the same type as the parameter, whose properties are set with the expected values.
+ An instance of the constraint that will do the actual check.
+
+ The parameter's public property values and public field values will be matched against the expected object's
+ public property values and public field values. The first mismatch will be reported and no further matching is done.
+ The matching is recursive for any property or field that has properties or fields of it's own.
+ Collections are supported through IEnumerable, which means the constraint will check if the actual and expected
+ collection contain the same values in the same order, where the values contained by the collection can have properties
+ and fields of their own that will be checked as well because of the recursive nature of this constraint.
+
+
+
+
+ Central location for constraints for object's public fields
+
+
+
+
+ Constrains the parameter to have a public field with the specified value
+
+ Name of the public field.
+ Expected value.
+
+
+
+
+ Constrains the parameter to have a public field with the specified value.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+ Expected value.
+
+
+
+
+ Constrains the parameter to have a public field satisfying a specified constraint.
+
+ Name of the public field.
+ Constraint for the public field.
+
+
+
+ Constrains the parameter to have a public field satisfying a specified constraint.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+ Constraint for the public field.
+
+
+
+ Determines whether the parameter has the specified public field and that it is null.
+
+ Name of the public field.
+
+
+
+
+ Determines whether the parameter has the specified public field and that it is null.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+
+
+
+
+ Determines whether the parameter has the specified public field and that it is not null.
+
+ Name of the public field.
+
+
+
+
+ Determines whether the parameter has the specified public field and that it is not null.
+
+ The type that declares the public field, used to disambiguate between public fields.
+ Name of the public field.
+
+
+
+
+ Central location for all text related constraints
+
+
+
+
+ Constrain the argument to starts with the specified string
+
+
+
+
+ Constrain the argument to end with the specified string
+
+
+
+
+ Constrain the argument to contain the specified string
+
+
+
+
+ Constrain the argument to validate according to regex pattern
+
+
+
+
+ Provides access to the constraintes defined in the class to be used in context
+ with the syntax.
+
+
+
+
+ Constrain the argument to starts with the specified string
+
+
+
+
+
+ Constrain the argument to end with the specified string
+
+
+
+
+ Constrain the argument to contain the specified string
+
+
+
+
+ Constrain the argument to validate according to regex pattern
+
+
+
+
+ Throws NotSupportedException. Don't use Equals to define constraints. Use Equal instead.
+
+
+
+
+
+
+ Serves as a hash function for a particular type.
+
+
+ A hash code for the current .
+
+
+
+
+ An expectaton violation was detected.
+
+
+
+
+ Creates a new instance.
+
+ Message.
+
+
+
+ Serialization constructor
+
+
+
+
+ Signals that an object was call on a mock repostiroy which doesn't
+ belong to this mock repository or not a mock
+
+
+
+
+ Creates a new instance.
+
+ Message.
+
+
+
+ Serialization constructor
+
+
+
+
+ Abstract class that holds common information for
+ expectations.
+
+
+
+
+ Interface to validate that a method call is correct.
+
+
+
+
+ Validate the arguments for the method.
+ This method can be called numerous times, so be careful about side effects
+
+ The arguments with which the method was called
+
+
+
+ Add an actual method call to this expectation
+
+
+
+
+ Returns the return value or throw the exception and setup any output / ref parameters
+ that has been set.
+
+
+
+
+ Allow to set the return value in the future, if it was already set.
+
+
+
+
+ Builds the verification failure message.
+
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ Range of expected calls
+
+
+
+
+ Number of call actually made for this method
+
+
+
+
+ If this expectation is still waiting for calls.
+
+
+
+
+ The return value for a method matching this expectation
+
+
+
+
+ Gets or sets the exception to throw on a method matching this expectation.
+
+
+
+
+ Gets a value indicating whether this instance's action is staisfied.
+ A staisfied instance means that there are no more requirements from
+ this method. A method with non void return value must register either
+ a return value or an exception to throw.
+
+
+
+
+ Gets the method this expectation is for.
+
+
+
+
+ Gets or sets what special condtions there are for this method
+ repeating.
+
+
+
+
+ Gets a value indicating whether this expectation was satisfied
+
+
+
+
+ Specify whatever this expectation has a return value set
+ You can't check ReturnValue for this because a valid return value include null.
+
+
+
+
+ An action to execute when the method is matched.
+
+
+
+
+ Set the out / ref parameters for the method call.
+ The indexing is zero based and ignores any non out/ref parameter.
+ It is possible not to pass all the parameters. This method can be called only once.
+
+
+
+
+ Documentation Message
+
+
+
+
+ Gets the invocation for this expectation
+
+ The invocation.
+
+
+
+ Occurs when the exceptation is match on a method call
+
+
+
+
+ Number of actuall calls made that passed this expectation
+
+
+
+
+ Range of expected calls that should pass this expectation.
+
+
+
+
+ The return value for a method matching this expectation
+
+
+
+
+ The exception to throw on a method matching this expectation.
+
+
+
+
+ The method this expectation is for.
+
+
+
+
+ The return value for this method was set
+
+
+
+
+ Whether this method will repeat
+ unlimited number of times.
+
+
+
+
+ A delegate that will be run when the
+ expectation is matched.
+
+
+
+
+ The arguments that matched this expectation.
+
+
+
+
+ Documentation message
+
+
+
+
+ The method originalInvocation
+
+
+
+
+ Get the hash code
+
+
+
+
+ Add an actual actualMethodCall call to this expectation
+
+
+
+
+ Builds the verification failure message.
+
+
+
+
+
+ Allow to set the return value in the future, if it was already set.
+
+
+
+
+ Returns the return value or throw the exception and setup output / ref parameters
+
+
+
+
+ Validate the arguments for the method on the child methods
+
+ The arguments with which the method was called
+
+
+
+ Creates a new instance.
+
+ The originalInvocation for this method, required because it contains the generic type infromation
+
+
+
+ Creates a new instance.
+
+ Expectation.
+
+
+
+ Validate the arguments for the method on the child methods
+
+ The arguments with which the method was called
+
+
+
+ Determines if this object equal to obj
+
+
+
+
+ The error message for these arguments
+
+
+
+
+ Asserts that the delegate has the same parameters as the expectation's method call
+
+
+
+
+ Setter for the outpur / ref parameters for this expecataion.
+ Can only be set once.
+
+
+
+
+ Specify whatever this expectation has a return value set
+ You can't check ReturnValue for this because a valid return value include null.
+
+
+
+
+ Gets the method this expectation is for.
+
+
+
+
+ Gets the originalInvocation for this expectation
+
+ The originalInvocation.
+
+
+
+ Gets or sets what special condtions there are for this method
+
+
+
+
+ Range of expected calls
+
+
+
+
+ Number of call actually made for this method
+
+
+
+
+ If this expectation is still waiting for calls.
+
+
+
+
+ Gets a value indicating whether this expectation was satisfied
+
+
+
+
+ The return value for a method matching this expectation
+
+
+
+
+ An action to execute when the method is matched.
+
+
+
+
+ Gets or sets the exception to throw on a method matching this expectation.
+
+
+
+
+ Gets a value indicating whether this instance's action is staisfied.
+ A staisfied instance means that there are no more requirements from
+ this method. A method with non void return value must register either
+ a return value or an exception to throw or an action to execute.
+
+
+
+
+ Documentation message
+
+
+
+
+ Occurs when the exceptation is match on a method call
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ Expectation that matchs any arguments for the method.
+
+
+
+
+ Creates a new instance.
+
+ Invocation for this expectation
+
+
+
+ Creates a new instance.
+
+ Expectation.
+
+
+
+ Validate the arguments for the method.
+
+ The arguments with which the method was called
+
+
+
+ Determines if the object equal to expectation
+
+
+
+
+ Get the hash code
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ Summary description for ArgsEqualExpectation.
+
+
+
+
+ Creates a new instance.
+
+ Expected args.
+ The invocation for this expectation
+
+
+
+ Validate the arguments for the method.
+
+ The arguments with which the method was called
+
+
+
+ Determines if the object equal to expectation
+
+
+
+
+ Get the hash code
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ Get the expected args.
+
+
+
+
+ Call a specified callback to verify the expectation
+
+
+
+
+ Creates a new instance.
+
+ Expectation.
+ Callback.
+
+
+
+ Creates a new instance.
+
+ Invocation for this expectation
+ Callback.
+
+
+
+ Validate the arguments for the method on the child methods
+
+ The arguments with which the method was called
+
+
+
+ Determines if the object equal to expectation
+
+
+
+
+ Get the hash code
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ Expect the method's arguments to match the contraints
+
+
+
+
+ Creates a new instance.
+
+ Invocation for this expectation
+ Constraints.
+
+
+
+ Creates a new instance.
+
+ Expectation.
+ Constraints.
+
+
+
+ Validate the arguments for the method.
+
+ The arguments with which the method was called
+
+
+
+ Determines if the object equal to expectation
+
+
+
+
+ Get the hash code
+
+
+
+
+ Gets the error message.
+
+
+
+
+
+ ExpectationsList
+
+
+
+
+ Dictionary
+
+
+
+
+ Dictionary class
+
+
+
+
+ Create a new instance of ProxyStateDictionary
+
+
+
+
+ Operation on a remoting proxy
+
+
+ It is not possible to directly communicate to a real proxy via transparent proxy.
+ Transparent proxy impersonates a user type and only methods of that user type are callable.
+ The only methods that are guaranteed to exist on any transparent proxy are methods defined
+ in Object: namely ToString(), GetHashCode(), and Equals()).
+
+ These three methods are the only way to tell the real proxy to do something.
+ Equals() is the most suitable of all, since it accepts an arbitrary object parameter.
+ The RemotingProxy code is built so that if it is compared to an IRemotingProxyOperation,
+ transparentProxy.Equals(operation) will call operation.Process(realProxy).
+ This way we can retrieve a real proxy from transparent proxy and perform
+ arbitrary operation on it.
+
+
+
+
+ Implementation of IInvocation based on remoting proxy
+
+ Some methods are marked NotSupported since they either don't make sense
+ for remoting proxies, or they are never called by Rhino Mocks
+
+
+
+ Generates remoting proxies and provides utility functions
+
+
+
+
+ Create the proxy using remoting
+
+
+
+
+ Check whether an object is a transparent proxy with a RemotingProxy behind it
+
+ Object to check
+ true if the object is a transparent proxy with a RemotingProxy instance behind it, false otherwise
+ We use Equals() method to communicate with the real proxy behind the object.
+ See IRemotingProxyOperation for more details
+
+
+
+ Retrieve a mocked object from a transparent proxy
+
+ Transparent proxy with a RemotingProxy instance behind it
+ Mocked object associated with the proxy
+ We use Equals() method to communicate with the real proxy behind the object.
+ See IRemotingProxyOperation for more details
+
+
+
+ Allows to call a method and immediatly get it's options.
+
+
+
+
+ Interface to allows to call a method and immediatly get it's options.
+
+
+
+
+ Get the method options for the call
+
+ The method call should go here, the return value is ignored
+
+
+
+ Creates a new instance.
+
+
+
+
+ Get the method options for the call
+
+ The method call should go here, the return value is ignored
+
+
+
+ Allows to call a method and immediatly get it's options.
+ Set the expected number for the call to Any()
+
+
+
+
+ Creates a new instance.
+
+ Proxy.
+ Mocked instance.
+
+
+
+ Get the method options for the call
+
+ The method call should go here, the return value is ignored
+
+
+
+ This class is reponsible for taking a delegate and creating a wrapper
+ interface around it, so it can be mocked.
+
+
+
+
+ The scope for all the delegate interfaces create by this mock repositroy.
+
+
+
+
+ Gets a type with an "Invoke" method suitable for use as a target of the
+ specified delegate type.
+
+
+
+
+
+
+ Raise events for all subscribers for an event
+
+
+
+
+ Raise events for all subscribers for an event
+
+
+
+
+ Raise the event
+
+
+
+
+ The most common form for the event handler signature
+
+
+
+
+ Create an event raise for the specified event on this instance.
+
+
+
+
+ Creates a new instance of EventRaiser
+
+
+
+
+ Raise the event
+
+
+
+
+ The most common signature for events
+ Here to allow intellisense to make better guesses about how
+ it should suggest parameters.
+
+
+
+
+ Allows to define what would happen when a method
+ is called.
+
+
+
+
+ Allows to define what would happen when a method
+ is called.
+
+
+
+
+ Set the return value for the method.
+
+ The object the method will return
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Allow to override this return value in the future
+
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Throws the specified exception when the method is called.
+
+ Exception to throw
+
+
+
+ Ignores the arguments for this method. Any argument will be matched
+ againt this method.
+
+
+
+
+ Add constraints for the method's arguments.
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched
+ and allow to optionally modify the invocation as needed
+
+
+
+
+ Call the original method on the class, bypassing the mocking layers.
+
+
+
+
+
+ Call the original method on the class, optionally bypassing the mocking layers.
+
+
+
+
+
+ Use the property as a simple property, getting/setting the values without
+ causing mock expectations.
+
+
+
+
+ Expect last (property) call as property setting, ignore the argument given
+
+
+
+
+
+ Expect last (property) call as property setting with a given argument.
+
+
+
+
+
+
+ Get an event raiser for the last subscribed event.
+
+
+
+
+ Set the parameter values for out and ref parameters.
+ This is done using zero based indexing, and _ignoring_ any non out/ref parameter.
+
+
+
+
+ Documentation message for the expectation
+
+ Message
+
+
+
+ Better syntax to define repeats.
+
+
+
+
+ Allows to specify the number of time for method calls
+
+
+
+
+ Repeat the method twice.
+
+
+
+
+ Repeat the method once.
+
+
+
+
+ Repeat the method at least once, then repeat as many time as it would like.
+
+
+
+
+ Repeat the method any number of times.
+ This has special affects in that this method would now ignore orderring.
+
+
+
+
+ Set the range to repeat an action.
+
+ Min.
+ Max.
+
+
+
+ Set the amount of times to repeat an action.
+
+
+
+
+ This method must not appear in the replay state.
+ This has special affects in that this method would now ignore orderring.
+
+
+
+
+ Creates a new instance.
+
+ the repository for this expectation
+ the recorder for this proxy
+ the proxy for this expectation
+ Expectation.
+
+
+
+ Add constraints for the method's arguments.
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Set the return value for the method.
+
+ The object the method will return
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Set the return value for the method, but allow to override this return value in the future
+
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Throws the specified exception when the method is called.
+
+ Exception to throw
+
+
+
+ Ignores the arguments for this method. Any argument will be matched
+ againt this method.
+
+
+
+
+ Call the original method on the class, bypassing the mocking layers.
+
+
+
+
+
+ Call the original method on the class, optionally bypassing the mocking layers
+
+
+
+
+
+ Use the property as a simple property, getting/setting the values without
+ causing mock expectations.
+
+
+
+
+ Expect last (property) call as property setting, ignore the argument given
+
+
+
+
+
+ Expect last (property) call as property setting with a given argument.
+
+
+
+
+
+
+ Gets the event raiser for the last event
+
+
+
+
+ Set the parameter values for out and ref parameters.
+ This is done using zero based indexing, and _ignoring_ any non out/ref parameter.
+
+
+
+
+ Repeat the method twice.
+
+
+
+
+ Repeat the method once.
+
+
+
+
+ Repeat the method at least once, then repeat as many time as it would like.
+
+
+
+
+ This method must not appear in the replay state.
+
+
+
+
+ Documentation message for the expectation
+
+ Message
+
+
+
+ Repeat the method any number of times.
+
+
+
+
+ Set the range to repeat an action.
+
+ Min.
+ Max.
+
+
+
+ Set the amount of times to repeat an action.
+
+
+
+
+ Better syntax to define repeats.
+
+
+
+
+ This class will provide hash code for hashtables without needing
+ to call the GetHashCode() on the object, which may very well be mocked.
+ This class has no state so it is a singelton to avoid creating a lot of objects
+ that does the exact same thing. See flyweight patterns.
+
+
+
+
+ Get the hash code for a proxy object without calling GetHashCode()
+ on the object.
+
+
+
+
+ Compares two instances of mocked objects
+
+
+
+
+ Compare two mocked objects
+
+
+
+
+ The next hash code value for a mock object.
+ This is safe for multi threading.
+
+
+
+
+ The sole instance of
+
+
+
+
+ Doesn't log anything, just makes happy noises
+
+
+
+
+ Log expectations - allows to see what is going on inside Rhino Mocks
+
+
+
+
+ Logs the expectation as is was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the expectation as it was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the unexpected method call.
+
+ The invocation.
+ The message.
+
+
+
+ Logs the expectation as is was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the expectation as it was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the unexpected method call.
+
+ The invocation.
+ The message.
+
+
+
+ This is a dummy type that is used merely to give DynamicProxy the proxy instance that
+ it needs to create IProxy's types.
+
+
+
+
+ Interface to find the repository of a mocked object
+
+
+
+
+ Return true if it should call the original method on the object
+ instead of pass it to the message chain.
+
+ The method to call
+
+
+
+ Register a method to be called on the object directly
+
+
+
+
+ Register a property on the object that will behave as a simple property
+
+
+
+
+ Check if the method was registered as a property method.
+
+
+
+
+ Do get/set on the property, according to need.
+
+
+
+
+ Do add/remove on the event
+
+
+
+
+ Get the subscribers of a spesific event
+
+
+
+
+ Gets the declaring type of the method, taking into acccount the possible generic
+ parameters that it was created with.
+
+
+
+
+ Clears the state of the object, remove original calls, property behavior, subscribed events, etc.
+
+
+
+
+ Get all the method calls arguments that were made against this object with the specificed
+ method.
+
+
+ Only method calls in replay mode are counted
+
+
+
+
+ Records the method call
+
+
+
+
+ The unique hash code of this mock, which is not related
+ to the value of the GetHashCode() call on the object.
+
+
+
+
+ Gets the repository.
+
+
+
+
+ Gets the implemented types by this mocked object
+
+ The implemented.
+
+
+
+ Gets or sets the constructor arguments.
+
+ The constructor arguments.
+
+
+
+ Create a new instance of
+
+
+
+
+ Return true if it should call the original method on the object
+ instead of pass it to the message chain.
+
+ The method to call
+
+
+
+ Register a method to be called on the object directly
+
+
+
+
+ Register a property on the object that will behave as a simple property
+ Return true if there is already a value for the property
+
+
+
+
+ Check if the method was registered as a property method.
+
+
+
+
+ Do get/set on the property, according to need.
+
+
+
+
+ Do add/remove on the event
+
+
+
+
+ Get the subscribers of a spesific event
+
+
+
+
+ Gets the declaring type of the method, taking into acccount the possible generic
+ parameters that it was created with.
+
+
+
+
+ Get all the method calls arguments that were made against this object with the specificed
+ method.
+
+
+
+
+ Only method calls in replay mode are counted
+
+
+
+
+ Records the method call
+
+
+
+
+
+
+ Clears the state of the object, remove original calls, property behavior, subscribed events, etc.
+
+
+
+
+ The unique hash code of this proxy, which is not related
+ to the value of the GetHashCode() call on the object.
+
+
+
+
+ Gets the repository.
+
+
+
+
+ Gets or sets the constructor arguments.
+
+ The constructor arguments.
+
+
+
+ Gets the implemented types by this mocked object
+
+ The implemented.
+
+
+
+ Range for expected method calls
+
+
+
+
+ Creates a new instance.
+
+ Min.
+ Max.
+
+
+
+ Return the string representation of this range.
+
+
+
+
+ Gets or sets the min.
+
+
+
+
+
+ Gets or sets the max.
+
+
+
+
+
+ Records all the expectations for a mock and
+ return a ReplayDynamicMockState when Replay()
+ is called.
+
+
+
+
+ Records all the expectations for a mock
+
+
+
+
+ Different actions on this mock
+
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Verify that this mock expectations have passed.
+
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Set the exception to throw when Verify is called.
+ This is used to report exception that may have happened but where caught in the code.
+ This way, they are reported anyway when Verify() is called.
+
+
+
+
+ This method is called to indicate that a property behavior call.
+ This is done so we generate good error message in the common case of people using
+ Stubbed properties with Return().
+
+
+
+
+ Gets the matching verify state for this state
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Set the exception to throw when Verify is called.
+ This is used to report exception that may have happened but where caught in the code.
+ This way, they are reported anyway when Verify() is called.
+
+
+
+
+ This method is called to indicate that a property behavior call.
+ This is done so we generate good error message in the common case of people using
+ Stubbed properties with Return().
+
+
+
+
+ Creates a new instance.
+
+ Repository.
+ The proxy that generates the method calls
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Verify that this mock expectations have passed.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Asserts the previous method is closed (had an expectation set on it so we can replay it correctly)
+
+
+
+
+ Gets the last expectation.
+
+
+
+
+ Gets the total method calls count.
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Gets the matching verify state for this state
+
+
+
+
+ Creates a new instance.
+
+ Repository.
+ The proxy that generates the method calls
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Records all the expectations for a mock and
+ return a ReplayPartialMockState when Replay()
+ is called.
+
+
+
+
+ Creates a new instance.
+
+ Repository.
+ The proxy that generates the method calls
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Options for special repeat option
+
+
+
+
+ This method can be called only as many times as the IMethodOptions.Expect allows.
+
+
+
+
+ This method should never be called
+
+
+
+
+ This method can be call any number of times
+
+
+
+
+ This method will call the original method
+
+
+
+
+ This method will call the original method, bypassing the mocking layer
+
+
+
+
+ This method will simulate simple property behavior
+
+
+
+
+ Validate all expectations on a mock and ignores calls to
+ any method that was not setup properly.
+
+
+
+
+ Validate all expectations on a mock
+
+
+
+
+ The repository for this state
+
+
+
+
+ The proxy object for this state
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Creates a new instance.
+
+ The previous state for this method
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Add a method call for this state' mock.
+ This allows derived method to cleanly get a the setupresult behavior while adding
+ their own.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Set the exception to throw when Verify is called.
+ This is used to report exception that may have happened but where caught in the code.
+ This way, they are reported anyway when Verify() is called.
+
+
+
+
+ not relevant
+
+
+
+
+ Verify that this mock expectations have passed.
+
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Gets the matching verify state for this state
+
+
+
+
+ Creates a new instance.
+
+ The previous state for this method
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Validate all expectations on a mock and ignores calls to
+ any method that was not setup properly.
+
+
+
+
+ Creates a new instance.
+
+ The previous state for this method
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Summary description for RhinoInterceptor.
+
+
+
+
+ Creates a new instance.
+
+
+
+
+ Intercept a method call and direct it to the repository.
+
+
+
+
+ Behave like a stub, all properties and events acts normally, methods calls
+ return default values by default (but can use expectations to set them up), etc.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The proxy that generates the method calls
+ Repository.
+
+
+
+ We don't care much about expectations here, so we will remove the exepctation if
+ it is not closed.
+
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+
+ Validate expectations on recorded methods, but in general completely ignoring them.
+ Similar to except that it would return a
+ when BackToRecord is called.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The previous state for this method
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Rudimetry implementation that simply logs methods calls as text.
+
+
+
+
+ Initializes a new instance of the class.
+
+ The writer.
+
+
+
+ Logs the expectation as is was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the expectation as it was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the unexpected method call.
+
+ The invocation.
+ The message.
+
+
+
+ Write rhino mocks log info to the trace
+
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Initializes a new instance of the class.
+
+ if set to true [log recorded].
+ if set to true [log replayed].
+ if set to true [log unexpected].
+
+
+
+ Logs the expectation as is was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the expectation as it was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the unexpected method call.
+
+ The invocation.
+ The message.
+
+
+
+ Writes log information as stack traces about rhino mocks activity
+
+
+
+
+ Allows to redirect output to a different location.
+
+
+
+
+ Logs the expectation as is was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the expectation as it was recorded
+
+ The invocation.
+ The expectation.
+
+
+
+ Logs the unexpected method call.
+
+ The invocation.
+ The message.
+
+
+
+ Validate arguments for methods
+
+
+
+
+ Validate that the passed argument is not null.
+
+ The object to validate
+ The name of the argument
+
+ If the obj is null, an ArgumentNullException with the passed name
+ is thrown.
+
+
+
+
+ Validate that the arguments are equal.
+
+ Expected args.
+ Actual Args.
+
+
+
+ Validate that the two argument are equals, including validation for
+ when the arguments are collections, in which case it will validate their values.
+
+
+
+
+ This method is safe for use even if any of the objects is a mocked object
+ that override equals.
+
+
+
+
+ Throw an object already verified when accessed
+
+
+
+
+ Create a new instance of VerifiedMockState
+
+ The previous mock state, used to get the initial record state
+
+
+
+ Add a method call for this state' mock.
+
+ The invocation for this method
+ The method that was called
+ The arguments this method was called with
+
+
+
+ Verify that this mock expectations have passed.
+
+
+
+
+ Verify that we can move to replay state and move
+ to the reply state.
+
+
+
+
+ Gets a mock state that match the original mock state of the object.
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Set the exception to throw when Verify is called.
+ This is used to report exception that may have happened but where caught in the code.
+ This way, they are reported anyway when Verify() is called.
+
+
+
+
+ not relevant
+
+
+
+
+ Gets the matching verify state for this state
+
+
+
+
+ Get the options for the last method call
+
+
+
+
+ Records the actions on all the mocks created by a repository.
+
+
+
+
+ Records the specified call with the specified args on the mocked object.
+
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+
+
+
+ This check the methods that were setup using the SetupResult.For()
+ or LastCall.Repeat.Any() and that bypass the whole expectation model.
+
+
+
+
+ Gets the all expectations for a mocked object and method combination,
+ regardless of the expected arguments / callbacks / contraints.
+
+ Mocked object.
+ Method.
+ List of all relevant expectation
+
+
+
+ Gets the all expectations for proxy.
+
+ Mocked object.
+ List of all relevant expectation
+
+
+
+ Removes all the repeatable expectations for proxy.
+
+ Mocked object.
+
+
+
+ Replaces the old expectation with the new expectation for the specified proxy/method pair.
+ This replace ALL expectations that equal to old expectations.
+
+ Proxy.
+ Method.
+ Old expectation.
+ New expectation.
+
+
+
+ Adds the recorder and turn it into the active recorder.
+
+ Recorder.
+
+
+
+ Moves to previous recorder.
+
+
+
+
+ Gets the recorded expectation or null.
+
+
+
+
+ Gets the next expected calls string.
+
+
+
+
+ Moves to parent recorder.
+
+
+
+
+ Set the expectation so it can repeat any number of times.
+
+
+
+
+ Removes the expectation from the recorder
+
+
+
+
+ Clear the replayer to call (and all its chain of replayers)
+ This also removes it from the list of expectations, so it will never be considered again
+
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+
+
+
+ Gets a value indicating whether this instance has expectations that weren't satisfied yet.
+
+
+ true if this instance has expectations; otherwise, false.
+
+
+
+
+ Marker interface used to indicate that this is a partial mock.
+
+
+
+
+ Options for CallOriginalMethod
+
+
+
+
+ No expectation is created, the method will be called directly
+
+
+
+
+ Normal expectation is created, but when the method is later called, it will also call the original method
+
+
+
+
+ Base class for method recorders, handle delegating to inner recorder if needed.
+
+
+
+
+ List of the expected actions on for this recorder
+ The legal values are:
+ * Expectations
+ * Method Recorders
+
+
+
+
+ The current recorder.
+
+
+
+
+ The current replayer;
+
+
+
+
+ The parent recorder of this one, may be null.
+
+
+
+
+ This contains a list of all the replayers that should be ignored
+ for a spesific method call. A replayer gets into this list by calling
+ ClearReplayerToCall() on its parent. This list is Clear()ed on each new invocation.
+
+
+
+
+ All the repeatable methods calls.
+
+
+
+
+ Counts the recursion depth of the current expectation search stack
+
+
+
+
+ Creates a new instance.
+
+
+
+
+ Creates a new instance.
+
+ Parent recorder.
+ Repeatable methods
+
+
+
+ Records the specified call with the specified args on the mocked object.
+
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+
+
+
+ Gets the all expectations for a mocked object and method combination,
+ regardless of the expected arguments / callbacks / contraints.
+
+ Mocked object.
+ Method.
+ List of all relevant expectation
+
+
+
+ Gets the all expectations for proxy.
+
+ Mocked object.
+ List of all relevant expectation
+
+
+
+ Replaces the old expectation with the new expectation for the specified proxy/method pair.
+ This replace ALL expectations that equal to old expectations.
+
+ Proxy.
+ Method.
+ Old expectation.
+ New expectation.
+
+
+
+ Remove the all repeatable expectations for proxy.
+
+ Mocked object.
+
+
+
+ Set the expectation so it can repeat any number of times.
+
+
+
+
+ Removes the expectation from the recorder
+
+
+
+
+ Adds the recorder and turn it into the active recorder.
+
+ Recorder.
+
+
+
+ Moves to previous recorder.
+
+
+
+
+ Moves to parent recorder.
+
+
+
+
+ Gets the recorded expectation or null.
+
+
+
+
+ Clear the replayer to call (and all its chain of replayers).
+ This also removes it from the list of expectations, so it will never be considered again
+
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+
+
+
+ Gets the next expected calls string.
+
+
+
+
+ Handles the real getting of the recorded expectation or null.
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Should this replayer be considered valid for this call?
+
+
+
+
+ This check the methods that were setup using the SetupResult.For()
+ or LastCall.Repeat.Any() and that bypass the whole expectation model.
+
+
+
+
+ Gets a value indicating whether this instance has expectations that weren't satisfied yet.
+
+
+ true if this instance has expectations; otherwise, false.
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Ordered collection of methods, methods must arrive in specified order
+ in order to pass.
+
+
+
+
+ Unordered collection of method records, any expectation that exist
+ will be matched.
+
+
+
+
+ The parent recorder we have redirected to.
+ Useful for certain edge cases in orderring.
+ See: FieldProblem_Entropy for the details.
+
+
+
+
+ Creates a new instance.
+
+ Parent recorder.
+ Repeatable methods
+
+
+
+ Creates a new instance.
+
+
+
+
+ Records the specified call with the specified args on the mocked object.
+
+ Mocked object.
+ Method.
+ Expectation.
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+ Invocation for this method
+ Mocked object.
+ Method.
+ Args.
+ True is the call was recorded, false otherwise
+
+
+
+ Gets the all expectations for a mocked object and method combination,
+ regardless of the expected arguments / callbacks / contraints.
+
+ Mocked object.
+ Method.
+ List of all relevant expectation
+
+
+
+ Gets the all expectations for proxy.
+
+ Mocked object.
+ List of all relevant expectation
+
+
+
+ Replaces the old expectation with the new expectation for the specified proxy/method pair.
+ This replace ALL expectations that equal to old expectations.
+
+ Proxy.
+ Method.
+ Old expectation.
+ New expectation.
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Handles the real getting of the recorded expectation or null.
+
+
+
+
+ Handle the real execution of this method for the derived class
+
+
+
+
+ Gets the next expected calls string.
+
+
+
+
+ Create an exception for an unexpected method call.
+
+
+
+
+ Gets a value indicating whether this instance has expectations that weren't satisfied yet.
+
+
+ true if this instance has expectations; otherwise, false.
+
+
+
+
+ Creates a new instance.
+
+ Parent recorder.
+ Repetable methods
+
+
+
+ Creates a new instance.
+
+
+
+
+ Handles the real getting of the recorded expectation or null.
+
+
+
+
+ Get the expectation for this method on this object with this arguments
+
+
+
+
+ Gets the next expected calls string.
+
+
+
+
+ Hold an expectation for a method call on an object
+
+
+
+
+ Creates a new instance.
+
+ Proxy.
+ Method.
+ Expectation.
+
+
+
+ Determains if the object equal to this instance
+
+ Obj.
+
+
+
+
+ Gets the hash code.
+
+
+
+
+
+ Gets the proxy.
+
+
+
+
+
+ Gets the method.
+
+
+
+
+
+ Gets the expectation.
+
+
+
+
+
+ Holds a pair of mocked object and a method
+ and allows to compare them against each other.
+ This allows us to have a distinction between mockOne.MyMethod() and
+ mockTwo.MyMethod()...
+
+
+
+
+ Creates a new instance.
+
+ Proxy.
+ Method.
+
+
+
+ Determains whatever obj equals to this instance.
+ ProxyMethodPairs are equals when they point to the same /instance/ of
+ an object, and to the same method.
+
+ Obj.
+
+
+
+
+ Gets the hash code.
+
+
+
+
+
+ Gets the proxy.
+
+
+
+
+
+ Gets the method.
+
+
+
+
+
+ Change the recorder from ordered to unordered and vice versa
+
+
+
+
+ Creates a new instance.
+
+
+
+
+ Disposes this instance.
+
+
+
+
+ Utility class for dealing with messing generics scenarios.
+
+
+
+
+ There are issues with trying to get this to work correctly with open generic types, since this is an edge case,
+ I am letting the runtime handle it.
+
+
+
+
+ Gets the real type, including de-constructing and constructing the type of generic
+ methods parameters.
+
+ The type.
+ The invocation.
+
+
+
+
+ Because we need to support complex types here (simple generics were handled above) we
+ need to be aware of the following scenarios:
+ List[T] and List[Foo[T]]
+
+
+
+
+ Utility class for working with method calls.
+
+
+
+
+ Return the string representation of a method call and its arguments.
+
+ The method
+ The method arguments
+ Invocation of the method, used to get the generics arguments
+ Delegate to format the parameter
+ The string representation of this method call
+
+
+
+ Return the string representation of a method call and its arguments.
+
+ The invocation of the method, used to get the generic parameters
+ The method
+ The method arguments
+ The string representation of this method call
+
+
+
+ Delegate to format the argument for the string representation of
+ the method call.
+
+
+
+
+ Utility to get the default value for a type
+
+
+
+
+ The default value for a type.
+ Null for reference types and void
+ 0 for value types.
+ First element for enums
+ Note that we need to get the value even for opened generic types, such as those from
+ generic methods.
+
+ Type.
+ The invocation.
+ the default value
+
+
+
+ Defines constraints and return values for arguments of a mock.
+ Only use Arg inside a method call on a mock that is recording.
+ Example:
+ ExpectCall(
+ mock.foo(
+ Arg<int>.Is.GreaterThan(2),
+ Arg<string>.Is.Anything
+ ));
+ Use Arg.Text for string specific constraints
+ Use Arg<ListClass>.List for list specific constraints
+
+
+
+
+
+ Register the predicate as a constraint for the current call.
+
+ The predicate.
+ default(T)
+
+ Allow you to use code to create constraints
+
+ demo.AssertWasCalled(x => x.Bar(Arg{string}.Matches(a => a.StartsWith("b") && a.Contains("ba"))));
+
+
+
+
+
+ Define a complex constraint for this argument by passing several constraints
+ combined with operators. (Use Is in simple cases.)
+ Example: Arg<string>.Matches(Is.Equal("Hello") || Text.EndsWith("u"));
+
+ Constraints using Is, Text and List
+ Dummy to satisfy the compiler
+
+
+
+ Define a Ref argument.
+
+ Constraints for this argument
+ value returned by the mock
+
+
+
+
+ Define a out parameter. Use it together with the keyword out and use the
+ Dummy field available by the return value.
+ Example: mock.foo( out Arg<string>.Out("hello").Dummy );
+
+
+
+
+
+
+ Define a simple constraint for this argument. (Use Matches in simple cases.)
+ Example:
+ Arg<int>.Is.Anthing
+ Arg<string>.Is.Equal("hello")
+
+
+
+
+ Define Constraints on list arguments.
+
+
+
+
+ Use the Arg class (without generic) to define Text constraints
+
+
+
+
+ Evaluate an equal constraint for .
+
+ The object the parameter should equal to
+
+
+
+ Define constraints on text arguments.
+
+
+
+
+ Used to manage the static state of the Arg<T> class"/>
+
+
+
+
+ Resets the static state
+
+
+
+
+ Returns return values for the out and ref parameters
+ Note: the array returned has the size of the number of out and ref
+ argument definitions
+
+
+
+
+
+ Returns the constraints for all arguments.
+ Out arguments have an Is.Anything constraint and are also in the list.
+
+
+
+
+
+ What should BackToRecord clear
+
+
+
+
+ Retain all expectations and behaviors and return to mock
+
+
+
+
+ All expectations
+
+
+
+
+ Event subscribers for this instance
+
+
+
+
+ Methods that should be forwarded to the base class implementation
+
+
+
+
+ Properties that should behave like properties
+
+
+
+
+ Remove all the behavior of the object
+
+
+
+
+ This delegate is compatible with the System.Func{T,R} signature
+ We have to define our own to get compatability with 2.0
+
+
+
+
+ This class defines a lot of method signatures, which we will use
+ to allow compatability on net-2.0
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ dummy
+
+
+
+
+ Allows expectations to be set on methods that should never be called.
+ For methods with void return value, you need to use LastCall or
+ DoNotExpect.Call() with a delegate.
+
+
+
+
+ Sets LastCall.Repeat.Never() on /any/ proxy on /any/ repository on the current thread.
+ This method if not safe for multi threading scenarios.
+
+
+
+
+ Accepts a delegate that will execute inside the method which
+ LastCall.Repeat.Never() will be applied to.
+ It is expected to be used with anonymous delegates / lambda expressions and only one
+ method should be called.
+
+
+ IService mockSrv = mocks.CreateMock(typeof(IService)) as IService;
+ DoNotExpect.Call(delegate{ mockSrv.Stop(); });
+ ...
+
+
+
+
+ Allows to set expectation on methods that has return values.
+ For methods with void return value, you need to use LastCall
+
+
+
+
+ The method options for the last call on /any/ proxy on /any/ repository on the current thread.
+ This method if not safe for multi threading scenarios, use .
+
+
+
+
+ Accepts a delegate that will execute inside the method, and then return the resulting
+ instance.
+ It is expected to be used with anonymous delegates / lambda expressions and only one
+ method should be called.
+
+
+ IService mockSrv = mocks.CreateMock(typeof(IService)) as IService;
+ Expect.Call(delegate{ mockSrv.Start(); }).Throw(new NetworkException());
+ ...
+
+
+
+
+ Get the method options for the last method call on the mockInstance.
+
+
+
+
+ A delegate that can be used to get better syntax on Expect.Call(delegate { foo.DoSomething(); });
+
+
+
+
+ Allows to set various options for the last method call on
+ a specified object.
+ If the method has a return value, it's recommended to use Expect
+
+
+
+
+ Allows to get an interface to work on the last call.
+
+ The mocked object
+ Interface that allows to set options for the last method call on this object
+
+
+
+ Set the return value for the method.
+
+ The object the method will return
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Set the return value for the method. This overload is needed for LastCall.Return(null)
+
+ The object the method will return
+ IRepeat that defines how many times the method will return this value
+
+
+
+ Throws the specified exception when the method is called.
+
+ Exception to throw
+
+
+
+ Ignores the arguments for this method. Any argument will be matched
+ againt this method.
+
+
+
+
+ Add constraints for the method's arguments.
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Set a callback method for the last call
+
+
+
+
+ Call the original method on the class, bypassing the mocking layers, for the last call.
+
+
+
+
+ Call the original method on the class, optionally bypassing the mocking layers, for the last call.
+
+
+
+
+ Set a delegate to be called when the expectation is matched.
+ The delegate return value will be returned from the expectation.
+
+
+
+
+ Gets an interface that will raise the last event when called.
+
+
+
+
+ Set the parameter values for out and ref parameters.
+ This is done using zero based indexing, and _ignoring_ any non out/ref parameter.
+
+
+
+
+ Documentation message for the expectation
+
+ Message
+
+
+
+ Use the property as a simple property, getting/setting the values without
+ causing mock expectations.
+
+
+
+
+ Better syntax to define repeats.
+
+
+
+
+ This is a data structure that is used by
+ to pass
+ the current method to the relevant delegate
+
+
+
+
+ Initializes a new instance of the class.
+
+ The invocation.
+
+
+
+ Gets the args for this method invocation
+
+
+
+
+ Gets or sets the return value for this method invocation
+
+ The return value.
+
+
+
+ Accessor for the current mocker
+
+
+
+
+ The current mocker
+
+
+
+
+ Creates proxied instances of types.
+
+
+ Adds optional new usage:
+ using(mockRepository.Record()) {
+ Expect.Call(mock.Method()).Return(retVal);
+ }
+ using(mockRepository.Playback()) {
+ // Execute code
+ }
+ N.B. mockRepository.ReplayAll() and mockRepository.VerifyAll()
+ calls are taken care of by Record/Playback
+
+
+
+
+ This is a map of types to ProxyGenerators.
+
+
+
+
+ This is used to record the last repository that has a method called on it.
+
+
+
+
+ this is used to get to the last proxy on this repository.
+
+
+
+
+ For mock delegates, maps the proxy instance from intercepted invocations
+ back to the delegate that was originally returned to client code, if any.
+
+
+
+
+ All the proxies in the mock repositories
+
+
+
+
+ This is here because we can't put it in any of the recorders, since repeatable methods
+ have no orderring, and if we try to handle them using the usual manner, we would get into
+ wierd situations where repeatable method that was defined in an orderring block doesn't
+ exists until we enter this block.
+
+
+
+
+ Creates a new instance.
+
+
+
+
+ Move the repository to ordered mode
+
+
+
+
+ Move the repository to un-ordered mode
+
+
+
+
+ Creates a mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a strict mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a remoting mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a strict remoting mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a remoting mock for the specified type.
+
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+
+ Creates a strict remoting mock for the specified type.
+
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+
+ Creates a mock from several types, with strict semantics.
+ Only may be a class.
+
+
+
+
+ Creates a strict mock from several types, with strict semantics.
+ Only may be a class.
+
+
+
+
+ Creates a mock from several types, with strict semantics.
+ Only may be a class.
+
+ The main type to mock.
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class.
+
+
+
+ Creates a strict mock from several types, with strict semantics.
+ Only may be a class.
+
+ The main type to mock.
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class.
+
+
+
+ Creates a mock from several types, with dynamic semantics.
+ Only may be a class.
+
+ The main type to mock.
+ Extra interface types to mock.
+
+
+
+ Creates a mock from several types, with dynamic semantics.
+ Only may be a class.
+
+ The main type to mock.
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class.
+
+
+
+ Creates a dynamic mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a dynamic mock for the specified type.
+
+ Type.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a dynamic mock for the specified type.
+
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+
+ Creates a mock object that defaults to calling the class methods.
+
+ Type.
+ Arguments for the class' constructor.
+
+
+
+ Creates a mock object that defaults to calling the class methods.
+
+ Type.
+ Extra interface types to mock.
+
+
+
+ Creates a mock object that defaults to calling the class methods.
+
+ Type.
+ Extra interface types to mock.
+ Arguments for the class' constructor.
+
+
+
+ Creates a mock object using remoting proxies
+
+ Type to mock - must be MarshalByRefObject
+ Mock object
+ Proxy mock can mock non-virtual methods, but not static methods
+ Creates the mock state for this proxy
+
+
+
+ Cause the mock state to change to replay, any further call is compared to the
+ ones that were called in the record state.
+
+ the object to move to replay state
+
+
+
+ Cause the mock state to change to replay, any further call is compared to the
+ ones that were called in the record state.
+
+ the object to move to replay state
+
+
+
+
+ Move the mocked object back to record state.
+ Will delete all current expectations!
+
+
+
+
+ Move the mocked object back to record state.
+ Optionally, can delete all current expectations, but allows more granularity about how
+ it would behave with regard to the object state.
+
+
+
+
+ Verify that all the expectations for this object were fulfilled.
+
+ the object to verify the expectations for
+
+
+
+ Get the method options for the last call on
+ mockedInstance.
+
+ The mock object
+ Method options for the last call
+
+
+
+ Maps an invocation proxy back to the mock object instance that was originally
+ returned to client code which might have been a delegate to this proxy.
+
+ The mock object proxy from the intercepted invocation
+ The mock object
+
+
+
+ This is provided to allow advance extention functionality, where Rhino Mocks standard
+ functionality is not enough.
+
+ The type to mock
+ Delegate that create the first state of the mocked object (usualy the record state).
+ Additional types to be implemented, this can be only interfaces
+ optional arguments for the constructor
+
+
+
+
+ Method: GetMockedObject
+ Get an IProxy from a mocked object instance, or throws if the
+ object is not a mock object.
+
+
+
+
+ Method: GetMockedObjectOrNull
+ Get an IProxy from a mocked object instance, or null if the
+ object is not a mock object.
+
+
+
+
+ Pops the recorder.
+
+
+
+
+ Pushes the recorder.
+
+ New recorder.
+
+
+
+ All the mock objects in this repository will be moved
+ to record state.
+
+
+
+
+ All the mock objects in this repository will be moved
+ to record state.
+
+
+
+
+ Replay all the mocks from this repository
+
+
+
+
+ Verify all the mocks from this repository
+
+
+
+
+ Gets the proxy generator for a specific type. Having a single ProxyGenerator
+ with multiple types linearly degrades the performance so this implementation
+ keeps one ProxyGenerator per type.
+
+
+
+
+ Set the exception to be thrown when verified is called.
+
+
+
+
+ Creates a mock for the spesified type.
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a strict mock for the spesified type.
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a dynamic mock for the specified type.
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Creates a mock object from several types.
+
+
+
+
+ Creates a strict mock object from several types.
+
+
+
+
+ Create a mock object from several types with dynamic semantics.
+
+
+
+
+ Create a mock object from several types with partial semantics.
+
+
+
+
+ Create a mock object from several types with strict semantics.
+
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Create a strict mock object from several types with strict semantics.
+
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Create a mock object from several types with dynamic semantics.
+
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Create a mock object from several types with partial semantics.
+
+ Extra interface types to mock.
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Create a mock object with from a class that defaults to calling the class methods
+
+ Arguments for the class' constructor, if mocking a concrete class
+
+
+
+ Create a stub object, one that has properties and events ready for use, and
+ can have methods called on it. It requires an explicit step in order to create
+ an expectation for a stub.
+
+ The arguments for constructor.
+
+
+
+ Create a stub object, one that has properties and events ready for use, and
+ can have methods called on it. It requires an explicit step in order to create
+ an expectation for a stub.
+
+ The type.
+ The arguments for constructor.
+
+
+
+
+ Generates a stub without mock repository
+
+ The arguments for constructor.
+
+
+
+
+ Generates the stub without mock repository
+
+ The type.
+ The arguments for constructor.
+
+
+
+ Returns true if the passed mock is currently in replay mode.
+
+ The mock to test.
+ True if the mock is in replay mode, false otherwise.
+
+
+
+ Generate a mock object without needing the mock repository
+
+
+
+
+ Determines whether the specified proxy is a stub.
+
+ The proxy.
+
+
+
+ Register a call on a prperty behavior
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gets the recorder.
+
+
+
+
+
+ Gets the replayer for this repository.
+
+
+
+
+
+ Gets the last proxy which had a method call.
+
+
+
+
+ Delegate: CreateMockState
+ This is used internally to cleanly handle the creation of different
+ RecordMockStates.
+
+
+
+
+ Used for [assembly: InternalsVisibleTo(RhinoMocks.StrongName)]
+ Used for [assembly: InternalsVisibleTo(RhinoMocks.NormalName)]
+
+
+
+
+ Strong name for the Dynamic Proxy assemblies. Used for InternalsVisibleTo specification.
+
+
+
+
+ Normal name for dynamic proxy assemblies. Used for InternalsVisibleTo specification.
+
+
+
+
+ Logs all method calls for methods
+
+
+
+
+ A set of extension methods that adds Arrange Act Assert mode to Rhino Mocks
+
+
+
+
+ Create an expectation on this mock for this action to occur
+
+
+ The mock.
+ The action.
+
+
+
+
+ Reset all expectations on this mock object
+
+
+ The mock.
+
+
+
+ Reset the selected expectation on this mock object
+
+
+ The mock.
+ The options to reset the expectations on this mock.
+
+
+
+ Cause the mock state to change to replay, any further call is compared to the
+ ones that were called in the record state.
+
+ the mocked object to move to replay state
+
+
+
+ Gets the mock repository for this specificied mock object
+
+
+ The mock.
+
+
+
+
+ Create an expectation on this mock for this action to occur
+
+
+
+ The mock.
+ The action.
+
+
+
+
+ Tell the mock object to perform a certain action when a matching
+ method is called.
+ Does not create an expectation for this method.
+
+
+ The mock.
+ The action.
+
+
+
+
+ Tell the mock object to perform a certain action when a matching
+ method is called.
+ Does not create an expectation for this method.
+
+
+
+ The mock.
+ The action.
+
+
+
+
+ Gets the arguments for calls made on this mock object and the method that was called
+ in the action.
+
+
+ The mock.
+ The action.
+
+
+ Here we will get all the arguments for all the calls made to DoSomething(int)
+
+ var argsForCalls = foo54.GetArgumentsForCallsMadeOn(x => x.DoSomething(0))
+
+
+
+
+
+ Gets the arguments for calls made on this mock object and the method that was called
+ in the action and matches the given constraints
+
+
+ The mock.
+ The action.
+ The setup constraints.
+
+
+ Here we will get all the arguments for all the calls made to DoSomething(int)
+
+ var argsForCalls = foo54.GetArgumentsForCallsMadeOn(x => x.DoSomething(0))
+
+
+
+
+
+ Asserts that a particular method was called on this mock object
+
+
+ The mock.
+ The action.
+
+
+
+ Asserts that a particular method was called on this mock object that match
+ a particular constraint set.
+
+
+ The mock.
+ The action.
+ The setup constraints.
+
+
+
+ Asserts that a particular method was NOT called on this mock object
+
+
+ The mock.
+ The action.
+
+
+
+ Asserts that a particular method was NOT called on this mock object that match
+ a particular constraint set.
+
+
+ The mock.
+ The action.
+ The setup constraints.
+
+
+
+ Finds the approprite implementation type of this item.
+ This is the class or an interface outside of the rhino mocks.
+
+ The mocked obj.
+
+
+
+
+ Verifies all expectations on this mock object
+
+ The mock object.
+
+
+
+ Gets the event raiser for the event that was called in the action passed
+
+ The type of the event source.
+ The mock object.
+ The event subscription.
+
+
+
+
+ Raise the specified event using the passed arguments.
+ The even is extracted from the passed labmda
+
+ The type of the event source.
+ The mock object.
+ The event subscription.
+ The sender.
+ The instance containing the event data.
+
+
+
+ Raise the specified event using the passed arguments.
+ The even is extracted from the passed labmda
+
+ The type of the event source.
+ The mock object.
+ The event subscription.
+ The args.
+
+
+
+ Fake type that disallow creating it.
+ Should have been System.Type, but we can't use it.
+
+
+
+
+ Setup method calls to repeat any number of times.
+
+
+
+
+ Get the method options and set the last method call to repeat
+ any number of times.
+ This also means that the method would transcend ordering
+
+
+
+
+ Get the method options for the last method call on the mockInstance and set it
+ to repeat any number of times.
+ This also means that the method would transcend ordering
+
+
+
+
+ Allows easier access to MockRepository, works closely with Mocker.Current to
+ allow access to a context where the mock repository is automatially verified at
+ the end of the code block.
+
+
+
+
+ Initialize a code block where Mocker.Current is initialized.
+ At the end of the code block, all the expectation will be verified.
+ This overload will create a new MockRepository.
+
+ The code that will be executed under the mock context
+
+
+
+ Initialize a code block where Mocker.Current is initialized.
+ At the end of the code block, all the expectation will be verified.
+ This overload will create a new MockRepository.
+
+ The mock repository to use, at the end of the code block, VerifyAll() will be called on the repository.
+ The code that will be executed under the mock context
+
+
+
+ Create a FluentMocker
+
+ The mock repository to use.
+
+
+
+ A method with no arguments and no return value that will be called under the mock context.
+
+
+
+
+ FluentMocker implements some kind of fluent interface attempt
+ for saying "With the Mocks [mocks], Expecting (in same order) [things] verify [that]."
+
+
+
+
+ Interface to verify previously defined expectations
+
+
+
+
+ Verifies if a piece of code
+
+
+
+
+ Defines unordered expectations
+
+ A delegate describing the expectations
+ an IMockVerifier
+
+
+
+ Defines ordered expectations
+
+ A delegate describing the expectations
+ an IMockVerifier
+
+
+
+ Verifies previously defined expectations
+
+
+
+
diff --git a/Library/Shared/RhinoMocks/acknowledgements.txt b/Library/Shared/RhinoMocks/acknowledgements.txt
new file mode 100644
index 0000000..01af4c1
--- /dev/null
+++ b/Library/Shared/RhinoMocks/acknowledgements.txt
@@ -0,0 +1,2 @@
+Rhino Mocks is using Castle Dynamic Proxy (http://www.castleproject.org/dynamicproxy/index.html) to handle proxying the types it needs to mock.
+The Dynamic Proxy project has been invaluable resource and made creating Rhino Mocks possible.
\ No newline at end of file
diff --git a/Library/Shared/RhinoMocks/license.txt b/Library/Shared/RhinoMocks/license.txt
new file mode 100644
index 0000000..1c8a46e
--- /dev/null
+++ b/Library/Shared/RhinoMocks/license.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2005 - 2008 Ayende Rahien (ayende@ayende.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Ayende Rahien nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/Library/Shared/StructureMap/LICENSE.TXT b/Library/Shared/StructureMap/LICENSE.TXT
new file mode 100644
index 0000000..ef08e66
--- /dev/null
+++ b/Library/Shared/StructureMap/LICENSE.TXT
@@ -0,0 +1,194 @@
+StructureMap
+
+Copyright 2004-2009 Jeremy D. Miller
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/Library/Shared/StructureMap/Rhino.Mocks.dll b/Library/Shared/StructureMap/Rhino.Mocks.dll
new file mode 100644
index 0000000..4b6904b
Binary files /dev/null and b/Library/Shared/StructureMap/Rhino.Mocks.dll differ
diff --git a/Library/Shared/StructureMap/StructureMap.AutoMocking.dll b/Library/Shared/StructureMap/StructureMap.AutoMocking.dll
new file mode 100644
index 0000000..40dc423
Binary files /dev/null and b/Library/Shared/StructureMap/StructureMap.AutoMocking.dll differ
diff --git a/Library/Shared/StructureMap/StructureMap.chm b/Library/Shared/StructureMap/StructureMap.chm
new file mode 100644
index 0000000..6c91685
Binary files /dev/null and b/Library/Shared/StructureMap/StructureMap.chm differ
diff --git a/Library/Shared/StructureMap/StructureMap.dll b/Library/Shared/StructureMap/StructureMap.dll
new file mode 100644
index 0000000..a8e84e5
Binary files /dev/null and b/Library/Shared/StructureMap/StructureMap.dll differ
diff --git a/Library/Shared/StructureMap/StructureMapDoctor.exe b/Library/Shared/StructureMap/StructureMapDoctor.exe
new file mode 100644
index 0000000..0d8a1df
Binary files /dev/null and b/Library/Shared/StructureMap/StructureMapDoctor.exe differ
diff --git a/LocalTestRun.testrunconfig b/LocalTestRun.testrunconfig
new file mode 100644
index 0000000..107aee7
--- /dev/null
+++ b/LocalTestRun.testrunconfig
@@ -0,0 +1,5 @@
+
+
+ Dies ist eine standardmäßige Testlaufkonfiguration für einen lokalen Testlauf.
+
+
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Data.Tests/App.config b/Tests/MiteDesk.Core.Data.Tests/App.config
new file mode 100644
index 0000000..90b8f64
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/App.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteCustomersTests.cs b/Tests/MiteDesk.Core.Data.Tests/MiteCustomersTests.cs
new file mode 100644
index 0000000..611297b
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteCustomersTests.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data.Tests
+{
+ [TestClass]
+ public class MiteCustomersTests
+ {
+
+ private MiteCustomers Repository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ var mockRepository = new MockRepository();
+ var configurationService = mockRepository.DynamicMock();
+ using (mockRepository.Record())
+ {
+ Expect.Call(configurationService.GetAppSettings()).Return(new AppSettings { AccountName = "win", Email = "bandt@69grad.de", Password = "winmite" }).Repeat.Any();
+ }
+ Repository = new MiteCustomers(configurationService);
+ }
+
+ [TestMethod]
+ public void GetAllActiveCustomers_liefert_eine_Liste_aller_aktiven_Kunden_zurück()
+ {
+ var result = Repository.GetAllActiveCustomers();
+ Assert.AreNotEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void GetAllArchivedCustomers_liefert_eine_Liste_aller_archivierten_Kunden_zurück()
+ {
+ // 1 Kunde, 17.08.2009
+ var result = Repository.GetAllArchivedCustomers();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void GetCustomerByID_liefert_einen_bestimmten_Kunden_anhand_seiner_ID_zurück()
+ {
+ // 54054, Microsoft, 17.08.2009
+ var result = Repository.GetCustomerByID(54054);
+ Assert.IsNotNull(result);
+ Assert.AreEqual("Microsoft", result.Name);
+ }
+
+ [TestMethod]
+ public void UpdateCustomer_aktualisiert_einen_Kunden_in_der_Mite_Datenbank()
+ {
+
+ // 54054, Microsoft, 17.08.2009
+ var id = 54054;
+ var note = Guid.NewGuid().ToString();
+
+ var customer = Repository.GetCustomerByID(id);
+
+ Assert.AreNotEqual(note, customer.Note);
+
+ customer.Note = note;
+ Repository.UpdateCustomer(customer);
+
+ customer = Repository.GetCustomerByID(id);
+ Assert.AreEqual(note, customer.Note);
+
+ }
+
+ [TestMethod]
+ public void DeleteCustomer_löscht_einen_Benutzer_anhand_seiner_ID_aus_der_mite_Datenbank()
+ {
+
+ var customer = new Customer();
+ customer.Note = Guid.NewGuid().ToString();
+ customer.Name = Guid.NewGuid().ToString();
+
+ Repository.CreateCustomer(customer);
+
+ var result = Repository.GetAllActiveCustomers().SingleOrDefault(c => c.Name == customer.Name);
+
+ Assert.IsNotNull(result);
+ Repository.DeleteCustomer(result.ID);
+
+ Exception exception = null;
+ try
+ {
+ Repository.GetCustomerByID(result.ID);
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(MiteConnectorException));
+ Assert.IsTrue(exception.Message.IndexOf("404") > -1);
+
+ }
+
+ [TestMethod]
+ public void CreateCustomer_legt_einen_neuen_Kunden_in_der_Mite_Datenbank_an()
+ {
+
+ var customer = new Customer();
+ customer.Note = Guid.NewGuid().ToString();
+ customer.Name = Guid.NewGuid().ToString();
+
+ Repository.CreateCustomer(customer);
+
+ var result = Repository.GetAllActiveCustomers().SingleOrDefault(c => c.Name == customer.Name);
+
+ Assert.IsNotNull(result);
+ Assert.AreEqual(customer.Note, result.Note);
+
+ Repository.DeleteCustomer(result.ID);
+
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteDesk.Core.Data.Tests.csproj b/Tests/MiteDesk.Core.Data.Tests/MiteDesk.Core.Data.Tests.csproj
new file mode 100644
index 0000000..63ba364
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteDesk.Core.Data.Tests.csproj
@@ -0,0 +1,130 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Data.Tests
+ MiteDesk.Core.Data.Tests
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ False
+ ..\..\Library\Shared\RhinoMocks\Rhino.Mocks.dll
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}
+ MiteDesk.Core.Data
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}
+ MiteDesk.Tools.Connector
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteProjectsTests.cs b/Tests/MiteDesk.Core.Data.Tests/MiteProjectsTests.cs
new file mode 100644
index 0000000..73a885c
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteProjectsTests.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data.Tests
+{
+ [TestClass]
+ public class MiteProjectsTests
+ {
+
+ private MiteProjects Repository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ var mockRepository = new MockRepository();
+ var configurationService = mockRepository.DynamicMock();
+ using (mockRepository.Record())
+ {
+ Expect.Call(configurationService.GetAppSettings()).Return(new AppSettings { AccountName = "win", Email = "bandt@69grad.de", Password = "winmite" }).Repeat.Any();
+ }
+ Repository = new MiteProjects(configurationService);
+ }
+
+ [TestMethod]
+ public void GetAllActiveProjects_liefert_eine_Liste_aller_aktiven_Projekte()
+ {
+ // 4 aktive Projekte, 12.09.2009
+ var result = Repository.GetAllActiveProjects();
+ Assert.AreEqual(5, result.Count);
+ }
+
+ [TestMethod]
+ public void GetProjectsByProject_liefert_eine_Liste_aller_Projekte_eines_Kunden()
+ {
+ // 54054, Microsoft, 2 Projekte 12.09.2009
+ var result = Repository.GetProjectsByCustomer(54054);
+ Assert.AreEqual(2, result.Count);
+ }
+
+
+ [TestMethod]
+ public void GetAllArchivedProjects_liefert_eine_Liste_aller_archivierten_Projekte_zurück()
+ {
+ // 1 archiviertes Projekt, 18.08.2009
+ var result = Repository.GetAllArchivedProjects();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void GetProjectByID_liefert_eine_bestimmtes_Projekt_anhand_seiner_ID_zurück()
+ {
+ // 152453, Snow Leopard, 18.08.2009
+ var result = Repository.GetProjectByID(152453);
+ Assert.IsNotNull(result);
+ Assert.AreEqual("Snow Leopard", result.Name);
+ }
+
+ [TestMethod]
+ public void UpdateProject_aktualisiert_ein_Projekt_in_der_Mite_Datenbank()
+ {
+
+ // 152453, Snow Leopard, 18.08.2009
+ var id = 152453;
+ var note = Guid.NewGuid().ToString();
+
+ var project = Repository.GetProjectByID(id);
+
+ Assert.AreNotEqual(note, project.Note);
+
+ project.Note = note;
+ Repository.UpdateProject(project);
+
+ project = Repository.GetProjectByID(id);
+ Assert.AreEqual(note, project.Note);
+
+ }
+
+ [TestMethod]
+ public void DeleteProject_löscht_ein_Projekt_anhand_seiner_ID_aus_der_mite_Datenbank()
+ {
+
+ var project = new Project();
+ project.Note = Guid.NewGuid().ToString();
+ project.Name = Guid.NewGuid().ToString();
+ project.BudgetType = "minutes";
+
+ Repository.CreateProject(project);
+
+ var result = Repository.GetAllActiveProjects().SingleOrDefault(c => c.Name == project.Name);
+
+ Assert.IsNotNull(result);
+ Repository.DeleteProject(result.ID);
+
+ Exception exception = null;
+ try
+ {
+ Repository.GetProjectByID(result.ID);
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(MiteConnectorException));
+ Assert.IsTrue(exception.Message.IndexOf("404") > -1);
+
+ }
+
+ [TestMethod]
+ public void CreateProject_legt_ein_neues_Projekt_in_der_Mite_Datenbank_an()
+ {
+
+ var project = new Project();
+ project.Note = Guid.NewGuid().ToString();
+ project.Name = Guid.NewGuid().ToString();
+ project.BudgetType = "minutes";
+
+ Repository.CreateProject(project);
+
+ var result = Repository.GetAllActiveProjects().SingleOrDefault(c => c.Name == project.Name);
+
+ Assert.IsNotNull(result);
+ Assert.AreEqual(project.Note, result.Note);
+
+ Repository.DeleteProject(result.ID);
+
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteServicesTests.cs b/Tests/MiteDesk.Core.Data.Tests/MiteServicesTests.cs
new file mode 100644
index 0000000..15f14c9
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteServicesTests.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data.Tests
+{
+ [TestClass]
+ public class MiteServicesTests
+ {
+
+ private MiteServices Repository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ var mockRepository = new MockRepository();
+ var configurationService = mockRepository.DynamicMock();
+ using (mockRepository.Record())
+ {
+ Expect.Call(configurationService.GetAppSettings()).Return(new AppSettings { AccountName = "win", Email = "bandt@69grad.de", Password = "winmite" }).Repeat.Any();
+ }
+ Repository = new MiteServices(configurationService);
+ }
+
+ [TestMethod]
+ public void GetAllActiveActivities_liefert_alle_aktiven_Leistungen_zurück()
+ {
+ // 3 Leistungen, 13.07.2009
+ var result = Repository.GetAllActiveActivities();
+ Assert.AreEqual(3, result.Count);
+ }
+
+ [TestMethod]
+ public void GetAllArchivedActivities_liefert_eine_Liste_aller_archivierten_Leistungen_zurück()
+ {
+ // 1 archivierte Leistung, 17.08.2009
+ var result = Repository.GetAllArchivedActivities();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void GetActivityByID_liefert_eine_bestimmte_Leistung_anhand_ihrer_ID_zurück()
+ {
+ // 76072, Entwickeln, 17.08.2009
+ var result = Repository.GetActivityByID(76072);
+ Assert.IsNotNull(result);
+ Assert.AreEqual("Entwickeln", result.Name);
+ }
+
+ [TestMethod]
+ public void UpdateActivity_aktualisiert_eine_Leistung_in_der_Mite_Datenbank()
+ {
+
+ // 76072, Entwickeln, 17.08.2009
+ var id = 76072;
+ var note = Guid.NewGuid().ToString();
+
+ var activity = Repository.GetActivityByID(id);
+
+ Assert.AreNotEqual(note, activity.Note);
+
+ activity.Note = note;
+ Repository.UpdateActivity(activity);
+
+ activity = Repository.GetActivityByID(id);
+ Assert.AreEqual(note, activity.Note);
+
+ }
+
+ [TestMethod]
+ public void DeleteActivity_löscht_eine_Leistung_anhand_ihrer_ID_aus_der_mite_Datenbank()
+ {
+
+ var activity = new Activity();
+ activity.Note = Guid.NewGuid().ToString();
+ activity.Name = Guid.NewGuid().ToString();
+
+ Repository.CreateActivity(activity);
+
+ var result = Repository.GetAllActiveActivities().SingleOrDefault(c => c.Name == activity.Name);
+
+ Assert.IsNotNull(result);
+ Repository.DeleteActivity(result.ID);
+
+ Exception exception = null;
+ try
+ {
+ Repository.GetActivityByID(result.ID);
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(MiteConnectorException));
+ Assert.IsTrue(exception.Message.IndexOf("404") > -1);
+
+ }
+
+ [TestMethod]
+ public void CreateActivity_legt_eine_neue_Leistung_in_der_Mite_Datenbank_an()
+ {
+
+ var activity = new Activity();
+ activity.Note = Guid.NewGuid().ToString();
+ activity.Name = Guid.NewGuid().ToString();
+
+ Repository.CreateActivity(activity);
+
+ var result = Repository.GetAllActiveActivities().SingleOrDefault(c => c.Name == activity.Name);
+
+ Assert.IsNotNull(result);
+ Assert.AreEqual(activity.Note, result.Note);
+
+ Repository.DeleteActivity(result.ID);
+
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteTimeEntriesTests.cs b/Tests/MiteDesk.Core.Data.Tests/MiteTimeEntriesTests.cs
new file mode 100644
index 0000000..ae5af67
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteTimeEntriesTests.cs
@@ -0,0 +1,222 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+using SixtyNineDegrees.MiteDesk.Tools.Connector;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data.Tests
+{
+ [TestClass]
+ public class MiteTimeEntriesTests
+ {
+
+ private MiteTimeEntries Repository;
+ private List TempEntries;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ var mockRepository = new MockRepository();
+ var configurationService = mockRepository.DynamicMock();
+ using (mockRepository.Record())
+ {
+ Expect.Call(configurationService.GetAppSettings()).Return(new AppSettings { AccountName = "win", Email = "bandt@69grad.de", Password = "winmite" }).Repeat.Any();
+ }
+ Repository = new MiteTimeEntries(configurationService);
+ TempEntries = new List();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ foreach (var entry in TempEntries)
+ {
+ Repository.DeleteTimeEntry(entry);
+ }
+ }
+
+ [TestMethod]
+ public void GetTimeEntries_liefert_alle_Einträge_zu_einem_Datum()
+ {
+ // 13.07.2009 - 3 Einträge
+ var result = Repository.GetTimeEntriesByDate(new DateTime(2009, 7, 13));
+ Assert.AreEqual(3, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntriesByActivityID_liefert_alle_Einträge_zu_einer_Leistung()
+ {
+ // Entwickeln - 76072, 15.12.2009
+ var result = Repository.GetTimeEntriesByActivityID(76072);
+ Assert.AreEqual(15, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntriesByProjectID_liefert_alle_Einträge_zu_einem_Projekt()
+ {
+ // Windows 7 - 152451, 5 Einträge, 15.12.2009
+ var result = Repository.GetTimeEntriesByProjectID(152451);
+ Assert.AreEqual(5, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntry_liefert_einen_bestimmten_Eintrag_anhand_seiner_ID()
+ {
+ // 1952882 - vom 13.07.2009
+ var result = Repository.GetTimeEntryByID(1952882);
+ Assert.AreEqual("Taskbar", result.Note);
+ }
+
+ [TestMethod]
+ public void CreateTimeEntry_erstellt_einen_neuen_Eintrag()
+ {
+
+ var entry = new TimeEntry
+ {
+ ActivityID = 76072,
+ ProjectID = 152455,
+ Minutes = 3,
+ Date = new DateTime(2009, 7, 12),
+ Note = Guid.NewGuid().ToString(),
+ ID = 0
+ };
+
+ Repository.CreateTimeEntry(ref entry);
+
+ Assert.AreNotEqual(0, entry.ID);
+
+ TempEntries.Add(entry.ID);
+
+ }
+
+ [TestMethod]
+ public void DeleteTimeEntry_löscht_einen_vorhandenen_Eintrag()
+ {
+
+ // Anlegen
+ var entry = new TimeEntry
+ {
+ ActivityID = 76072,
+ ProjectID = 152455,
+ Minutes = 3,
+ Date = new DateTime(2009, 7, 12),
+ Note = Guid.NewGuid().ToString(),
+ ID = 0
+ };
+
+ Repository.CreateTimeEntry(ref entry);
+ Assert.AreNotEqual(0, entry.ID);
+
+ // Löschen
+ Repository.DeleteTimeEntry(entry.ID);
+
+ // Server muss 404 liefern (Der Remoteserver hat einen Fehler zurückgegeben: (404) Nicht gefunden..)
+ MiteConnectorException exception = null;
+ try
+ {
+ Repository.GetTimeEntryByID(entry.ID);
+ }
+ catch (MiteConnectorException e)
+ {
+ exception = e;
+ }
+ Assert.IsNotNull(exception);
+
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_Aktualisiert_einen_vorhandenen_Eintrag()
+ {
+
+ // Eintrag steht am 7.7.09 fest drin
+
+ var entry = new TimeEntry
+ {
+ Note = Guid.NewGuid().ToString(),
+ ID = 1954379,
+ ActivityID = 76073,
+ ProjectID = 152451,
+ Minutes = 0,
+ Date = new DateTime(2009, 7, 7)
+ };
+
+ Repository.UpdateTimeEntry(entry);
+
+ // Prüfen ob der Text aktualisiert wurde
+ var result = Repository.GetTimeEntryByID(entry.ID);
+ Assert.AreEqual(entry.Note, result.Note);
+
+ }
+
+ [TestMethod]
+ public void StartStopwatch_startet_die_Stopuhr_auf_einen_angegebenen_Zeiteintrag()
+ {
+ // Eintrag 1954379 steht am 7.7.09 fest drin
+
+ // Check
+ var result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.IsNull(result);
+
+ // Start
+ Repository.StartStopwatch(1954379);
+
+ // Check
+ result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.AreEqual(1954379, result.ID);
+
+ // Stop
+ Repository.StopStopwatch(1954379);
+ }
+
+ [TestMethod]
+ public void StopStopwatch_stoppt_die_Stopuhr_auf_einen_angegebenen_Zeiteintrag()
+ {
+ // Eintrag 1954379 steht am 7.7.09 fest drin
+
+ // Start
+ Repository.StartStopwatch(1954379);
+
+ // Check
+ var result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.AreEqual(1954379, result.ID);
+
+ // Stop
+ Repository.StopStopwatch(1954379);
+
+ // Check
+ result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.IsNull(result);
+ }
+
+ [TestMethod]
+ public void GetTimeEntryCurrentlyTrackedByStopwatch_liefert_den_Zeiteintrag_der_gerade_gestoppt_wird()
+ {
+ // Eintrag 1954379 steht am 7.7.09 fest drin
+
+ // Check
+ var result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.IsNull(result);
+
+ // Start
+ Repository.StartStopwatch(1954379);
+
+ // Check
+ result = Repository.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.AreEqual(1954379, result.ID);
+
+ // Stop
+ Repository.StopStopwatch(1954379);
+ }
+
+ [TestMethod]
+ public void GetTimeEntryDatesByRange_liefert_eine_Liste_von_Dates_in_einem_bestimmten_Datumsbereich()
+ {
+ var result = Repository.GetTimeEntryDatesByRange(new DateTime(2009, 8, 1), new DateTime(2009, 8, 31), 18352);
+ Assert.AreEqual(7, result.Count);
+ Assert.AreEqual(new DateTime(2009, 8, 3), result[6]);
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Data.Tests/MiteUsersTests.cs b/Tests/MiteDesk.Core.Data.Tests/MiteUsersTests.cs
new file mode 100644
index 0000000..a49b83d
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/MiteUsersTests.cs
@@ -0,0 +1,35 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Infrastructure;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Data.Tests
+{
+ [TestClass]
+ public class MiteUsersTests
+ {
+
+ private MiteUsers Repository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ var mockRepository = new MockRepository();
+ var configurationService = mockRepository.DynamicMock();
+ using (mockRepository.Record())
+ {
+ Expect.Call(configurationService.GetAppSettings()).Return(new AppSettings { AccountName = "win", Email = "bandt@69grad.de", Password = "winmite" }).Repeat.Any();
+ }
+ Repository = new MiteUsers(configurationService);
+ }
+
+ [TestMethod]
+ public void GetAuthenticatedUser_liefert_den_aktuell_angemeldeten_Benutzer()
+ {
+ // Benutzer 18352, bandt@69grad.de
+ var result = Repository.GetAuthenticatedUser();
+ Assert.AreEqual(18352, result.ID);
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Data.Tests/Properties/AssemblyInfo.cs b/Tests/MiteDesk.Core.Data.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..83e3ba6
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,34 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("MiteDesk.Core.Data.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MiteDesk.Core.Data.Tests")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("64dd6542-07d0-4b83-9ed3-a1e3bf3b944b")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Revisions- und Buildnummern
+// übernehmen, indem Sie "*" eingeben:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/MiteDesk.Core.Data.Tests/TestAccounts.txt b/Tests/MiteDesk.Core.Data.Tests/TestAccounts.txt
new file mode 100644
index 0000000..6ee6e73
--- /dev/null
+++ b/Tests/MiteDesk.Core.Data.Tests/TestAccounts.txt
@@ -0,0 +1,4 @@
+• "time_tracker" Zeiterfasser public@bandt.ws aae01461
+• "coworker" Standard-Nutzer mail@thomasbandt.de 259c8768
+• "admin" Administrator info@69grad.de 4cf82f2e
+• "owner" Besitzer des Accounts bandt@69grad.de winmite
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Infrastructure.Tests/ConfigurationServiceTests.cs b/Tests/MiteDesk.Core.Infrastructure.Tests/ConfigurationServiceTests.cs
new file mode 100644
index 0000000..6bbc3b6
--- /dev/null
+++ b/Tests/MiteDesk.Core.Infrastructure.Tests/ConfigurationServiceTests.cs
@@ -0,0 +1,431 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Infrastructure.Tests
+{
+
+ [TestClass]
+ public class ConfigurationServiceTests
+ {
+
+ #region Setup
+
+ private ConfigurationService ConfigurationService;
+ private MockRepository MockRepository;
+ private IRegistryService RegistryService;
+ private string ApplicationID;
+ private IEncryptionService EncryptionService;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ MockRepository = new MockRepository();
+ ApplicationID = new Guid("32141871-78de-40b2-a715-49ced5c0c872").ToString();
+ EncryptionService = new EncryptionService();
+ RegistryService = MockRepository.DynamicMock();
+ ConfigurationService = new ConfigurationService(RegistryService, EncryptionService, ApplicationID, "executablepath");
+ using(MockRepository.Record())
+ {
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("D")).Return("T/jSvAFKeMsiOAk5IfqEEg==").Repeat.Any(); // Klartext: Email
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("C")).Return("gnrAw6R9MIEu7ODFX5vFP8oG3ViER5xKMPwe74iQBUQ=").Repeat.Any(); // Klartext: AccountName
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("F")).Return("drn0I4314VvDkPx/CLSu1kBHLLW1D6Fy7HlYwAMcMyw=").Repeat.Any(); // Klartext: Password
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("E")).Return("lW0Qqcm99mIdHsRVHRsXdg==").Repeat.Any(); // Klartext: APIKey
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("G")).Return("true").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("H")).Return("true").Repeat.Any();
+ Expect.Call(RegistryService.ApplicationRegistryKeyExists()).Return(true).Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk")).Return("executablepath").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("I")).Return("true").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("J")).Return("14").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("K")).Return(new DateTime(2009, 9, 14).ToShortDateString()).Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("L")).Return("12345").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("M")).Return("54321").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("N")).Return("en-US").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("O")).Return("false").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("P")).Return("proxy").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("Q")).Return("8080").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("R")).Return("N6bmZIEuU+0a3j3UB186eQ==").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("S")).Return("ygNNVm9GOfo5hZPeIrv67RunNJVsLJg+v9JlAReQE7Q=").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("T")).Return("true").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("U")).Return("true").Repeat.Any();
+ Expect.Call(RegistryService.GetApplicationRegistryKeyValue("V")).Return("true").Repeat.Any();
+ }
+ }
+
+ #endregion
+
+ #region UpdateAppSettings
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_einen_Fehler_mit_Key_AccountName_wenn_dieser_leer_ist()
+ {
+ var settings = new AppSettings { AccountName = "" };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.IsTrue(result.ContainsKey("AccountName"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_einen_Fehler_mit_Key_Email_wenn_diese_leer_ist_und_AuthenticationType_EmailAndPassword()
+ {
+ var settings = new AppSettings { Email = "", AuthenticationType = AuthenticationType.EmailAndPassword };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.IsTrue(result.ContainsKey("Email"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_einen_Fehler_mit_Key_Email_wenn_diese_falsch_formatiert_istund_AuthenticationType_EmailAndPassword()
+ {
+ var settings = new AppSettings { Email = "falsch", AuthenticationType = AuthenticationType.EmailAndPassword };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.IsTrue(result.ContainsKey("Email"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_einen_Fehler_mit_Key_Password_wenn_das_Passwort_nicht_angegeben_ist_und_AuthenticationType_EmailAndPassword()
+ {
+ var settings = new AppSettings { Password = "", AuthenticationType = AuthenticationType.EmailAndPassword };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.IsTrue(result.ContainsKey("Password"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_einen_Fehler_mit_Key_APIKey_wenn_dieser_leer_ist_und_AuthenticationType_APIKey()
+ {
+ var settings = new AppSettings { APIKey = "", AuthenticationType = AuthenticationType.APIKey };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.IsTrue(result.ContainsKey("APIKey"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_liefert_keinen_Fehler_wenn_alle_Angaben_korrekt_ausgefüllt_sind()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "test", Email = "info@test.com" };
+ var result = ConfigurationService.UpdateAppSettings(settings);
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Emailadresse_wenn_angegeben_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "test", Email = "info@test.com" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("D", "H2KJPyLdpQ6aO3A83t3k54y48/oFoCfi49Ac7sISTDc="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_das_Passwort_wenn_angegeben_verschlüsselt_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "Password", AccountName = "test", Email = "info@test.com" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("F", "drn0I4314VvDkPx/CLSu1kBHLLW1D6Fy7HlYwAMcMyw="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Emailadresse_wenn_nicht_angegeben_als_Leerstring_in_der_Registry()
+ {
+ var settings = new AppSettings { AccountName = "AccountName", APIKey = "Key", AuthenticationType = AuthenticationType.APIKey};
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("D", string.Empty));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_das_Passwort_wennn_nicht_angegeben_als_Leerstring_in_der_Registry()
+ {
+ var settings = new AppSettings { AccountName = "AccountName", APIKey = "Key", AuthenticationType = AuthenticationType.APIKey };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("F", string.Empty));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_ApiKey_wenn_angegeben_verschlüsselt_in_der_Registry()
+ {
+ var settings = new AppSettings { AccountName = "AccountName", APIKey = "APIKey", AuthenticationType = AuthenticationType.APIKey };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("E", "lW0Qqcm99mIdHsRVHRsXdg=="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_ApiKey_als_Leerstring_in_der_Registry_wenn_nicht_angegeben()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("E", string.Empty));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_Accountnamen_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("C", "gnrAw6R9MIEu7ODFX5vFP8oG3ViER5xKMPwe74iQBUQ="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_das_Fenster_beim_Schließen_minimiert_wird_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", MinimizeByClosing = false};
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("H", Boolean.FalseString));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_Pfad_zur_Anwendung_wenn_die_Anwendung_per_Autostart_geladen_werden_soll_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", Autostart = true };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk", "executablepath"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_löscht_den_Pfad_zur_Anwendung_wenn_die_Anwendung_nicht_per_Autostart_geladen_werden_soll_aus_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", Autostart = false };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.DeleteApplicationRegistryKeyValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "mite.desk"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_die_Anwendung_minimiert_gestartet_werden_soll_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", StartMinimized = false };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("I", Boolean.FalseString));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_das_zuletzt_gewählte_Projekt_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", SelectedProjectID = 123 };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("L", "123"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_zuletzt_gewählte_Leistung_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", SelectedActivityID = 456 };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("M", "456"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Culture_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", Culture = "de-DE" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("N", "de-DE"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_ein_Proxy_verwendet_wird_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", UseProxy = true };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("O", true.ToString()));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_Proxyserver_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", ProxyServer = "proxy" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("P", "proxy"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_Proxyport_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", ProxyPort = 8080 };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("Q", "8080"));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_den_ProxyUser_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", ProxyUser = "user" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("R", "N6bmZIEuU+0a3j3UB186eQ=="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_das_ProxyPasswort_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", ProxyPassword = "password" };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("S", "ygNNVm9GOfo5hZPeIrv67RunNJVsLJg+v9JlAReQE7Q="));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_die_Stoppuhr_beim_Schließen_automatisch_gestoppt_wird_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", StopStopwatchByClosing = true };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("T", true.ToString()));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_beim_Schließen_gefragt_wird_ob_die_Stoppuhr_gestoppt_wird_in_der_Registry()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", AskForStoppingStopwatchByClosing = false };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("U", false.ToString()));
+ }
+
+ [TestMethod]
+ public void UpdateAppSettings_speichert_die_Info_ob_Zeiteinträge_absteigend_sortiert_werden_sollen()
+ {
+ var settings = new AppSettings { Password = "test", AccountName = "AccountName", Email = "info@test.com", SortTimeEntriesDescending = false };
+ ConfigurationService.UpdateAppSettings(settings);
+ RegistryService.AssertWasCalled(r => r.SetApplicationRegistryKeyValue("V", false.ToString()));
+ }
+
+ #endregion
+
+ #region GetAppSettings
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_in_der_Registry_gespeicherte_Email_Adresse()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("Email", result.Email);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_in_der_Registry_gespeicherten_ApiKey_entschlüsselt()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("APIKey", result.APIKey);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_in_der_Registry_gespeicherten_Accountnamen()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("AccountName", result.AccountName);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_in_der_Registry_gespeicherte_Info_ob_das_Fenster_beim_Schließen_minimiert_wird()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.MinimizeByClosing);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_in_der_Registry_gespeicherte_Info_ob_die_Anwendung_per_Autostart_gestartet_wird()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.Autostart);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_in_der_Registry_gespeicherte_Info_ob_die_Anwendung_minimiert_gestartet_wird()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.StartMinimized);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_Tag_an_dem_der_letzte_UpdateCheck_durchgeführt_wurde()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual(new DateTime(2009, 9, 14), result.LastUpdateCheck);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_ID_der_zuletzt_gewählten_Leistung()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual(54321, result.SelectedActivityID);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_ID_des_zuletzt_gewählten_Projektes()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual(12345, result.SelectedProjectID);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_aktuelle_Culture_wenn_in_Registry_vorhanden()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("en-US", result.Culture);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_als_aktuelle_Culture_deDE_wenn_nicht_in_Registry_gesetzt()
+ {
+ var tmpRegistryService = MockRepository.DynamicMock();
+ using (MockRepository.Record())
+ {
+ Expect.Call(tmpRegistryService.ApplicationRegistryKeyExists()).Return(true).Repeat.Any();
+ Expect.Call(tmpRegistryService.GetApplicationRegistryKeyValue("N")).Return("").Repeat.Any();
+ }
+ var tmpConfigurationService = new ConfigurationService(tmpRegistryService, EncryptionService, ApplicationID, "executablepath");
+ var result = tmpConfigurationService.GetAppSettings();
+ Assert.AreEqual("de-DE", result.Culture);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_Proxyserver()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsFalse(result.UseProxy);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_Proxyport()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("proxy", result.ProxyServer);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_die_Info_ob_ein_Proxy_verwendet_werden_soll()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual(8080, result.ProxyPort);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_den_Proxyuser()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("user", result.ProxyUser);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_das_Proxypasswort()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.AreEqual("password", result.ProxyPassword);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_StopStopwatchByClosing()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.StopStopwatchByClosing);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_AskForStoppingStopwatchByClosing()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.AskForStoppingStopwatchByClosing);
+ }
+
+ [TestMethod]
+ public void GetAppSettings_liefert_SortTimeEntriesDescending()
+ {
+ var result = ConfigurationService.GetAppSettings();
+ Assert.IsTrue(result.SortTimeEntriesDescending);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Infrastructure.Tests/MiteDesk.Core.Infrastructure.Tests.csproj b/Tests/MiteDesk.Core.Infrastructure.Tests/MiteDesk.Core.Infrastructure.Tests.csproj
new file mode 100644
index 0000000..ec5cd36
--- /dev/null
+++ b/Tests/MiteDesk.Core.Infrastructure.Tests/MiteDesk.Core.Infrastructure.Tests.csproj
@@ -0,0 +1,110 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F}
+ Library
+ Properties
+ MiteDesk.Core.Infrastructure.Tests
+ MiteDesk.Core.Infrastructure.Tests
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ False
+ ..\..\Library\Shared\RhinoMocks\Rhino.Mocks.dll
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Infrastructure.Tests/Properties/AssemblyInfo.cs b/Tests/MiteDesk.Core.Infrastructure.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9c61405
--- /dev/null
+++ b/Tests/MiteDesk.Core.Infrastructure.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("MiteDesk.Core.Infrastructure.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MiteDesk.Core.Infrastructure.Tests")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("85c923e4-680f-4423-9f81-558020b9687a")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Revisions- und Buildnummern
+// übernehmen, indem Sie "*" eingeben:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/MiteDesk.Core.Services.Tests/ActivityServiceTests.cs b/Tests/MiteDesk.Core.Services.Tests/ActivityServiceTests.cs
new file mode 100644
index 0000000..211cf1c
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/ActivityServiceTests.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Tests
+{
+ [TestClass]
+ public class ActivityServiceTests
+ {
+
+ #region Setup
+
+ private ActivityService ActivityService;
+ private MockRepository MockRepository;
+ private IActivityRepository ActivityRepository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+
+ MockRepository = new MockRepository();
+ ActivityRepository = MockRepository.DynamicMock();
+ ActivityService = new ActivityService(ActivityRepository);
+
+ using (MockRepository.Record())
+ {
+ Expect.Call(ActivityRepository.GetAllActiveActivities()).Return(new List(new[] { new Activity(), new Activity() })).Repeat.Any();
+ Expect.Call(ActivityRepository.GetAllArchivedActivities()).Return(new List(new[] { new Activity() })).Repeat.Any();
+ Expect.Call(ActivityRepository.GetActivityByID(1234)).Return(new Activity() { ID = 1234 }).Repeat.Any();
+ }
+
+ }
+
+ #endregion
+
+ [TestMethod]
+ public void GetAllActiveActivities_liefert_eine_Liste_aller_aktiven_Leistungen()
+ {
+ var result = ActivityService.GetAllActiveActivities();
+ Assert.AreEqual(2, result.Count);
+ }
+
+ [TestMethod]
+ public void GetAllArchivedActivities_liefert_alle_archivierten_Leistungen_aus_dem_ActivityRepository()
+ {
+ var result = ActivityService.GetAllArchivedActivities();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void DeleteActivity_ruft_das_Repository_zum_Löschen_der_gewählten_Leistung_auf()
+ {
+ ActivityService.DeleteActivity(123456);
+ ActivityRepository.AssertWasCalled(r => r.DeleteActivity(123456));
+ }
+
+ [TestMethod]
+ public void GetActivityByID_liefert_eine_bestimmte_Leistung_aus_dem_Repository_anhand_ihrer_ID()
+ {
+ var result = ActivityService.GetActivityByID(1234);
+ Assert.IsNotNull(result);
+ Assert.AreEqual(1234, result.ID);
+ }
+
+ [TestMethod]
+ public void CreateActivity_liefert_einen_Fehler_wenn_der_Name_einer_Leistung_nicht_angegeben_wurde()
+ {
+ var activity = new Activity { Name = "" };
+ var result = ActivityService.CreateActivity(activity, "");
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void CreateActivity_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var activity = new Activity { Name = "Testleistung" };
+ var result = ActivityService.CreateActivity(activity, "");
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void CreateActivity_speichert_die_Leistung_im_Repository_wenn_alles_okay()
+ {
+ var activity = new Activity { Name = "Testleistung" };
+ ActivityService.CreateActivity(activity, "");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(activity));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25_komma_50_2550_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "25,50");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 2550 }));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25__komma_r_2500_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "25,r");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 2500 }));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25__komma_799_2580_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "25,799");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 2580 }));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_r_komma_50_50_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "r,50");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 50 }));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_einem_Leerstring_0_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 0 }));
+ }
+
+ [TestMethod]
+ public void CreateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_100_10000_ans_Repository()
+ {
+ var activity = new Activity { Name = "OK" };
+ ActivityService.CreateActivity(activity, "100");
+ ActivityRepository.AssertWasCalled(r => r.CreateActivity(new Activity { Name = "OK", HourlyRate = 10000 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_liefert_einen_Fehler_wenn_der_Name_der_Leistung_nicht_angegeben_wurde()
+ {
+ var activity = new Activity { ID = 3, Name = "" };
+ var result = ActivityService.UpdateActivity(activity, "");
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_wirft_eine_ArgumentException_wenn_die_ID_der_Leistung_nicht_angegeben_wurde()
+ {
+ Exception exception = null;
+ var activity = new Activity { ID = 0 };
+ try
+ {
+ ActivityService.UpdateActivity(activity, "");
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(ArgumentException));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var activity = new Activity { ID = 3, Name = "Testleistung" };
+ var result = ActivityService.UpdateActivity(activity, "");
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void UpdateActivity_speichert_die_Leistung_im_Repository_wenn_alles_okay()
+ {
+ var activity = new Activity { ID = 3, Name = "Testleistung" };
+ ActivityService.UpdateActivity(activity, "");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(activity));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25_komma_50_2550_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "25,50");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 2550 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25__komma_r_2500_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "25,r");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 2500 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_r_komma_50_50_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "r,50");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 50 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_einem_Leerstring_0_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 0 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_100_10000_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "100");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 10000 }));
+ }
+
+ [TestMethod]
+ public void UpdateActivity_übergibt_als_Stundensatz_bei_Eingabe_von_25__komma_799_2580_ans_Repository()
+ {
+ var activity = new Activity { ID = 3, Name = "OK" };
+ ActivityService.UpdateActivity(activity, "25,799");
+ ActivityRepository.AssertWasCalled(r => r.UpdateActivity(new Activity { ID = 3, Name = "OK", HourlyRate = 2580 }));
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Services.Tests/AuthenticationServiceTests.cs b/Tests/MiteDesk.Core.Services.Tests/AuthenticationServiceTests.cs
new file mode 100644
index 0000000..b99c169
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/AuthenticationServiceTests.cs
@@ -0,0 +1,38 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Tests
+{
+ [TestClass]
+ public class AuthenticationServiceTests
+ {
+
+ #region Setup
+
+ private IAuthenticationService AuthenticationService;
+ private MockRepository MockRepository;
+ private IUserRepository UserRepository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ MockRepository = new MockRepository();
+ UserRepository = MockRepository.DynamicMock();
+ using (MockRepository.Record())
+ {
+ }
+ AuthenticationService = new AuthenticationService(UserRepository);
+ }
+
+ #endregion
+
+ [TestMethod]
+ public void GetAuthenticatedUser_holt_den_aktuellen_Benutzer_aus_dem_Repository()
+ {
+ AuthenticationService.GetAuthenticatedUser();
+ UserRepository.AssertWasCalled(r => r.GetAuthenticatedUser());
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Services.Tests/CustomerServiceTests.cs b/Tests/MiteDesk.Core.Services.Tests/CustomerServiceTests.cs
new file mode 100644
index 0000000..8f35bc3
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/CustomerServiceTests.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Tests
+{
+ [TestClass]
+ public class CustomerServiceTests
+ {
+
+ #region Setup
+
+ private CustomerService CustomerService;
+ private MockRepository MockRepository;
+ private ICustomerRepository CustomerRepository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+
+ MockRepository = new MockRepository();
+ CustomerRepository = MockRepository.DynamicMock();
+ CustomerService = new CustomerService(CustomerRepository);
+
+ using (MockRepository.Record())
+ {
+ Expect.Call(CustomerRepository.GetAllActiveCustomers()).Return(new List(new[] { new Customer(), new Customer { ID = 2 }, new Customer() })).Repeat.Any();
+ Expect.Call(CustomerRepository.GetAllArchivedCustomers()).Return(new List(new[] { new Customer() })).Repeat.Any();
+ Expect.Call(CustomerRepository.GetCustomerByID(1234)).Return(new Customer { ID = 1234 }).Repeat.Any();
+ }
+
+ }
+
+ #endregion
+
+ [TestMethod]
+ public void GetAllActiveCustomers_liefert_alle_aktiven_Kunden_aus_dem_CustomerRepository()
+ {
+ var result = CustomerService.GetAllActiveCustomers();
+ Assert.AreEqual(3, result.Count);
+ Assert.AreEqual(2, result[1].ID);
+ }
+
+ [TestMethod]
+ public void GetAllArchivedCustomers_liefert_alle_archivierten_Kunden_aus_dem_CustomerRepository()
+ {
+ var result = CustomerService.GetAllArchivedCustomers();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void DeleteCustomer_ruft_das_Repository_zum_Löschen_des_gewählten_Kunden_auf()
+ {
+ CustomerService.DeleteCustomer(123456);
+ CustomerRepository.AssertWasCalled(r => r.DeleteCustomer(123456));
+ }
+
+ [TestMethod]
+ public void GetCustomerByID_liefert_einen_bestimmten_Kunden_aus_dem_Repository_anhand_seiner_ID()
+ {
+ var result = CustomerService.GetCustomerByID(1234);
+ Assert.IsNotNull(result);
+ Assert.AreEqual(1234, result.ID);
+ }
+
+ [TestMethod]
+ public void CreateCustomer_liefert_einen_Fehler_wenn_der_name_des_Kunden_nicht_angegeben_wurde()
+ {
+ var customer = new Customer { Name = "" };
+ var result = CustomerService.CreateCustomer(customer);
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void CreateCustomer_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var customer = new Customer { Name = "Testkunde" };
+ var result = CustomerService.CreateCustomer(customer);
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void CreateCustomer_speichert_den_Kunden_im_Repository_wenn_alles_okay()
+ {
+ var customer = new Customer { Name = "Testkunde" };
+ CustomerService.CreateCustomer(customer);
+ CustomerRepository.AssertWasCalled(r => r.CreateCustomer(customer));
+ }
+
+ [TestMethod]
+ public void UpdateCustomer_liefert_einen_Fehler_wenn_der_Name_des_Kunden_nicht_angegeben_wurde()
+ {
+ var customer = new Customer { ID = 3, Name = "" };
+ var result = CustomerService.UpdateCustomer(customer);
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void UpdateCustomer_wirft_eine_ArgumentException_wenn_die_ID_des_Kunden_nicht_angegeben_wurde()
+ {
+ Exception exception = null;
+ var customer = new Customer { ID = 0 };
+ try
+ {
+ CustomerService.UpdateCustomer(customer);
+ }
+ catch(Exception e)
+ {
+ exception = e;
+ }
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(ArgumentException));
+ }
+
+ [TestMethod]
+ public void UpdateCustomer_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var customer = new Customer { ID = 3, Name = "Testkunde" };
+ var result = CustomerService.UpdateCustomer(customer);
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void UpdateCustomer_speichert_den_Kunden_im_Repository_wenn_alles_okay()
+ {
+ var customer = new Customer { ID = 3, Name = "Testkunde" };
+ CustomerService.UpdateCustomer(customer);
+ CustomerRepository.AssertWasCalled(r => r.UpdateCustomer(customer));
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Services.Tests/MiteDesk.Core.Services.Tests.csproj b/Tests/MiteDesk.Core.Services.Tests/MiteDesk.Core.Services.Tests.csproj
new file mode 100644
index 0000000..bee0982
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/MiteDesk.Core.Services.Tests.csproj
@@ -0,0 +1,131 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {C9BD6574-4771-4068-B321-40943DCD3C88}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Core.Services.Tests
+ MiteDesk.Core.Services.Tests
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ False
+ ..\..\Library\Shared\RhinoMocks\Rhino.Mocks.dll
+
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}
+ MiteDesk.Core.Data
+
+
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}
+ MiteDesk.Core.Infrastructure
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}
+ MiteDesk.Core.Services
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/MiteDesk.Core.Services.Tests/ProjectServiceTests.cs b/Tests/MiteDesk.Core.Services.Tests/ProjectServiceTests.cs
new file mode 100644
index 0000000..edb4039
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/ProjectServiceTests.cs
@@ -0,0 +1,271 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Tests
+{
+
+ [TestClass]
+ public class ProjectServiceTests
+ {
+
+ #region Setup
+
+ private ProjectService ProjectService;
+ private MockRepository MockRepository;
+ private IProjectRepository ProjectRepository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+
+ MockRepository = new MockRepository();
+ ProjectRepository = MockRepository.DynamicMock();
+ ProjectService = new ProjectService(ProjectRepository);
+
+ using (MockRepository.Record())
+ {
+ Expect.Call(ProjectRepository.GetAllActiveProjects()).Return(new List(new[] { new Project(), new Project(), new Project(), new Project() })).Repeat.Any();
+ Expect.Call(ProjectRepository.GetAllArchivedProjects()).Return(new List(new[] { new Project() })).Repeat.Any();
+ Expect.Call(ProjectRepository.GetProjectsByCustomer(34)).Return(new List(new[] { new Project(), new Project() })).Repeat.Any();
+ Expect.Call(ProjectService.GetProjectByID(1234)).Return(new Project {ID = 1234}).Repeat.Any();
+ }
+
+ }
+
+ #endregion
+
+ [TestMethod]
+ public void GetAllActiveProjects_liefert_eine_Liste_aller_aktiven_Projekte()
+ {
+ var result = ProjectService.GetAllActiveProjects();
+ Assert.AreEqual(4, result.Count);
+ }
+
+ [TestMethod]
+ public void GetProjectsByCustomer_liefert_alle_Projekte_eines_einzelnen_Kunden()
+ {
+ var result = ProjectService.GetProjectsByCustomer(34);
+ Assert.AreEqual(2, result.Count);
+ }
+
+ [TestMethod]
+ public void GetAllArchivedProjects_liefert_alle_archivierten_Projekte_aus_dem_ProjectRepository()
+ {
+ var result = ProjectService.GetAllArchivedProjects();
+ Assert.AreEqual(1, result.Count);
+ }
+
+ [TestMethod]
+ public void DeleteProject_ruft_das_Repository_zum_Löschen_des_gewählten_Projektes_auf()
+ {
+ ProjectService.DeleteProject(123456);
+ ProjectRepository.AssertWasCalled(r => r.DeleteProject(123456));
+ }
+
+ [TestMethod]
+ public void GetProjectByID_liefert_ein_bestimmtes_Projekt_aus_dem_Repository_anhand_seiner_ID()
+ {
+ var result = ProjectService.GetProjectByID(1234);
+ Assert.IsNotNull(result);
+ Assert.AreEqual(1234, result.ID);
+ }
+
+ [TestMethod]
+ public void CreateProject_liefert_einen_Fehler_wenn_der_name_des_Projektes_nicht_angegeben_wurde()
+ {
+ var project = new Project { Name = "" };
+ var result = ProjectService.CreateProject(project, "");
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void CreateProject_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var project = new Project { Name = "Testprojekt" };
+ var result = ProjectService.CreateProject(project, "");
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void CreateProject_speichert_das_Projekt_im_Repository_wenn_alles_okay()
+ {
+ var project = new Project { Name = "Testprojekt" };
+ ProjectService.CreateProject(project, "");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(project));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25_komma_50_2550_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "25,50");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 2550 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25__komma_r_2500_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "25,r");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 2500 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25__komma_799_2580_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "25,799");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 2580 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_r_komma_50_50_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "r,50");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 50 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_einem_Leerstring_0_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 0 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_100_10000_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "euro" };
+ ProjectService.CreateProject(project, "100");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "euro", Budget = 10000 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_Minutes_bei_Eingabe_von_3_180_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "minutes" };
+ ProjectService.CreateProject(project, "3");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "minutes", Budget = 180 }));
+ }
+
+ [TestMethod]
+ public void CreateProject_übergibt_als_Budget_Minutes_bei_Eingabe_von_3_20_200_ans_Repository()
+ {
+ var project = new Project { Name = "OK", BudgetType = "minutes" };
+ ProjectService.CreateProject(project, "3:20");
+ ProjectRepository.AssertWasCalled(r => r.CreateProject(new Project { Name = "OK", BudgetType = "minutes", Budget = 200 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_liefert_einen_Fehler_wenn_der_Name_des_Projektes_nicht_angegeben_wurde()
+ {
+ var project = new Project { ID = 3, Name = "" };
+ var result = ProjectService.UpdateProject(project, "");
+ Assert.IsTrue(result.ContainsKey("Name"));
+ }
+
+ [TestMethod]
+ public void UpdateProject_wirft_eine_ArgumentException_wenn_die_ID_des_Projektes_nicht_angegeben_wurde()
+ {
+ Exception exception = null;
+ var project = new Project { ID = 0 };
+ try
+ {
+ ProjectService.UpdateProject(project, "");
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+ Assert.IsNotNull(exception);
+ Assert.IsInstanceOfType(exception, typeof(ArgumentException));
+ }
+
+ [TestMethod]
+ public void UpdateProject_liefert_keinen_Fehler_wenn_alles_okay()
+ {
+ var project = new Project { ID = 3, Name = "Testprojekt" };
+ var result = ProjectService.UpdateProject(project, "");
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void UpdateProject_speichert_das_Projekt_im_Repository_wenn_alles_okay()
+ {
+ var project = new Project { ID = 3, Name = "Testprojekt" };
+ ProjectService.UpdateProject(project, "");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(project));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25_komma_50_2550_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "25,50");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 2550 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25__komma_r_2500_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "25,r");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 2500 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_25__komma_799_2580_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "25,799");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 2580 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_r_komma_50_50_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "r,50");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 50 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_einem_Leerstring_0_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 0 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_EUR_bei_Eingabe_von_100_10000_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "euro" };
+ ProjectService.UpdateProject(project, "100");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "euro", Budget = 10000 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_Minutes_bei_Eingabe_von_3_180_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "minutes" };
+ ProjectService.UpdateProject(project, "3");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "minutes", Budget = 180 }));
+ }
+
+ [TestMethod]
+ public void UpdateProject_übergibt_als_Budget_Minutes_bei_Eingabe_von_3_20_200_ans_Repository()
+ {
+ var project = new Project { ID = 3, Name = "OK", BudgetType = "minutes" };
+ ProjectService.UpdateProject(project, "3:20");
+ ProjectRepository.AssertWasCalled(r => r.UpdateProject(new Project { ID = 3, Name = "OK", BudgetType = "minutes", Budget = 200 }));
+ }
+
+ }
+}
diff --git a/Tests/MiteDesk.Core.Services.Tests/Properties/AssemblyInfo.cs b/Tests/MiteDesk.Core.Services.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0789cb0
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,34 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("MiteDesk.Core.Services.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MiteDesk.Core.Services.Tests")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("61e43971-6af0-4a7e-b4c8-4c952958b0a1")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Revisions- und Buildnummern
+// übernehmen, indem Sie "*" eingeben:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/MiteDesk.Core.Services.Tests/TimeEntryServiceTests.cs b/Tests/MiteDesk.Core.Services.Tests/TimeEntryServiceTests.cs
new file mode 100644
index 0000000..2aad0f9
--- /dev/null
+++ b/Tests/MiteDesk.Core.Services.Tests/TimeEntryServiceTests.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Rhino.Mocks;
+using SixtyNineDegrees.MiteDesk.Core.Data;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Core.Services.Tests
+{
+ [TestClass]
+ public class TimeEntryServiceTests
+ {
+
+ #region Setup
+
+ private ITimeEntryService TimeEntryService;
+ private MockRepository MockRepository;
+ private ITimeEntryRepository TimeEntryRepository;
+
+ [TestInitialize]
+ public void Setup()
+ {
+
+ MockRepository = new MockRepository();
+
+ TimeEntryRepository = MockRepository.DynamicMock();
+ IProjectRepository projectRepository = MockRepository.DynamicMock();
+ IActivityRepository activityRepository = MockRepository.DynamicMock();
+
+ TimeEntryService = new TimeEntryService(TimeEntryRepository, new ProjectService(projectRepository), new ActivityService(activityRepository));
+
+ using (MockRepository.Record())
+ {
+ Expect.Call(projectRepository.GetAllActiveProjects()).Return(new List(new[] { new Project(), new Project { ID = 2 } })).Repeat.Any();
+ Expect.Call(activityRepository.GetAllActiveActivities()).Return(new List(new[] { new Activity(), new Activity { ID = 2 } })).Repeat.Any();
+ Expect.Call(TimeEntryRepository.GetTimeEntryByID(15)).Return(new TimeEntry { ID = 15 }).Repeat.Any();
+ Expect.Call(TimeEntryRepository.GetTimeEntryCurrentlyTrackedByStopwatch()).Return(new TimeEntry { ID = 34 }).Repeat.Any();
+ Expect.Call(TimeEntryRepository.GetTimeEntriesByDate(new DateTime(2009, 7, 14))).Return(new List(new [] { new TimeEntry(), new TimeEntry(), new TimeEntry() })).Repeat.Any();
+ Expect.Call(TimeEntryRepository.GetTimeEntriesByActivityID(35)).Return(new List(new[] { new TimeEntry(), new TimeEntry(), })).Repeat.Any();
+ Expect.Call(TimeEntryRepository.GetTimeEntriesByProjectID(2)).Return(new List(new[] { new TimeEntry(), new TimeEntry(), })).Repeat.Any();
+ Expect.Call(TimeEntryService.GetTimeEntryDatesByRange(new DateTime(2009, 8, 1), new DateTime(2009, 8, 15), 18352)).Return(new List(new[] { new DateTime(2009, 8, 1), new DateTime(2009, 8, 12) }));
+ }
+
+ }
+
+ #endregion
+
+ [TestMethod]
+ public void CreateTimeEntry_liefert_einen_Fehler_wenn_die_ProjektID_nicht_in_der_Liste_der_verfügbaren_Projekte_vorhanden_ist()
+ {
+ var entry = new TimeEntry { ProjectID = -1 };
+ var result = TimeEntryService.CreateTimeEntry(ref entry, "");
+ Assert.IsTrue(result.ContainsKey("ProjectID"));
+ }
+
+ [TestMethod]
+ public void CreateTimeEntry_liefert_einen_Fehler_wenn_die_ActivityID_nicht_in_der_Liste_der_verfügbaren_Leistungen_vorhanden_ist()
+ {
+ var entry = new TimeEntry { ActivityID = -1 };
+ var result = TimeEntryService.CreateTimeEntry(ref entry, "");
+ Assert.IsTrue(result.ContainsKey("ActivityID"));
+ }
+
+ [TestMethod]
+ public void CreateTimeEntry_liefert_einen_Fehler_wenn_das_Datum_nicht_angegeben_ist()
+ {
+ var entry = new TimeEntry();
+ var result = TimeEntryService.CreateTimeEntry(ref entry, "");
+ Assert.IsTrue(result.ContainsKey("Date"));
+ }
+
+ [TestMethod]
+ public void CreateTimeEntry_liefert_einen_Fehler_wenn_die_Zeit_nicht_korrekt_formatiert_ist()
+ {
+ var entry = new TimeEntry();
+ var result = TimeEntryService.CreateTimeEntry(ref entry, "ccxc");
+ Assert.IsTrue(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void CreateTimeEntry_übergibt_den_neuen_TimeEntry_ans_Repository_wenn_Validierung_erfolgreich()
+ {
+ var entry = new TimeEntry { ActivityID = 2, Date = DateTime.Now, Minutes = 30, ProjectID = 2 };
+ TimeEntryService.CreateTimeEntry(ref entry, "1:30");
+ TimeEntryRepository.AssertWasCalled(r => r.CreateTimeEntry(ref entry));
+ }
+
+ [TestMethod]
+ public void GetTimeEntriesByDate_liefert_alle_Einträge_zu_einem_Datum()
+ {
+ var result = TimeEntryService.GetTimeEntriesByDate(new DateTime(2009, 7, 14));
+ Assert.AreEqual(3, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntriesByActivityID_liefert_alle_Einträge_zu_einer_leistung()
+ {
+ var result = TimeEntryService.GetTimeEntriesByActivityID(35);
+ Assert.AreEqual(2, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntriesByProjectID_liefert_alle_Einträge_zu_einem_Projekt()
+ {
+ var result = TimeEntryService.GetTimeEntriesByProjectID(2);
+ Assert.AreEqual(2, result.Count);
+ }
+
+ [TestMethod]
+ public void GetTimeEntryByID_liefert_einen_bestimmten_Eintrag_anhand_seiner_ID()
+ {
+ var result = TimeEntryService.GetTimeEntryByID(15);
+ Assert.IsNotNull(result);
+ Assert.AreEqual(15, result.ID);
+ }
+
+ [TestMethod]
+ public void DeleteTimeEntry_ruft_das_Repository_zum_Löschen_des_gewählten_Eintrags_auf()
+ {
+ TimeEntryService.DeleteTimeEntry(34);
+ TimeEntryRepository.AssertWasCalled(r => r.DeleteTimeEntry(34));
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_liefert_einen_Fehler_wenn_die_ProjektID_nicht_in_der_Liste_der_verfügbaren_Projekte_vorhanden_ist()
+ {
+ var entry = new TimeEntry { ProjectID = -1 };
+ var result = TimeEntryService.UpdateTimeEntry(entry, "");
+ Assert.IsTrue(result.ContainsKey("ProjectID"));
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_liefert_einen_Fehler_wenn_die_ActivityID_nicht_in_der_Liste_der_verfügbaren_Leistungen_vorhanden_ist()
+ {
+ var entry = new TimeEntry { ActivityID = -1 };
+ var result = TimeEntryService.UpdateTimeEntry(entry, "");
+ Assert.IsTrue(result.ContainsKey("ActivityID"));
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_liefert_einen_Fehler_wenn_das_Datum_nicht_angegeben_ist()
+ {
+ var entry = new TimeEntry();
+ var result = TimeEntryService.UpdateTimeEntry(entry, "");
+ Assert.IsTrue(result.ContainsKey("Date"));
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_liefert_einen_Fehler_wenn_die_Zeit_nicht_korrekt_formatiert_ist()
+ {
+ var entry = new TimeEntry();
+ var result = TimeEntryService.UpdateTimeEntry(entry, "ccxc");
+ Assert.IsTrue(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void UpdateTimeEntry_übergibt_den_neuen_TimeEntry_ans_Repository_wenn_Validierung_erfolgreich()
+ {
+ var entry = new TimeEntry { ActivityID = 2, Date = DateTime.Now, Minutes = 30, ProjectID = 2 };
+ TimeEntryService.UpdateTimeEntry(entry, "1:30");
+ TimeEntryRepository.AssertWasCalled(r => r.UpdateTimeEntry(entry));
+ }
+
+ [TestMethod]
+ public void StartStopwatch_ruft_StartStopwatch_im_Repository_für_die_übergebene_ID_auf()
+ {
+ TimeEntryService.StartStopwatch(456);
+ TimeEntryRepository.AssertWasCalled(r => r.StartStopwatch(456));
+ }
+
+ [TestMethod]
+ public void StopStopwatch_ruft_StopStopwatch_im_Repository_für_die_übergebene_ID_auf()
+ {
+ TimeEntryService.StopStopwatch(456);
+ TimeEntryRepository.AssertWasCalled(r => r.StopStopwatch(456));
+ }
+
+ [TestMethod]
+ public void GetTimeEntryCurrentlyTrackedByStopwatch_liefert_den_Zeiteintrag_aus_dem_Repository_der_gerade_gestoppt_wird()
+ {
+ var result = TimeEntryService.GetTimeEntryCurrentlyTrackedByStopwatch();
+ Assert.IsNotNull(result);
+ Assert.AreEqual(34, result.ID);
+ }
+
+ [TestMethod]
+ public void GetTimeEntryDatesByRange_liefert_eine_Liste_von_Dates_in_einem_bestimmten_Datums_bereich()
+ {
+ var result = TimeEntryService.GetTimeEntryDatesByRange(new DateTime(2009, 8, 1), new DateTime(2009, 8, 15), 18352);
+ Assert.AreEqual(new DateTime(2009, 8, 1), result[0]);
+ Assert.AreEqual(new DateTime(2009, 8, 12), result[1]);
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format1()
+ {
+ // 01:35 = 95
+ var time = "01:35";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(95, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format2()
+ {
+ // 01:00 = 60
+ var time = "01:00";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(60, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format3()
+ {
+ // 0:00 = 0
+ var time = "0:00";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(0, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format4()
+ {
+ // 0 = 0
+ var time = "0";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(0, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format5()
+ {
+ // 13 = 780
+ var time = "13";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(780, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format6()
+ {
+ // 4,25 = 255
+ var time = "4,25";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(timeEntry.Minutes, 255);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format7()
+ {
+ // 5.5 = 330
+ var time = "5.5";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(330, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format8()
+ {
+ // 1,30 = 78
+ var time = "1,30";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(78, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ [TestMethod]
+ public void ValidateTimeEntry_errechnet_die_Minuten_aus_korrekter_Zeiteingabe_richtig_Format9()
+ {
+ // = 0
+ var time = "";
+ var timeEntry = new TimeEntry();
+ var result = TimeEntryService.ValidateTimeEntry(timeEntry, time);
+ Assert.AreEqual(0, timeEntry.Minutes);
+ Assert.IsFalse(result.ContainsKey("Time"));
+ }
+
+ }
+}
+
diff --git a/Tools/MiteDesk.Tools.Connector/Connector.cs b/Tools/MiteDesk.Tools.Connector/Connector.cs
new file mode 100644
index 0000000..96b54bd
--- /dev/null
+++ b/Tools/MiteDesk.Tools.Connector/Connector.cs
@@ -0,0 +1,146 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml.Linq;
+using SixtyNineDegrees.MiteDesk.Core.Model;
+
+namespace SixtyNineDegrees.MiteDesk.Tools.Connector
+{
+ public class Connector
+ {
+
+ public Connector(AppSettings settings)
+ {
+ Settings = settings;
+ }
+
+ private readonly AppSettings Settings;
+
+ private string MiteAPIBaseURL
+ {
+ get { return "https://" + Settings.AccountName + ".mite.yo.lk/"; }
+ }
+
+ private void Authenticate(ref HttpWebRequest request)
+ {
+
+ if (!string.IsNullOrEmpty(Settings.APIKey))
+ request.Headers.Add("X-MiteApiKey", Settings.APIKey);
+ else
+ request.Credentials = new NetworkCredential(Settings.Email, Settings.Password);
+
+ if (Settings.UseProxy && !string.IsNullOrEmpty(Settings.ProxyServer))
+ {
+ WebProxy proxy = new WebProxy(Settings.ProxyServer, Settings.ProxyPort);
+ if (!string.IsNullOrEmpty(Settings.ProxyUser) && !string.IsNullOrEmpty(Settings.ProxyPassword))
+ {
+ proxy.UseDefaultCredentials = false;
+ proxy.Credentials = new NetworkCredential(Settings.ProxyUser, Settings.ProxyUser);
+ }
+ else
+ {
+ proxy.UseDefaultCredentials = false;
+ proxy.Credentials = null;
+ }
+ request.Proxy = proxy;
+ }
+
+ // User-Agent
+ request.UserAgent = "mite.desk/1.2.14";
+
+ }
+
+ public XElement HttpGet(string url)
+ {
+ try
+ {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MiteAPIBaseURL + url);
+ Authenticate(ref request);
+ request.Timeout = 15000;
+ using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
+ {
+ using (StreamReader reader = new StreamReader(response.GetResponseStream()))
+ {
+ return XElement.Parse(reader.ReadToEnd());
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ throw new MiteConnectorException(exception.Message);
+ }
+ }
+
+ public XElement HttpPost(string url, string xml)
+ {
+ try
+ {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MiteAPIBaseURL + url);
+ Authenticate(ref request);
+ request.Timeout = 5000;
+ request.Method = "POST";
+ request.ContentType = "application/xml";
+
+ byte[] data = Encoding.UTF8.GetBytes(xml);
+
+ using (var requestStream = request.GetRequestStream())
+ {
+ requestStream.Write(data, 0, data.Length);
+ }
+
+ using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
+ {
+ return XElement.Parse(new StreamReader(response.GetResponseStream()).ReadToEnd());
+ }
+ }
+ catch (Exception exception)
+ {
+ throw new MiteConnectorException(exception.Message);
+ }
+ }
+
+ public void HttpDelete(string url)
+ {
+ try
+ {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MiteAPIBaseURL + url);
+ Authenticate(ref request);
+ request.Timeout = 5000;
+ request.Method = "DELETE";
+ request.ContentType = "application/xml";
+ using (request.GetResponse()) { }
+ }
+ catch (Exception exception)
+ {
+ throw new MiteConnectorException(exception.Message);
+ }
+ }
+
+ public void HttpPut(string url, string xml)
+ {
+ try
+ {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MiteAPIBaseURL + url);
+ Authenticate(ref request);
+ request.Timeout = 5000;
+ request.Method = "PUT";
+ request.ContentType = "application/xml";
+
+ byte[] data = Encoding.UTF8.GetBytes(xml);
+
+ using (var requestStream = request.GetRequestStream())
+ {
+ requestStream.Write(data, 0, data.Length);
+ }
+
+ using (request.GetResponse()) { }
+ }
+ catch (Exception exception)
+ {
+ throw new MiteConnectorException(exception.Message);
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Tools/MiteDesk.Tools.Connector/MiteConnectorException.cs b/Tools/MiteDesk.Tools.Connector/MiteConnectorException.cs
new file mode 100644
index 0000000..9fa4d62
--- /dev/null
+++ b/Tools/MiteDesk.Tools.Connector/MiteConnectorException.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace SixtyNineDegrees.MiteDesk.Tools.Connector
+{
+ public class MiteConnectorException : Exception
+ {
+
+ public MiteConnectorException(string message)
+ {
+ this.message = message;
+ }
+
+ private readonly string message;
+
+ public override string Message
+ {
+ get { return message; }
+ }
+
+ }
+}
diff --git a/Tools/MiteDesk.Tools.Connector/MiteDesk.Tools.Connector.csproj b/Tools/MiteDesk.Tools.Connector/MiteDesk.Tools.Connector.csproj
new file mode 100644
index 0000000..ad089f8
--- /dev/null
+++ b/Tools/MiteDesk.Tools.Connector/MiteDesk.Tools.Connector.csproj
@@ -0,0 +1,101 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}
+ Library
+ Properties
+ SixtyNineDegrees.MiteDesk.Tools.Connector
+ mite.desk.tools.connector
+ v3.5
+ 512
+ true
+
+
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}
+ MiteDesk.Core.Model
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Tools/MiteDesk.Tools.Connector/Properties/AssemblyInfo.cs b/Tools/MiteDesk.Tools.Connector/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ce91e2d
--- /dev/null
+++ b/Tools/MiteDesk.Tools.Connector/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("mite.desk.tools.connector")]
+[assembly: AssemblyDescription("mite.desk..tools.connector")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyProduct("mite.desk")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+[assembly: Guid("469493a7-3d64-4c65-82ba-db1f9bfc95fb")]
+
+[assembly: AssemblyVersion("1.2.17")]
+[assembly: AssemblyFileVersion("1.2.17")]
diff --git a/Tools/MiteDesk.Tools.RegistryCleaner/MiteDesk.Tools.RegistryCleaner.csproj b/Tools/MiteDesk.Tools.RegistryCleaner/MiteDesk.Tools.RegistryCleaner.csproj
new file mode 100644
index 0000000..04f225e
--- /dev/null
+++ b/Tools/MiteDesk.Tools.RegistryCleaner/MiteDesk.Tools.RegistryCleaner.csproj
@@ -0,0 +1,97 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}
+ Exe
+ Properties
+ MiteDesk.Tools.RegistryCleaner
+ MiteDesk.Tools.RegistryCleaner
+ v3.5
+ 512
+
+
+ 3.5
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ true
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Tools/MiteDesk.Tools.RegistryCleaner/Program.cs b/Tools/MiteDesk.Tools.RegistryCleaner/Program.cs
new file mode 100644
index 0000000..04f3add
--- /dev/null
+++ b/Tools/MiteDesk.Tools.RegistryCleaner/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using Microsoft.Win32;
+
+namespace MiteDesk.Tools.RegistryCleaner
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (Registry.CurrentUser.OpenSubKey("Software\\69 Grad") != null)
+ {
+ Registry.CurrentUser.DeleteSubKeyTree("Software\\69 Grad");
+ Console.WriteLine("Aktion erfolgreich. Du kannst die Anwendung jetzt schließen.");
+ }
+ else
+ {
+ Console.WriteLine("Nichts zum Aufräumen gefunden. Du kannst die Anwendung jetzt schließen.");
+ }
+ Console.ReadLine();
+ }
+ }
+}
diff --git a/Tools/MiteDesk.Tools.RegistryCleaner/Properties/AssemblyInfo.cs b/Tools/MiteDesk.Tools.RegistryCleaner/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5bc101a
--- /dev/null
+++ b/Tools/MiteDesk.Tools.RegistryCleaner/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("MiteDesk.Tools.RegistryCleaner")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("69°")]
+[assembly: AssemblyProduct("MiteDesk.Tools.RegistryCleaner")]
+[assembly: AssemblyCopyright("Copyright © 69° 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("241206ef-9009-4fb1-b81c-1dbd90434b53")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/mite.desk.sln b/mite.desk.sln
new file mode 100644
index 0000000..f08ef63
--- /dev/null
+++ b/mite.desk.sln
@@ -0,0 +1,113 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{3E096A6F-58B7-4CC9-AE27-BC39AB46A999}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{162AA04A-FA08-44DE-B642-25EBE5F7FB4C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{40B8DF61-C708-4EF3-89A1-F74AEED41DBF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EC53198E-BB8B-4D88-A8A1-55C0A3ED752A}"
+ ProjectSection(SolutionItems) = preProject
+ LocalTestRun.testrunconfig = LocalTestRun.testrunconfig
+ mite.desk.vsmdi = mite.desk.vsmdi
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Setup", "Setup", "{C7B9AE1C-36C3-4367-8BB2-308A4C763885}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{43527D84-2933-43D7-AB30-7721020FFF27}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Model", "Core\MiteDesk.Core.Model\MiteDesk.Core.Model.csproj", "{AE69F9FC-F9D4-41D8-9B00-1261F492FB89}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Services", "Core\MiteDesk.Core.Services\MiteDesk.Core.Services.csproj", "{B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Data", "Core\MiteDesk.Core.Data\MiteDesk.Core.Data.csproj", "{AD8740D8-14A7-4A31-8F96-7DF850D3D957}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.WinForms", "App\MiteDesk.WinForms\MiteDesk.WinForms.csproj", "{352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Services.Tests", "Tests\MiteDesk.Core.Services.Tests\MiteDesk.Core.Services.Tests.csproj", "{C9BD6574-4771-4068-B321-40943DCD3C88}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Data.Tests", "Tests\MiteDesk.Core.Data.Tests\MiteDesk.Core.Data.Tests.csproj", "{DFD37C08-9F36-4534-96B2-4A67AEE85F00}"
+EndProject
+Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "MiteDesk.WinForms.Setup", "Deployment\MiteDesk.WinForms.Setup\MiteDesk.WinForms.Setup.vdproj", "{D3F6F4AB-5890-4646-9DD6-C0DD31008ACA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Tools.Connector", "Tools\MiteDesk.Tools.Connector\MiteDesk.Tools.Connector.csproj", "{1B74B3CE-8969-4157-8B86-AEDA27494109}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Infrastructure", "Core\MiteDesk.Core.Infrastructure\MiteDesk.Core.Infrastructure.csproj", "{733C8DE9-36B5-4C9F-9701-FDD19B64B966}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Core.Infrastructure.Tests", "Tests\MiteDesk.Core.Infrastructure.Tests\MiteDesk.Core.Infrastructure.Tests.csproj", "{BEE63E05-FFC7-4F80-A938-2B4272683E0F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiteDesk.Tools.RegistryCleaner", "Tools\MiteDesk.Tools.RegistryCleaner\MiteDesk.Tools.RegistryCleaner.csproj", "{CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957}.Release|Any CPU.Build.0 = Release|Any CPU
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C9BD6574-4771-4068-B321-40943DCD3C88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C9BD6574-4771-4068-B321-40943DCD3C88}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C9BD6574-4771-4068-B321-40943DCD3C88}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C9BD6574-4771-4068-B321-40943DCD3C88}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D3F6F4AB-5890-4646-9DD6-C0DD31008ACA}.Debug|Any CPU.ActiveCfg = Debug
+ {D3F6F4AB-5890-4646-9DD6-C0DD31008ACA}.Release|Any CPU.ActiveCfg = Release
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B74B3CE-8969-4157-8B86-AEDA27494109}.Release|Any CPU.Build.0 = Release|Any CPU
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {EC53198E-BB8B-4D88-A8A1-55C0A3ED752A} = {40B8DF61-C708-4EF3-89A1-F74AEED41DBF}
+ {AE69F9FC-F9D4-41D8-9B00-1261F492FB89} = {3E096A6F-58B7-4CC9-AE27-BC39AB46A999}
+ {B7B67B5C-47F1-4E3D-8759-EA8E31AC951E} = {3E096A6F-58B7-4CC9-AE27-BC39AB46A999}
+ {AD8740D8-14A7-4A31-8F96-7DF850D3D957} = {3E096A6F-58B7-4CC9-AE27-BC39AB46A999}
+ {352CDDB3-9A72-43FE-84B4-7021C6CBCAD4} = {162AA04A-FA08-44DE-B642-25EBE5F7FB4C}
+ {C9BD6574-4771-4068-B321-40943DCD3C88} = {40B8DF61-C708-4EF3-89A1-F74AEED41DBF}
+ {DFD37C08-9F36-4534-96B2-4A67AEE85F00} = {40B8DF61-C708-4EF3-89A1-F74AEED41DBF}
+ {D3F6F4AB-5890-4646-9DD6-C0DD31008ACA} = {C7B9AE1C-36C3-4367-8BB2-308A4C763885}
+ {1B74B3CE-8969-4157-8B86-AEDA27494109} = {43527D84-2933-43D7-AB30-7721020FFF27}
+ {733C8DE9-36B5-4C9F-9701-FDD19B64B966} = {3E096A6F-58B7-4CC9-AE27-BC39AB46A999}
+ {BEE63E05-FFC7-4F80-A938-2B4272683E0F} = {40B8DF61-C708-4EF3-89A1-F74AEED41DBF}
+ {CA4BEC83-51A1-4E67-B2C7-3598E51A98AF} = {43527D84-2933-43D7-AB30-7721020FFF27}
+ EndGlobalSection
+ GlobalSection(TestCaseManagementSettings) = postSolution
+ CategoryFile = mite.desk.vsmdi
+ EndGlobalSection
+EndGlobal
diff --git a/mite.desk.vsmdi b/mite.desk.vsmdi
new file mode 100644
index 0000000..03611a8
--- /dev/null
+++ b/mite.desk.vsmdi
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file