source: trunk/CrypPlugins/PlayfairAnalysis/KeySearcher.cs @ 2334

Last change on this file since 2334 was 1979, checked in by Christoph Hartmann, 11 years ago

accepts a custom (user defined) bigraph statistic, wich is generated by the PlayfairAnalysisStatistic plugin

File size: 26.7 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Linq;
5using System.Text;
6using Cryptool.PluginBase;
7using Cryptool.PluginBase.Miscellaneous;
8using Mischel.Collections;
9
10using System.Windows.Controls;
11using Cryptool.PluginBase.Analysis;
12using Cryptool.PluginBase.Cryptography;
13using Cryptool.PluginBase.IO;
14
15
16namespace Cryptool.Plugins.PlayfairAnalysis
17{
18    class KeySearcher
19    {
20        int matrixSize = 5;
21        double[,] bigraphStat;
22        double[,] CipherStat;
23        int[, ,] DecodingTab;
24        int DecodingTabLength;
25        string cipherText;
26        string plainText;       
27        int keyHeapSize;
28        string alphabet;
29
30
31        public string CipherText
32        {
33            get
34            {               
35                return cipherText;
36            }
37            set
38            {
39                cipherText = value;
40            }
41        }
42
43        public string PlainText
44        {
45            get
46            {
47                return plainText;
48            }
49            set
50            {
51                plainText = value;
52            }
53        }
54
55        public double[,] BigraphStat
56        {
57            get
58            {
59                return bigraphStat;
60            }
61            set
62            {
63                bigraphStat = value;
64            }
65        }
66
67        public int KeyHeapSize
68        {
69            get
70            {
71                return keyHeapSize;
72            }
73            set
74            {
75                keyHeapSize = value;
76            }
77        }
78
79        public int MatrixSize
80        {
81            get
82            {
83                return matrixSize;
84            }
85            set
86            {
87                matrixSize = value;
88            }
89        }
90
91        public KeySearcher()
92        {
93            bigraphStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
94            CipherStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
95            DecodingTab = new int[(int)Math.Pow(matrixSize, 2) * ((int)Math.Pow(matrixSize, 2) - 1), 2, 2];
96        }
97
98        public KeySearcher(int matrixSize)
99        {
100            this.matrixSize = matrixSize;
101            bigraphStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
102            CipherStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
103            DecodingTab = new int[(int)Math.Pow(matrixSize, 2) * ((int)Math.Pow(matrixSize, 2) - 1), 2, 2]; 
104        }
105
106        public KeySearcher(int matrixSize, int keyHeapSize, double[,] bs, string alphabet, string cipherText)
107        {
108            this.matrixSize = matrixSize;
109            this.keyHeapSize = keyHeapSize;           
110            this.cipherText = cipherText;
111            bigraphStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
112            CipherStat = new double[(int)Math.Pow(matrixSize, 2), (int)Math.Pow(matrixSize, 2)];
113            DecodingTab = new int[(int)Math.Pow(matrixSize, 2) * ((int)Math.Pow(matrixSize, 2) - 1), 2, 2];
114            this.bigraphStat = bs;
115            this.alphabet = alphabet;
116        }
117
118
119
120        public string Encrypt(Key key, string PlainText)
121        {
122            char Char1, Char2;
123            int RowChar1, RowChar2, ColumnChar1, ColumnChar2;
124            StringBuilder CipherText = new StringBuilder(PlainText.Length / 2);
125
126            for (int i = 0; i < PlainText.Length; i += 2)
127            {
128                Char1 = PlainText[i];
129                Char2 = PlainText[i + 1];
130
131                int[] pos1 = key.GetPosition(Char1);
132                int[] pos2 = key.GetPosition(Char2);
133
134                RowChar1 = pos1[0];
135                ColumnChar1 = pos1[1];
136                RowChar2 = pos2[0];
137                ColumnChar2 = pos2[1];
138
139                if (RowChar1 == RowChar2)
140                {
141                    CipherText.Append(key.Mat[RowChar1, (ColumnChar1 + 1) % matrixSize]);
142                    CipherText.Append(key.Mat[RowChar2, (ColumnChar2 + 1) % matrixSize]);
143                }
144                else if (ColumnChar1 == ColumnChar2)
145                {
146                    CipherText.Append(key.Mat[(RowChar1 + 1) % matrixSize, ColumnChar1]);
147                    CipherText.Append(key.Mat[(RowChar2 + 1) % matrixSize, ColumnChar2]);
148                }
149                else
150                {
151                    CipherText.Append(key.Mat[RowChar1, ColumnChar2]);
152                    CipherText.Append(key.Mat[RowChar2, ColumnChar1]);
153                }
154
155            }
156
157            return CipherText.ToString();
158        }
159
160        public string Decrypt(Key key, string CipherText)
161        {
162            char Char1, Char2;
163            int RowChar1, RowChar2, ColumnChar1, ColumnChar2;
164            StringBuilder PlainText = new StringBuilder(CipherText.Length);
165
166            for (int i = 0; i < CipherText.Length; i += 2)
167            {
168                Char1 = CipherText[i];
169                Char2 = CipherText[i + 1];
170
171                int[] pos1 = key.GetPosition(Char1);
172                int[] pos2 = key.GetPosition(Char2);
173
174                RowChar1 = pos1[0];
175                ColumnChar1 = pos1[1];
176                RowChar2 = pos2[0];
177                ColumnChar2 = pos2[1];
178
179                if (RowChar1 == RowChar2)
180                {
181                    PlainText.Append(key.Mat[RowChar1, (ColumnChar1 + matrixSize - 1) % matrixSize]);
182                    PlainText.Append(key.Mat[RowChar2, (ColumnChar2 + matrixSize - 1) % matrixSize]);
183                }
184                else if (ColumnChar1 == ColumnChar2)
185                {
186                    PlainText.Append(key.Mat[(RowChar1 + matrixSize - 1) % matrixSize, ColumnChar1]);
187                    PlainText.Append(key.Mat[(RowChar2 + matrixSize - 1) % matrixSize, ColumnChar2]);
188                }
189                else
190                {
191                    PlainText.Append(key.Mat[RowChar1, ColumnChar2]);
192                    PlainText.Append(key.Mat[RowChar2, ColumnChar1]);
193                }
194
195            }
196
197            return PlainText.ToString();
198        }
199       
200        public string Format(string UnformattedText)
201        {
202            string PreformattedText;
203            StringBuilder FormattedText = new StringBuilder(UnformattedText.Length);
204           
205            PreformattedText = UnformattedText.ToUpper();
206
207            switch (matrixSize)
208            {
209                case 5:
210                    for (int i = 0; i < PreformattedText.Length; i += 1)
211                    {
212                        if (PreformattedText[i] == 'J')
213                            FormattedText.Append("I");
214                        else if (PreformattedText[i] >= 'A' && PreformattedText[i] <= 'Z')
215                        {
216                            FormattedText.Append(PreformattedText[i]);
217                        }
218                        else if (PreformattedText[i] == 'Ä')
219                            FormattedText.Append("AE");
220                        else if (PreformattedText[i] == 'Ö')
221                            FormattedText.Append("OE");
222                        else if (PreformattedText[i] == 'Ü')
223                            FormattedText.Append("UE");
224                        else if (PreformattedText[i] == 'ß')
225                            FormattedText.Append("SS");
226                    }
227                    break;
228                case 6:
229                    for (int i = 0; i < PreformattedText.Length; i += 1)
230                    {
231
232                        if ((PreformattedText[i] >= 'A' && PreformattedText[i] <= 'Z') || (PreformattedText[i] >= '0' && PreformattedText[i] <= '9'))
233                        {
234                            FormattedText.Append(PreformattedText[i]);
235                        }
236                        else if (PreformattedText[i] == 'Ä')
237                            FormattedText.Append("AE");
238                        else if (PreformattedText[i] == 'Ö')
239                            FormattedText.Append("OE");
240                        else if (PreformattedText[i] == 'Ü')
241                            FormattedText.Append("UE");
242                        else if (PreformattedText[i] == 'ß')
243                            FormattedText.Append("SS");
244                    }
245                    break;
246            }
247
248            int Length = FormattedText.Length;
249            for (int i = 0; i < Length - 1; i += 2)
250            {
251                if (FormattedText[i] == FormattedText[i + 1])
252                {
253                    if (FormattedText[i] != 'X')
254                    {
255                        FormattedText = FormattedText.Insert(i + 1, "X");                       
256                    }
257                    else
258                    {
259                        FormattedText = FormattedText.Insert(i + 1, "Y");
260                    }
261                    Length += 1;
262                }
263            }
264
265            if ((FormattedText.Length % 2) == 1)
266            {
267                if (FormattedText[FormattedText.Length - 1] != 'X')
268                {
269                    FormattedText.Append("X");
270                }
271                else
272                {
273                    FormattedText.Append("Y");
274                }
275            }
276
277            return FormattedText.ToString();
278        }
279
280        public void Attack()
281        {                       
282            BigraphStatistic CS = new BigraphStatistic(matrixSize);
283            CipherStat = CS.CalcLogStat(cipherText, alphabet);           
284            int[] TestKey = new int[(int)Math.Pow(matrixSize, 2)];
285            double Score2;
286            int[] WorstKey = new int[(int)Math.Pow(matrixSize, 2)];
287            int[] BestKey = new int[(int)Math.Pow(matrixSize, 2)];
288            double WorstScore = 0;
289            double BestScore;
290            int Count = 0;
291
292                       
293            if (LogMessageByKeySearcher != null)
294            {
295                LogMessageByKeySearcher("Calculating decoding tab..", NotificationLevel.Info);               
296            }
297           
298            CalcDecodingTab(5);
299
300
301            //SortedDictionary<double, int[]> KeyHeap = new SortedDictionary<double, int[]>();           
302            //SortedDictionary<double, int[]>.KeyCollection KeyColl = KeyHeap.Keys;
303
304            PriorityQueue<int[], double>[] keyHeap = new PriorityQueue<int[], double>[2];
305            keyHeap[0] = new PriorityQueue<int[], double>();
306            keyHeap[1] = new PriorityQueue<int[], double>();
307
308
309            if (LogMessageByKeySearcher != null)
310            {
311                LogMessageByKeySearcher("Testing all partial keys of length 5 ", NotificationLevel.Info);
312            }
313           
314
315            DateTime time1 = DateTime.Now;
316
317            for (int i = 0; i < (int)Math.Pow(matrixSize, 2); i++)
318            {
319
320                if (ProgressChangedByKeySearcher != null)
321                {
322                    ProgressChangedByKeySearcher(i, (int)Math.Pow(matrixSize, 2) * 2);
323                }
324               
325                TestKey[0] = i;
326                for (int j = 0; j < (int)Math.Pow(matrixSize, 2); j++)
327                    if (j != i)
328                    {
329                        TestKey[1] = j;
330                        for (int k = 0; k < (int)Math.Pow(matrixSize, 2); k++)
331                            if (k != i && k != j)
332                            {
333                                TestKey[2] = k;
334                                for (int l = 0; l < (int)Math.Pow(matrixSize, 2); l++)
335                                    if (l != i && l != j && l != k)
336                                    {
337                                        TestKey[3] = l;
338                                        for (int m = 0; m < (int)Math.Pow(matrixSize, 2); m++)
339                                            if (m != i && m != j && m != k && m != l)
340                                            {
341                                                TestKey[4] = m;
342                                                Score2 = EvaluateKey2(TestKey);
343                                                if (Count > keyHeapSize - 1)
344                                                {
345                                                    if (Score2 < WorstScore)
346                                                    {
347                                                        try
348                                                        {
349                                                            //if (!KeyHeap.Contains(Score2))
350                                                            {
351                                                                keyHeap[0].Dequeue();
352                                                                keyHeap[0].Enqueue((int[])TestKey.Clone(), Score2);
353                                                                WorstScore = keyHeap[0].Peek().Priority;
354                                                            }
355                                                        }
356                                                        catch (ArgumentException)
357                                                        {
358                                                            Console.Out.WriteLine("Wert bereits im Heap (> {0})", keyHeapSize);
359                                                        }
360                                                    }
361                                                }
362                                                else
363                                                {
364                                                    try
365                                                    {
366                                                        keyHeap[0].Enqueue(TestKey, Score2);
367                                                        WorstScore = Math.Max(WorstScore, Score2);
368                                                        Count = keyHeap[0].Count;
369                                                    }
370                                                    catch (ArgumentException)
371                                                    {
372                                                        Console.Out.WriteLine("Wert bereits im Heap (< {0})", keyHeapSize);
373                                                    }
374                                                }
375                                            }
376                                    }
377                            }
378                    }
379            }
380
381
382            DateTime time2 = DateTime.Now;
383            TimeSpan diff = time2 - time1;
384
385            if (LogMessageByKeySearcher != null)
386            {
387                LogMessageByKeySearcher("\n\ntime required: " + Convert.ToString(diff.TotalSeconds) + " seconds", NotificationLevel.Info);
388            }
389           
390
391            WorstKey = keyHeap[0].Peek().Value;
392            BestScore = double.MaxValue;
393            foreach (PriorityQueueItem<int[], double> pqi in keyHeap[0])
394            {
395                if (pqi.Priority < BestScore)
396                {
397                    BestScore = pqi.Priority;
398                    BestKey = pqi.Value;
399                }
400            }
401
402            if (LogMessageByKeySearcher != null)
403            {
404                LogMessageByKeySearcher("\nBest Score: " +  Convert.ToString(BestScore), NotificationLevel.Info);
405                LogMessageByKeySearcher("\nBest Key: ", NotificationLevel.Info);
406
407                LogMessageByKeySearcher("\nWorst Score: " + Convert.ToString(WorstScore), NotificationLevel.Info);
408                LogMessageByKeySearcher("\nWorst Key: ", NotificationLevel.Info);
409
410                LogMessageByKeySearcher("\nAmount of keys in Heap: " + Convert.ToString(keyHeap[0].Count), NotificationLevel.Info);
411                LogMessageByKeySearcher("\nTesting next position of keys in heap...", NotificationLevel.Info);
412            }
413
414
415            time1 = DateTime.Now;
416
417            for (int pos = 5; pos < (int)Math.Pow(matrixSize, 2); pos++)
418            {
419                keyHeap[pos % 2].Clear();
420                CalcDecodingTab(pos + 1);
421                Count = 0;
422
423                if (ProgressChangedByKeySearcher != null)
424                {
425                    ProgressChangedByKeySearcher((pos - 5) + ((int)Math.Pow(matrixSize, 2) - 5), ((int)Math.Pow(matrixSize, 2) - 5) * 2);
426                }
427
428                foreach (PriorityQueueItem<int[], double> pqi in keyHeap[(pos + 1) % 2])
429                {
430                    bool[] letterinkey = new bool[(int)Math.Pow(matrixSize, 2)];
431                    for (int i = 0; i < pos; i++)
432                    {
433                        letterinkey[pqi.Value[i]] = true;
434                    }
435                    for (int i = 0; i < (int)Math.Pow(matrixSize, 2); i++)
436                    {
437                        if (!letterinkey[i])
438                        {
439                            pqi.Value[pos] = i;
440                            Score2 = EvaluateKey2(pqi.Value);
441                            if (Count > keyHeapSize - 1)
442                            {
443                                if (Score2 < WorstScore)
444                                {
445                                    keyHeap[pos & 1].Dequeue();
446                                    keyHeap[pos & 1].Enqueue((int[])pqi.Value.Clone(), Score2);
447                                    WorstScore = keyHeap[pos & 1].Peek().Priority;
448                                }
449                            }
450                            else
451                            {
452                                keyHeap[pos & 1].Enqueue(pqi.Value, Score2);
453                                WorstScore = Math.Max(WorstScore, Score2);
454                                Count = keyHeap[pos & 1].Count;
455                            }
456                        }
457                    }
458                }
459                if (LogMessageByKeySearcher != null)
460                {
461                    LogMessageByKeySearcher("Position " + Convert.ToString(pos+1) + " done.", NotificationLevel.Info);
462                }
463            }
464
465
466            time2 = DateTime.Now;
467            diff = time2 - time1;
468
469            if (LogMessageByKeySearcher != null)
470            {
471                LogMessageByKeySearcher("\ntime required: " + Convert.ToString(diff.TotalSeconds) + " seconds", NotificationLevel.Info);
472            }
473           
474
475            BestScore = double.MaxValue;
476
477            foreach (PriorityQueueItem<int[], double> pqi in keyHeap[((int)Math.Pow(matrixSize, 2) - 1) % 2])
478            {
479                if (pqi.Priority < BestScore)
480                {
481                    BestScore = pqi.Priority;
482                    BestKey = (int[])pqi.Value.Clone();
483                }
484            }
485
486
487            if (LogMessageByKeySearcher != null)
488            {
489                LogMessageByKeySearcher("\nBest Score: " + Convert.ToString(BestScore), NotificationLevel.Info);
490                LogMessageByKeySearcher("\nBest Key: ", NotificationLevel.Info);
491            }
492
493
494            int[] CorrectKey = new int[(int)Math.Pow(matrixSize, 2)];
495            for (int i = 0; i < (int)Math.Pow(matrixSize, 2); i++)
496                CorrectKey[i] = i;
497
498            if (LogMessageByKeySearcher != null)
499            {
500                LogMessageByKeySearcher("\nCorrect Key Score: " + Convert.ToString(EvaluateKey2(CorrectKey)), NotificationLevel.Info);
501                LogMessageByKeySearcher("\nCorrect Key: ", NotificationLevel.Info);
502            }
503           
504           
505            Key BestKeyMatrix = new Key(Key.ConvertToChar(BestKey, alphabet));
506
507            plainText =  Decrypt(BestKeyMatrix, cipherText);
508           
509        }
510
511        public Double EvaluateKey(int[] Key)
512        {
513            double Mean = 0;
514            int MeanLength = 0;
515            double SumProbCipher = 0;
516            int BigraphsInCipher = 0;
517            double Score = 0;
518
519            for (int i = 0; i < DecodingTabLength; i++)
520            {
521                if (bigraphStat[Key[DecodingTab[i, 1, 0]], Key[DecodingTab[i, 1, 1]]] > -9)
522                {
523                    Mean += bigraphStat[Key[DecodingTab[i, 1, 0]], Key[DecodingTab[i, 1, 1]]];
524                    MeanLength++;
525                }
526                if (CipherStat[Key[DecodingTab[i, 0, 0]], Key[DecodingTab[i, 0, 1]]] > -100)
527                {
528                    SumProbCipher += CipherStat[Key[DecodingTab[i, 0, 0]], Key[DecodingTab[i, 0, 1]]];
529                    BigraphsInCipher++;
530                }
531            }
532
533            //Console.Out.WriteLine("Summe der " + Convert.ToString(MeanLength) + " allg. Wahrsch. > -9 : " + Convert.ToString(Mean));
534            Mean /= MeanLength;
535
536            //Console.Out.WriteLine("Durchschnitt: " + Convert.ToString(Mean));
537
538            //Console.Out.WriteLine("Summe der " + Convert.ToString(BigraphsInCipher) + " Wahrsch. > -100 im Ciphertext: " + Convert.ToString(SumProbCipher));
539
540            Score = SumProbCipher - BigraphsInCipher * Mean;
541
542            //Console.Out.WriteLine("Score: " + Convert.ToString(Score));
543
544            return Score;
545        }
546
547        public Double EvaluateKey2(int[] Key)
548        {
549            Double Score2 = 0;
550                       
551            for (int i = 0; i < DecodingTabLength; i++)
552            {
553                //if (bigraphStat[Key[DecodingTab[i, 1, 0]], Key[DecodingTab[i, 1, 1]]] > -11)
554                Score2 += Math.Abs(bigraphStat[Key[DecodingTab[i, 1, 0]], Key[DecodingTab[i, 1, 1]]] - CipherStat[Key[DecodingTab[i, 0, 0]], Key[DecodingTab[i, 0, 1]]]);
555            }
556
557            return Score2;
558        }
559
560        public int[, ,] CalcDecodingTab(int KeyLength)
561        {
562            int index = 0;
563
564            for (int i = 0; i < KeyLength - 1; i++)
565            {
566                for (int j = i + 1; j < KeyLength; j++)
567                {
568                    if ((i / matrixSize) == (j / matrixSize))     // i and j in same row
569                    {
570                        if ((i % matrixSize) > 0)
571                        {
572                            DecodingTab[index, 0, 0] = i;
573                            DecodingTab[index, 0, 1] = j;
574                            DecodingTab[index, 1, 0] = i - 1;
575                            DecodingTab[index, 1, 1] = j - 1;
576                            index++;
577                            DecodingTab[index, 0, 0] = DecodingTab[index - 1, 0, 1];
578                            DecodingTab[index, 0, 1] = DecodingTab[index - 1, 0, 0];
579                            DecodingTab[index, 1, 0] = DecodingTab[index - 1, 1, 1];
580                            DecodingTab[index, 1, 1] = DecodingTab[index - 1, 1, 0];
581                            index++;
582                        }
583                        else if (i + matrixSize - 1 < KeyLength)
584                        {
585                            DecodingTab[index, 0, 0] = i;
586                            DecodingTab[index, 0, 1] = j;
587                            DecodingTab[index, 1, 0] = i + matrixSize - 1;
588                            DecodingTab[index, 1, 1] = j - 1;
589                            index++;
590                            DecodingTab[index, 0, 0] = DecodingTab[index - 1, 0, 1];
591                            DecodingTab[index, 0, 1] = DecodingTab[index - 1, 0, 0];
592                            DecodingTab[index, 1, 0] = DecodingTab[index - 1, 1, 1];
593                            DecodingTab[index, 1, 1] = DecodingTab[index - 1, 1, 0];
594                            index++;
595                        }
596                    }
597
598                    else if ((i % matrixSize) == (j % matrixSize))      // i and j in same column
599                    {
600                        if ((i / matrixSize) > 0)
601                        {
602                            DecodingTab[index, 0, 0] = i;
603                            DecodingTab[index, 0, 1] = j;
604                            DecodingTab[index, 1, 0] = i - matrixSize;
605                            DecodingTab[index, 1, 1] = j - matrixSize;
606                            index++;
607                            DecodingTab[index, 0, 0] = DecodingTab[index - 1, 0, 1];
608                            DecodingTab[index, 0, 1] = DecodingTab[index - 1, 0, 0];
609                            DecodingTab[index, 1, 0] = DecodingTab[index - 1, 1, 1];
610                            DecodingTab[index, 1, 1] = DecodingTab[index - 1, 1, 0];
611                            index++;
612                        }
613                        else if (i + (matrixSize * (matrixSize - 1)) < KeyLength)
614                        {
615                            DecodingTab[index, 0, 0] = i;
616                            DecodingTab[index, 0, 1] = j;
617                            DecodingTab[index, 1, 0] = i + (matrixSize * (matrixSize - 1));
618                            DecodingTab[index, 1, 1] = j - matrixSize;
619                            index++;
620                            DecodingTab[index, 0, 0] = DecodingTab[index - 1, 0, 1];
621                            DecodingTab[index, 0, 1] = DecodingTab[index - 1, 0, 0];
622                            DecodingTab[index, 1, 0] = DecodingTab[index - 1, 1, 1];
623                            DecodingTab[index, 1, 1] = DecodingTab[index - 1, 1, 0];
624                            index++;
625                        }
626                    }
627                    else if ((i / matrixSize) * matrixSize + (j % matrixSize) < KeyLength && (j / matrixSize) * matrixSize + (i % matrixSize) < KeyLength)   // i and j in a square
628                    {
629                        DecodingTab[index, 0, 0] = i;
630                        DecodingTab[index, 0, 1] = j;
631                        DecodingTab[index, 1, 0] = (i / matrixSize) * matrixSize + (j % matrixSize);
632                        DecodingTab[index, 1, 1] = (j / matrixSize) * matrixSize + (i % matrixSize);
633                        index++;
634                        DecodingTab[index, 0, 0] = DecodingTab[index - 1, 0, 1];
635                        DecodingTab[index, 0, 1] = DecodingTab[index - 1, 0, 0];
636                        DecodingTab[index, 1, 0] = DecodingTab[index - 1, 1, 1];
637                        DecodingTab[index, 1, 1] = DecodingTab[index - 1, 1, 0];
638                        index++;
639                    }
640
641                }
642            }
643
644            DecodingTabLength = index;
645            return DecodingTab;
646        }
647
648        #region Event Handling
649
650
651        public delegate void LogMessageByKeySearcherEventHandler(string message, NotificationLevel logLevel);
652        public event LogMessageByKeySearcherEventHandler LogMessageByKeySearcher;
653
654        public delegate void ProgressChangedByKeySearcherEventHandler(double value, double max);
655        public event ProgressChangedByKeySearcherEventHandler ProgressChangedByKeySearcher;
656
657       
658        #endregion
659
660    }
661}
Note: See TracBrowser for help on using the repository browser.