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

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

Playfair Analysis Plugin (basically runs, but not ready yet)

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