comparison pidgin/plugins/spellchk.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children d75099d2567e
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /*
2 * Gaim - Replace certain misspelled words with their correct form.
3 *
4 * Signification changes were made by Benjamin Kahn ("xkahn") and
5 * Richard Laager ("rlaager") in April 2005--you may want to contact
6 * them if you have questions.
7 *
8 * Gaim is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28 /*
29 * A lot of this code (especially the config code) was taken directly
30 * or nearly directly from xchat, version 1.4.2 by Peter Zelezny and others.
31 */
32
33 #include "internal.h"
34 #include "gtkgaim.h"
35
36 #include "debug.h"
37 #include "notify.h"
38 #include "signals.h"
39 #include "util.h"
40 #include "version.h"
41
42 #include "gtkplugin.h"
43 #include "gtkprefs.h"
44 #include "gtkutils.h"
45
46 #include <stdio.h>
47 #include <string.h>
48 #ifndef _WIN32
49 #include <strings.h>
50 #endif
51 #include <sys/types.h>
52 #include <sys/stat.h>
53
54 #define SPELLCHECK_PLUGIN_ID "gtk-spellcheck"
55 #define SPELLCHK_OBJECT_KEY "spellchk"
56
57 enum {
58 BAD_COLUMN,
59 GOOD_COLUMN,
60 WORD_ONLY_COLUMN,
61 CASE_SENSITIVE_COLUMN,
62 N_COLUMNS
63 };
64
65 struct _spellchk {
66 GtkTextView *view;
67 GtkTextMark *mark_insert_start;
68 GtkTextMark *mark_insert_end;
69
70 const gchar *word;
71 gboolean inserting;
72 gboolean ignore_correction;
73 gboolean ignore_correction_on_send;
74 gint pos;
75 };
76
77 typedef struct _spellchk spellchk;
78
79 static GtkListStore *model;
80
81 static gboolean
82 is_word_uppercase(const gchar *word)
83 {
84 for (; word[0] != '\0'; word = g_utf8_find_next_char (word, NULL)) {
85 gunichar c = g_utf8_get_char(word);
86
87 if (!(g_unichar_isupper(c) ||
88 g_unichar_ispunct(c) ||
89 g_unichar_isspace(c)))
90 return FALSE;
91 }
92
93 return TRUE;
94 }
95
96 static gboolean
97 is_word_lowercase(const gchar *word)
98 {
99 for (; word[0] != '\0'; word = g_utf8_find_next_char(word, NULL)) {
100 gunichar c = g_utf8_get_char(word);
101
102 if (!(g_unichar_islower(c) ||
103 g_unichar_ispunct(c) ||
104 g_unichar_isspace(c)))
105 return FALSE;
106 }
107
108 return TRUE;
109 }
110
111 static gboolean
112 is_word_proper(const gchar *word)
113 {
114 if (word[0] == '\0')
115 return FALSE;
116
117 if (!g_unichar_isupper(g_utf8_get_char_validated(word, -1)))
118 return FALSE;
119
120 return is_word_lowercase(g_utf8_offset_to_pointer(word, 1));
121 }
122
123 static gchar *
124 make_word_proper(const gchar *word)
125 {
126 char buf[7];
127 gchar *lower = g_utf8_strdown(word, -1);
128 gint bytes;
129 gchar *ret;
130
131 bytes = g_unichar_to_utf8(g_unichar_toupper(g_utf8_get_char(word)), buf);
132 buf[MIN(bytes, sizeof(buf) - 1)] = '\0';
133
134 ret = g_strconcat(buf, g_utf8_offset_to_pointer(lower, 1), NULL);
135 g_free(lower);
136
137 return ret;
138 }
139
140 static gboolean
141 substitute_simple_buffer(GtkTextBuffer *buffer)
142 {
143 GtkTextIter start;
144 GtkTextIter end;
145 GtkTreeIter treeiter;
146 gchar *text = NULL;
147
148 gtk_text_buffer_get_iter_at_offset(buffer, &start, 0);
149 gtk_text_buffer_get_iter_at_offset(buffer, &end, 0);
150 gtk_text_iter_forward_to_end(&end);
151
152 text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
153
154 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &treeiter) && text) {
155 do {
156 GValue val1;
157 const gchar *bad;
158 gchar *cursor;
159 glong char_pos;
160
161 val1.g_type = 0;
162 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, WORD_ONLY_COLUMN, &val1);
163 if (g_value_get_boolean(&val1))
164 {
165 g_value_unset(&val1);
166 continue;
167 }
168 g_value_unset(&val1);
169
170 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, BAD_COLUMN, &val1);
171 bad = g_value_get_string(&val1);
172
173 /* using g_utf8_* to get /character/ offsets instead of byte offsets for buffer */
174 if ((cursor = g_strrstr(text, bad)))
175 {
176 GValue val2;
177 const gchar *good;
178
179 val2.g_type = 0;
180 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &treeiter, GOOD_COLUMN, &val2);
181 good = g_value_get_string(&val2);
182
183 char_pos = g_utf8_pointer_to_offset(text, cursor);
184 gtk_text_buffer_get_iter_at_offset(buffer, &start, char_pos);
185 gtk_text_buffer_get_iter_at_offset(buffer, &end, char_pos + g_utf8_strlen(bad, -1));
186 gtk_text_buffer_delete(buffer, &start, &end);
187
188 gtk_text_buffer_get_iter_at_offset(buffer, &start, char_pos);
189 gtk_text_buffer_insert(buffer, &start, good, -1);
190
191 g_value_unset(&val2);
192 g_free(text);
193
194 g_value_unset(&val1);
195 return TRUE;
196 }
197
198 g_value_unset(&val1);
199 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &treeiter));
200 }
201
202 g_free(text);
203 return FALSE;
204 }
205
206 static gchar *
207 substitute_word(gchar *word)
208 {
209 GtkTreeIter iter;
210 gchar *outword;
211 gchar *lowerword;
212 gchar *foldedword;
213
214 if (word == NULL)
215 return NULL;
216
217 lowerword = g_utf8_strdown(word, -1);
218 foldedword = g_utf8_casefold(word, -1);
219
220 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) {
221 do {
222 GValue val1;
223 gboolean case_sensitive;
224 const char *bad;
225 gchar *tmpbad = NULL;
226
227 val1.g_type = 0;
228 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &val1);
229 if (!g_value_get_boolean(&val1)) {
230 g_value_unset(&val1);
231 continue;
232 }
233 g_value_unset(&val1);
234
235 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &val1);
236 case_sensitive = g_value_get_boolean(&val1);
237 g_value_unset(&val1);
238
239 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &val1);
240 bad = g_value_get_string(&val1);
241
242 if ((case_sensitive && !strcmp(bad, word)) ||
243 (!case_sensitive && (!strcmp(bad, lowerword) ||
244 (!is_word_lowercase(bad) &&
245 !strcmp((tmpbad = g_utf8_casefold(bad, -1)), foldedword)))))
246 {
247 GValue val2;
248 const char *good;
249
250 g_free(tmpbad);
251
252 val2.g_type = 0;
253 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GOOD_COLUMN, &val2);
254 good = g_value_get_string(&val2);
255
256 if (!case_sensitive && is_word_lowercase(bad) && is_word_lowercase(good))
257 {
258 if (is_word_uppercase(word))
259 outword = g_utf8_strup(good, -1);
260 else if (is_word_proper(word))
261 outword = make_word_proper(good);
262 else
263 outword = g_strdup(good);
264 }
265 else
266 outword = g_strdup(good);
267
268 g_value_unset(&val1);
269 g_value_unset(&val2);
270
271 g_free(foldedword);
272 return outword;
273 }
274
275 g_value_unset(&val1);
276 g_free(tmpbad);
277
278 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
279 }
280 g_free(foldedword);
281
282 return NULL;
283 }
284
285 static void
286 spellchk_free(spellchk *spell)
287 {
288 GtkTextBuffer *buffer;
289
290 g_return_if_fail(spell != NULL);
291
292 buffer = gtk_text_view_get_buffer(spell->view);
293
294 g_signal_handlers_disconnect_matched(buffer,
295 G_SIGNAL_MATCH_DATA,
296 0, 0, NULL, NULL,
297 spell);
298 g_free(spell);
299 }
300
301 /* Pango doesn't know about the "'" character. Let's fix that. */
302 static gboolean
303 spellchk_inside_word(GtkTextIter *iter)
304 {
305 gunichar ucs4_char = gtk_text_iter_get_char(iter);
306 gchar *utf8_str;
307 gchar c = 0;
308
309 utf8_str = g_ucs4_to_utf8(&ucs4_char, 1, NULL, NULL, NULL);
310 if (utf8_str != NULL)
311 {
312 c = utf8_str[0];
313 g_free(utf8_str);
314 }
315
316 /* Hack because otherwise typing things like U.S. gets difficult
317 * if you have 'u' -> 'you' set as a correction...
318 *
319 * Part 1 of 2: This marks . as being an inside-word character. */
320 if (c == '.')
321 return TRUE;
322
323 /* Avoid problems with \r, for example (SF #1289031). */
324 if (c == '\\')
325 return TRUE;
326
327 if (gtk_text_iter_inside_word (iter) == TRUE)
328 return TRUE;
329
330 if (c == '\'') {
331 gboolean result = gtk_text_iter_backward_char(iter);
332 gboolean output = gtk_text_iter_inside_word(iter);
333
334 if (result)
335 {
336 /*
337 * Hack so that "u'll" will correct correctly.
338 */
339 ucs4_char = gtk_text_iter_get_char(iter);
340 utf8_str = g_ucs4_to_utf8(&ucs4_char, 1, NULL, NULL, NULL);
341 if (utf8_str != NULL)
342 {
343 c = utf8_str[0];
344 g_free(utf8_str);
345
346 if (c == 'u' || c == 'U')
347 {
348 gtk_text_iter_forward_char(iter);
349 return FALSE;
350 }
351 }
352
353 gtk_text_iter_forward_char(iter);
354 }
355
356 return output;
357 }
358 else if (c == '&')
359 return TRUE;
360
361 return FALSE;
362 }
363
364 static gboolean
365 spellchk_backward_word_start(GtkTextIter *iter)
366 {
367 int output;
368 int result;
369
370 output = gtk_text_iter_backward_word_start(iter);
371
372 /* It didn't work... */
373 if (!output)
374 return FALSE;
375
376 while (spellchk_inside_word(iter)) {
377 result = gtk_text_iter_backward_char(iter);
378
379 /* We can't go backwards anymore? We're at the beginning of the word. */
380 if (!result)
381 return TRUE;
382
383 if (!spellchk_inside_word(iter)) {
384 gtk_text_iter_forward_char(iter);
385 return TRUE;
386 }
387
388 output = gtk_text_iter_backward_word_start(iter);
389 if (!output)
390 return FALSE;
391 }
392
393 return TRUE;
394 }
395
396 static gboolean
397 check_range(spellchk *spell, GtkTextBuffer *buffer,
398 GtkTextIter start, GtkTextIter end, gboolean sending)
399 {
400 gboolean replaced;
401 gboolean result;
402 gchar *tmp;
403 int period_count = 0;
404 gchar *word;
405 GtkTextMark *mark;
406 GtkTextIter pos;
407
408 if ((replaced = substitute_simple_buffer(buffer)))
409 {
410 mark = gtk_text_buffer_get_insert(buffer);
411 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
412 spell->pos = gtk_text_iter_get_offset(&pos);
413
414 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
415 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
416 }
417
418 if (!sending)
419 {
420 /* We need to go backwords to find out if we are inside a word or not. */
421 gtk_text_iter_backward_char(&end);
422
423 if (spellchk_inside_word(&end))
424 {
425 gtk_text_iter_forward_char(&end);
426 return replaced; /* We only pay attention to whole words. */
427 }
428 }
429
430 /* We could be in the middle of a whitespace block. Check for that. */
431 result = gtk_text_iter_backward_char(&end);
432
433 if (!spellchk_inside_word(&end))
434 {
435 if (result)
436 gtk_text_iter_forward_char(&end);
437 return replaced;
438 }
439
440 if (result)
441 gtk_text_iter_forward_char(&end);
442
443 /* Move backwards to the beginning of the word. */
444 spellchk_backward_word_start(&start);
445
446 spell->word = gtk_text_iter_get_text(&start, &end);
447
448 /* Hack because otherwise typing things like U.S. gets difficult
449 * if you have 'u' -> 'you' set as a correction...
450 *
451 * Part 2 of 2: This chops periods off the end of the word so
452 * the right substitution entry is found. */
453 tmp = g_strdup(spell->word);
454 if (tmp != NULL && *tmp != '\0') {
455 gchar *c;
456 for (c = tmp + strlen(tmp) - 1 ; c != tmp ; c--) {
457 if (*c == '.') {
458 *c = '\0';
459 period_count++;
460 } else
461 break;
462 }
463 }
464
465 if ((word = substitute_word(tmp))) {
466 GtkTextMark *mark;
467 GtkTextIter pos;
468 gchar *tmp2;
469 int i;
470
471 for (i = 1 ; i <= period_count ; i++) {
472 tmp2 = g_strconcat(word, ".", NULL);
473 g_free(word);
474 word = tmp2;
475 }
476
477 gtk_text_buffer_delete(buffer, &start, &end);
478 gtk_text_buffer_insert(buffer, &start, word, -1);
479
480 mark = gtk_text_buffer_get_insert(buffer);
481 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
482 spell->pos = gtk_text_iter_get_offset(&pos);
483
484 g_free(word);
485 g_free(tmp);
486 return TRUE;
487 }
488 g_free(tmp);
489
490 spell->word = NULL;
491
492 return replaced;
493 }
494
495 /* insertion works like this:
496 * - before the text is inserted, we mark the position in the buffer.
497 * - after the text is inserted, we see where our mark is and use that and
498 * the current position to check the entire range of inserted text.
499 *
500 * this may be overkill for the common case (inserting one character). */
501 static void
502 insert_text_before(GtkTextBuffer *buffer, GtkTextIter *iter,
503 gchar *text, gint len, spellchk *spell)
504 {
505 if (spell->inserting == TRUE)
506 return;
507
508 spell->inserting = TRUE;
509
510 spell->word = NULL;
511
512 gtk_text_buffer_move_mark(buffer, spell->mark_insert_start, iter);
513 }
514
515 static void
516 insert_text_after(GtkTextBuffer *buffer, GtkTextIter *iter,
517 gchar *text, gint len, spellchk *spell)
518 {
519 GtkTextIter start, end;
520 GtkTextMark *mark;
521
522 spell->ignore_correction_on_send = FALSE;
523
524 if (spell->ignore_correction) {
525 spell->ignore_correction = FALSE;
526 return;
527 }
528
529 /* we need to check a range of text. */
530 gtk_text_buffer_get_iter_at_mark(buffer, &start, spell->mark_insert_start);
531
532 if (len == 1)
533 check_range(spell, buffer, start, *iter, FALSE);
534
535 /* if check_range modified the buffer, iter has been invalidated */
536 mark = gtk_text_buffer_get_insert(buffer);
537 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
538 gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, &end);
539
540 spell->inserting = FALSE;
541 }
542
543 static void
544 delete_range_after(GtkTextBuffer *buffer,
545 GtkTextIter *start, GtkTextIter *end, spellchk *spell)
546 {
547 GtkTextIter start2, end2;
548 GtkTextMark *mark;
549 GtkTextIter pos;
550 gint place;
551
552 spell->ignore_correction_on_send = FALSE;
553
554 if (!spell->word)
555 return;
556
557 if (spell->inserting == TRUE)
558 return;
559
560 spell->inserting = TRUE;
561
562 mark = gtk_text_buffer_get_insert(buffer);
563 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
564 place = gtk_text_iter_get_offset(&pos);
565
566 if ((place + 1) != spell->pos) {
567 spell->word = NULL;
568 return;
569 }
570
571 gtk_text_buffer_get_iter_at_mark(buffer, &start2, spell->mark_insert_start);
572 gtk_text_buffer_get_iter_at_mark(buffer, &end2, spell->mark_insert_end);
573
574 gtk_text_buffer_delete(buffer, &start2, &end2);
575 gtk_text_buffer_insert(buffer, &start2, spell->word, -1);
576 spell->ignore_correction = TRUE;
577 spell->ignore_correction_on_send = TRUE;
578
579 spell->inserting = FALSE;
580 spell->word = NULL;
581 }
582
583 static void
584 message_send_cb(GtkWidget *widget, spellchk *spell)
585 {
586 GtkTextBuffer *buffer;
587 GtkTextIter start, end;
588 GtkTextMark *mark;
589 gboolean replaced;
590
591 if (spell->ignore_correction_on_send)
592 {
593 spell->ignore_correction_on_send = FALSE;
594 return;
595 }
596
597 #if 0
598 if (!gaim_prefs_get_bool("/plugins/gtk/spellchk/last_word_replace"))
599 return;
600 #endif
601
602 buffer = gtk_text_view_get_buffer(spell->view);
603
604 gtk_text_buffer_get_end_iter(buffer, &start);
605 gtk_text_buffer_get_end_iter(buffer, &end);
606 spell->inserting = TRUE;
607 replaced = check_range(spell, buffer, start, end, TRUE);
608 spell->inserting = FALSE;
609
610 /* if check_range modified the buffer, iter has been invalidated */
611 mark = gtk_text_buffer_get_insert(buffer);
612 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
613 gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, &end);
614
615 if (replaced)
616 {
617 g_signal_stop_emission_by_name(widget, "message_send");
618 spell->ignore_correction_on_send = TRUE;
619 }
620 }
621
622 static void
623 spellchk_new_attach(GaimConversation *conv)
624 {
625 spellchk *spell;
626 GtkTextBuffer *buffer;
627 GtkTextIter start, end;
628 GaimGtkConversation *gtkconv;
629 GtkTextView *view;
630
631 gtkconv = GAIM_GTK_CONVERSATION(conv);
632
633 view = GTK_TEXT_VIEW(gtkconv->entry);
634
635 spell = g_object_get_data(G_OBJECT(view), SPELLCHK_OBJECT_KEY);
636 if (spell != NULL)
637 return;
638
639 /* attach to the widget */
640 spell = g_new0(spellchk, 1);
641 spell->view = view;
642
643 g_object_set_data_full(G_OBJECT(view), SPELLCHK_OBJECT_KEY, spell,
644 (GDestroyNotify)spellchk_free);
645
646 buffer = gtk_text_view_get_buffer(view);
647
648 /* we create the mark here, but we don't use it until text is
649 * inserted, so we don't really care where iter points. */
650 gtk_text_buffer_get_bounds(buffer, &start, &end);
651 spell->mark_insert_start = gtk_text_buffer_create_mark(buffer,
652 "spellchk-insert-start",
653 &start, TRUE);
654 spell->mark_insert_end = gtk_text_buffer_create_mark(buffer,
655 "spellchk-insert-end",
656 &start, TRUE);
657
658 g_signal_connect_after(G_OBJECT(buffer),
659 "delete-range",
660 G_CALLBACK(delete_range_after), spell);
661 g_signal_connect(G_OBJECT(buffer),
662 "insert-text",
663 G_CALLBACK(insert_text_before), spell);
664 g_signal_connect_after(G_OBJECT(buffer),
665 "insert-text",
666 G_CALLBACK(insert_text_after), spell);
667
668 g_signal_connect(G_OBJECT(gtkconv->entry), "message_send",
669 G_CALLBACK(message_send_cb), spell);
670 return;
671 }
672
673 static int buf_get_line(char *ibuf, char **buf, int *position, int len)
674 {
675 int pos = *position;
676 int spos = pos;
677
678 if (pos == len)
679 return 0;
680
681 while (!(ibuf[pos] == '\n' ||
682 (ibuf[pos] == '\r' && ibuf[pos + 1] != '\n')))
683 {
684 pos++;
685 if (pos == len)
686 return 0;
687 }
688
689 if (pos != 0 && ibuf[pos] == '\n' && ibuf[pos - 1] == '\r')
690 ibuf[pos - 1] = '\0';
691
692 ibuf[pos] = '\0';
693 *buf = &ibuf[spos];
694
695 pos++;
696 *position = pos;
697
698 return 1;
699 }
700
701 static void load_conf()
702 {
703 /* Corrections to change "...", "(c)", "(r)", and "(tm)" to their
704 * Unicode character equivalents were not added here even though
705 * they existed in the source list(s). I think these corrections
706 * would be more trouble than they're worth.
707 */
708 const char * const defaultconf =
709 "BAD abbout\nGOOD about\n"
710 "BAD abotu\nGOOD about\n"
711 "BAD abouta\nGOOD about a\n"
712 "BAD aboutit\nGOOD about it\n"
713 "BAD aboutthe\nGOOD about the\n"
714 "BAD abscence\nGOOD absence\n"
715 "BAD accesories\nGOOD accessories\n"
716 "BAD accidant\nGOOD accident\n"
717 "BAD accomodate\nGOOD accommodate\n"
718 "BAD accordingto\nGOOD according to\n"
719 "BAD accross\nGOOD across\n"
720 "BAD acheive\nGOOD achieve\n"
721 "BAD acheived\nGOOD achieved\n"
722 "BAD acheiving\nGOOD achieving\n"
723 "BAD acn\nGOOD can\n"
724 "BAD acommodate\nGOOD accommodate\n"
725 "BAD acomodate\nGOOD accommodate\n"
726 "BAD actualyl\nGOOD actually\n"
727 "BAD additinal\nGOOD additional\n"
728 "BAD addtional\nGOOD additional\n"
729 "BAD adequit\nGOOD adequate\n"
730 "BAD adequite\nGOOD adequate\n"
731 "BAD adn\nGOOD and\n"
732 "BAD advanage\nGOOD advantage\n"
733 "BAD affraid\nGOOD afraid\n"
734 "BAD afterthe\nGOOD after the\n"
735 "COMPLETE 0\nBAD againstt he \nGOOD against the \n"
736 "BAD aganist\nGOOD against\n"
737 "BAD aggresive\nGOOD aggressive\n"
738 "BAD agian\nGOOD again\n"
739 "BAD agreemeent\nGOOD agreement\n"
740 "BAD agreemeents\nGOOD agreements\n"
741 "BAD agreemnet\nGOOD agreement\n"
742 "BAD agreemnets\nGOOD agreements\n"
743 "BAD agressive\nGOOD aggressive\n"
744 "BAD agressiveness\nGOOD aggressiveness\n"
745 "BAD ahd\nGOOD had\n"
746 "BAD ahold\nGOOD a hold\n"
747 "BAD ahppen\nGOOD happen\n"
748 "BAD ahve\nGOOD have\n"
749 "BAD allready\nGOOD already\n"
750 "BAD allwasy\nGOOD always\n"
751 "BAD allwyas\nGOOD always\n"
752 "BAD almots\nGOOD almost\n"
753 "BAD almsot\nGOOD almost\n"
754 "BAD alomst\nGOOD almost\n"
755 "BAD alot\nGOOD a lot\n"
756 "BAD alraedy\nGOOD already\n"
757 "BAD alreayd\nGOOD already\n"
758 "BAD alreday\nGOOD already\n"
759 "BAD alwasy\nGOOD always\n"
760 "BAD alwats\nGOOD always\n"
761 "BAD alway\nGOOD always\n"
762 "BAD alwyas\nGOOD always\n"
763 "BAD amde\nGOOD made\n"
764 "BAD Ameria\nGOOD America\n"
765 "BAD amke\nGOOD make\n"
766 "BAD amkes\nGOOD makes\n"
767 "BAD anbd\nGOOD and\n"
768 "BAD andone\nGOOD and one\n"
769 "BAD andteh\nGOOD and the\n"
770 "BAD andthe\nGOOD and the\n"
771 "COMPLETE 0\nBAD andt he \nGOOD and the \n"
772 "BAD anothe\nGOOD another\n"
773 "BAD anual\nGOOD annual\n"
774 "BAD any1\nGOOD anyone\n"
775 "BAD apparant\nGOOD apparent\n"
776 "BAD apparrent\nGOOD apparent\n"
777 "BAD appearence\nGOOD appearance\n"
778 "BAD appeares\nGOOD appears\n"
779 "BAD applicaiton\nGOOD application\n"
780 "BAD applicaitons\nGOOD applications\n"
781 "BAD applyed\nGOOD applied\n"
782 "BAD appointiment\nGOOD appointment\n"
783 "BAD approrpiate\nGOOD appropriate\n"
784 "BAD approrpriate\nGOOD appropriate\n"
785 "BAD aquisition\nGOOD acquisition\n"
786 "BAD aquisitions\nGOOD acquisitions\n"
787 "BAD arent\nGOOD aren't\n"
788 "COMPLETE 0\nBAD aren;t \nGOOD aren't \n"
789 "BAD arguement\nGOOD argument\n"
790 "BAD arguements\nGOOD arguments\n"
791 "COMPLETE 0\nBAD arn't \nGOOD aren't \n"
792 "BAD arond\nGOOD around\n"
793 "BAD artical\nGOOD article\n"
794 "BAD articel\nGOOD article\n"
795 "BAD asdvertising\nGOOD advertising\n"
796 "COMPLETE 0\nBAD askt he \nGOOD ask the \n"
797 "BAD assistent\nGOOD assistant\n"
798 "BAD asthe\nGOOD as the\n"
799 "BAD atention\nGOOD attention\n"
800 "BAD atmospher\nGOOD atmosphere\n"
801 "BAD attentioin\nGOOD attention\n"
802 "BAD atthe\nGOOD at the\n"
803 "BAD audeince\nGOOD audience\n"
804 "BAD audiance\nGOOD audience\n"
805 "BAD authentification\nGOOD authentication\n"
806 "BAD availalbe\nGOOD available\n"
807 "BAD awya\nGOOD away\n"
808 "BAD aywa\nGOOD away\n"
809 "BAD b4\nGOOD before\n"
810 "BAD bakc\nGOOD back\n"
811 "BAD balence\nGOOD balance\n"
812 "BAD ballance\nGOOD balance\n"
813 "BAD baout\nGOOD about\n"
814 "BAD bcak\nGOOD back\n"
815 "BAD bcuz\nGOOD because\n"
816 "BAD beacuse\nGOOD because\n"
817 "BAD becasue\nGOOD because\n"
818 "BAD becaus\nGOOD because\n"
819 "BAD becausea\nGOOD because a\n"
820 "BAD becauseof\nGOOD because of\n"
821 "BAD becausethe\nGOOD because the\n"
822 "BAD becauseyou\nGOOD because you\n"
823 "COMPLETE 0\nBAD beckon call\nGOOD beck and call\n"
824 "BAD becomeing\nGOOD becoming\n"
825 "BAD becomming\nGOOD becoming\n"
826 "BAD becuase\nGOOD because\n"
827 "BAD becuse\nGOOD because\n"
828 "BAD befoer\nGOOD before\n"
829 "BAD beggining\nGOOD beginning\n"
830 "BAD begining\nGOOD beginning\n"
831 "BAD beginining\nGOOD beginning\n"
832 "BAD beleiev\nGOOD believe\n"
833 "BAD beleieve\nGOOD believe\n"
834 "BAD beleif\nGOOD belief\n"
835 "BAD beleive\nGOOD believe\n"
836 "BAD beleived\nGOOD believed\n"
837 "BAD beleives\nGOOD believes\n"
838 "BAD belive\nGOOD believe\n"
839 "BAD belived\nGOOD believed\n"
840 "BAD belives\nGOOD believes\n"
841 "BAD benifit\nGOOD benefit\n"
842 "BAD benifits\nGOOD benefits\n"
843 "BAD betwen\nGOOD between\n"
844 "BAD beutiful\nGOOD beautiful\n"
845 "BAD blase\nGOOD blas\303\251\n"
846 "BAD boxs\nGOOD boxes\n"
847 "BAD brodcast\nGOOD broadcast\n"
848 "BAD butthe\nGOOD but the\n"
849 "BAD bve\nGOOD be\n"
850 "COMPLETE 0\nBAD byt he \nGOOD by the \n"
851 "BAD cafe\nGOOD caf\303\251\n"
852 "BAD caharcter\nGOOD character\n"
853 "BAD calcullated\nGOOD calculated\n"
854 "BAD calulated\nGOOD calculated\n"
855 "BAD candidtae\nGOOD candidate\n"
856 "BAD candidtaes\nGOOD candidates\n"
857 "COMPLETE 0\nBAD case and point\nGOOD case in point\n"
858 "BAD cant\nGOOD can't\n"
859 "COMPLETE 0\nBAD can;t \nGOOD can't \n"
860 "COMPLETE 0\nBAD can't of been\nGOOD can't have been\n"
861 "BAD catagory\nGOOD category\n"
862 "BAD categiory\nGOOD category\n"
863 "BAD certian\nGOOD certain\n"
864 "BAD challange\nGOOD challenge\n"
865 "BAD challanges\nGOOD challenges\n"
866 "BAD chaneg\nGOOD change\n"
867 "BAD chanegs\nGOOD changes\n"
868 "BAD changable\nGOOD changeable\n"
869 "BAD changeing\nGOOD changing\n"
870 "BAD changng\nGOOD changing\n"
871 "BAD charachter\nGOOD character\n"
872 "BAD charachters\nGOOD characters\n"
873 "BAD charactor\nGOOD character\n"
874 "BAD charecter\nGOOD character\n"
875 "BAD charector\nGOOD character\n"
876 "BAD cheif\nGOOD chief\n"
877 "BAD chekc\nGOOD check\n"
878 "BAD chnage\nGOOD change\n"
879 "BAD cieling\nGOOD ceiling\n"
880 "BAD circut\nGOOD circuit\n"
881 "BAD claer\nGOOD clear\n"
882 "BAD claered\nGOOD cleared\n"
883 "BAD claerly\nGOOD clearly\n"
884 "BAD cliant\nGOOD client\n"
885 "BAD cliche\nGOOD clich\303\251\n"
886 "BAD cna\nGOOD can\n"
887 "BAD colection\nGOOD collection\n"
888 "BAD comanies\nGOOD companies\n"
889 "BAD comany\nGOOD company\n"
890 "BAD comapnies\nGOOD companies\n"
891 "BAD comapny\nGOOD company\n"
892 "BAD combintation\nGOOD combination\n"
893 "BAD comited\nGOOD committed\n"
894 "BAD comittee\nGOOD committee\n"
895 "BAD commadn\nGOOD command\n"
896 "BAD comming\nGOOD coming\n"
897 "BAD commitee\nGOOD committee\n"
898 "BAD committe\nGOOD committee\n"
899 "BAD committment\nGOOD commitment\n"
900 "BAD committments\nGOOD commitments\n"
901 "BAD committy\nGOOD committee\n"
902 "BAD comntain\nGOOD contain\n"
903 "BAD comntains\nGOOD contains\n"
904 "BAD compair\nGOOD compare\n"
905 "COMPLETE 0\nBAD company;s \nGOOD company's \n"
906 "BAD competetive\nGOOD competitive\n"
907 "BAD compleated\nGOOD completed\n"
908 "BAD compleatly\nGOOD completely\n"
909 "BAD compleatness\nGOOD completeness\n"
910 "BAD completly\nGOOD completely\n"
911 "BAD completness\nGOOD completeness\n"
912 "BAD composate\nGOOD composite\n"
913 "BAD comtain\nGOOD contain\n"
914 "BAD comtains\nGOOD contains\n"
915 "BAD comunicate\nGOOD communicate\n"
916 "BAD comunity\nGOOD community\n"
917 "BAD condolances\nGOOD condolences\n"
918 "BAD conected\nGOOD connected\n"
919 "BAD conferance\nGOOD conference\n"
920 "BAD confirmmation\nGOOD confirmation\n"
921 "BAD congradulations\nGOOD congratulations\n"
922 "BAD considerit\nGOOD considerate\n"
923 "BAD considerite\nGOOD considerate\n"
924 "BAD consonent\nGOOD consonant\n"
925 "BAD conspiricy\nGOOD conspiracy\n"
926 "BAD consultent\nGOOD consultant\n"
927 "BAD convertable\nGOOD convertible\n"
928 "BAD cooparate\nGOOD cooperate\n"
929 "BAD cooporate\nGOOD cooperate\n"
930 "BAD corproation\nGOOD corporation\n"
931 "BAD corproations\nGOOD corporations\n"
932 "BAD corruptable\nGOOD corruptible\n"
933 "BAD cotten\nGOOD cotton\n"
934 "BAD coudl\nGOOD could\n"
935 "COMPLETE 0\nBAD coudln't \nGOOD couldn't \n"
936 "COMPLETE 0\nBAD coudn't \nGOOD couldn't \n"
937 "BAD couldnt\nGOOD couldn't\n"
938 "COMPLETE 0\nBAD couldn;t \nGOOD couldn't \n"
939 "COMPLETE 0\nBAD could of been\nGOOD could have been\n"
940 "COMPLETE 0\nBAD could of had\nGOOD could have had\n"
941 "BAD couldthe\nGOOD could the\n"
942 "BAD couldve\nGOOD could've\n"
943 "BAD cpoy\nGOOD copy\n"
944 "BAD creme\nGOOD cr\303\250me\n"
945 "BAD ctaegory\nGOOD category\n"
946 "BAD cu\nGOOD see you\n"
947 "BAD cusotmer\nGOOD customer\n"
948 "BAD cusotmers\nGOOD customers\n"
949 "BAD cutsomer\nGOOD customer\n"
950 "BAD cutsomers\nGOOD customer\n"
951 "BAD cuz\nGOOD because\n"
952 "BAD cxan\nGOOD can\n"
953 "BAD danceing\nGOOD dancing\n"
954 "BAD dcument\nGOOD document\n"
955 "BAD deatils\nGOOD details\n"
956 "BAD decison\nGOOD decision\n"
957 "BAD decisons\nGOOD decisions\n"
958 "BAD decor\nGOOD d\303\251cor\n"
959 "BAD defendent\nGOOD defendant\n"
960 "BAD definately\nGOOD definitely\n"
961 "COMPLETE 0\nBAD deja vu\nGOOD d\303\251j\303\240 vu\n"
962 "BAD deptartment\nGOOD department\n"
963 "BAD desicion\nGOOD decision\n"
964 "BAD desicions\nGOOD decisions\n"
965 "BAD desision\nGOOD decision\n"
966 "BAD desisions\nGOOD decisions\n"
967 "BAD detente\nGOOD d\303\251tente\n"
968 "BAD develeoprs\nGOOD developers\n"
969 "BAD devellop\nGOOD develop\n"
970 "BAD develloped\nGOOD developed\n"
971 "BAD develloper\nGOOD developer\n"
972 "BAD devellopers\nGOOD developers\n"
973 "BAD develloping\nGOOD developing\n"
974 "BAD devellopment\nGOOD development\n"
975 "BAD devellopments\nGOOD developments\n"
976 "BAD devellops\nGOOD develop\n"
977 "BAD develope\nGOOD develop\n"
978 "BAD developement\nGOOD development\n"
979 "BAD developements\nGOOD developments\n"
980 "BAD developor\nGOOD developer\n"
981 "BAD developors\nGOOD developers\n"
982 "BAD develpment\nGOOD development\n"
983 "BAD diaplay\nGOOD display\n"
984 "BAD didint\nGOOD didn't\n"
985 "BAD didnot\nGOOD did not\n"
986 "BAD didnt\nGOOD didn't\n"
987 "COMPLETE 0\nBAD didn;t \nGOOD didn't \n"
988 "BAD difefrent\nGOOD different\n"
989 "BAD diferences\nGOOD differences\n"
990 "BAD differance\nGOOD difference\n"
991 "BAD differances\nGOOD differences\n"
992 "BAD differant\nGOOD different\n"
993 "BAD differemt\nGOOD different\n"
994 "BAD differnt\nGOOD different\n"
995 "BAD diffrent\nGOOD different\n"
996 "BAD directer\nGOOD director\n"
997 "BAD directers\nGOOD directors\n"
998 "BAD directiosn\nGOOD direction\n"
999 "BAD disatisfied\nGOOD dissatisfied\n"
1000 "BAD discoverd\nGOOD discovered\n"
1001 "BAD disign\nGOOD design\n"
1002 "BAD dispaly\nGOOD display\n"
1003 "BAD dissonent\nGOOD dissonant\n"
1004 "BAD distribusion\nGOOD distribution\n"
1005 "BAD divsion\nGOOD division\n"
1006 "BAD docuement\nGOOD documents\n"
1007 "BAD docuemnt\nGOOD document\n"
1008 "BAD documetn\nGOOD document\n"
1009 "BAD documnet\nGOOD document\n"
1010 "BAD documnets\nGOOD documents\n"
1011 "COMPLETE 0\nBAD doens't \nGOOD doesn't \n"
1012 "BAD doese\nGOOD does\n"
1013 "COMPLETE 0\nBAD doe snot \nGOOD does not \n"
1014 "BAD doesnt\nGOOD doesn't\n"
1015 "COMPLETE 0\nBAD doesn;t \nGOOD doesn't \n"
1016 "BAD doign\nGOOD doing\n"
1017 "BAD doimg\nGOOD doing\n"
1018 "BAD doind\nGOOD doing\n"
1019 "BAD dollers\nGOOD dollars\n"
1020 "BAD donig\nGOOD doing\n"
1021 "BAD donno\nGOOD don't know\n"
1022 "BAD dont\nGOOD don't\n"
1023 "COMPLETE 0\nBAD do'nt \nGOOD don't \n"
1024 "COMPLETE 0\nBAD don;t \nGOOD don't \n"
1025 "COMPLETE 0\nBAD don't no \nGOOD don't know \n"
1026 "COMPLETE 0\nBAD dosn't \nGOOD doesn't \n"
1027 "BAD driveing\nGOOD driving\n"
1028 "BAD drnik\nGOOD drink\n"
1029 "BAD dunno\nGOOD don't know\n"
1030 "BAD eclair\nGOOD \303\251clair\n"
1031 "BAD efel\nGOOD feel\n"
1032 "BAD effecient\nGOOD efficient\n"
1033 "BAD efort\nGOOD effort\n"
1034 "BAD eforts\nGOOD efforts\n"
1035 "BAD ehr\nGOOD her\n"
1036 "BAD eligable\nGOOD eligible\n"
1037 "BAD embarass\nGOOD embarrass\n"
1038 "BAD emigre\nGOOD \303\251migr\303\251\n"
1039 "BAD enought\nGOOD enough\n"
1040 "BAD entree\nGOOD entr\303\251e\n"
1041 "BAD enuf\nGOOD enough\n"
1042 "BAD equippment\nGOOD equipment\n"
1043 "BAD equivalant\nGOOD equivalent\n"
1044 "BAD esle\nGOOD else\n"
1045 "BAD especally\nGOOD especially\n"
1046 "BAD especialyl\nGOOD especially\n"
1047 "BAD espesially\nGOOD especially\n"
1048 "BAD essense\nGOOD essence\n"
1049 "BAD excellance\nGOOD excellence\n"
1050 "BAD excellant\nGOOD excellent\n"
1051 "BAD excercise\nGOOD exercise\n"
1052 "BAD exchagne\nGOOD exchange\n"
1053 "BAD exchagnes\nGOOD exchanges\n"
1054 "BAD excitment\nGOOD excitement\n"
1055 "BAD exhcange\nGOOD exchange\n"
1056 "BAD exhcanges\nGOOD exchanges\n"
1057 "BAD experiance\nGOOD experience\n"
1058 "BAD experienc\nGOOD experience\n"
1059 "BAD exprience\nGOOD experience\n"
1060 "BAD exprienced\nGOOD experienced\n"
1061 "BAD eyt\nGOOD yet\n"
1062 "BAD facade\nGOOD fa\303\247ade\n"
1063 "BAD faeture\nGOOD feature\n"
1064 "BAD faetures\nGOOD feature\n"
1065 "BAD familair\nGOOD familiar\n"
1066 "BAD familar\nGOOD familiar\n"
1067 "BAD familliar\nGOOD familiar\n"
1068 "BAD fammiliar\nGOOD familiar\n"
1069 "BAD feild\nGOOD field\n"
1070 "BAD feilds\nGOOD fields\n"
1071 "BAD fianlly\nGOOD finally\n"
1072 "BAD fidn\nGOOD find\n"
1073 "BAD finalyl\nGOOD finally\n"
1074 "BAD firends\nGOOD friends\n"
1075 "BAD firts\nGOOD first\n"
1076 "BAD follwo\nGOOD follow\n"
1077 "BAD follwoing\nGOOD following\n"
1078 "BAD fora\nGOOD for a\n"
1079 "COMPLETE 0\nBAD for all intensive purposes\nfor all intents and purposes\n"
1080 "BAD foriegn\nGOOD foreign\n"
1081 "BAD forthe\nGOOD for the\n"
1082 "BAD forwrd\nGOOD forward\n"
1083 "BAD forwrds\nGOOD forwards\n"
1084 "BAD foudn\nGOOD found\n"
1085 "BAD foward\nGOOD forward\n"
1086 "BAD fowards\nGOOD forwards\n"
1087 "BAD freind\nGOOD friend\n"
1088 "BAD freindly\nGOOD friendly\n"
1089 "BAD freinds\nGOOD friends\n"
1090 "BAD friday\nGOOD Friday\n"
1091 "BAD frmo\nGOOD from\n"
1092 "BAD fromthe\nGOOD from the\n"
1093 "COMPLETE 0\nBAD fromt he \nGOOD from the \n"
1094 "BAD furneral\nGOOD funeral\n"
1095 "BAD fwe\nGOOD few\n"
1096 "BAD garantee\nGOOD guarantee\n"
1097 "BAD gaurd\nGOOD guard\n"
1098 "BAD gemeral\nGOOD general\n"
1099 "BAD gerat\nGOOD great\n"
1100 "BAD geting\nGOOD getting\n"
1101 "BAD gettin\nGOOD getting\n"
1102 "BAD gievn\nGOOD given\n"
1103 "BAD giveing\nGOOD giving\n"
1104 "BAD gloabl\nGOOD global\n"
1105 "BAD goign\nGOOD going\n"
1106 "BAD gonig\nGOOD going\n"
1107 "BAD govenment\nGOOD government\n"
1108 "BAD goverment\nGOOD government\n"
1109 "BAD gruop\nGOOD group\n"
1110 "BAD gruops\nGOOD groups\n"
1111 "BAD grwo\nGOOD grow\n"
1112 "BAD guidlines\nGOOD guidelines\n"
1113 "BAD hadbeen\nGOOD had been\n"
1114 "BAD hadnt\nGOOD hadn't\n"
1115 "COMPLETE 0\nBAD hadn;t \nGOOD hadn't \n"
1116 "BAD haev\nGOOD have\n"
1117 "BAD hapen\nGOOD happen\n"
1118 "BAD hapened\nGOOD happened\n"
1119 "BAD hapening\nGOOD happening\n"
1120 "BAD hapens\nGOOD happens\n"
1121 "BAD happend\nGOOD happened\n"
1122 "BAD hasbeen\nGOOD has been\n"
1123 "BAD hasnt\nGOOD hasn't\n"
1124 "COMPLETE 0\nBAD hasn;t \nGOOD hasn't \n"
1125 "BAD havebeen\nGOOD have been\n"
1126 "BAD haveing\nGOOD having\n"
1127 "BAD havent\nGOOD haven't\n"
1128 "COMPLETE 0\nBAD haven;t \nGOOD haven't \n"
1129 "BAD hda\nGOOD had\n"
1130 "BAD hearign\nGOOD hearing\n"
1131 "COMPLETE 0\nBAD he;d \nGOOD he'd \n"
1132 "BAD heirarchy\nGOOD hierarchy\n"
1133 "BAD hel\nGOOD he'll\n"
1134 "COMPLETE 0\nBAD he;ll \nGOOD he'll \n"
1135 "BAD helpfull\nGOOD helpful\n"
1136 "BAD herat\nGOOD heart\n"
1137 "BAD heres\nGOOD here's\n"
1138 "COMPLETE 0\nBAD here;s \nGOOD here's \n"
1139 "BAD hes\nGOOD he's\n"
1140 "COMPLETE 0\nBAD he;s \nGOOD he's \n"
1141 "BAD hesaid\nGOOD he said\n"
1142 "BAD hewas\nGOOD he was\n"
1143 "BAD hge\nGOOD he\n"
1144 "BAD hismelf\nGOOD himself\n"
1145 "BAD hlep\nGOOD help\n"
1146 "BAD hott\nGOOD hot\n"
1147 "BAD hows\nGOOD how's\n"
1148 "BAD hsa\nGOOD has\n"
1149 "BAD hse\nGOOD she\n"
1150 "BAD hsi\nGOOD his\n"
1151 "BAD hte\nGOOD the\n"
1152 "BAD htere\nGOOD there\n"
1153 "BAD htese\nGOOD these\n"
1154 "BAD htey\nGOOD they\n"
1155 "BAD hting\nGOOD thing\n"
1156 "BAD htink\nGOOD think\n"
1157 "BAD htis\nGOOD this\n"
1158 "COMPLETE 0\nBAD htp:\nGOOD http:\n"
1159 "COMPLETE 0\nBAD http:\\\\nGOOD http://\n"
1160 "BAD httpL\nGOOD http:\n"
1161 "BAD hvae\nGOOD have\n"
1162 "BAD hvaing\nGOOD having\n"
1163 "BAD hwich\nGOOD which\n"
1164 "BAD i\nGOOD I\n"
1165 "COMPLETE 0\nBAD i c \nGOOD I see \n"
1166 "COMPLETE 0\nBAD i;d \nGOOD I'd \n"
1167 "COMPLETE 0\nBAD i'd \nGOOD I'd \n"
1168 "COMPLETE 0\nBAD I;d \nGOOD I'd \n"
1169 "BAD idae\nGOOD idea\n"
1170 "BAD idaes\nGOOD ideas\n"
1171 "BAD identofy\nGOOD identify\n"
1172 "BAD ihs\nGOOD his\n"
1173 "BAD iits the\nGOOD it's the\n"
1174 "COMPLETE 0\nBAD i'll \nGOOD I'll \n"
1175 "COMPLETE 0\nBAD I;ll \nGOOD I'll \n"
1176 "COMPLETE 0\nBAD i;m \nGOOD I'm \n"
1177 "COMPLETE 0\nBAD i'm \nGOOD I'm \n"
1178 "COMPLETE 0\nBAD I\"m \nGOOD I'm \n"
1179 "BAD imediate\nGOOD immediate\n"
1180 "BAD imediatly\nGOOD immediately\n"
1181 "BAD immediatly\nGOOD immediately\n"
1182 "BAD importent\nGOOD important\n"
1183 "BAD importnat\nGOOD important\n"
1184 "BAD impossable\nGOOD impossible\n"
1185 "BAD improvemnt\nGOOD improvement\n"
1186 "BAD improvment\nGOOD improvement\n"
1187 "BAD includ\nGOOD include\n"
1188 "BAD indecate\nGOOD indicate\n"
1189 "BAD indenpendence\nGOOD independence\n"
1190 "BAD indenpendent\nGOOD independent\n"
1191 "BAD indepedent\nGOOD independent\n"
1192 "BAD independance\nGOOD independence\n"
1193 "BAD independant\nGOOD independent\n"
1194 "BAD influance\nGOOD influence\n"
1195 "BAD infomation\nGOOD information\n"
1196 "BAD informatoin\nGOOD information\n"
1197 "BAD inital\nGOOD initial\n"
1198 "BAD instaleld\nGOOD installed\n"
1199 "BAD insted\nGOOD instead\n"
1200 "BAD insurence\nGOOD insurance\n"
1201 "BAD inteh\nGOOD in the\n"
1202 "BAD interum\nGOOD interim\n"
1203 "BAD inthe\nGOOD in the\n"
1204 "COMPLETE 0\nBAD int he \nGOOD in the \n"
1205 "BAD inturn\nGOOD intern\n"
1206 "BAD inwhich\nGOOD in which\n"
1207 "COMPLETE 0\nBAD i snot \nGOOD is not \n"
1208 "BAD isnt\nGOOD isn't\n"
1209 "COMPLETE 0\nBAD isn;t \nGOOD isn't \n"
1210 "BAD isthe\nGOOD is the\n"
1211 "BAD itd\nGOOD it'd\n"
1212 "COMPLETE 0\nBAD it;d \nGOOD it'd \n"
1213 "BAD itis\nGOOD it is\n"
1214 "BAD ititial\nGOOD initial\n"
1215 "BAD itll\nGOOD it'll\n"
1216 "COMPLETE 0\nBAD it;ll \nGOOD it'll \n"
1217 "BAD itnerest\nGOOD interest\n"
1218 "BAD itnerested\nGOOD interested\n"
1219 "BAD itneresting\nGOOD interesting\n"
1220 "BAD itnerests\nGOOD interests\n"
1221 "COMPLETE 0\nBAD it;s \nGOOD it's \n"
1222 "BAD itsa\nGOOD it's a\n"
1223 "COMPLETE 0\nBAD its a \nGOOD it's a \n"
1224 "COMPLETE 0\nBAD it snot \nGOOD it's not \n"
1225 "COMPLETE 0\nBAD it' snot \nGOOD it's not \n"
1226 "COMPLETE 0\nBAD its the \nGOOD it's the \n"
1227 "BAD itwas\nGOOD it was\n"
1228 "BAD ive\nGOOD I've\n"
1229 "COMPLETE 0\nBAD i;ve \nGOOD I've \n"
1230 "COMPLETE 0\nBAD i've \nGOOD I've \n"
1231 "BAD iwll\nGOOD will\n"
1232 "BAD iwth\nGOOD with\n"
1233 "BAD jsut\nGOOD just\n"
1234 "BAD jugment\nGOOD judgment\n"
1235 "BAD kno\nGOOD know\n"
1236 "BAD knowldge\nGOOD knowledge\n"
1237 "BAD knowlege\nGOOD knowledge\n"
1238 "BAD knwo\nGOOD know\n"
1239 "BAD knwon\nGOOD known\n"
1240 "BAD knwos\nGOOD knows\n"
1241 "BAD konw\nGOOD know\n"
1242 "BAD konwn\nGOOD known\n"
1243 "BAD konws\nGOOD knows\n"
1244 "BAD labratory\nGOOD laboratory\n"
1245 "BAD labtop\nGOOD laptop\n"
1246 "BAD lastyear\nGOOD last year\n"
1247 "BAD laterz\nGOOD later\n"
1248 "BAD learnign\nGOOD learning\n"
1249 "BAD lenght\nGOOD length\n"
1250 "COMPLETE 0\nBAD let;s \nGOOD let's \n"
1251 "COMPLETE 0\nBAD let's him \nGOOD lets him \n"
1252 "COMPLETE 0\nBAD let's it \nGOOD lets it \n"
1253 "BAD levle\nGOOD level\n"
1254 "BAD libary\nGOOD library\n"
1255 "BAD librarry\nGOOD library\n"
1256 "BAD librery\nGOOD library\n"
1257 "BAD liek\nGOOD like\n"
1258 "BAD liekd\nGOOD liked\n"
1259 "BAD lieutenent\nGOOD lieutenant\n"
1260 "BAD liev\nGOOD live\n"
1261 "BAD likly\nGOOD likely\n"
1262 "BAD lisense\nGOOD license\n"
1263 "BAD littel\nGOOD little\n"
1264 "BAD litttle\nGOOD little\n"
1265 "BAD liuke\nGOOD like\n"
1266 "BAD liveing\nGOOD living\n"
1267 "BAD loev\nGOOD love\n"
1268 "BAD lonly\nGOOD lonely\n"
1269 "BAD lookign\nGOOD looking\n"
1270 "BAD m\nGOOD am\n"
1271 "BAD maintainence\nGOOD maintenance\n"
1272 "BAD maintenence\nGOOD maintenance\n"
1273 "BAD makeing\nGOOD making\n"
1274 "BAD managment\nGOOD management\n"
1275 "BAD mantain\nGOOD maintain\n"
1276 "BAD marraige\nGOOD marriage\n"
1277 "COMPLETE 0\nBAD may of been\nGOOD may have been\n"
1278 "COMPLETE 0\nBAD may of had\nGOOD may have had\n"
1279 "BAD memeber\nGOOD member\n"
1280 "BAD merchent\nGOOD merchant\n"
1281 "BAD mesage\nGOOD message\n"
1282 "BAD mesages\nGOOD messages\n"
1283 "COMPLETE 0\nBAD might of been\nGOOD might have been\n"
1284 "COMPLETE 0\nBAD might of had\nGOOD might have had\n"
1285 "BAD mispell\nGOOD misspell\n"
1286 "BAD mispelling\nGOOD misspelling\n"
1287 "BAD mispellings\nGOOD misspellings\n"
1288 "BAD mkae\nGOOD make\n"
1289 "BAD mkaes\nGOOD makes\n"
1290 "BAD mkaing\nGOOD making\n"
1291 "BAD moeny\nGOOD money\n"
1292 "BAD monday\nGOOD Monday\n"
1293 "BAD morgage\nGOOD mortgage\n"
1294 "BAD mroe\nGOOD more\n"
1295 "COMPLETE 0\nBAD must of been\nGOOD must have been\n"
1296 "COMPLETE 0\nBAD must of had\nGOOD must have had\n"
1297 "COMPLETE 0\nBAD mute point\nGOOD moot point\n"
1298 "BAD mysefl\nGOOD myself\n"
1299 "BAD myu\nGOOD my\n"
1300 "BAD naive\nGOOD naïve\n"
1301 "BAD ne1\nGOOD anyone\n"
1302 "BAD neway\nGOOD anyway\n"
1303 "BAD neways\nGOOD anyways\n"
1304 "BAD necassarily\nGOOD necessarily\n"
1305 "BAD necassary\nGOOD necessary\n"
1306 "BAD neccessarily\nGOOD necessarily\n"
1307 "BAD neccessary\nGOOD necessary\n"
1308 "BAD necesarily\nGOOD necessarily\n"
1309 "BAD necesary\nGOOD necessary\n"
1310 "BAD negotiaing\nGOOD negotiating\n"
1311 "BAD nkow\nGOOD know\n"
1312 "BAD nothign\nGOOD nothing\n"
1313 "BAD nto\nGOOD not\n"
1314 "BAD nver\nGOOD never\n"
1315 "BAD nwe\nGOOD new\n"
1316 "BAD nwo\nGOOD now\n"
1317 "BAD obediant\nGOOD obedient\n"
1318 "BAD ocasion\nGOOD occasion\n"
1319 "BAD occassion\nGOOD occasion\n"
1320 "BAD occurance\nGOOD occurrence\n"
1321 "BAD occured\nGOOD occurred\n"
1322 "BAD occurence\nGOOD occurrence\n"
1323 "BAD occurrance\nGOOD occurrence\n"
1324 "BAD oclock\nGOOD o'clock\n"
1325 "BAD oculd\nGOOD could\n"
1326 "BAD ocur\nGOOD occur\n"
1327 "BAD oeprator\nGOOD operator\n"
1328 "BAD ofits\nGOOD of its\n"
1329 "BAD ofthe\nGOOD of the\n"
1330 "BAD oft he\nGOOD of the\n"
1331 "BAD oging\nGOOD going\n"
1332 "BAD ohter\nGOOD other\n"
1333 "BAD omre\nGOOD more\n"
1334 "BAD oneof\nGOOD one of\n"
1335 "BAD onepoint\nGOOD one point\n"
1336 "BAD onthe\nGOOD on the\n"
1337 "COMPLETE 0\nBAD ont he \nGOOD on the \n"
1338 "BAD onyl\nGOOD only\n"
1339 "BAD oppasite\nGOOD opposite\n"
1340 "BAD opperation\nGOOD operation\n"
1341 "BAD oppertunity\nGOOD opportunity\n"
1342 "BAD opposate\nGOOD opposite\n"
1343 "BAD opposible\nGOOD opposable\n"
1344 "BAD opposit\nGOOD opposite\n"
1345 "BAD oppotunities\nGOOD opportunities\n"
1346 "BAD oppotunity\nGOOD opportunity\n"
1347 "BAD orginization\nGOOD organization\n"
1348 "BAD orginized\nGOOD organized\n"
1349 "BAD otehr\nGOOD other\n"
1350 "BAD otu\nGOOD out\n"
1351 "BAD outof\nGOOD out of\n"
1352 "BAD overthe\nGOOD over the\n"
1353 "BAD owrk\nGOOD work\n"
1354 "BAD owuld\nGOOD would\n"
1355 "BAD oxident\nGOOD oxidant\n"
1356 "BAD papaer\nGOOD paper\n"
1357 "BAD passe\nGOOD pass\303\251\n"
1358 "BAD parliment\nGOOD parliament\n"
1359 "BAD partof\nGOOD part of\n"
1360 "BAD paymetn\nGOOD payment\n"
1361 "BAD paymetns\nGOOD payments\n"
1362 "BAD pciture\nGOOD picture\n"
1363 "BAD peice\nGOOD piece\n"
1364 "BAD peices\nGOOD pieces\n"
1365 "BAD peolpe\nGOOD people\n"
1366 "BAD peopel\nGOOD people\n"
1367 "BAD percentof\nGOOD percent of\n"
1368 "BAD percentto\nGOOD percent to\n"
1369 "BAD performence\nGOOD performance\n"
1370 "BAD perhasp\nGOOD perhaps\n"
1371 "BAD perhpas\nGOOD perhaps\n"
1372 "BAD permanant\nGOOD permanent\n"
1373 "BAD perminent\nGOOD permanent\n"
1374 "BAD personalyl\nGOOD personally\n"
1375 "BAD pleasent\nGOOD pleasant\n"
1376 "BAD pls\nGOOD please\n"
1377 "BAD plz\nGOOD please\n"
1378 "BAD poeple\nGOOD people\n"
1379 "BAD porblem\nGOOD problem\n"
1380 "BAD porblems\nGOOD problems\n"
1381 "BAD porvide\nGOOD provide\n"
1382 "BAD possable\nGOOD possible\n"
1383 "BAD postition\nGOOD position\n"
1384 "BAD potatoe\nGOOD potato\n"
1385 "BAD potatos\nGOOD potatoes\n"
1386 "BAD potentialy\nGOOD potentially\n"
1387 "BAD ppl\nGOOD people\n"
1388 "BAD pregnent\nGOOD pregnant\n"
1389 "BAD presance\nGOOD presence\n"
1390 "BAD primative\nGOOD primitive\n"
1391 "BAD probally\nGOOD probably\n"
1392 "BAD probelm\nGOOD problem\n"
1393 "BAD probelms\nGOOD problems\n"
1394 "BAD probly\nGOOD probably\n"
1395 "BAD prolly\nGOOD probably\n"
1396 "BAD proly\nGOOD probably\n"
1397 "BAD prominant\nGOOD prominent\n"
1398 "BAD proposterous\nGOOD preposterous\n"
1399 "BAD protege\nGOOD prot\303\251g\303\251\n"
1400 "BAD protoge\nGOOD prot\303\251g\303\251\n"
1401 "BAD psoition\nGOOD position\n"
1402 "BAD ptogress\nGOOD progress\n"
1403 "BAD pursuade\nGOOD persuade\n"
1404 "BAD puting\nGOOD putting\n"
1405 "BAD pwoer\nGOOD power\n"
1406 "BAD quater\nGOOD quarter\n"
1407 "BAD quaters\nGOOD quarters\n"
1408 "BAD quesion\nGOOD question\n"
1409 "BAD quesions\nGOOD questions\n"
1410 "BAD questioms\nGOOD questions\n"
1411 "BAD questiosn\nGOOD questions\n"
1412 "BAD questoin\nGOOD question\n"
1413 "BAD quetion\nGOOD question\n"
1414 "BAD quetions\nGOOD questions\n"
1415 "BAD r\nGOOD are\n"
1416 "BAD raeson\nGOOD reason\n"
1417 "BAD realyl\nGOOD really\n"
1418 "BAD reccomend\nGOOD recommend\n"
1419 "BAD reccommend\nGOOD recommend\n"
1420 "BAD receieve\nGOOD receive\n"
1421 "BAD recieve\nGOOD receive\n"
1422 "BAD recieved\nGOOD received\n"
1423 "BAD recieving\nGOOD receiving\n"
1424 "BAD recomend\nGOOD recommend\n"
1425 "BAD recomendation\nGOOD recommendation\n"
1426 "BAD recomendations\nGOOD recommendations\n"
1427 "BAD recomended\nGOOD recommended\n"
1428 "BAD reconize\nGOOD recognize\n"
1429 "BAD recrod\nGOOD record\n"
1430 "BAD rediculous\nGOOD ridiculous\n"
1431 "BAD rediculus\nGOOD ridiculous\n"
1432 "BAD reguard\nGOOD regard\n"
1433 "BAD religous\nGOOD religious\n"
1434 "BAD reluctent\nGOOD reluctant\n"
1435 "BAD remeber\nGOOD remember\n"
1436 "BAD reommend\nGOOD recommend\n"
1437 "BAD representativs\nGOOD representatives\n"
1438 "BAD representives\nGOOD representatives\n"
1439 "BAD represetned\nGOOD represented\n"
1440 "BAD represnt\nGOOD represent\n"
1441 "BAD reserach\nGOOD research\n"
1442 "BAD resollution\nGOOD resolution\n"
1443 "BAD resorces\nGOOD resources\n"
1444 "BAD respomd\nGOOD respond\n"
1445 "BAD respomse\nGOOD response\n"
1446 "BAD responce\nGOOD response\n"
1447 "BAD responsability\nGOOD responsibility\n"
1448 "BAD responsable\nGOOD responsible\n"
1449 "BAD responsibile\nGOOD responsible\n"
1450 "BAD responsiblity\nGOOD responsibility\n"
1451 "BAD restaraunt\nGOOD restaurant\n"
1452 "BAD restuarant\nGOOD restaurant\n"
1453 "BAD reult\nGOOD result\n"
1454 "BAD reveiw\nGOOD review\n"
1455 "BAD reveiwing\nGOOD reviewing\n"
1456 "BAD rumers\nGOOD rumors\n"
1457 "BAD rwite\nGOOD write\n"
1458 "BAD rythm\nGOOD rhythm\n"
1459 "BAD saidhe\nGOOD said he\n"
1460 "BAD saidit\nGOOD said it\n"
1461 "BAD saidthat\nGOOD said that\n"
1462 "BAD saidthe\nGOOD said the\n"
1463 "COMPLETE 0\nBAD saidt he \nGOOD said the \n"
1464 "BAD sandwhich\nGOOD sandwich\n"
1465 "BAD sandwitch\nGOOD sandwich\n"
1466 "BAD saturday\nGOOD Saturday\n"
1467 "BAD scedule\nGOOD schedule\n"
1468 "BAD sceduled\nGOOD scheduled\n"
1469 "BAD seance\nGOOD s\303\251ance\n"
1470 "BAD secratary\nGOOD secretary\n"
1471 "BAD sectino\nGOOD section\n"
1472 "BAD seh\nGOOD she\n"
1473 "BAD selectoin\nGOOD selection\n"
1474 "BAD sence\nGOOD sense\n"
1475 "BAD sentance\nGOOD sentence\n"
1476 "BAD separeate\nGOOD separate\n"
1477 "BAD seperate\nGOOD separate\n"
1478 "BAD sercumstances\nGOOD circumstances\n"
1479 "BAD shcool\nGOOD school\n"
1480 "COMPLETE 0\nBAD she;d \nGOOD she'd \n"
1481 "COMPLETE 0\nBAD she;ll \nGOOD she'll \n"
1482 "BAD shes\nGOOD she's\n"
1483 "COMPLETE 0\nBAD she;s \nGOOD she's \n"
1484 "BAD shesaid\nGOOD she said\n"
1485 "BAD shineing\nGOOD shining\n"
1486 "BAD shiped\nGOOD shipped\n"
1487 "BAD shoudl\nGOOD should\n"
1488 "COMPLETE 0\nBAD shoudln't \nGOOD shouldn't \n"
1489 "BAD shouldent\nGOOD shouldn't\n"
1490 "BAD shouldnt\nGOOD shouldn't\n"
1491 "COMPLETE 0\nBAD shouldn;t \nGOOD shouldn't \n"
1492 "COMPLETE 0\nBAD should of been\nGOOD should have been\n"
1493 "COMPLETE 0\nBAD should of had\nGOOD should have had\n"
1494 "BAD shouldve\nGOOD should've\n"
1495 "BAD showinf\nGOOD showing\n"
1496 "BAD signifacnt\nGOOD significant\n"
1497 "BAD simalar\nGOOD similar\n"
1498 "BAD similiar\nGOOD similar\n"
1499 "BAD simpyl\nGOOD simply\n"
1500 "BAD sincerly\nGOOD sincerely\n"
1501 "BAD sitll\nGOOD still\n"
1502 "BAD smae\nGOOD same\n"
1503 "BAD smoe\nGOOD some\n"
1504 "BAD soem\nGOOD some\n"
1505 "BAD sohw\nGOOD show\n"
1506 "BAD soical\nGOOD social\n"
1507 "BAD some1\nGOOD someone\n"
1508 "BAD somethign\nGOOD something\n"
1509 "BAD someting\nGOOD something\n"
1510 "BAD somewaht\nGOOD somewhat\n"
1511 "BAD somthing\nGOOD something\n"
1512 "BAD somtimes\nGOOD sometimes\n"
1513 "COMPLETE 0\nBAD sot hat \nGOOD so that \n"
1514 "BAD soudn\nGOOD sound\n"
1515 "BAD soudns\nGOOD sounds\n"
1516 "BAD speach\nGOOD speech\n"
1517 "BAD specificaly\nGOOD specifically\n"
1518 "BAD specificalyl\nGOOD specifically\n"
1519 "BAD spelt\nGOOD spelled\n"
1520 "BAD sry\nGOOD sorry\n"
1521 "COMPLETE 0\nBAD state of the ark\nGOOD state of the art\n"
1522 "BAD statment\nGOOD statement\n"
1523 "BAD statments\nGOOD statements\n"
1524 "BAD stnad\nGOOD stand\n"
1525 "BAD stopry\nGOOD story\n"
1526 "BAD stoyr\nGOOD story\n"
1527 "BAD stpo\nGOOD stop\n"
1528 "BAD strentgh\nGOOD strength\n"
1529 "BAD stroy\nGOOD story\n"
1530 "BAD struggel\nGOOD struggle\n"
1531 "BAD strugle\nGOOD struggle\n"
1532 "BAD studnet\nGOOD student\n"
1533 "BAD successfull\nGOOD successful\n"
1534 "BAD successfuly\nGOOD successfully\n"
1535 "BAD successfulyl\nGOOD successfully\n"
1536 "BAD sucess\nGOOD success\n"
1537 "BAD sucessfull\nGOOD successful\n"
1538 "BAD sufficiant\nGOOD sufficient\n"
1539 "BAD sum1\nGOOD someone\n"
1540 "BAD sunday\nGOOD Sunday\n"
1541 "BAD suposed\nGOOD supposed\n"
1542 "BAD supposably\nGOOD supposedly\n"
1543 "BAD suppossed\nGOOD supposed\n"
1544 "BAD suprise\nGOOD surprise\n"
1545 "BAD suprised\nGOOD surprised\n"
1546 "BAD sux\nGOOD sucks\n"
1547 "BAD swiming\nGOOD swimming\n"
1548 "BAD tahn\nGOOD than\n"
1549 "BAD taht\nGOOD that\n"
1550 "COMPLETE 0\nBAD take it for granite\nGOOD take it for granted\n"
1551 "COMPLETE 0\nBAD taken for granite\nGOOD taken for granted\n"
1552 "BAD talekd\nGOOD talked\n"
1553 "BAD talkign\nGOOD talking\n"
1554 "BAD tath\nGOOD that\n"
1555 "BAD tecnical\nGOOD technical\n"
1556 "BAD teh\nGOOD the\n"
1557 "BAD tehy\nGOOD they\n"
1558 "COMPLETE 0\nBAD tellt he \nGOOD tell the \n"
1559 "BAD termoil\nGOOD turmoil\n"
1560 "BAD tets\nGOOD test\n"
1561 "BAD tghe\nGOOD the\n"
1562 "BAD tghis\nGOOD this\n"
1563 "BAD thansk\nGOOD thanks\n"
1564 "BAD thanx\nGOOD thanks\n"
1565 "BAD thats\nGOOD that's\n"
1566 "BAD thatthe\nGOOD that the\n"
1567 "COMPLETE 0\nBAD thatt he \nGOOD that the \n"
1568 "BAD thecompany\nGOOD the company\n"
1569 "BAD thefirst\nGOOD the first\n"
1570 "BAD thegovernment\nGOOD the government\n"
1571 "COMPLETE 0\nBAD their are \nGOOD there are \n"
1572 "COMPLETE 0\nBAD their aren't \nGOOD there aren't \n"
1573 "COMPLETE 0\nBAD their is \nGOOD there is \n"
1574 "BAD themself\nGOOD themselves\n"
1575 "BAD themselfs\nGOOD themselves\n"
1576 "BAD thenew\nGOOD the new\n"
1577 "BAD theres\nGOOD there's\n"
1578 "COMPLETE 0\nBAD there's is \nGOOD theirs is \n"
1579 "COMPLETE 0\nBAD there's isn't \nGOOD theirs isn't \n"
1580 "BAD theri\nGOOD their\n"
1581 "BAD thesame\nGOOD the same\n"
1582 "BAD thetwo\nGOOD the two\n"
1583 "BAD theyd\nGOOD they'd\n"
1584 "COMPLETE 0\nBAD they;d \nGOOD they'd \n"
1585 "COMPLETE 0\nBAD they;l \nGOOD they'll \n"
1586 "BAD theyll\nGOOD they'll\n"
1587 "COMPLETE 0\nBAD they;ll \nGOOD they'll \n"
1588 "COMPLETE 0\nBAD they;r \nGOOD they're \n"
1589 "COMPLETE 0\nBAD theyre \nGOOD they're \n"
1590 "COMPLETE 0\nBAD they;re \nGOOD they're \n"
1591 "COMPLETE 0\nBAD they're are \nGOOD there are \n"
1592 "COMPLETE 0\nBAD they're is \nGOOD there is \n"
1593 "COMPLETE 0\nBAD they;v \nGOOD they've \n"
1594 "BAD theyve\nGOOD they've\n"
1595 "COMPLETE 0\nBAD they;ve \nGOOD they've \n"
1596 "BAD thgat\nGOOD that\n"
1597 "BAD thge\nGOOD the\n"
1598 "BAD thier\nGOOD their \n"
1599 "BAD thigsn\nGOOD things\n"
1600 "BAD thisyear\nGOOD this year\n"
1601 "BAD thme\nGOOD them\n"
1602 "BAD thna\nGOOD than\n"
1603 "BAD thne\nGOOD then\n"
1604 "BAD thnig\nGOOD thing\n"
1605 "BAD thnigs\nGOOD things\n"
1606 "BAD tho\nGOOD though\n"
1607 "BAD threatend\nGOOD threatened\n"
1608 "BAD thsi\nGOOD this\n"
1609 "BAD thsoe\nGOOD those\n"
1610 "BAD thta\nGOOD that\n"
1611 "BAD thursday\nGOOD Thursday\n"
1612 "BAD thx\nGOOD thanks\n"
1613 "BAD tihs\nGOOD this\n"
1614 "BAD timne\nGOOD time\n"
1615 "BAD tiogether\nGOOD together\n"
1616 "BAD tje\nGOOD the\n"
1617 "BAD tjhe\nGOOD the\n"
1618 "BAD tkae\nGOOD take\n"
1619 "BAD tkaes\nGOOD takes\n"
1620 "BAD tkaing\nGOOD taking\n"
1621 "BAD tlaking\nGOOD talking\n"
1622 "BAD tnx\nGOOD thanks\n"
1623 "BAD todya\nGOOD today\n"
1624 "BAD togehter\nGOOD together\n"
1625 "COMPLETE 0\nBAD toldt he \nGOOD told the \n"
1626 "BAD tomorow\nGOOD tomorrow\n"
1627 "BAD tongiht\nGOOD tonight\n"
1628 "BAD tonihgt\nGOOD tonight\n"
1629 "BAD tonite\nGOOD tonight\n"
1630 "BAD totaly\nGOOD totally\n"
1631 "BAD totalyl\nGOOD totally\n"
1632 "BAD tothe\nGOOD to the\n"
1633 "COMPLETE 0\nBAD tot he \nGOOD to the \n"
1634 "BAD touche\nGOOD touch\303\251\n"
1635 "BAD towrad\nGOOD toward\n"
1636 "BAD traditionalyl\nGOOD traditionally\n"
1637 "BAD transfered\nGOOD transferred\n"
1638 "BAD truely\nGOOD truly\n"
1639 "BAD truley\nGOOD truly\n"
1640 "BAD tryed\nGOOD tried\n"
1641 "BAD tthe\nGOOD the\n"
1642 "BAD tuesday\nGOOD Tuesday\n"
1643 "BAD tyhat\nGOOD that\n"
1644 "BAD tyhe\nGOOD the\n"
1645 "BAD u\nGOOD you\n"
1646 "BAD udnerstand\nGOOD understand\n"
1647 "BAD understnad\nGOOD understand\n"
1648 "COMPLETE 0\nBAD undert he \nGOOD under the \n"
1649 "BAD unforseen\nGOOD unforeseen\n"
1650 "BAD UnitedStates\nGOOD United States\n"
1651 "BAD unliek\nGOOD unlike\n"
1652 "BAD unpleasently\nGOOD unpleasantly\n"
1653 "BAD untill\nGOOD until\n"
1654 "BAD untilll\nGOOD until\n"
1655 "BAD ur\nGOOD you are\n"
1656 "BAD useing\nGOOD using\n"
1657 "BAD usualyl\nGOOD usually\n"
1658 "BAD veyr\nGOOD very\n"
1659 "BAD virtualyl\nGOOD virtually\n"
1660 "BAD visavis\nGOOD vis-a-vis\n"
1661 "COMPLETE 0\nBAD vis-a-vis\nGOOD vis-\303\240-vis\n"
1662 "BAD vrey\nGOOD very\n"
1663 "BAD vulnerible\nGOOD vulnerable\n"
1664 "BAD waht\nGOOD what\n"
1665 "BAD warrent\nGOOD warrant\n"
1666 "COMPLETE 0\nBAD wa snot \nGOOD was not \n"
1667 "COMPLETE 0\nBAD wasnt \nGOOD wasn't \n"
1668 "COMPLETE 0\nBAD wasn;t \nGOOD wasn't \n"
1669 "BAD wat\nGOOD what\n"
1670 "BAD watn\nGOOD want\n"
1671 "COMPLETE 0\nBAD we;d \nGOOD we'd \n"
1672 "BAD wednesday\nGOOD Wednesday\n"
1673 "BAD wehn\nGOOD when\n"
1674 "COMPLETE 0\nBAD we'l \nGOOD we'll \n"
1675 "COMPLETE 0\nBAD we;ll \nGOOD we'll \n"
1676 "COMPLETE 0\nBAD we;re \nGOOD we're \n"
1677 "BAD werent\nGOOD weren't\n"
1678 "COMPLETE 0\nBAD weren;t \nGOOD weren't \n"
1679 "COMPLETE 0\nBAD wern't \nGOOD weren't \n"
1680 "BAD werre\nGOOD were\n"
1681 "BAD weve\nGOOD we've\n"
1682 "COMPLETE 0\nBAD we;ve \nGOOD we've \n"
1683 "BAD whats\nGOOD what's\n"
1684 "COMPLETE 0\nBAD what;s \nGOOD what's \n"
1685 "BAD whcih\nGOOD which\n"
1686 "COMPLETE 0\nBAD whent he \nGOOD when the \n"
1687 "BAD wheres\nGOOD where's\n"
1688 "COMPLETE 0\nBAD where;s \nGOOD where's \n"
1689 "BAD wherre\nGOOD where\n"
1690 "BAD whic\nGOOD which\n"
1691 "COMPLETE 0\nBAD whicht he \nGOOD which the \n"
1692 "BAD whihc\nGOOD which\n"
1693 "BAD wholl\nGOOD who'll\n"
1694 "BAD whos\nGOOD who's\n"
1695 "COMPLETE 0\nBAD who;s \nGOOD who's \n"
1696 "BAD whove\nGOOD who've\n"
1697 "COMPLETE 0\nBAD who;ve \nGOOD who've \n"
1698 "BAD whta\nGOOD what\n"
1699 "BAD whys\nGOOD why's\n"
1700 "BAD wief\nGOOD wife\n"
1701 "BAD wierd\nGOOD weird\n"
1702 "BAD wihch\nGOOD which\n"
1703 "BAD wiht\nGOOD with\n"
1704 "BAD willbe\nGOOD will be\n"
1705 "COMPLETE 0\nBAD will of been\nGOOD will have been\n"
1706 "COMPLETE 0\nBAD will of had\nGOOD will have had\n"
1707 "BAD windoes\nGOOD windows\n"
1708 "BAD witha\nGOOD with a\n"
1709 "BAD withdrawl\nGOOD withdrawal\n"
1710 "BAD withe\nGOOD with\n"
1711 "COMPLETE 0\nBAD withthe \nGOOD with the \n"
1712 "BAD witht he\nGOOD with the\n"
1713 "BAD wiull\nGOOD will\n"
1714 "BAD wnat\nGOOD want\n"
1715 "BAD wnated\nGOOD wanted\n"
1716 "BAD wnats\nGOOD wants\n"
1717 "BAD woh\nGOOD who\n"
1718 "BAD wohle\nGOOD whole\n"
1719 "BAD wokr\nGOOD work\n"
1720 "BAD wont\nGOOD won't\n"
1721 "COMPLETE 0\nBAD wo'nt \nGOOD won't \n"
1722 "COMPLETE 0\nBAD won;t \nGOOD won't \n"
1723 "BAD woudl\nGOOD would\n"
1724 "COMPLETE 0\nBAD woudln't \nGOOD wouldn't \n"
1725 "BAD wouldbe\nGOOD would be\n"
1726 "BAD wouldnt\nGOOD wouldn't\n"
1727 "COMPLETE 0\nBAD wouldn;t \nGOOD wouldn't \n"
1728 "COMPLETE 0\nBAD would of been\nGOOD would have been\n"
1729 "COMPLETE 0\nBAD would of had\nGOOD would have had\n"
1730 "BAD wouldve\nGOOD would've\n"
1731 "BAD wriet\nGOOD write\n"
1732 "BAD writting\nGOOD writing\n"
1733 "BAD wrod\nGOOD word\n"
1734 "BAD wroet\nGOOD wrote\n"
1735 "BAD wroking\nGOOD working\n"
1736 "BAD wtih\nGOOD with\n"
1737 "BAD wuould\nGOOD would\n"
1738 "BAD wut\nGOOD what\n"
1739 "BAD wya\nGOOD way\n"
1740 "BAD y\nGOOD why\n"
1741 "BAD yeh\nGOOD yeah\n"
1742 "BAD yera\nGOOD year\n"
1743 "BAD yeras\nGOOD years\n"
1744 "BAD yersa\nGOOD years\n"
1745 "BAD yoiu\nGOOD you\n"
1746 "BAD youare\nGOOD you are\n"
1747 "BAD youd\nGOOD you'd\n"
1748 "COMPLETE 0\nBAD you;d \nGOOD you'd \n"
1749 "BAD youll\nGOOD you'll\n"
1750 "COMPLETE 0\nBAD your a \nGOOD you're a \n"
1751 "COMPLETE 0\nBAD your an \nGOOD you're an \n"
1752 "BAD youre\nGOOD you're\n"
1753 "COMPLETE 0\nBAD you;re \nGOOD you're \n"
1754 "COMPLETE 0\nBAD you're own \nGOOD your own \n"
1755 "COMPLETE 0\nBAD your her \nGOOD you're her \n"
1756 "COMPLETE 0\nBAD your here \nGOOD you're here \n"
1757 "COMPLETE 0\nBAD your his \nGOOD you're his \n"
1758 "COMPLETE 0\nBAD your my \nGOOD you're my \n"
1759 "COMPLETE 0\nBAD your the \nGOOD you're the \n"
1760 "COMPLETE 0\nBAD your their \nGOOD you're their \n"
1761 "COMPLETE 0\nBAD your your \nGOOD you're your \n"
1762 "BAD youve\nGOOD you've\n"
1763 "COMPLETE 0\nBAD you;ve \nGOOD you've \n"
1764 "BAD ytou\nGOOD you\n"
1765 "BAD yuo\nGOOD you\n"
1766 "BAD yuor\nGOOD your\n";
1767 gchar *buf;
1768 gchar *ibuf;
1769 GHashTable *hashes;
1770 char bad[82] = "";
1771 char good[256] = "";
1772 int pnt = 0;
1773 gsize size;
1774 gboolean complete = TRUE;
1775 gboolean case_sensitive = FALSE;
1776
1777 buf = g_build_filename(gaim_user_dir(), "dict", NULL);
1778 g_file_get_contents(buf, &ibuf, &size, NULL);
1779 g_free(buf);
1780 if (!ibuf) {
1781 ibuf = g_strdup(defaultconf);
1782 size = strlen(defaultconf);
1783 }
1784
1785 model = gtk_list_store_new((gint)N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
1786 hashes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1787
1788 while (buf_get_line(ibuf, &buf, &pnt, size)) {
1789 if (*buf != '#') {
1790 if (!strncasecmp(buf, "BAD ", 4))
1791 {
1792 strncpy(bad, buf + 4, 81);
1793 }
1794 else if(!strncasecmp(buf, "CASE ", 5))
1795 {
1796 case_sensitive = *(buf+5) == '0' ? FALSE : TRUE;
1797 }
1798 else if(!strncasecmp(buf, "COMPLETE ", 9))
1799 {
1800 complete = *(buf+9) == '0' ? FALSE : TRUE;
1801 }
1802 else if (!strncasecmp(buf, "GOOD ", 5))
1803 {
1804 strncpy(good, buf + 5, 255);
1805
1806 if (*bad && *good && g_hash_table_lookup(hashes, bad) == NULL) {
1807 GtkTreeIter iter;
1808
1809 /* We don't actually need to store the good string, since this
1810 * hash is just being used to eliminate duplicate bad strings.
1811 * The value has to be non-NULL so the lookup above will work.
1812 */
1813 g_hash_table_insert(hashes, g_strdup(bad), GINT_TO_POINTER(1));
1814
1815 if (!complete)
1816 case_sensitive = TRUE;
1817
1818 gtk_list_store_append(model, &iter);
1819 gtk_list_store_set(model, &iter,
1820 BAD_COLUMN, bad,
1821 GOOD_COLUMN, good,
1822 WORD_ONLY_COLUMN, complete,
1823 CASE_SENSITIVE_COLUMN, case_sensitive,
1824 -1);
1825 }
1826 bad[0] = '\0';
1827 complete = TRUE;
1828 case_sensitive = FALSE;
1829 }
1830 }
1831 }
1832 g_free(ibuf);
1833 g_hash_table_destroy(hashes);
1834
1835 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
1836 0, GTK_SORT_ASCENDING);
1837 }
1838
1839 static GtkWidget *tree;
1840 static GtkWidget *bad_entry;
1841 static GtkWidget *good_entry;
1842 static GtkWidget *complete_toggle;
1843 static GtkWidget *case_toggle;
1844
1845 static void save_list(void);
1846
1847 static void on_edited(GtkCellRendererText *cellrenderertext,
1848 gchar *path, gchar *arg2, gpointer data)
1849 {
1850 GtkTreeIter iter;
1851 GValue val;
1852
1853 if (arg2[0] == '\0') {
1854 gdk_beep();
1855 return;
1856 }
1857
1858 g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path));
1859 val.g_type = 0;
1860 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GPOINTER_TO_INT(data), &val);
1861
1862 if (strcmp(arg2, g_value_get_string(&val))) {
1863 gtk_list_store_set(model, &iter, GPOINTER_TO_INT(data), arg2, -1);
1864 save_list();
1865 }
1866 g_value_unset(&val);
1867 }
1868
1869
1870 static void word_only_toggled(GtkCellRendererToggle *cellrenderertoggle,
1871 gchar *path, gpointer data){
1872 GtkTreeIter iter;
1873 gboolean enabled;
1874
1875 g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path));
1876 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1877 WORD_ONLY_COLUMN, &enabled,
1878 -1);
1879
1880 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1881 WORD_ONLY_COLUMN, !enabled,
1882 -1);
1883
1884 /* I want to be sure that the above change has happened to the GtkTreeView first. */
1885 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1886 CASE_SENSITIVE_COLUMN, enabled,
1887 -1);
1888
1889 save_list();
1890 }
1891
1892 static void case_sensitive_toggled(GtkCellRendererToggle *cellrenderertoggle,
1893 gchar *path, gpointer data){
1894 GtkTreeIter iter;
1895 gboolean enabled;
1896
1897 g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path));
1898
1899 /* Prevent the case sensitive column from changing on non-whole word replacements.
1900 * Ideally, the column would be set insensitive in the word_only_toggled callback. */
1901 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1902 WORD_ONLY_COLUMN, &enabled,
1903 -1);
1904 if (!enabled)
1905 return;
1906
1907 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1908 CASE_SENSITIVE_COLUMN, &enabled,
1909 -1);
1910
1911 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1912 CASE_SENSITIVE_COLUMN, !enabled,
1913 -1);
1914
1915 save_list();
1916 }
1917
1918 static void list_add_new()
1919 {
1920 GtkTreeIter iter;
1921 const char *word = gtk_entry_get_text(GTK_ENTRY(bad_entry));
1922 gboolean case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(case_toggle));
1923
1924 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) {
1925 char *tmpword = g_utf8_casefold(word, -1);
1926
1927 do {
1928 GValue bad_val;
1929 gboolean match;
1930
1931 bad_val.g_type = 0;
1932 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &bad_val);
1933
1934 if (case_sensitive)
1935 {
1936 GValue case_sensitive_val;
1937 case_sensitive_val.g_type = 0;
1938 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &case_sensitive_val);
1939
1940 /* If they're both case-sensitive, then compare directly.
1941 * Otherwise, they overlap. */
1942 if (g_value_get_boolean(&case_sensitive_val))
1943 {
1944 match = !strcmp(g_value_get_string(&bad_val), word);
1945 }
1946 else
1947 {
1948 char *bad = g_utf8_casefold(g_value_get_string(&bad_val), -1);
1949 match = !strcmp(bad, tmpword);
1950 g_free(bad);
1951 }
1952 g_value_unset(&case_sensitive_val);
1953 }
1954 else
1955 {
1956 char *bad = g_utf8_casefold(g_value_get_string(&bad_val), -1);
1957 match = !strcmp(bad, tmpword);
1958 g_free(bad);
1959 }
1960
1961 if (match) {
1962 g_value_unset(&bad_val);
1963 g_free(tmpword);
1964
1965 gaim_notify_error(NULL, _("Duplicate Correction"),
1966 _("The specified word already exists in the correction list."),
1967 gtk_entry_get_text(GTK_ENTRY(bad_entry)));
1968 return;
1969 }
1970
1971 g_value_unset(&bad_val);
1972
1973 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
1974
1975 g_free(tmpword);
1976 }
1977
1978
1979 gtk_list_store_append(model, &iter);
1980 gtk_list_store_set(model, &iter,
1981 BAD_COLUMN, word,
1982 GOOD_COLUMN, gtk_entry_get_text(GTK_ENTRY(good_entry)),
1983 WORD_ONLY_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(complete_toggle)),
1984 CASE_SENSITIVE_COLUMN, case_sensitive,
1985 -1);
1986
1987 gtk_editable_delete_text(GTK_EDITABLE(bad_entry), 0, -1);
1988 gtk_editable_delete_text(GTK_EDITABLE(good_entry), 0, -1);
1989 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(complete_toggle), TRUE);
1990 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_toggle), FALSE);
1991 gtk_widget_grab_focus(bad_entry);
1992
1993 save_list();
1994 }
1995
1996 static void add_selected_row_to_list(GtkTreeModel *model, GtkTreePath *path,
1997 GtkTreeIter *iter, gpointer data)
1998 {
1999 GtkTreeRowReference *row_reference;
2000 GSList **list = (GSList **)data;
2001 row_reference = gtk_tree_row_reference_new(model, path);
2002 *list = g_slist_prepend(*list, row_reference);
2003 }
2004
2005 static void remove_row(void *data1, gpointer data2)
2006 {
2007 GtkTreeRowReference *row_reference;
2008 GtkTreePath *path;
2009 GtkTreeIter iter;
2010
2011 row_reference = (GtkTreeRowReference *)data1;
2012 path = gtk_tree_row_reference_get_path(row_reference);
2013
2014 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
2015 gtk_list_store_remove(model, &iter);
2016
2017 gtk_tree_path_free(path);
2018 gtk_tree_row_reference_free(row_reference);
2019 }
2020
2021 static void list_delete()
2022 {
2023 GtkTreeSelection *sel;
2024 GSList *list = NULL;
2025
2026 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
2027 gtk_tree_selection_selected_foreach(sel, add_selected_row_to_list, &list);
2028
2029 g_slist_foreach(list, remove_row, NULL);
2030 g_slist_free(list);
2031
2032 save_list();
2033 }
2034
2035 static void save_list()
2036 {
2037 GString *data;
2038 GtkTreeIter iter;
2039
2040 data = g_string_new("");
2041
2042 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) {
2043 do {
2044 GValue val0;
2045 GValue val1;
2046 GValue val2;
2047 GValue val3;
2048
2049 val0.g_type = 0;
2050 val1.g_type = 0;
2051 val2.g_type = 0;
2052 val3.g_type = 0;
2053
2054 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &val0);
2055 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GOOD_COLUMN, &val1);
2056 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &val2);
2057 gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &val3);
2058
2059 g_string_append_printf(data, "COMPLETE %d\nCASE %d\nBAD %s\nGOOD %s\n\n",
2060 g_value_get_boolean(&val2),
2061 g_value_get_boolean(&val3),
2062 g_value_get_string(&val0),
2063 g_value_get_string(&val1));
2064
2065 g_value_unset(&val0);
2066 g_value_unset(&val1);
2067 g_value_unset(&val2);
2068 g_value_unset(&val3);
2069
2070 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
2071 }
2072
2073 gaim_util_write_data_to_file("dict", data->str, -1);
2074
2075 g_string_free(data, TRUE);
2076 }
2077
2078 #if !GTK_CHECK_VERSION(2,2,0)
2079 static void
2080 count_selected_helper(GtkTreeModel *model, GtkTreePath *path,
2081 GtkTreeIter *iter, gpointer user_data)
2082 {
2083 (*(gint *)user_data)++;
2084 }
2085 #endif
2086
2087 static void on_selection_changed(GtkTreeSelection *sel,
2088 gpointer data)
2089 {
2090 gint num_selected;
2091 #if GTK_CHECK_VERSION(2,2,0)
2092 num_selected = gtk_tree_selection_count_selected_rows(sel);
2093 #else
2094 gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected);
2095 #endif
2096 gtk_widget_set_sensitive((GtkWidget*)data, (num_selected > 0));
2097 }
2098
2099 static gboolean non_empty(const char *s)
2100 {
2101 while (*s && g_ascii_isspace(*s))
2102 s++;
2103 return *s;
2104 }
2105
2106 static void on_entry_changed(GtkEditable *editable, gpointer data)
2107 {
2108 gtk_widget_set_sensitive((GtkWidget*)data,
2109 non_empty(gtk_entry_get_text(GTK_ENTRY(bad_entry))) &&
2110 non_empty(gtk_entry_get_text(GTK_ENTRY(good_entry))));
2111 }
2112
2113 /*
2114 * EXPORTED FUNCTIONS
2115 */
2116
2117 static gboolean
2118 plugin_load(GaimPlugin *plugin)
2119 {
2120 void *conv_handle = gaim_conversations_get_handle();
2121 GList *convs;
2122
2123 load_conf();
2124
2125 /* Attach to existing conversations */
2126 for (convs = gaim_get_conversations(); convs != NULL; convs = convs->next)
2127 {
2128 spellchk_new_attach((GaimConversation *)convs->data);
2129 }
2130
2131 gaim_signal_connect(conv_handle, "conversation-created",
2132 plugin, GAIM_CALLBACK(spellchk_new_attach), NULL);
2133
2134 return TRUE;
2135 }
2136
2137 static gboolean
2138 plugin_unload(GaimPlugin *plugin)
2139 {
2140 GList *convs;
2141
2142 /* Detach from existing conversations */
2143 for (convs = gaim_get_conversations(); convs != NULL; convs = convs->next)
2144 {
2145 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION((GaimConversation *)convs->data);
2146 spellchk *spell = g_object_get_data(G_OBJECT(gtkconv->entry), SPELLCHK_OBJECT_KEY);
2147
2148 g_signal_handlers_disconnect_by_func(gtkconv->entry, message_send_cb, spell);
2149 g_object_set_data(G_OBJECT(gtkconv->entry), SPELLCHK_OBJECT_KEY, NULL);
2150 }
2151
2152 return TRUE;
2153 }
2154
2155 static void whole_words_button_toggled(GtkToggleButton *complete_toggle, GtkToggleButton *case_toggle)
2156 {
2157 gboolean enabled = gtk_toggle_button_get_active(complete_toggle);
2158
2159 gtk_toggle_button_set_active(case_toggle, !enabled);
2160 gtk_widget_set_sensitive(GTK_WIDGET(case_toggle), enabled);
2161 }
2162
2163 static GtkWidget *
2164 get_config_frame(GaimPlugin *plugin)
2165 {
2166 GtkWidget *ret, *vbox, *win;
2167 GtkWidget *hbox, *label;
2168 GtkWidget *button;
2169 GtkSizeGroup *sg;
2170 GtkSizeGroup *sg2;
2171 GtkCellRenderer *renderer;
2172 GtkTreeViewColumn *column;
2173 GtkWidget *vbox2;
2174 GtkWidget *hbox2;
2175 GtkWidget *vbox3;
2176
2177 ret = gtk_vbox_new(FALSE, GAIM_HIG_CAT_SPACE);
2178 gtk_container_set_border_width (GTK_CONTAINER(ret), GAIM_HIG_BORDER);
2179
2180 vbox = gaim_gtk_make_frame(ret, _("Text Replacements"));
2181 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2182 gtk_widget_show(vbox);
2183
2184 win = gtk_scrolled_window_new(0, 0);
2185 gtk_box_pack_start(GTK_BOX(vbox), win, TRUE, TRUE, 0);
2186 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win),
2187 GTK_SHADOW_IN);
2188 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win),
2189 GTK_POLICY_NEVER,
2190 GTK_POLICY_ALWAYS);
2191 gtk_widget_show(win);
2192
2193 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
2194 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
2195 gtk_widget_set_size_request(tree, -1, 200);
2196
2197 renderer = gtk_cell_renderer_text_new();
2198 g_object_set(G_OBJECT(renderer),
2199 "editable", TRUE,
2200 NULL);
2201 g_signal_connect(G_OBJECT(renderer), "edited",
2202 G_CALLBACK(on_edited), GINT_TO_POINTER(0));
2203 column = gtk_tree_view_column_new_with_attributes(_("You type"), renderer,
2204 "text", BAD_COLUMN,
2205 NULL);
2206 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2207 gtk_tree_view_column_set_fixed_width(column, 150);
2208 gtk_tree_view_column_set_resizable(column, TRUE);
2209 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
2210
2211 renderer = gtk_cell_renderer_text_new();
2212 g_object_set(G_OBJECT(renderer),
2213 "editable", TRUE,
2214 NULL);
2215 g_signal_connect(G_OBJECT(renderer), "edited",
2216 G_CALLBACK(on_edited), GINT_TO_POINTER(1));
2217 column = gtk_tree_view_column_new_with_attributes(_("You send"), renderer,
2218 "text", GOOD_COLUMN,
2219 NULL);
2220 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2221 gtk_tree_view_column_set_fixed_width(column, 150);
2222 gtk_tree_view_column_set_resizable(column, TRUE);
2223 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
2224
2225 renderer = gtk_cell_renderer_toggle_new();
2226 g_object_set(G_OBJECT(renderer),
2227 "activatable", TRUE,
2228 NULL);
2229 g_signal_connect(G_OBJECT(renderer), "toggled",
2230 G_CALLBACK(word_only_toggled), NULL);
2231 column = gtk_tree_view_column_new_with_attributes(_("Whole words only"), renderer,
2232 "active", WORD_ONLY_COLUMN,
2233 NULL);
2234 gtk_tree_view_column_set_resizable(column, TRUE);
2235 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
2236
2237 renderer = gtk_cell_renderer_toggle_new();
2238 g_object_set(G_OBJECT(renderer),
2239 "activatable", TRUE,
2240 NULL);
2241 g_signal_connect(G_OBJECT(renderer), "toggled",
2242 G_CALLBACK(case_sensitive_toggled), NULL);
2243 column = gtk_tree_view_column_new_with_attributes(_("Case sensitive"), renderer,
2244 "active", CASE_SENSITIVE_COLUMN,
2245 NULL);
2246 gtk_tree_view_column_set_resizable(column, TRUE);
2247 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
2248
2249 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
2250 GTK_SELECTION_MULTIPLE);
2251 gtk_container_add(GTK_CONTAINER(win), tree);
2252 gtk_widget_show(tree);
2253
2254 hbox = gtk_hbutton_box_new();
2255 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2256 gtk_widget_show(hbox);
2257
2258 button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
2259 g_signal_connect(G_OBJECT(button), "clicked",
2260 G_CALLBACK(list_delete), NULL);
2261 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2262 gtk_widget_set_sensitive(button, FALSE);
2263
2264 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))),
2265 "changed", G_CALLBACK(on_selection_changed), button);
2266
2267 gtk_widget_show(button);
2268
2269 vbox = gaim_gtk_make_frame(ret, _("Add a new text replacement"));
2270
2271 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
2272 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
2273 gtk_widget_show(hbox);
2274 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
2275 gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
2276 gtk_widget_show(vbox2);
2277
2278 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2279 sg2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2280
2281 hbox2 = gtk_hbox_new(FALSE, 2);
2282 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
2283 gtk_widget_show(hbox2);
2284
2285 label = gtk_label_new_with_mnemonic(_("You _type:"));
2286 gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
2287 gtk_size_group_add_widget(sg, label);
2288 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
2289
2290 bad_entry = gtk_entry_new();
2291 /* Set a minimum size. Since they're in a size group, the other entry will match up. */
2292 gtk_widget_set_size_request(bad_entry, 350, -1);
2293 gtk_box_pack_start(GTK_BOX(hbox2), bad_entry, TRUE, TRUE, 0);
2294 gtk_size_group_add_widget(sg2, bad_entry);
2295 gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry);
2296 gtk_widget_show(bad_entry);
2297
2298 hbox2 = gtk_hbox_new(FALSE, 2);
2299 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
2300 gtk_widget_show(hbox2);
2301
2302 label = gtk_label_new_with_mnemonic(_("You _send:"));
2303 gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
2304 gtk_size_group_add_widget(sg, label);
2305 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
2306
2307 good_entry = gtk_entry_new();
2308 gtk_box_pack_start(GTK_BOX(hbox2), good_entry, TRUE, TRUE, 0);
2309 gtk_size_group_add_widget(sg2, good_entry);
2310 gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry);
2311 gtk_widget_show(good_entry);
2312
2313 /* Created here so it can be passed to whole_words_button_toggled. */
2314 case_toggle = gtk_check_button_new_with_mnemonic(_("_Exact case match (uncheck for automatic case handling)"));
2315
2316 complete_toggle = gtk_check_button_new_with_mnemonic(_("Only replace _whole words"));
2317 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(complete_toggle), TRUE);
2318 g_signal_connect(G_OBJECT(complete_toggle), "clicked",
2319 G_CALLBACK(whole_words_button_toggled), case_toggle);
2320 gtk_widget_show(complete_toggle);
2321 gtk_box_pack_start(GTK_BOX(vbox2), complete_toggle, FALSE, FALSE, 0);
2322
2323 /* The button is created above so it can be passed to whole_words_button_toggled. */
2324 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_toggle), FALSE);
2325 gtk_widget_show(case_toggle);
2326 gtk_box_pack_start(GTK_BOX(vbox2), case_toggle, FALSE, FALSE, 0);
2327
2328 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
2329 g_signal_connect(G_OBJECT(button), "clicked",
2330 G_CALLBACK(list_add_new), NULL);
2331 vbox3 = gtk_vbox_new(FALSE, 0);
2332 gtk_box_pack_start(GTK_BOX(hbox), vbox3, TRUE, FALSE, 0);
2333 gtk_widget_show(vbox3);
2334 gtk_box_pack_end(GTK_BOX(vbox3), button, FALSE, FALSE, 0);
2335 g_signal_connect(G_OBJECT(bad_entry), "changed", G_CALLBACK(on_entry_changed), button);
2336 g_signal_connect(G_OBJECT(good_entry), "changed", G_CALLBACK(on_entry_changed), button);
2337 gtk_widget_set_sensitive(button, FALSE);
2338 gtk_widget_show(button);
2339
2340 #if 0
2341 vbox = gaim_gtk_make_frame(ret, _("General Text Replacement Options"));
2342 gaim_gtk_prefs_checkbox(_("Enable replacement of last word on send"),
2343 "/plugins/gtk/spellchk/last_word_replace", vbox);
2344 #endif
2345
2346 gtk_widget_show_all(ret);
2347 return ret;
2348 }
2349
2350 static GaimGtkPluginUiInfo ui_info =
2351 {
2352 get_config_frame,
2353 0 /* page_num (Reserved) */
2354 };
2355
2356 static GaimPluginInfo info =
2357 {
2358 GAIM_PLUGIN_MAGIC,
2359 GAIM_MAJOR_VERSION,
2360 GAIM_MINOR_VERSION,
2361 GAIM_PLUGIN_STANDARD,
2362 GAIM_GTK_PLUGIN_TYPE,
2363 0,
2364 NULL,
2365 GAIM_PRIORITY_DEFAULT,
2366 SPELLCHECK_PLUGIN_ID,
2367 N_("Text replacement"),
2368 VERSION,
2369 N_("Replaces text in outgoing messages according to user-defined rules."),
2370 N_("Replaces text in outgoing messages according to user-defined rules."),
2371 "Eric Warmenhoven <eric@warmenhoven.org>",
2372 GAIM_WEBSITE,
2373 plugin_load,
2374 plugin_unload,
2375 NULL,
2376 &ui_info,
2377 NULL,
2378 NULL,
2379 NULL
2380 };
2381
2382 static void
2383 init_plugin(GaimPlugin *plugin)
2384 {
2385 #if 0
2386 gaim_prefs_add_none("/plugins");
2387 gaim_prefs_add_none("/plugins/gtk");
2388 gaim_prefs_add_none("/plugins/gtk/spellchk");
2389 gaim_prefs_add_bool("/plugins/gtk/spellchk/last_word_replace", TRUE);
2390 #endif
2391 }
2392
2393 GAIM_INIT_PLUGIN(spellcheck, init_plugin, info)