pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Fix some GError leaks.
2020-11-20, Elliott Sales de Andrade
4726bf0ff977
Fix some GError leaks.
Testing Done:
Compile only
Reviewed at https://reviews.imfreedom.org/r/244/
/*
* Purple - Replace certain misspelled words with their correct form.
*
* Signification changes were made by Benjamin Kahn ("xkahn") and
* Richard Laager ("rlaager") in April 2005--you may want to contact
* them if you have questions.
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
*/
/*
* A lot of this code (especially the config code) was taken directly
* or nearly directly from xchat, version 1.4.2 by Peter Zelezny and others.
*/
#include
<stdio.h>
#include
<string.h>
#include
<sys/types.h>
#include
<glib/gi18n-lib.h>
#include
<purple.h>
#include
<pidgin.h>
#define SPELLCHECK_PLUGIN_ID "gtk-spellcheck"
#define SPELLCHK_OBJECT_KEY "spellchk"
enum
{
BAD_COLUMN
,
GOOD_COLUMN
,
WORD_ONLY_COLUMN
,
CASE_SENSITIVE_COLUMN
,
N_COLUMNS
};
struct
_spellchk
{
GtkTextView
*
view
;
GtkTextMark
*
mark_insert_start
;
GtkTextMark
*
mark_insert_end
;
gchar
*
word
;
gboolean
inserting
;
gboolean
ignore_correction
;
gboolean
ignore_correction_on_send
;
gint
pos
;
};
typedef
struct
_spellchk
spellchk
;
static
GtkListStore
*
model
;
static
gboolean
is_word_uppercase
(
const
gchar
*
word
)
{
for
(;
word
[
0
]
!=
'\0'
;
word
=
g_utf8_find_next_char
(
word
,
NULL
))
{
gunichar
c
=
g_utf8_get_char
(
word
);
if
(
!
(
g_unichar_isupper
(
c
)
||
g_unichar_ispunct
(
c
)
||
g_unichar_isspace
(
c
)))
return
FALSE
;
}
return
TRUE
;
}
static
gboolean
is_word_lowercase
(
const
gchar
*
word
)
{
for
(;
word
[
0
]
!=
'\0'
;
word
=
g_utf8_find_next_char
(
word
,
NULL
))
{
gunichar
c
=
g_utf8_get_char
(
word
);
if
(
!
(
g_unichar_islower
(
c
)
||
g_unichar_ispunct
(
c
)
||
g_unichar_isspace
(
c
)))
return
FALSE
;
}
return
TRUE
;
}
static
gboolean
is_word_proper
(
const
gchar
*
word
)
{
if
(
word
[
0
]
==
'\0'
)
return
FALSE
;
if
(
!
g_unichar_isupper
(
g_utf8_get_char_validated
(
word
,
-1
)))
return
FALSE
;
return
is_word_lowercase
(
g_utf8_offset_to_pointer
(
word
,
1
));
}
static
gchar
*
make_word_proper
(
const
gchar
*
word
)
{
char
buf
[
7
];
gchar
*
lower
=
g_utf8_strdown
(
word
,
-1
);
gint
bytes
;
gchar
*
ret
;
bytes
=
g_unichar_to_utf8
(
g_unichar_toupper
(
g_utf8_get_char
(
word
)),
buf
);
g_assert
(
bytes
>=
0
);
buf
[
MIN
((
gsize
)
bytes
,
sizeof
(
buf
)
-
1
)]
=
'\0'
;
ret
=
g_strconcat
(
buf
,
g_utf8_offset_to_pointer
(
lower
,
1
),
NULL
);
g_free
(
lower
);
return
ret
;
}
static
gboolean
substitute_simple_buffer
(
GtkTextBuffer
*
buffer
)
{
GtkTextIter
start
;
GtkTextIter
end
;
GtkTreeIter
treeiter
;
gchar
*
text
=
NULL
;
gtk_text_buffer_get_iter_at_offset
(
buffer
,
&
start
,
0
);
gtk_text_buffer_get_iter_at_offset
(
buffer
,
&
end
,
0
);
gtk_text_iter_forward_to_end
(
&
end
);
text
=
gtk_text_buffer_get_text
(
buffer
,
&
start
,
&
end
,
FALSE
);
if
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
model
),
&
treeiter
)
&&
text
)
{
do
{
GValue
val1
;
const
gchar
*
bad
;
gchar
*
cursor
;
glong
char_pos
;
val1
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
treeiter
,
WORD_ONLY_COLUMN
,
&
val1
);
if
(
g_value_get_boolean
(
&
val1
))
{
g_value_unset
(
&
val1
);
continue
;
}
g_value_unset
(
&
val1
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
treeiter
,
BAD_COLUMN
,
&
val1
);
bad
=
g_value_get_string
(
&
val1
);
/* using g_utf8_* to get /character/ offsets instead of byte offsets for buffer */
if
((
cursor
=
g_strrstr
(
text
,
bad
)))
{
GValue
val2
;
const
gchar
*
good
;
val2
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
treeiter
,
GOOD_COLUMN
,
&
val2
);
good
=
g_value_get_string
(
&
val2
);
char_pos
=
g_utf8_pointer_to_offset
(
text
,
cursor
);
gtk_text_buffer_get_iter_at_offset
(
buffer
,
&
start
,
char_pos
);
gtk_text_buffer_get_iter_at_offset
(
buffer
,
&
end
,
char_pos
+
g_utf8_strlen
(
bad
,
-1
));
gtk_text_buffer_delete
(
buffer
,
&
start
,
&
end
);
gtk_text_buffer_get_iter_at_offset
(
buffer
,
&
start
,
char_pos
);
gtk_text_buffer_insert
(
buffer
,
&
start
,
good
,
-1
);
g_value_unset
(
&
val2
);
g_free
(
text
);
g_value_unset
(
&
val1
);
return
TRUE
;
}
g_value_unset
(
&
val1
);
}
while
(
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
model
),
&
treeiter
));
}
g_free
(
text
);
return
FALSE
;
}
static
gchar
*
substitute_word
(
gchar
*
word
)
{
GtkTreeIter
iter
;
gchar
*
outword
;
gchar
*
lowerword
;
gchar
*
foldedword
;
if
(
word
==
NULL
)
return
NULL
;
lowerword
=
g_utf8_strdown
(
word
,
-1
);
foldedword
=
g_utf8_casefold
(
word
,
-1
);
if
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
model
),
&
iter
))
{
do
{
GValue
val1
;
gboolean
case_sensitive
;
const
char
*
bad
;
gchar
*
tmpbad
=
NULL
;
val1
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
WORD_ONLY_COLUMN
,
&
val1
);
if
(
!
g_value_get_boolean
(
&
val1
))
{
g_value_unset
(
&
val1
);
continue
;
}
g_value_unset
(
&
val1
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
&
val1
);
case_sensitive
=
g_value_get_boolean
(
&
val1
);
g_value_unset
(
&
val1
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
BAD_COLUMN
,
&
val1
);
bad
=
g_value_get_string
(
&
val1
);
if
((
case_sensitive
&&
purple_strequal
(
bad
,
word
))
||
(
!
case_sensitive
&&
(
purple_strequal
(
bad
,
lowerword
)
||
(
!
is_word_lowercase
(
bad
)
&&
purple_strequal
((
tmpbad
=
g_utf8_casefold
(
bad
,
-1
)),
foldedword
)))))
{
GValue
val2
;
const
char
*
good
;
g_free
(
tmpbad
);
val2
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
GOOD_COLUMN
,
&
val2
);
good
=
g_value_get_string
(
&
val2
);
if
(
!
case_sensitive
&&
is_word_lowercase
(
bad
)
&&
is_word_lowercase
(
good
))
{
if
(
is_word_uppercase
(
word
))
outword
=
g_utf8_strup
(
good
,
-1
);
else
if
(
is_word_proper
(
word
))
outword
=
make_word_proper
(
good
);
else
outword
=
g_strdup
(
good
);
}
else
outword
=
g_strdup
(
good
);
g_value_unset
(
&
val1
);
g_value_unset
(
&
val2
);
g_free
(
lowerword
);
g_free
(
foldedword
);
return
outword
;
}
g_value_unset
(
&
val1
);
g_free
(
tmpbad
);
}
while
(
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
model
),
&
iter
));
}
g_free
(
lowerword
);
g_free
(
foldedword
);
return
NULL
;
}
static
void
spellchk_free
(
spellchk
*
spell
)
{
GtkTextBuffer
*
buffer
;
g_return_if_fail
(
spell
!=
NULL
);
buffer
=
gtk_text_view_get_buffer
(
spell
->
view
);
g_signal_handlers_disconnect_matched
(
buffer
,
G_SIGNAL_MATCH_DATA
,
0
,
0
,
NULL
,
NULL
,
spell
);
g_free
(
spell
->
word
);
g_free
(
spell
);
}
/* Pango doesn't know about the "'" character. Let's fix that. */
static
gboolean
spellchk_inside_word
(
GtkTextIter
*
iter
)
{
gunichar
ucs4_char
=
gtk_text_iter_get_char
(
iter
);
gchar
*
utf8_str
;
gchar
c
=
0
;
utf8_str
=
g_ucs4_to_utf8
(
&
ucs4_char
,
1
,
NULL
,
NULL
,
NULL
);
if
(
utf8_str
!=
NULL
)
{
c
=
utf8_str
[
0
];
g_free
(
utf8_str
);
}
/* Hack because otherwise typing things like U.S. gets difficult
* if you have 'u' -> 'you' set as a correction...
*
* Part 1 of 2: This marks . as being an inside-word character. */
if
(
c
==
'.'
)
return
TRUE
;
if
(
c
==
'+'
)
return
TRUE
;
if
(
c
==
'-'
)
return
TRUE
;
/* Avoid problems with \r, for example (SF #1289031). */
if
(
c
==
'\\'
)
return
TRUE
;
if
(
gtk_text_iter_inside_word
(
iter
)
==
TRUE
)
return
TRUE
;
if
(
c
==
'\''
)
{
gboolean
result
=
gtk_text_iter_backward_char
(
iter
);
gboolean
output
=
gtk_text_iter_inside_word
(
iter
);
if
(
result
)
{
/*
* Hack so that "u'll" will correct correctly.
*/
ucs4_char
=
gtk_text_iter_get_char
(
iter
);
utf8_str
=
g_ucs4_to_utf8
(
&
ucs4_char
,
1
,
NULL
,
NULL
,
NULL
);
if
(
utf8_str
!=
NULL
)
{
c
=
utf8_str
[
0
];
g_free
(
utf8_str
);
if
(
c
==
'u'
||
c
==
'U'
)
{
gtk_text_iter_forward_char
(
iter
);
return
FALSE
;
}
}
gtk_text_iter_forward_char
(
iter
);
}
return
output
;
}
else
if
(
c
==
'&'
)
return
TRUE
;
return
FALSE
;
}
static
gboolean
spellchk_backward_word_start
(
GtkTextIter
*
iter
)
{
int
output
;
int
result
;
output
=
gtk_text_iter_backward_word_start
(
iter
);
/* It didn't work... */
if
(
!
output
)
return
FALSE
;
while
(
spellchk_inside_word
(
iter
))
{
result
=
gtk_text_iter_backward_char
(
iter
);
/* We can't go backwards anymore? We're at the beginning of the word. */
if
(
!
result
)
return
TRUE
;
if
(
!
spellchk_inside_word
(
iter
))
{
gtk_text_iter_forward_char
(
iter
);
return
TRUE
;
}
output
=
gtk_text_iter_backward_word_start
(
iter
);
if
(
!
output
)
return
FALSE
;
}
return
TRUE
;
}
static
gboolean
check_range
(
spellchk
*
spell
,
GtkTextBuffer
*
buffer
,
GtkTextIter
start
,
GtkTextIter
end
,
gboolean
sending
)
{
gboolean
replaced
;
gboolean
result
;
gchar
*
tmp
;
int
period_count
=
0
;
gchar
*
word
;
GtkTextMark
*
mark
;
GtkTextIter
pos
;
if
((
replaced
=
substitute_simple_buffer
(
buffer
)))
{
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
pos
,
mark
);
spell
->
pos
=
gtk_text_iter_get_offset
(
&
pos
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
start
,
mark
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
end
,
mark
);
}
if
(
!
sending
)
{
/* We need to go backwords to find out if we are inside a word or not. */
gtk_text_iter_backward_char
(
&
end
);
if
(
spellchk_inside_word
(
&
end
))
{
gtk_text_iter_forward_char
(
&
end
);
return
replaced
;
/* We only pay attention to whole words. */
}
}
/* We could be in the middle of a whitespace block. Check for that. */
result
=
gtk_text_iter_backward_char
(
&
end
);
if
(
!
spellchk_inside_word
(
&
end
))
{
if
(
result
)
gtk_text_iter_forward_char
(
&
end
);
return
replaced
;
}
if
(
result
)
gtk_text_iter_forward_char
(
&
end
);
/* Move backwards to the beginning of the word. */
spellchk_backward_word_start
(
&
start
);
g_free
(
spell
->
word
);
spell
->
word
=
gtk_text_iter_get_text
(
&
start
,
&
end
);
/* Hack because otherwise typing things like U.S. gets difficult
* if you have 'u' -> 'you' set as a correction...
*
* Part 2 of 2: This chops periods off the end of the word so
* the right substitution entry is found. */
tmp
=
g_strdup
(
spell
->
word
);
if
(
tmp
!=
NULL
&&
*
tmp
!=
'\0'
)
{
gchar
*
c
;
for
(
c
=
tmp
+
strlen
(
tmp
)
-
1
;
c
!=
tmp
;
c
--
)
{
if
(
*
c
==
'.'
)
{
*
c
=
'\0'
;
period_count
++
;
}
else
break
;
}
}
if
((
word
=
substitute_word
(
tmp
)))
{
GtkTextMark
*
mark
;
GtkTextIter
pos
;
gchar
*
tmp2
;
int
i
;
for
(
i
=
1
;
i
<=
period_count
;
i
++
)
{
tmp2
=
g_strconcat
(
word
,
"."
,
NULL
);
g_free
(
word
);
word
=
tmp2
;
}
gtk_text_buffer_delete
(
buffer
,
&
start
,
&
end
);
gtk_text_buffer_insert
(
buffer
,
&
start
,
word
,
-1
);
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
pos
,
mark
);
spell
->
pos
=
gtk_text_iter_get_offset
(
&
pos
);
g_free
(
word
);
g_free
(
tmp
);
return
TRUE
;
}
g_free
(
tmp
);
g_free
(
spell
->
word
);
spell
->
word
=
NULL
;
return
replaced
;
}
/* insertion works like this:
* - before the text is inserted, we mark the position in the buffer.
* - after the text is inserted, we see where our mark is and use that and
* the current position to check the entire range of inserted text.
*
* this may be overkill for the common case (inserting one character). */
static
void
insert_text_before
(
GtkTextBuffer
*
buffer
,
GtkTextIter
*
iter
,
gchar
*
text
,
gint
len
,
spellchk
*
spell
)
{
if
(
spell
->
inserting
==
TRUE
)
return
;
spell
->
inserting
=
TRUE
;
g_free
(
spell
->
word
);
spell
->
word
=
NULL
;
gtk_text_buffer_move_mark
(
buffer
,
spell
->
mark_insert_start
,
iter
);
}
static
void
insert_text_after
(
GtkTextBuffer
*
buffer
,
GtkTextIter
*
iter
,
gchar
*
text
,
gint
len
,
spellchk
*
spell
)
{
GtkTextIter
start
,
end
;
GtkTextMark
*
mark
;
spell
->
ignore_correction_on_send
=
FALSE
;
if
(
spell
->
ignore_correction
)
{
spell
->
ignore_correction
=
FALSE
;
return
;
}
/* we need to check a range of text. */
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
start
,
spell
->
mark_insert_start
);
if
(
len
==
1
)
check_range
(
spell
,
buffer
,
start
,
*
iter
,
FALSE
);
/* if check_range modified the buffer, iter has been invalidated */
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
end
,
mark
);
gtk_text_buffer_move_mark
(
buffer
,
spell
->
mark_insert_end
,
&
end
);
spell
->
inserting
=
FALSE
;
}
static
void
delete_range_after
(
GtkTextBuffer
*
buffer
,
GtkTextIter
*
start
,
GtkTextIter
*
end
,
spellchk
*
spell
)
{
GtkTextIter
start2
,
end2
;
GtkTextMark
*
mark
;
GtkTextIter
pos
;
gint
place
;
spell
->
ignore_correction_on_send
=
FALSE
;
if
(
!
spell
->
word
)
return
;
if
(
spell
->
inserting
==
TRUE
)
return
;
spell
->
inserting
=
TRUE
;
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
pos
,
mark
);
place
=
gtk_text_iter_get_offset
(
&
pos
);
if
((
place
+
1
)
!=
spell
->
pos
)
{
g_free
(
spell
->
word
);
spell
->
word
=
NULL
;
return
;
}
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
start2
,
spell
->
mark_insert_start
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
end2
,
spell
->
mark_insert_end
);
gtk_text_buffer_delete
(
buffer
,
&
start2
,
&
end2
);
gtk_text_buffer_insert
(
buffer
,
&
start2
,
spell
->
word
,
-1
);
spell
->
ignore_correction
=
TRUE
;
spell
->
ignore_correction_on_send
=
TRUE
;
spell
->
inserting
=
FALSE
;
g_free
(
spell
->
word
);
spell
->
word
=
NULL
;
}
static
void
message_send_cb
(
GtkWidget
*
widget
,
spellchk
*
spell
)
{
GtkTextBuffer
*
buffer
;
GtkTextIter
start
,
end
;
GtkTextMark
*
mark
;
gboolean
replaced
;
if
(
spell
->
ignore_correction_on_send
)
{
spell
->
ignore_correction_on_send
=
FALSE
;
return
;
}
#if 0
if (!purple_prefs_get_bool("/plugins/gtk/spellchk/last_word_replace"))
return;
#endif
buffer
=
gtk_text_view_get_buffer
(
spell
->
view
);
gtk_text_buffer_get_end_iter
(
buffer
,
&
start
);
gtk_text_buffer_get_end_iter
(
buffer
,
&
end
);
spell
->
inserting
=
TRUE
;
replaced
=
check_range
(
spell
,
buffer
,
start
,
end
,
TRUE
);
spell
->
inserting
=
FALSE
;
/* if check_range modified the buffer, iter has been invalidated */
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
end
,
mark
);
gtk_text_buffer_move_mark
(
buffer
,
spell
->
mark_insert_end
,
&
end
);
if
(
replaced
)
{
g_signal_stop_emission_by_name
(
widget
,
"message_send"
);
spell
->
ignore_correction_on_send
=
TRUE
;
}
}
static
void
spellchk_new_attach
(
PurpleConversation
*
conv
)
{
spellchk
*
spell
;
GtkTextBuffer
*
buffer
;
GtkTextIter
start
,
end
;
PidginConversation
*
gtkconv
;
GtkTextView
*
view
;
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
view
=
GTK_TEXT_VIEW
(
gtkconv
->
entry
);
spell
=
g_object_get_data
(
G_OBJECT
(
view
),
SPELLCHK_OBJECT_KEY
);
if
(
spell
!=
NULL
)
return
;
/* attach to the widget */
spell
=
g_new0
(
spellchk
,
1
);
spell
->
view
=
view
;
g_object_set_data_full
(
G_OBJECT
(
view
),
SPELLCHK_OBJECT_KEY
,
spell
,
(
GDestroyNotify
)
spellchk_free
);
buffer
=
gtk_text_view_get_buffer
(
view
);
/* we create the mark here, but we don't use it until text is
* inserted, so we don't really care where iter points. */
gtk_text_buffer_get_bounds
(
buffer
,
&
start
,
&
end
);
spell
->
mark_insert_start
=
gtk_text_buffer_create_mark
(
buffer
,
"spellchk-insert-start"
,
&
start
,
TRUE
);
spell
->
mark_insert_end
=
gtk_text_buffer_create_mark
(
buffer
,
"spellchk-insert-end"
,
&
start
,
TRUE
);
g_signal_connect_after
(
G_OBJECT
(
buffer
),
"delete-range"
,
G_CALLBACK
(
delete_range_after
),
spell
);
g_signal_connect
(
G_OBJECT
(
buffer
),
"insert-text"
,
G_CALLBACK
(
insert_text_before
),
spell
);
g_signal_connect_after
(
G_OBJECT
(
buffer
),
"insert-text"
,
G_CALLBACK
(
insert_text_after
),
spell
);
g_signal_connect
(
G_OBJECT
(
gtkconv
->
entry
),
"message_send"
,
G_CALLBACK
(
message_send_cb
),
spell
);
}
static
int
buf_get_line
(
char
*
ibuf
,
char
**
buf
,
gsize
*
position
,
gsize
len
)
{
gsize
pos
=
*
position
;
gsize
spos
=
pos
;
if
(
pos
==
len
)
return
0
;
while
(
!
(
ibuf
[
pos
]
==
'\n'
||
(
ibuf
[
pos
]
==
'\r'
&&
ibuf
[
pos
+
1
]
!=
'\n'
)))
{
pos
++
;
if
(
pos
==
len
)
return
0
;
}
if
(
pos
!=
0
&&
ibuf
[
pos
]
==
'\n'
&&
ibuf
[
pos
-
1
]
==
'\r'
)
ibuf
[
pos
-
1
]
=
'\0'
;
ibuf
[
pos
]
=
'\0'
;
*
buf
=
&
ibuf
[
spos
];
pos
++
;
*
position
=
pos
;
return
1
;
}
static
void
load_conf
(
void
)
{
/* Corrections to change "...", "(c)", "(r)", and "(tm)" to their
* Unicode character equivalents were not added here even though
* they existed in the source list(s). I think these corrections
* would be more trouble than they're worth.
*/
const
char
*
const
defaultconf
=
"BAD abbout
\n
GOOD about
\n
"
"BAD abotu
\n
GOOD about
\n
"
"BAD abouta
\n
GOOD about a
\n
"
"BAD aboutit
\n
GOOD about it
\n
"
"BAD aboutthe
\n
GOOD about the
\n
"
"BAD abscence
\n
GOOD absence
\n
"
"BAD accesories
\n
GOOD accessories
\n
"
"BAD accidant
\n
GOOD accident
\n
"
"BAD accomodate
\n
GOOD accommodate
\n
"
"BAD accordingto
\n
GOOD according to
\n
"
"BAD accross
\n
GOOD across
\n
"
"BAD acheive
\n
GOOD achieve
\n
"
"BAD acheived
\n
GOOD achieved
\n
"
"BAD acheiving
\n
GOOD achieving
\n
"
"BAD acn
\n
GOOD can
\n
"
"BAD acommodate
\n
GOOD accommodate
\n
"
"BAD acomodate
\n
GOOD accommodate
\n
"
"BAD actualyl
\n
GOOD actually
\n
"
"BAD additinal
\n
GOOD additional
\n
"
"BAD addtional
\n
GOOD additional
\n
"
"BAD adequit
\n
GOOD adequate
\n
"
"BAD adequite
\n
GOOD adequate
\n
"
"BAD adn
\n
GOOD and
\n
"
"BAD advanage
\n
GOOD advantage
\n
"
"BAD affraid
\n
GOOD afraid
\n
"
"BAD afterthe
\n
GOOD after the
\n
"
"COMPLETE 0
\n
BAD againstt he
\n
GOOD against the
\n
"
"BAD aganist
\n
GOOD against
\n
"
"BAD aggresive
\n
GOOD aggressive
\n
"
"BAD agian
\n
GOOD again
\n
"
"BAD agreemeent
\n
GOOD agreement
\n
"
"BAD agreemeents
\n
GOOD agreements
\n
"
"BAD agreemnet
\n
GOOD agreement
\n
"
"BAD agreemnets
\n
GOOD agreements
\n
"
"BAD agressive
\n
GOOD aggressive
\n
"
"BAD agressiveness
\n
GOOD aggressiveness
\n
"
"BAD ahd
\n
GOOD had
\n
"
"BAD ahold
\n
GOOD a hold
\n
"
"BAD ahppen
\n
GOOD happen
\n
"
"BAD ahve
\n
GOOD have
\n
"
"BAD allready
\n
GOOD already
\n
"
"BAD allwasy
\n
GOOD always
\n
"
"BAD allwyas
\n
GOOD always
\n
"
"BAD almots
\n
GOOD almost
\n
"
"BAD almsot
\n
GOOD almost
\n
"
"BAD alomst
\n
GOOD almost
\n
"
"BAD alot
\n
GOOD a lot
\n
"
"BAD alraedy
\n
GOOD already
\n
"
"BAD alreayd
\n
GOOD already
\n
"
"BAD alreday
\n
GOOD already
\n
"
"BAD alwasy
\n
GOOD always
\n
"
"BAD alwats
\n
GOOD always
\n
"
"BAD alway
\n
GOOD always
\n
"
"BAD alwyas
\n
GOOD always
\n
"
"BAD amde
\n
GOOD made
\n
"
"BAD Ameria
\n
GOOD America
\n
"
"BAD amke
\n
GOOD make
\n
"
"BAD amkes
\n
GOOD makes
\n
"
"BAD anbd
\n
GOOD and
\n
"
"BAD andone
\n
GOOD and one
\n
"
"BAD andteh
\n
GOOD and the
\n
"
"BAD andthe
\n
GOOD and the
\n
"
"COMPLETE 0
\n
BAD andt he
\n
GOOD and the
\n
"
"BAD anothe
\n
GOOD another
\n
"
"BAD anual
\n
GOOD annual
\n
"
"BAD any1
\n
GOOD anyone
\n
"
"BAD apparant
\n
GOOD apparent
\n
"
"BAD apparrent
\n
GOOD apparent
\n
"
"BAD appearence
\n
GOOD appearance
\n
"
"BAD appeares
\n
GOOD appears
\n
"
"BAD applicaiton
\n
GOOD application
\n
"
"BAD applicaitons
\n
GOOD applications
\n
"
"BAD applyed
\n
GOOD applied
\n
"
"BAD appointiment
\n
GOOD appointment
\n
"
"BAD approrpiate
\n
GOOD appropriate
\n
"
"BAD approrpriate
\n
GOOD appropriate
\n
"
"BAD aquisition
\n
GOOD acquisition
\n
"
"BAD aquisitions
\n
GOOD acquisitions
\n
"
"BAD arent
\n
GOOD aren't
\n
"
"COMPLETE 0
\n
BAD aren;t
\n
GOOD aren't
\n
"
"BAD arguement
\n
GOOD argument
\n
"
"BAD arguements
\n
GOOD arguments
\n
"
"COMPLETE 0
\n
BAD arn't
\n
GOOD aren't
\n
"
"BAD arond
\n
GOOD around
\n
"
"BAD artical
\n
GOOD article
\n
"
"BAD articel
\n
GOOD article
\n
"
"BAD asdvertising
\n
GOOD advertising
\n
"
"COMPLETE 0
\n
BAD askt he
\n
GOOD ask the
\n
"
"BAD assistent
\n
GOOD assistant
\n
"
"BAD asthe
\n
GOOD as the
\n
"
"BAD atention
\n
GOOD attention
\n
"
"BAD atmospher
\n
GOOD atmosphere
\n
"
"BAD attentioin
\n
GOOD attention
\n
"
"BAD atthe
\n
GOOD at the
\n
"
"BAD audeince
\n
GOOD audience
\n
"
"BAD audiance
\n
GOOD audience
\n
"
"BAD authentification
\n
GOOD authentication
\n
"
"BAD availalbe
\n
GOOD available
\n
"
"BAD awya
\n
GOOD away
\n
"
"BAD aywa
\n
GOOD away
\n
"
"BAD b4
\n
GOOD before
\n
"
"BAD bakc
\n
GOOD back
\n
"
"BAD balence
\n
GOOD balance
\n
"
"BAD ballance
\n
GOOD balance
\n
"
"BAD baout
\n
GOOD about
\n
"
"BAD bcak
\n
GOOD back
\n
"
"BAD bcuz
\n
GOOD because
\n
"
"BAD beacuse
\n
GOOD because
\n
"
"BAD becasue
\n
GOOD because
\n
"
"BAD becaus
\n
GOOD because
\n
"
"BAD becausea
\n
GOOD because a
\n
"
"BAD becauseof
\n
GOOD because of
\n
"
"BAD becausethe
\n
GOOD because the
\n
"
"BAD becauseyou
\n
GOOD because you
\n
"
"COMPLETE 0
\n
BAD beckon call
\n
GOOD beck and call
\n
"
"BAD becomeing
\n
GOOD becoming
\n
"
"BAD becomming
\n
GOOD becoming
\n
"
"BAD becuase
\n
GOOD because
\n
"
"BAD becuse
\n
GOOD because
\n
"
"BAD befoer
\n
GOOD before
\n
"
"BAD beggining
\n
GOOD beginning
\n
"
"BAD begining
\n
GOOD beginning
\n
"
"BAD beginining
\n
GOOD beginning
\n
"
"BAD beleiev
\n
GOOD believe
\n
"
"BAD beleieve
\n
GOOD believe
\n
"
"BAD beleif
\n
GOOD belief
\n
"
"BAD beleive
\n
GOOD believe
\n
"
"BAD beleived
\n
GOOD believed
\n
"
"BAD beleives
\n
GOOD believes
\n
"
"BAD belive
\n
GOOD believe
\n
"
"BAD belived
\n
GOOD believed
\n
"
"BAD belives
\n
GOOD believes
\n
"
"BAD benifit
\n
GOOD benefit
\n
"
"BAD benifits
\n
GOOD benefits
\n
"
"BAD betwen
\n
GOOD between
\n
"
"BAD beutiful
\n
GOOD beautiful
\n
"
"BAD blase
\n
GOOD blas
\303\251\n
"
"BAD boxs
\n
GOOD boxes
\n
"
"BAD brodcast
\n
GOOD broadcast
\n
"
"BAD butthe
\n
GOOD but the
\n
"
"BAD bve
\n
GOOD be
\n
"
"COMPLETE 0
\n
BAD byt he
\n
GOOD by the
\n
"
"BAD cafe
\n
GOOD caf
\303\251\n
"
"BAD caharcter
\n
GOOD character
\n
"
"BAD calcullated
\n
GOOD calculated
\n
"
"BAD calulated
\n
GOOD calculated
\n
"
"BAD candidtae
\n
GOOD candidate
\n
"
"BAD candidtaes
\n
GOOD candidates
\n
"
"COMPLETE 0
\n
BAD case and point
\n
GOOD case in point
\n
"
"BAD cant
\n
GOOD can't
\n
"
"COMPLETE 0
\n
BAD can;t
\n
GOOD can't
\n
"
"COMPLETE 0
\n
BAD can't of been
\n
GOOD can't have been
\n
"
"BAD catagory
\n
GOOD category
\n
"
"BAD categiory
\n
GOOD category
\n
"
"BAD certian
\n
GOOD certain
\n
"
"BAD challange
\n
GOOD challenge
\n
"
"BAD challanges
\n
GOOD challenges
\n
"
"BAD chaneg
\n
GOOD change
\n
"
"BAD chanegs
\n
GOOD changes
\n
"
"BAD changable
\n
GOOD changeable
\n
"
"BAD changeing
\n
GOOD changing
\n
"
"BAD changng
\n
GOOD changing
\n
"
"BAD charachter
\n
GOOD character
\n
"
"BAD charachters
\n
GOOD characters
\n
"
"BAD charactor
\n
GOOD character
\n
"
"BAD charecter
\n
GOOD character
\n
"
"BAD charector
\n
GOOD character
\n
"
"BAD cheif
\n
GOOD chief
\n
"
"BAD chekc
\n
GOOD check
\n
"
"BAD chnage
\n
GOOD change
\n
"
"BAD cieling
\n
GOOD ceiling
\n
"
"BAD circut
\n
GOOD circuit
\n
"
"BAD claer
\n
GOOD clear
\n
"
"BAD claered
\n
GOOD cleared
\n
"
"BAD claerly
\n
GOOD clearly
\n
"
"BAD cliant
\n
GOOD client
\n
"
"BAD cliche
\n
GOOD clich
\303\251\n
"
"BAD cna
\n
GOOD can
\n
"
"BAD colection
\n
GOOD collection
\n
"
"BAD comanies
\n
GOOD companies
\n
"
"BAD comany
\n
GOOD company
\n
"
"BAD comapnies
\n
GOOD companies
\n
"
"BAD comapny
\n
GOOD company
\n
"
"BAD combintation
\n
GOOD combination
\n
"
"BAD comited
\n
GOOD committed
\n
"
"BAD comittee
\n
GOOD committee
\n
"
"BAD commadn
\n
GOOD command
\n
"
"BAD comming
\n
GOOD coming
\n
"
"BAD commitee
\n
GOOD committee
\n
"
"BAD committe
\n
GOOD committee
\n
"
"BAD committment
\n
GOOD commitment
\n
"
"BAD committments
\n
GOOD commitments
\n
"
"BAD committy
\n
GOOD committee
\n
"
"BAD comntain
\n
GOOD contain
\n
"
"BAD comntains
\n
GOOD contains
\n
"
"BAD compair
\n
GOOD compare
\n
"
"COMPLETE 0
\n
BAD company;s
\n
GOOD company's
\n
"
"BAD competetive
\n
GOOD competitive
\n
"
"BAD compleated
\n
GOOD completed
\n
"
"BAD compleatly
\n
GOOD completely
\n
"
"BAD compleatness
\n
GOOD completeness
\n
"
"BAD completly
\n
GOOD completely
\n
"
"BAD completness
\n
GOOD completeness
\n
"
"BAD composate
\n
GOOD composite
\n
"
"BAD comtain
\n
GOOD contain
\n
"
"BAD comtains
\n
GOOD contains
\n
"
"BAD comunicate
\n
GOOD communicate
\n
"
"BAD comunity
\n
GOOD community
\n
"
"BAD condolances
\n
GOOD condolences
\n
"
"BAD conected
\n
GOOD connected
\n
"
"BAD conferance
\n
GOOD conference
\n
"
"BAD confirmmation
\n
GOOD confirmation
\n
"
"BAD congradulations
\n
GOOD congratulations
\n
"
"BAD considerit
\n
GOOD considerate
\n
"
"BAD considerite
\n
GOOD considerate
\n
"
"BAD consonent
\n
GOOD consonant
\n
"
"BAD conspiricy
\n
GOOD conspiracy
\n
"
"BAD consultent
\n
GOOD consultant
\n
"
"BAD convertable
\n
GOOD convertible
\n
"
"BAD cooparate
\n
GOOD cooperate
\n
"
"BAD cooporate
\n
GOOD cooperate
\n
"
"BAD corproation
\n
GOOD corporation
\n
"
"BAD corproations
\n
GOOD corporations
\n
"
"BAD corruptable
\n
GOOD corruptible
\n
"
"BAD cotten
\n
GOOD cotton
\n
"
"BAD coudl
\n
GOOD could
\n
"
"COMPLETE 0
\n
BAD coudln't
\n
GOOD couldn't
\n
"
"COMPLETE 0
\n
BAD coudn't
\n
GOOD couldn't
\n
"
"BAD couldnt
\n
GOOD couldn't
\n
"
"COMPLETE 0
\n
BAD couldn;t
\n
GOOD couldn't
\n
"
"COMPLETE 0
\n
BAD could of been
\n
GOOD could have been
\n
"
"COMPLETE 0
\n
BAD could of had
\n
GOOD could have had
\n
"
"BAD couldthe
\n
GOOD could the
\n
"
"BAD couldve
\n
GOOD could've
\n
"
"BAD cpoy
\n
GOOD copy
\n
"
"BAD creme
\n
GOOD cr
\303\250
me
\n
"
"BAD ctaegory
\n
GOOD category
\n
"
"BAD cu
\n
GOOD see you
\n
"
"BAD cusotmer
\n
GOOD customer
\n
"
"BAD cusotmers
\n
GOOD customers
\n
"
"BAD cutsomer
\n
GOOD customer
\n
"
"BAD cutsomers
\n
GOOD customer
\n
"
"BAD cuz
\n
GOOD because
\n
"
"BAD cxan
\n
GOOD can
\n
"
"BAD danceing
\n
GOOD dancing
\n
"
"BAD dcument
\n
GOOD document
\n
"
"BAD deatils
\n
GOOD details
\n
"
"BAD decison
\n
GOOD decision
\n
"
"BAD decisons
\n
GOOD decisions
\n
"
"BAD decor
\n
GOOD d
\303\251
cor
\n
"
"BAD defendent
\n
GOOD defendant
\n
"
"BAD definately
\n
GOOD definitely
\n
"
"COMPLETE 0
\n
BAD deja vu
\n
GOOD d
\303\251
j
\303\240
vu
\n
"
"BAD deptartment
\n
GOOD department
\n
"
"BAD desicion
\n
GOOD decision
\n
"
"BAD desicions
\n
GOOD decisions
\n
"
"BAD desision
\n
GOOD decision
\n
"
"BAD desisions
\n
GOOD decisions
\n
"
"BAD detente
\n
GOOD d
\303\251
tente
\n
"
"BAD develeoprs
\n
GOOD developers
\n
"
"BAD devellop
\n
GOOD develop
\n
"
"BAD develloped
\n
GOOD developed
\n
"
"BAD develloper
\n
GOOD developer
\n
"
"BAD devellopers
\n
GOOD developers
\n
"
"BAD develloping
\n
GOOD developing
\n
"
"BAD devellopment
\n
GOOD development
\n
"
"BAD devellopments
\n
GOOD developments
\n
"
"BAD devellops
\n
GOOD develop
\n
"
"BAD develope
\n
GOOD develop
\n
"
"BAD developement
\n
GOOD development
\n
"
"BAD developements
\n
GOOD developments
\n
"
"BAD developor
\n
GOOD developer
\n
"
"BAD developors
\n
GOOD developers
\n
"
"BAD develpment
\n
GOOD development
\n
"
"BAD diaplay
\n
GOOD display
\n
"
"BAD didint
\n
GOOD didn't
\n
"
"BAD didnot
\n
GOOD did not
\n
"
"BAD didnt
\n
GOOD didn't
\n
"
"COMPLETE 0
\n
BAD didn;t
\n
GOOD didn't
\n
"
"BAD difefrent
\n
GOOD different
\n
"
"BAD diferences
\n
GOOD differences
\n
"
"BAD differance
\n
GOOD difference
\n
"
"BAD differances
\n
GOOD differences
\n
"
"BAD differant
\n
GOOD different
\n
"
"BAD differemt
\n
GOOD different
\n
"
"BAD differnt
\n
GOOD different
\n
"
"BAD diffrent
\n
GOOD different
\n
"
"BAD directer
\n
GOOD director
\n
"
"BAD directers
\n
GOOD directors
\n
"
"BAD directiosn
\n
GOOD direction
\n
"
"BAD disatisfied
\n
GOOD dissatisfied
\n
"
"BAD discoverd
\n
GOOD discovered
\n
"
"BAD disign
\n
GOOD design
\n
"
"BAD dispaly
\n
GOOD display
\n
"
"BAD dissonent
\n
GOOD dissonant
\n
"
"BAD distribusion
\n
GOOD distribution
\n
"
"BAD divsion
\n
GOOD division
\n
"
"BAD docuement
\n
GOOD documents
\n
"
"BAD docuemnt
\n
GOOD document
\n
"
"BAD documetn
\n
GOOD document
\n
"
"BAD documnet
\n
GOOD document
\n
"
"BAD documnets
\n
GOOD documents
\n
"
"COMPLETE 0
\n
BAD doens't
\n
GOOD doesn't
\n
"
"BAD doese
\n
GOOD does
\n
"
"COMPLETE 0
\n
BAD doe snot
\n
GOOD does not
\n
"
"BAD doesnt
\n
GOOD doesn't
\n
"
"COMPLETE 0
\n
BAD doesn;t
\n
GOOD doesn't
\n
"
"BAD doign
\n
GOOD doing
\n
"
"BAD doimg
\n
GOOD doing
\n
"
"BAD doind
\n
GOOD doing
\n
"
"BAD dollers
\n
GOOD dollars
\n
"
"BAD donig
\n
GOOD doing
\n
"
"BAD donno
\n
GOOD don't know
\n
"
"BAD dont
\n
GOOD don't
\n
"
"COMPLETE 0
\n
BAD do'nt
\n
GOOD don't
\n
"
"COMPLETE 0
\n
BAD don;t
\n
GOOD don't
\n
"
"COMPLETE 0
\n
BAD don't no
\n
GOOD don't know
\n
"
"COMPLETE 0
\n
BAD dosn't
\n
GOOD doesn't
\n
"
"BAD driveing
\n
GOOD driving
\n
"
"BAD drnik
\n
GOOD drink
\n
"
"BAD dunno
\n
GOOD don't know
\n
"
"BAD eclair
\n
GOOD
\303\251
clair
\n
"
"BAD efel
\n
GOOD feel
\n
"
"BAD effecient
\n
GOOD efficient
\n
"
"BAD efort
\n
GOOD effort
\n
"
"BAD eforts
\n
GOOD efforts
\n
"
"BAD ehr
\n
GOOD her
\n
"
"BAD eligable
\n
GOOD eligible
\n
"
"BAD embarass
\n
GOOD embarrass
\n
"
"BAD emigre
\n
GOOD
\303\251
migr
\303\251\n
"
"BAD enought
\n
GOOD enough
\n
"
"BAD entree
\n
GOOD entr
\303\251
e
\n
"
"BAD enuf
\n
GOOD enough
\n
"
"BAD equippment
\n
GOOD equipment
\n
"
"BAD equivalant
\n
GOOD equivalent
\n
"
"BAD esle
\n
GOOD else
\n
"
"BAD especally
\n
GOOD especially
\n
"
"BAD especialyl
\n
GOOD especially
\n
"
"BAD espesially
\n
GOOD especially
\n
"
"BAD essense
\n
GOOD essence
\n
"
"BAD excellance
\n
GOOD excellence
\n
"
"BAD excellant
\n
GOOD excellent
\n
"
"BAD excercise
\n
GOOD exercise
\n
"
"BAD exchagne
\n
GOOD exchange
\n
"
"BAD exchagnes
\n
GOOD exchanges
\n
"
"BAD excitment
\n
GOOD excitement
\n
"
"BAD exhcange
\n
GOOD exchange
\n
"
"BAD exhcanges
\n
GOOD exchanges
\n
"
"BAD experiance
\n
GOOD experience
\n
"
"BAD experienc
\n
GOOD experience
\n
"
"BAD exprience
\n
GOOD experience
\n
"
"BAD exprienced
\n
GOOD experienced
\n
"
"BAD eyt
\n
GOOD yet
\n
"
"BAD facade
\n
GOOD fa
\303\247
ade
\n
"
"BAD faeture
\n
GOOD feature
\n
"
"BAD faetures
\n
GOOD feature
\n
"
"BAD familair
\n
GOOD familiar
\n
"
"BAD familar
\n
GOOD familiar
\n
"
"BAD familliar
\n
GOOD familiar
\n
"
"BAD fammiliar
\n
GOOD familiar
\n
"
"BAD feild
\n
GOOD field
\n
"
"BAD feilds
\n
GOOD fields
\n
"
"BAD fianlly
\n
GOOD finally
\n
"
"BAD fidn
\n
GOOD find
\n
"
"BAD finalyl
\n
GOOD finally
\n
"
"BAD firends
\n
GOOD friends
\n
"
"BAD firts
\n
GOOD first
\n
"
"BAD follwo
\n
GOOD follow
\n
"
"BAD follwoing
\n
GOOD following
\n
"
"BAD fora
\n
GOOD for a
\n
"
"COMPLETE 0
\n
BAD for all intensive purposes
\n
for all intents and purposes
\n
"
"BAD foriegn
\n
GOOD foreign
\n
"
"BAD forthe
\n
GOOD for the
\n
"
"BAD forwrd
\n
GOOD forward
\n
"
"BAD forwrds
\n
GOOD forwards
\n
"
"BAD foudn
\n
GOOD found
\n
"
"BAD foward
\n
GOOD forward
\n
"
"BAD fowards
\n
GOOD forwards
\n
"
"BAD freind
\n
GOOD friend
\n
"
"BAD freindly
\n
GOOD friendly
\n
"
"BAD freinds
\n
GOOD friends
\n
"
"BAD friday
\n
GOOD Friday
\n
"
"BAD frmo
\n
GOOD from
\n
"
"BAD fromthe
\n
GOOD from the
\n
"
"COMPLETE 0
\n
BAD fromt he
\n
GOOD from the
\n
"
"BAD furneral
\n
GOOD funeral
\n
"
"BAD fwe
\n
GOOD few
\n
"
"BAD garantee
\n
GOOD guarantee
\n
"
"BAD gaurd
\n
GOOD guard
\n
"
"BAD gemeral
\n
GOOD general
\n
"
"BAD gerat
\n
GOOD great
\n
"
"BAD geting
\n
GOOD getting
\n
"
"BAD gettin
\n
GOOD getting
\n
"
"BAD gievn
\n
GOOD given
\n
"
"BAD giveing
\n
GOOD giving
\n
"
"BAD gloabl
\n
GOOD global
\n
"
"BAD goign
\n
GOOD going
\n
"
"BAD gonig
\n
GOOD going
\n
"
"BAD govenment
\n
GOOD government
\n
"
"BAD goverment
\n
GOOD government
\n
"
"BAD gruop
\n
GOOD group
\n
"
"BAD gruops
\n
GOOD groups
\n
"
"BAD grwo
\n
GOOD grow
\n
"
"BAD guidlines
\n
GOOD guidelines
\n
"
"BAD hadbeen
\n
GOOD had been
\n
"
"BAD hadnt
\n
GOOD hadn't
\n
"
"COMPLETE 0
\n
BAD hadn;t
\n
GOOD hadn't
\n
"
"BAD haev
\n
GOOD have
\n
"
"BAD hapen
\n
GOOD happen
\n
"
"BAD hapened
\n
GOOD happened
\n
"
"BAD hapening
\n
GOOD happening
\n
"
"BAD hapens
\n
GOOD happens
\n
"
"BAD happend
\n
GOOD happened
\n
"
"BAD hasbeen
\n
GOOD has been
\n
"
"BAD hasnt
\n
GOOD hasn't
\n
"
"COMPLETE 0
\n
BAD hasn;t
\n
GOOD hasn't
\n
"
"BAD havebeen
\n
GOOD have been
\n
"
"BAD haveing
\n
GOOD having
\n
"
"BAD havent
\n
GOOD haven't
\n
"
"COMPLETE 0
\n
BAD haven;t
\n
GOOD haven't
\n
"
"BAD hda
\n
GOOD had
\n
"
"BAD hearign
\n
GOOD hearing
\n
"
"COMPLETE 0
\n
BAD he;d
\n
GOOD he'd
\n
"
"BAD heirarchy
\n
GOOD hierarchy
\n
"
"BAD hel
\n
GOOD he'll
\n
"
"COMPLETE 0
\n
BAD he;ll
\n
GOOD he'll
\n
"
"BAD helpfull
\n
GOOD helpful
\n
"
"BAD herat
\n
GOOD heart
\n
"
"BAD heres
\n
GOOD here's
\n
"
"COMPLETE 0
\n
BAD here;s
\n
GOOD here's
\n
"
"BAD hes
\n
GOOD he's
\n
"
"COMPLETE 0
\n
BAD he;s
\n
GOOD he's
\n
"
"BAD hesaid
\n
GOOD he said
\n
"
"BAD hewas
\n
GOOD he was
\n
"
"BAD hge
\n
GOOD he
\n
"
"BAD hismelf
\n
GOOD himself
\n
"
"BAD hlep
\n
GOOD help
\n
"
"BAD hott
\n
GOOD hot
\n
"
"BAD hows
\n
GOOD how's
\n
"
"BAD hsa
\n
GOOD has
\n
"
"BAD hse
\n
GOOD she
\n
"
"BAD hsi
\n
GOOD his
\n
"
"BAD hte
\n
GOOD the
\n
"
"BAD htere
\n
GOOD there
\n
"
"BAD htese
\n
GOOD these
\n
"
"BAD htey
\n
GOOD they
\n
"
"BAD hting
\n
GOOD thing
\n
"
"BAD htink
\n
GOOD think
\n
"
"BAD htis
\n
GOOD this
\n
"
"COMPLETE 0
\n
BAD htp:
\n
GOOD http:
\n
"
"COMPLETE 0
\n
BAD http:
\\\\
nGOOD http://
\n
"
"BAD httpL
\n
GOOD http:
\n
"
"BAD hvae
\n
GOOD have
\n
"
"BAD hvaing
\n
GOOD having
\n
"
"BAD hwich
\n
GOOD which
\n
"
"BAD i
\n
GOOD I
\n
"
"COMPLETE 0
\n
BAD i c
\n
GOOD I see
\n
"
"COMPLETE 0
\n
BAD i;d
\n
GOOD I'd
\n
"
"COMPLETE 0
\n
BAD i'd
\n
GOOD I'd
\n
"
"COMPLETE 0
\n
BAD I;d
\n
GOOD I'd
\n
"
"BAD idae
\n
GOOD idea
\n
"
"BAD idaes
\n
GOOD ideas
\n
"
"BAD identofy
\n
GOOD identify
\n
"
"BAD ihs
\n
GOOD his
\n
"
"BAD iits the
\n
GOOD it's the
\n
"
"COMPLETE 0
\n
BAD i'll
\n
GOOD I'll
\n
"
"COMPLETE 0
\n
BAD I;ll
\n
GOOD I'll
\n
"
"COMPLETE 0
\n
BAD i;m
\n
GOOD I'm
\n
"
"COMPLETE 0
\n
BAD i'm
\n
GOOD I'm
\n
"
"COMPLETE 0
\n
BAD I
\"
m
\n
GOOD I'm
\n
"
"BAD imediate
\n
GOOD immediate
\n
"
"BAD imediatly
\n
GOOD immediately
\n
"
"BAD immediatly
\n
GOOD immediately
\n
"
"BAD importent
\n
GOOD important
\n
"
"BAD importnat
\n
GOOD important
\n
"
"BAD impossable
\n
GOOD impossible
\n
"
"BAD improvemnt
\n
GOOD improvement
\n
"
"BAD improvment
\n
GOOD improvement
\n
"
"BAD includ
\n
GOOD include
\n
"
"BAD indecate
\n
GOOD indicate
\n
"
"BAD indenpendence
\n
GOOD independence
\n
"
"BAD indenpendent
\n
GOOD independent
\n
"
"BAD indepedent
\n
GOOD independent
\n
"
"BAD independance
\n
GOOD independence
\n
"
"BAD independant
\n
GOOD independent
\n
"
"BAD influance
\n
GOOD influence
\n
"
"BAD infomation
\n
GOOD information
\n
"
"BAD informatoin
\n
GOOD information
\n
"
"BAD inital
\n
GOOD initial
\n
"
"BAD instaleld
\n
GOOD installed
\n
"
"BAD insted
\n
GOOD instead
\n
"
"BAD insurence
\n
GOOD insurance
\n
"
"BAD inteh
\n
GOOD in the
\n
"
"BAD interum
\n
GOOD interim
\n
"
"BAD inthe
\n
GOOD in the
\n
"
"COMPLETE 0
\n
BAD int he
\n
GOOD in the
\n
"
"BAD inturn
\n
GOOD intern
\n
"
"BAD inwhich
\n
GOOD in which
\n
"
"COMPLETE 0
\n
BAD i snot
\n
GOOD is not
\n
"
"BAD isnt
\n
GOOD isn't
\n
"
"COMPLETE 0
\n
BAD isn;t
\n
GOOD isn't
\n
"
"BAD isthe
\n
GOOD is the
\n
"
"BAD itd
\n
GOOD it'd
\n
"
"COMPLETE 0
\n
BAD it;d
\n
GOOD it'd
\n
"
"BAD itis
\n
GOOD it is
\n
"
"BAD ititial
\n
GOOD initial
\n
"
"BAD itll
\n
GOOD it'll
\n
"
"COMPLETE 0
\n
BAD it;ll
\n
GOOD it'll
\n
"
"BAD itnerest
\n
GOOD interest
\n
"
"BAD itnerested
\n
GOOD interested
\n
"
"BAD itneresting
\n
GOOD interesting
\n
"
"BAD itnerests
\n
GOOD interests
\n
"
"COMPLETE 0
\n
BAD it;s
\n
GOOD it's
\n
"
"BAD itsa
\n
GOOD it's a
\n
"
"COMPLETE 0
\n
BAD its a
\n
GOOD it's a
\n
"
"COMPLETE 0
\n
BAD it snot
\n
GOOD it's not
\n
"
"COMPLETE 0
\n
BAD it' snot
\n
GOOD it's not
\n
"
"COMPLETE 0
\n
BAD its the
\n
GOOD it's the
\n
"
"BAD itwas
\n
GOOD it was
\n
"
"BAD ive
\n
GOOD I've
\n
"
"COMPLETE 0
\n
BAD i;ve
\n
GOOD I've
\n
"
"COMPLETE 0
\n
BAD i've
\n
GOOD I've
\n
"
"BAD iwll
\n
GOOD will
\n
"
"BAD iwth
\n
GOOD with
\n
"
"BAD jsut
\n
GOOD just
\n
"
"BAD jugment
\n
GOOD judgment
\n
"
"BAD kno
\n
GOOD know
\n
"
"BAD knowldge
\n
GOOD knowledge
\n
"
"BAD knowlege
\n
GOOD knowledge
\n
"
"BAD knwo
\n
GOOD know
\n
"
"BAD knwon
\n
GOOD known
\n
"
"BAD knwos
\n
GOOD knows
\n
"
"BAD konw
\n
GOOD know
\n
"
"BAD konwn
\n
GOOD known
\n
"
"BAD konws
\n
GOOD knows
\n
"
"BAD labratory
\n
GOOD laboratory
\n
"
"BAD labtop
\n
GOOD laptop
\n
"
"BAD lastyear
\n
GOOD last year
\n
"
"BAD laterz
\n
GOOD later
\n
"
"BAD learnign
\n
GOOD learning
\n
"
"BAD lenght
\n
GOOD length
\n
"
"COMPLETE 0
\n
BAD let;s
\n
GOOD let's
\n
"
"COMPLETE 0
\n
BAD let's him
\n
GOOD lets him
\n
"
"COMPLETE 0
\n
BAD let's it
\n
GOOD lets it
\n
"
"BAD levle
\n
GOOD level
\n
"
"BAD libary
\n
GOOD library
\n
"
"BAD librarry
\n
GOOD library
\n
"
"BAD librery
\n
GOOD library
\n
"
"BAD liek
\n
GOOD like
\n
"
"BAD liekd
\n
GOOD liked
\n
"
"BAD lieutenent
\n
GOOD lieutenant
\n
"
"BAD liev
\n
GOOD live
\n
"
"BAD likly
\n
GOOD likely
\n
"
"BAD lisense
\n
GOOD license
\n
"
"BAD littel
\n
GOOD little
\n
"
"BAD litttle
\n
GOOD little
\n
"
"BAD liuke
\n
GOOD like
\n
"
"BAD liveing
\n
GOOD living
\n
"
"BAD loev
\n
GOOD love
\n
"
"BAD lonly
\n
GOOD lonely
\n
"
"BAD lookign
\n
GOOD looking
\n
"
"BAD m
\n
GOOD am
\n
"
"BAD maintainence
\n
GOOD maintenance
\n
"
"BAD maintenence
\n
GOOD maintenance
\n
"
"BAD makeing
\n
GOOD making
\n
"
"BAD managment
\n
GOOD management
\n
"
"BAD mantain
\n
GOOD maintain
\n
"
"BAD marraige
\n
GOOD marriage
\n
"
"COMPLETE 0
\n
BAD may of been
\n
GOOD may have been
\n
"
"COMPLETE 0
\n
BAD may of had
\n
GOOD may have had
\n
"
"BAD memeber
\n
GOOD member
\n
"
"BAD merchent
\n
GOOD merchant
\n
"
"BAD mesage
\n
GOOD message
\n
"
"BAD mesages
\n
GOOD messages
\n
"
"COMPLETE 0
\n
BAD might of been
\n
GOOD might have been
\n
"
"COMPLETE 0
\n
BAD might of had
\n
GOOD might have had
\n
"
"BAD mispell
\n
GOOD misspell
\n
"
"BAD mispelling
\n
GOOD misspelling
\n
"
"BAD mispellings
\n
GOOD misspellings
\n
"
"BAD mkae
\n
GOOD make
\n
"
"BAD mkaes
\n
GOOD makes
\n
"
"BAD mkaing
\n
GOOD making
\n
"
"BAD moeny
\n
GOOD money
\n
"
"BAD monday
\n
GOOD Monday
\n
"
"BAD morgage
\n
GOOD mortgage
\n
"
"BAD mroe
\n
GOOD more
\n
"
"COMPLETE 0
\n
BAD must of been
\n
GOOD must have been
\n
"
"COMPLETE 0
\n
BAD must of had
\n
GOOD must have had
\n
"
"COMPLETE 0
\n
BAD mute point
\n
GOOD moot point
\n
"
"BAD mysefl
\n
GOOD myself
\n
"
"BAD myu
\n
GOOD my
\n
"
"BAD naive
\n
GOOD naïve
\n
"
"BAD ne1
\n
GOOD anyone
\n
"
"BAD neway
\n
GOOD anyway
\n
"
"BAD neways
\n
GOOD anyways
\n
"
"BAD necassarily
\n
GOOD necessarily
\n
"
"BAD necassary
\n
GOOD necessary
\n
"
"BAD neccessarily
\n
GOOD necessarily
\n
"
"BAD neccessary
\n
GOOD necessary
\n
"
"BAD necesarily
\n
GOOD necessarily
\n
"
"BAD necesary
\n
GOOD necessary
\n
"
"BAD negotiaing
\n
GOOD negotiating
\n
"
"BAD nkow
\n
GOOD know
\n
"
"BAD nothign
\n
GOOD nothing
\n
"
"BAD nto
\n
GOOD not
\n
"
"BAD nver
\n
GOOD never
\n
"
"BAD nwe
\n
GOOD new
\n
"
"BAD nwo
\n
GOOD now
\n
"
"BAD obediant
\n
GOOD obedient
\n
"
"BAD ocasion
\n
GOOD occasion
\n
"
"BAD occassion
\n
GOOD occasion
\n
"
"BAD occurance
\n
GOOD occurrence
\n
"
"BAD occured
\n
GOOD occurred
\n
"
"BAD occurence
\n
GOOD occurrence
\n
"
"BAD occurrance
\n
GOOD occurrence
\n
"
"BAD oclock
\n
GOOD o'clock
\n
"
"BAD oculd
\n
GOOD could
\n
"
"BAD ocur
\n
GOOD occur
\n
"
"BAD oeprator
\n
GOOD operator
\n
"
"BAD ofits
\n
GOOD of its
\n
"
"BAD ofthe
\n
GOOD of the
\n
"
"BAD oft he
\n
GOOD of the
\n
"
"BAD oging
\n
GOOD going
\n
"
"BAD ohter
\n
GOOD other
\n
"
"BAD omre
\n
GOOD more
\n
"
"BAD oneof
\n
GOOD one of
\n
"
"BAD onepoint
\n
GOOD one point
\n
"
"BAD onthe
\n
GOOD on the
\n
"
"COMPLETE 0
\n
BAD ont he
\n
GOOD on the
\n
"
"BAD onyl
\n
GOOD only
\n
"
"BAD oppasite
\n
GOOD opposite
\n
"
"BAD opperation
\n
GOOD operation
\n
"
"BAD oppertunity
\n
GOOD opportunity
\n
"
"BAD opposate
\n
GOOD opposite
\n
"
"BAD opposible
\n
GOOD opposable
\n
"
"BAD opposit
\n
GOOD opposite
\n
"
"BAD oppotunities
\n
GOOD opportunities
\n
"
"BAD oppotunity
\n
GOOD opportunity
\n
"
"BAD orginization
\n
GOOD organization
\n
"
"BAD orginized
\n
GOOD organized
\n
"
"BAD otehr
\n
GOOD other
\n
"
"BAD otu
\n
GOOD out
\n
"
"BAD outof
\n
GOOD out of
\n
"
"BAD overthe
\n
GOOD over the
\n
"
"BAD owrk
\n
GOOD work
\n
"
"BAD owuld
\n
GOOD would
\n
"
"BAD oxident
\n
GOOD oxidant
\n
"
"BAD papaer
\n
GOOD paper
\n
"
"BAD passe
\n
GOOD pass
\303\251\n
"
"BAD parliment
\n
GOOD parliament
\n
"
"BAD partof
\n
GOOD part of
\n
"
"BAD paymetn
\n
GOOD payment
\n
"
"BAD paymetns
\n
GOOD payments
\n
"
"BAD pciture
\n
GOOD picture
\n
"
"BAD peice
\n
GOOD piece
\n
"
"BAD peices
\n
GOOD pieces
\n
"
"BAD peolpe
\n
GOOD people
\n
"
"BAD peopel
\n
GOOD people
\n
"
"BAD percentof
\n
GOOD percent of
\n
"
"BAD percentto
\n
GOOD percent to
\n
"
"BAD performence
\n
GOOD performance
\n
"
"BAD perhasp
\n
GOOD perhaps
\n
"
"BAD perhpas
\n
GOOD perhaps
\n
"
"BAD permanant
\n
GOOD permanent
\n
"
"BAD perminent
\n
GOOD permanent
\n
"
"BAD personalyl
\n
GOOD personally
\n
"
"BAD pleasent
\n
GOOD pleasant
\n
"
"BAD pls
\n
GOOD please
\n
"
"BAD plz
\n
GOOD please
\n
"
"BAD poeple
\n
GOOD people
\n
"
"BAD porblem
\n
GOOD problem
\n
"
"BAD porblems
\n
GOOD problems
\n
"
"BAD porvide
\n
GOOD provide
\n
"
"BAD possable
\n
GOOD possible
\n
"
"BAD postition
\n
GOOD position
\n
"
"BAD potatoe
\n
GOOD potato
\n
"
"BAD potatos
\n
GOOD potatoes
\n
"
"BAD potentialy
\n
GOOD potentially
\n
"
"BAD ppl
\n
GOOD people
\n
"
"BAD pregnent
\n
GOOD pregnant
\n
"
"BAD presance
\n
GOOD presence
\n
"
"BAD primative
\n
GOOD primitive
\n
"
"BAD probally
\n
GOOD probably
\n
"
"BAD probelm
\n
GOOD problem
\n
"
"BAD probelms
\n
GOOD problems
\n
"
"BAD probly
\n
GOOD probably
\n
"
"BAD prolly
\n
GOOD probably
\n
"
"BAD proly
\n
GOOD probably
\n
"
"BAD prominant
\n
GOOD prominent
\n
"
"BAD proposterous
\n
GOOD preposterous
\n
"
"BAD protege
\n
GOOD prot
\303\251
g
\303\251\n
"
"BAD protoge
\n
GOOD prot
\303\251
g
\303\251\n
"
"BAD psoition
\n
GOOD position
\n
"
"BAD ptogress
\n
GOOD progress
\n
"
"BAD pursuade
\n
GOOD persuade
\n
"
"BAD puting
\n
GOOD putting
\n
"
"BAD pwoer
\n
GOOD power
\n
"
"BAD quater
\n
GOOD quarter
\n
"
"BAD quaters
\n
GOOD quarters
\n
"
"BAD quesion
\n
GOOD question
\n
"
"BAD quesions
\n
GOOD questions
\n
"
"BAD questioms
\n
GOOD questions
\n
"
"BAD questiosn
\n
GOOD questions
\n
"
"BAD questoin
\n
GOOD question
\n
"
"BAD quetion
\n
GOOD question
\n
"
"BAD quetions
\n
GOOD questions
\n
"
"BAD r
\n
GOOD are
\n
"
"BAD raeson
\n
GOOD reason
\n
"
"BAD realyl
\n
GOOD really
\n
"
"BAD reccomend
\n
GOOD recommend
\n
"
"BAD reccommend
\n
GOOD recommend
\n
"
"BAD receieve
\n
GOOD receive
\n
"
"BAD recieve
\n
GOOD receive
\n
"
"BAD recieved
\n
GOOD received
\n
"
"BAD recieving
\n
GOOD receiving
\n
"
"BAD recomend
\n
GOOD recommend
\n
"
"BAD recomendation
\n
GOOD recommendation
\n
"
"BAD recomendations
\n
GOOD recommendations
\n
"
"BAD recomended
\n
GOOD recommended
\n
"
"BAD reconize
\n
GOOD recognize
\n
"
"BAD recrod
\n
GOOD record
\n
"
"BAD rediculous
\n
GOOD ridiculous
\n
"
"BAD rediculus
\n
GOOD ridiculous
\n
"
"BAD reguard
\n
GOOD regard
\n
"
"BAD religous
\n
GOOD religious
\n
"
"BAD reluctent
\n
GOOD reluctant
\n
"
"BAD remeber
\n
GOOD remember
\n
"
"BAD reommend
\n
GOOD recommend
\n
"
"BAD representativs
\n
GOOD representatives
\n
"
"BAD representives
\n
GOOD representatives
\n
"
"BAD represetned
\n
GOOD represented
\n
"
"BAD represnt
\n
GOOD represent
\n
"
"BAD reserach
\n
GOOD research
\n
"
"BAD resollution
\n
GOOD resolution
\n
"
"BAD resorces
\n
GOOD resources
\n
"
"BAD respomd
\n
GOOD respond
\n
"
"BAD respomse
\n
GOOD response
\n
"
"BAD responce
\n
GOOD response
\n
"
"BAD responsability
\n
GOOD responsibility
\n
"
"BAD responsable
\n
GOOD responsible
\n
"
"BAD responsibile
\n
GOOD responsible
\n
"
"BAD responsiblity
\n
GOOD responsibility
\n
"
"BAD restaraunt
\n
GOOD restaurant
\n
"
"BAD restuarant
\n
GOOD restaurant
\n
"
"BAD reult
\n
GOOD result
\n
"
"BAD reveiw
\n
GOOD review
\n
"
"BAD reveiwing
\n
GOOD reviewing
\n
"
"BAD rumers
\n
GOOD rumors
\n
"
"BAD rwite
\n
GOOD write
\n
"
"BAD rythm
\n
GOOD rhythm
\n
"
"BAD saidhe
\n
GOOD said he
\n
"
"BAD saidit
\n
GOOD said it
\n
"
"BAD saidthat
\n
GOOD said that
\n
"
"BAD saidthe
\n
GOOD said the
\n
"
"COMPLETE 0
\n
BAD saidt he
\n
GOOD said the
\n
"
"BAD sandwhich
\n
GOOD sandwich
\n
"
"BAD sandwitch
\n
GOOD sandwich
\n
"
"BAD saturday
\n
GOOD Saturday
\n
"
"BAD scedule
\n
GOOD schedule
\n
"
"BAD sceduled
\n
GOOD scheduled
\n
"
"BAD seance
\n
GOOD s
\303\251
ance
\n
"
"BAD secratary
\n
GOOD secretary
\n
"
"BAD sectino
\n
GOOD section
\n
"
"BAD seh
\n
GOOD she
\n
"
"BAD selectoin
\n
GOOD selection
\n
"
"BAD sence
\n
GOOD sense
\n
"
"BAD sentance
\n
GOOD sentence
\n
"
"BAD separeate
\n
GOOD separate
\n
"
"BAD seperate
\n
GOOD separate
\n
"
"BAD sercumstances
\n
GOOD circumstances
\n
"
"BAD shcool
\n
GOOD school
\n
"
"COMPLETE 0
\n
BAD she;d
\n
GOOD she'd
\n
"
"COMPLETE 0
\n
BAD she;ll
\n
GOOD she'll
\n
"
"BAD shes
\n
GOOD she's
\n
"
"COMPLETE 0
\n
BAD she;s
\n
GOOD she's
\n
"
"BAD shesaid
\n
GOOD she said
\n
"
"BAD shineing
\n
GOOD shining
\n
"
"BAD shiped
\n
GOOD shipped
\n
"
"BAD shoudl
\n
GOOD should
\n
"
"COMPLETE 0
\n
BAD shoudln't
\n
GOOD shouldn't
\n
"
"BAD shouldent
\n
GOOD shouldn't
\n
"
"BAD shouldnt
\n
GOOD shouldn't
\n
"
"COMPLETE 0
\n
BAD shouldn;t
\n
GOOD shouldn't
\n
"
"COMPLETE 0
\n
BAD should of been
\n
GOOD should have been
\n
"
"COMPLETE 0
\n
BAD should of had
\n
GOOD should have had
\n
"
"BAD shouldve
\n
GOOD should've
\n
"
"BAD showinf
\n
GOOD showing
\n
"
"BAD signifacnt
\n
GOOD significant
\n
"
"BAD simalar
\n
GOOD similar
\n
"
"BAD similiar
\n
GOOD similar
\n
"
"BAD simpyl
\n
GOOD simply
\n
"
"BAD sincerly
\n
GOOD sincerely
\n
"
"BAD sitll
\n
GOOD still
\n
"
"BAD smae
\n
GOOD same
\n
"
"BAD smoe
\n
GOOD some
\n
"
"BAD soem
\n
GOOD some
\n
"
"BAD sohw
\n
GOOD show
\n
"
"BAD soical
\n
GOOD social
\n
"
"BAD some1
\n
GOOD someone
\n
"
"BAD somethign
\n
GOOD something
\n
"
"BAD someting
\n
GOOD something
\n
"
"BAD somewaht
\n
GOOD somewhat
\n
"
"BAD somthing
\n
GOOD something
\n
"
"BAD somtimes
\n
GOOD sometimes
\n
"
"COMPLETE 0
\n
BAD sot hat
\n
GOOD so that
\n
"
"BAD soudn
\n
GOOD sound
\n
"
"BAD soudns
\n
GOOD sounds
\n
"
"BAD speach
\n
GOOD speech
\n
"
"BAD specificaly
\n
GOOD specifically
\n
"
"BAD specificalyl
\n
GOOD specifically
\n
"
"BAD spelt
\n
GOOD spelled
\n
"
"BAD sry
\n
GOOD sorry
\n
"
"COMPLETE 0
\n
BAD state of the ark
\n
GOOD state of the art
\n
"
"BAD statment
\n
GOOD statement
\n
"
"BAD statments
\n
GOOD statements
\n
"
"BAD stnad
\n
GOOD stand
\n
"
"BAD stopry
\n
GOOD story
\n
"
"BAD stoyr
\n
GOOD story
\n
"
"BAD stpo
\n
GOOD stop
\n
"
"BAD strentgh
\n
GOOD strength
\n
"
"BAD stroy
\n
GOOD story
\n
"
"BAD struggel
\n
GOOD struggle
\n
"
"BAD strugle
\n
GOOD struggle
\n
"
"BAD studnet
\n
GOOD student
\n
"
"BAD successfull
\n
GOOD successful
\n
"
"BAD successfuly
\n
GOOD successfully
\n
"
"BAD successfulyl
\n
GOOD successfully
\n
"
"BAD sucess
\n
GOOD success
\n
"
"BAD sucessfull
\n
GOOD successful
\n
"
"BAD sufficiant
\n
GOOD sufficient
\n
"
"BAD sum1
\n
GOOD someone
\n
"
"BAD sunday
\n
GOOD Sunday
\n
"
"BAD suposed
\n
GOOD supposed
\n
"
"BAD supposably
\n
GOOD supposedly
\n
"
"BAD suppossed
\n
GOOD supposed
\n
"
"BAD suprise
\n
GOOD surprise
\n
"
"BAD suprised
\n
GOOD surprised
\n
"
"BAD sux
\n
GOOD sucks
\n
"
"BAD swiming
\n
GOOD swimming
\n
"
"BAD tahn
\n
GOOD than
\n
"
"BAD taht
\n
GOOD that
\n
"
"COMPLETE 0
\n
BAD take it for granite
\n
GOOD take it for granted
\n
"
"COMPLETE 0
\n
BAD taken for granite
\n
GOOD taken for granted
\n
"
"BAD talekd
\n
GOOD talked
\n
"
"BAD talkign
\n
GOOD talking
\n
"
"BAD tath
\n
GOOD that
\n
"
"BAD tecnical
\n
GOOD technical
\n
"
"BAD teh
\n
GOOD the
\n
"
"BAD tehy
\n
GOOD they
\n
"
"COMPLETE 0
\n
BAD tellt he
\n
GOOD tell the
\n
"
"BAD termoil
\n
GOOD turmoil
\n
"
"BAD tets
\n
GOOD test
\n
"
"BAD tghe
\n
GOOD the
\n
"
"BAD tghis
\n
GOOD this
\n
"
"BAD thansk
\n
GOOD thanks
\n
"
"BAD thanx
\n
GOOD thanks
\n
"
"BAD thats
\n
GOOD that's
\n
"
"BAD thatthe
\n
GOOD that the
\n
"
"COMPLETE 0
\n
BAD thatt he
\n
GOOD that the
\n
"
"BAD thecompany
\n
GOOD the company
\n
"
"BAD thefirst
\n
GOOD the first
\n
"
"BAD thegovernment
\n
GOOD the government
\n
"
"COMPLETE 0
\n
BAD their are
\n
GOOD there are
\n
"
"COMPLETE 0
\n
BAD their aren't
\n
GOOD there aren't
\n
"
"COMPLETE 0
\n
BAD their is
\n
GOOD there is
\n
"
"BAD themself
\n
GOOD themselves
\n
"
"BAD themselfs
\n
GOOD themselves
\n
"
"BAD thenew
\n
GOOD the new
\n
"
"BAD theres
\n
GOOD there's
\n
"
"COMPLETE 0
\n
BAD there's is
\n
GOOD theirs is
\n
"
"COMPLETE 0
\n
BAD there's isn't
\n
GOOD theirs isn't
\n
"
"BAD theri
\n
GOOD their
\n
"
"BAD thesame
\n
GOOD the same
\n
"
"BAD thetwo
\n
GOOD the two
\n
"
"BAD theyd
\n
GOOD they'd
\n
"
"COMPLETE 0
\n
BAD they;d
\n
GOOD they'd
\n
"
"COMPLETE 0
\n
BAD they;l
\n
GOOD they'll
\n
"
"BAD theyll
\n
GOOD they'll
\n
"
"COMPLETE 0
\n
BAD they;ll
\n
GOOD they'll
\n
"
"COMPLETE 0
\n
BAD they;r
\n
GOOD they're
\n
"
"COMPLETE 0
\n
BAD theyre
\n
GOOD they're
\n
"
"COMPLETE 0
\n
BAD they;re
\n
GOOD they're
\n
"
"COMPLETE 0
\n
BAD they're are
\n
GOOD there are
\n
"
"COMPLETE 0
\n
BAD they're is
\n
GOOD there is
\n
"
"COMPLETE 0
\n
BAD they;v
\n
GOOD they've
\n
"
"BAD theyve
\n
GOOD they've
\n
"
"COMPLETE 0
\n
BAD they;ve
\n
GOOD they've
\n
"
"BAD thgat
\n
GOOD that
\n
"
"BAD thge
\n
GOOD the
\n
"
"BAD thier
\n
GOOD their
\n
"
"BAD thigsn
\n
GOOD things
\n
"
"BAD thisyear
\n
GOOD this year
\n
"
"BAD thme
\n
GOOD them
\n
"
"BAD thna
\n
GOOD than
\n
"
"BAD thne
\n
GOOD then
\n
"
"BAD thnig
\n
GOOD thing
\n
"
"BAD thnigs
\n
GOOD things
\n
"
"BAD tho
\n
GOOD though
\n
"
"BAD threatend
\n
GOOD threatened
\n
"
"BAD thsi
\n
GOOD this
\n
"
"BAD thsoe
\n
GOOD those
\n
"
"BAD thta
\n
GOOD that
\n
"
"BAD thursday
\n
GOOD Thursday
\n
"
"BAD thx
\n
GOOD thanks
\n
"
"BAD tihs
\n
GOOD this
\n
"
"BAD timne
\n
GOOD time
\n
"
"BAD tiogether
\n
GOOD together
\n
"
"BAD tje
\n
GOOD the
\n
"
"BAD tjhe
\n
GOOD the
\n
"
"BAD tkae
\n
GOOD take
\n
"
"BAD tkaes
\n
GOOD takes
\n
"
"BAD tkaing
\n
GOOD taking
\n
"
"BAD tlaking
\n
GOOD talking
\n
"
"BAD tnx
\n
GOOD thanks
\n
"
"BAD todya
\n
GOOD today
\n
"
"BAD togehter
\n
GOOD together
\n
"
"COMPLETE 0
\n
BAD toldt he
\n
GOOD told the
\n
"
"BAD tomorow
\n
GOOD tomorrow
\n
"
"BAD tongiht
\n
GOOD tonight
\n
"
"BAD tonihgt
\n
GOOD tonight
\n
"
"BAD tonite
\n
GOOD tonight
\n
"
"BAD totaly
\n
GOOD totally
\n
"
"BAD totalyl
\n
GOOD totally
\n
"
"BAD tothe
\n
GOOD to the
\n
"
"COMPLETE 0
\n
BAD tot he
\n
GOOD to the
\n
"
"BAD touche
\n
GOOD touch
\303\251\n
"
"BAD towrad
\n
GOOD toward
\n
"
"BAD traditionalyl
\n
GOOD traditionally
\n
"
"BAD transfered
\n
GOOD transferred
\n
"
"BAD truely
\n
GOOD truly
\n
"
"BAD truley
\n
GOOD truly
\n
"
"BAD tryed
\n
GOOD tried
\n
"
"BAD tthe
\n
GOOD the
\n
"
"BAD tuesday
\n
GOOD Tuesday
\n
"
"BAD tyhat
\n
GOOD that
\n
"
"BAD tyhe
\n
GOOD the
\n
"
"BAD u
\n
GOOD you
\n
"
"BAD udnerstand
\n
GOOD understand
\n
"
"BAD understnad
\n
GOOD understand
\n
"
"COMPLETE 0
\n
BAD undert he
\n
GOOD under the
\n
"
"BAD unforseen
\n
GOOD unforeseen
\n
"
"BAD UnitedStates
\n
GOOD United States
\n
"
"BAD unliek
\n
GOOD unlike
\n
"
"BAD unpleasently
\n
GOOD unpleasantly
\n
"
"BAD untill
\n
GOOD until
\n
"
"BAD untilll
\n
GOOD until
\n
"
"BAD ur
\n
GOOD you are
\n
"
"BAD useing
\n
GOOD using
\n
"
"BAD usualyl
\n
GOOD usually
\n
"
"BAD veyr
\n
GOOD very
\n
"
"BAD virtualyl
\n
GOOD virtually
\n
"
"BAD visavis
\n
GOOD vis-a-vis
\n
"
"COMPLETE 0
\n
BAD vis-a-vis
\n
GOOD vis-
\303\240
-vis
\n
"
"BAD vrey
\n
GOOD very
\n
"
"BAD vulnerible
\n
GOOD vulnerable
\n
"
"BAD waht
\n
GOOD what
\n
"
"BAD warrent
\n
GOOD warrant
\n
"
"COMPLETE 0
\n
BAD wa snot
\n
GOOD was not
\n
"
"COMPLETE 0
\n
BAD wasnt
\n
GOOD wasn't
\n
"
"COMPLETE 0
\n
BAD wasn;t
\n
GOOD wasn't
\n
"
"BAD wat
\n
GOOD what
\n
"
"BAD watn
\n
GOOD want
\n
"
"COMPLETE 0
\n
BAD we;d
\n
GOOD we'd
\n
"
"BAD wednesday
\n
GOOD Wednesday
\n
"
"BAD wehn
\n
GOOD when
\n
"
"COMPLETE 0
\n
BAD we'l
\n
GOOD we'll
\n
"
"COMPLETE 0
\n
BAD we;ll
\n
GOOD we'll
\n
"
"COMPLETE 0
\n
BAD we;re
\n
GOOD we're
\n
"
"BAD werent
\n
GOOD weren't
\n
"
"COMPLETE 0
\n
BAD weren;t
\n
GOOD weren't
\n
"
"COMPLETE 0
\n
BAD wern't
\n
GOOD weren't
\n
"
"BAD werre
\n
GOOD were
\n
"
"BAD weve
\n
GOOD we've
\n
"
"COMPLETE 0
\n
BAD we;ve
\n
GOOD we've
\n
"
"BAD whats
\n
GOOD what's
\n
"
"COMPLETE 0
\n
BAD what;s
\n
GOOD what's
\n
"
"BAD whcih
\n
GOOD which
\n
"
"COMPLETE 0
\n
BAD whent he
\n
GOOD when the
\n
"
"BAD wheres
\n
GOOD where's
\n
"
"COMPLETE 0
\n
BAD where;s
\n
GOOD where's
\n
"
"BAD wherre
\n
GOOD where
\n
"
"BAD whic
\n
GOOD which
\n
"
"COMPLETE 0
\n
BAD whicht he
\n
GOOD which the
\n
"
"BAD whihc
\n
GOOD which
\n
"
"BAD wholl
\n
GOOD who'll
\n
"
"BAD whos
\n
GOOD who's
\n
"
"COMPLETE 0
\n
BAD who;s
\n
GOOD who's
\n
"
"BAD whove
\n
GOOD who've
\n
"
"COMPLETE 0
\n
BAD who;ve
\n
GOOD who've
\n
"
"BAD whta
\n
GOOD what
\n
"
"BAD whys
\n
GOOD why's
\n
"
"BAD wief
\n
GOOD wife
\n
"
"BAD wierd
\n
GOOD weird
\n
"
"BAD wihch
\n
GOOD which
\n
"
"BAD wiht
\n
GOOD with
\n
"
"BAD willbe
\n
GOOD will be
\n
"
"COMPLETE 0
\n
BAD will of been
\n
GOOD will have been
\n
"
"COMPLETE 0
\n
BAD will of had
\n
GOOD will have had
\n
"
"BAD windoes
\n
GOOD windows
\n
"
"BAD witha
\n
GOOD with a
\n
"
"BAD withdrawl
\n
GOOD withdrawal
\n
"
"BAD withe
\n
GOOD with
\n
"
"COMPLETE 0
\n
BAD withthe
\n
GOOD with the
\n
"
"BAD witht he
\n
GOOD with the
\n
"
"BAD wiull
\n
GOOD will
\n
"
"BAD wnat
\n
GOOD want
\n
"
"BAD wnated
\n
GOOD wanted
\n
"
"BAD wnats
\n
GOOD wants
\n
"
"BAD woh
\n
GOOD who
\n
"
"BAD wohle
\n
GOOD whole
\n
"
"BAD wokr
\n
GOOD work
\n
"
"BAD wont
\n
GOOD won't
\n
"
"COMPLETE 0
\n
BAD wo'nt
\n
GOOD won't
\n
"
"COMPLETE 0
\n
BAD won;t
\n
GOOD won't
\n
"
"BAD woudl
\n
GOOD would
\n
"
"COMPLETE 0
\n
BAD woudln't
\n
GOOD wouldn't
\n
"
"BAD wouldbe
\n
GOOD would be
\n
"
"BAD wouldnt
\n
GOOD wouldn't
\n
"
"COMPLETE 0
\n
BAD wouldn;t
\n
GOOD wouldn't
\n
"
"COMPLETE 0
\n
BAD would of been
\n
GOOD would have been
\n
"
"COMPLETE 0
\n
BAD would of had
\n
GOOD would have had
\n
"
"BAD wouldve
\n
GOOD would've
\n
"
"BAD wriet
\n
GOOD write
\n
"
"BAD writting
\n
GOOD writing
\n
"
"BAD wrod
\n
GOOD word
\n
"
"BAD wroet
\n
GOOD wrote
\n
"
"BAD wroking
\n
GOOD working
\n
"
"BAD wtih
\n
GOOD with
\n
"
"BAD wuould
\n
GOOD would
\n
"
"BAD wud
\n
GOOD would
\n
"
"BAD wut
\n
GOOD what
\n
"
"BAD wya
\n
GOOD way
\n
"
"BAD y
\n
GOOD why
\n
"
"BAD yeh
\n
GOOD yeah
\n
"
"BAD yera
\n
GOOD year
\n
"
"BAD yeras
\n
GOOD years
\n
"
"BAD yersa
\n
GOOD years
\n
"
"BAD yoiu
\n
GOOD you
\n
"
"BAD youare
\n
GOOD you are
\n
"
"BAD youd
\n
GOOD you'd
\n
"
"COMPLETE 0
\n
BAD you;d
\n
GOOD you'd
\n
"
"BAD youll
\n
GOOD you'll
\n
"
"COMPLETE 0
\n
BAD your a
\n
GOOD you're a
\n
"
"COMPLETE 0
\n
BAD your an
\n
GOOD you're an
\n
"
"BAD youre
\n
GOOD you're
\n
"
"COMPLETE 0
\n
BAD you;re
\n
GOOD you're
\n
"
"COMPLETE 0
\n
BAD you're own
\n
GOOD your own
\n
"
"COMPLETE 0
\n
BAD your her
\n
GOOD you're her
\n
"
"COMPLETE 0
\n
BAD your here
\n
GOOD you're here
\n
"
"COMPLETE 0
\n
BAD your his
\n
GOOD you're his
\n
"
"COMPLETE 0
\n
BAD your my
\n
GOOD you're my
\n
"
"COMPLETE 0
\n
BAD your the
\n
GOOD you're the
\n
"
"COMPLETE 0
\n
BAD your their
\n
GOOD you're their
\n
"
"COMPLETE 0
\n
BAD your your
\n
GOOD you're your
\n
"
"BAD youve
\n
GOOD you've
\n
"
"COMPLETE 0
\n
BAD you;ve
\n
GOOD you've
\n
"
"BAD ytou
\n
GOOD you
\n
"
"BAD yuo
\n
GOOD you
\n
"
"BAD yuor
\n
GOOD your
\n
"
;
gchar
*
buf
;
gchar
*
ibuf
;
GHashTable
*
hashes
;
char
bad
[
82
]
=
""
;
char
good
[
256
]
=
""
;
gsize
pnt
=
0
;
gsize
size
;
gboolean
complete
=
TRUE
;
gboolean
case_sensitive
=
FALSE
;
buf
=
g_build_filename
(
purple_config_dir
(),
"dict"
,
NULL
);
if
(
!
(
g_file_get_contents
(
buf
,
&
ibuf
,
&
size
,
NULL
)
&&
ibuf
))
{
ibuf
=
g_strdup
(
defaultconf
);
size
=
strlen
(
defaultconf
);
}
g_free
(
buf
);
model
=
gtk_list_store_new
((
gint
)
N_COLUMNS
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_BOOLEAN
,
G_TYPE_BOOLEAN
);
hashes
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
while
(
ibuf
&&
buf_get_line
(
ibuf
,
&
buf
,
&
pnt
,
size
))
{
if
(
*
buf
!=
'#'
)
{
if
(
!
g_ascii_strncasecmp
(
buf
,
"BAD "
,
4
))
{
strncpy
(
bad
,
buf
+
4
,
81
);
}
else
if
(
!
g_ascii_strncasecmp
(
buf
,
"CASE "
,
5
))
{
case_sensitive
=
*
(
buf
+
5
)
==
'0'
?
FALSE
:
TRUE
;
}
else
if
(
!
g_ascii_strncasecmp
(
buf
,
"COMPLETE "
,
9
))
{
complete
=
*
(
buf
+
9
)
==
'0'
?
FALSE
:
TRUE
;
}
else
if
(
!
g_ascii_strncasecmp
(
buf
,
"GOOD "
,
5
))
{
strncpy
(
good
,
buf
+
5
,
255
);
if
(
*
bad
&&
*
good
&&
g_hash_table_lookup
(
hashes
,
bad
)
==
NULL
)
{
GtkTreeIter
iter
;
/* We don't actually need to store the good string, since this
* hash is just being used to eliminate duplicate bad strings.
* The value has to be non-NULL so the lookup above will work.
*/
g_hash_table_insert
(
hashes
,
g_strdup
(
bad
),
GINT_TO_POINTER
(
1
));
if
(
!
complete
)
case_sensitive
=
TRUE
;
gtk_list_store_append
(
model
,
&
iter
);
gtk_list_store_set
(
model
,
&
iter
,
BAD_COLUMN
,
bad
,
GOOD_COLUMN
,
good
,
WORD_ONLY_COLUMN
,
complete
,
CASE_SENSITIVE_COLUMN
,
case_sensitive
,
-1
);
}
bad
[
0
]
=
'\0'
;
complete
=
TRUE
;
case_sensitive
=
FALSE
;
}
}
}
g_free
(
ibuf
);
g_hash_table_destroy
(
hashes
);
gtk_tree_sortable_set_sort_column_id
(
GTK_TREE_SORTABLE
(
model
),
0
,
GTK_SORT_ASCENDING
);
}
static
GtkWidget
*
tree
;
static
GtkWidget
*
bad_entry
;
static
GtkWidget
*
good_entry
;
static
GtkWidget
*
complete_toggle
;
static
GtkWidget
*
case_toggle
;
static
void
save_list
(
void
);
static
void
on_edited
(
GtkCellRendererText
*
cellrenderertext
,
gchar
*
path
,
gchar
*
arg2
,
gpointer
data
)
{
GtkTreeIter
iter
;
GValue
val
;
if
(
arg2
[
0
]
==
'\0'
)
{
gdk_beep
();
return
;
}
g_return_if_fail
(
gtk_tree_model_get_iter_from_string
(
GTK_TREE_MODEL
(
model
),
&
iter
,
path
));
val
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
GPOINTER_TO_INT
(
data
),
&
val
);
if
(
!
purple_strequal
(
arg2
,
g_value_get_string
(
&
val
)))
{
gtk_list_store_set
(
model
,
&
iter
,
GPOINTER_TO_INT
(
data
),
arg2
,
-1
);
save_list
();
}
g_value_unset
(
&
val
);
}
static
void
word_only_toggled
(
GtkCellRendererToggle
*
cellrenderertoggle
,
gchar
*
path
,
gpointer
data
){
GtkTreeIter
iter
;
gboolean
enabled
;
g_return_if_fail
(
gtk_tree_model_get_iter_from_string
(
GTK_TREE_MODEL
(
model
),
&
iter
,
path
));
gtk_tree_model_get
(
GTK_TREE_MODEL
(
model
),
&
iter
,
WORD_ONLY_COLUMN
,
&
enabled
,
-1
);
gtk_list_store_set
(
GTK_LIST_STORE
(
model
),
&
iter
,
WORD_ONLY_COLUMN
,
!
enabled
,
-1
);
/* I want to be sure that the above change has happened to the GtkTreeView first. */
gtk_list_store_set
(
GTK_LIST_STORE
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
enabled
,
-1
);
save_list
();
}
static
void
case_sensitive_toggled
(
GtkCellRendererToggle
*
cellrenderertoggle
,
gchar
*
path
,
gpointer
data
){
GtkTreeIter
iter
;
gboolean
enabled
;
g_return_if_fail
(
gtk_tree_model_get_iter_from_string
(
GTK_TREE_MODEL
(
model
),
&
iter
,
path
));
/* Prevent the case sensitive column from changing on non-whole word replacements.
* Ideally, the column would be set insensitive in the word_only_toggled callback. */
gtk_tree_model_get
(
GTK_TREE_MODEL
(
model
),
&
iter
,
WORD_ONLY_COLUMN
,
&
enabled
,
-1
);
if
(
!
enabled
)
return
;
gtk_tree_model_get
(
GTK_TREE_MODEL
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
&
enabled
,
-1
);
gtk_list_store_set
(
GTK_LIST_STORE
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
!
enabled
,
-1
);
save_list
();
}
static
void
list_add_new
(
void
)
{
GtkTreeIter
iter
;
const
char
*
word
=
gtk_entry_get_text
(
GTK_ENTRY
(
bad_entry
));
gboolean
case_sensitive
=
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
case_toggle
));
if
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
model
),
&
iter
))
{
char
*
tmpword
=
g_utf8_casefold
(
word
,
-1
);
do
{
GValue
bad_val
;
gboolean
match
;
bad_val
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
BAD_COLUMN
,
&
bad_val
);
if
(
case_sensitive
)
{
GValue
case_sensitive_val
;
case_sensitive_val
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
&
case_sensitive_val
);
/* If they're both case-sensitive, then compare directly.
* Otherwise, they overlap. */
if
(
g_value_get_boolean
(
&
case_sensitive_val
))
{
match
=
purple_strequal
(
g_value_get_string
(
&
bad_val
),
word
);
}
else
{
char
*
bad
=
g_utf8_casefold
(
g_value_get_string
(
&
bad_val
),
-1
);
match
=
purple_strequal
(
bad
,
tmpword
);
g_free
(
bad
);
}
g_value_unset
(
&
case_sensitive_val
);
}
else
{
char
*
bad
=
g_utf8_casefold
(
g_value_get_string
(
&
bad_val
),
-1
);
match
=
purple_strequal
(
bad
,
tmpword
);
g_free
(
bad
);
}
if
(
match
)
{
g_value_unset
(
&
bad_val
);
g_free
(
tmpword
);
purple_notify_error
(
NULL
,
_
(
"Duplicate Correction"
),
_
(
"The specified word already exists in the correction list."
),
gtk_entry_get_text
(
GTK_ENTRY
(
bad_entry
)),
NULL
);
return
;
}
g_value_unset
(
&
bad_val
);
}
while
(
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
model
),
&
iter
));
g_free
(
tmpword
);
}
gtk_list_store_append
(
model
,
&
iter
);
gtk_list_store_set
(
model
,
&
iter
,
BAD_COLUMN
,
word
,
GOOD_COLUMN
,
gtk_entry_get_text
(
GTK_ENTRY
(
good_entry
)),
WORD_ONLY_COLUMN
,
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
complete_toggle
)),
CASE_SENSITIVE_COLUMN
,
case_sensitive
,
-1
);
gtk_editable_delete_text
(
GTK_EDITABLE
(
bad_entry
),
0
,
-1
);
gtk_editable_delete_text
(
GTK_EDITABLE
(
good_entry
),
0
,
-1
);
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
complete_toggle
),
TRUE
);
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
case_toggle
),
FALSE
);
gtk_widget_grab_focus
(
bad_entry
);
save_list
();
}
static
void
add_selected_row_to_list
(
GtkTreeModel
*
model
,
GtkTreePath
*
path
,
GtkTreeIter
*
iter
,
gpointer
data
)
{
GtkTreeRowReference
*
row_reference
;
GSList
**
list
=
(
GSList
**
)
data
;
row_reference
=
gtk_tree_row_reference_new
(
model
,
path
);
*
list
=
g_slist_prepend
(
*
list
,
row_reference
);
}
static
void
remove_row
(
gpointer
data
)
{
GtkTreeRowReference
*
row_reference
=
(
GtkTreeRowReference
*
)
data
;
GtkTreePath
*
path
;
GtkTreeIter
iter
;
path
=
gtk_tree_row_reference_get_path
(
row_reference
);
if
(
gtk_tree_model_get_iter
(
GTK_TREE_MODEL
(
model
),
&
iter
,
path
))
gtk_list_store_remove
(
model
,
&
iter
);
gtk_tree_path_free
(
path
);
gtk_tree_row_reference_free
(
row_reference
);
}
static
void
list_delete
(
void
)
{
GtkTreeSelection
*
sel
;
GSList
*
list
=
NULL
;
sel
=
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
tree
));
gtk_tree_selection_selected_foreach
(
sel
,
add_selected_row_to_list
,
&
list
);
g_slist_free_full
(
list
,
remove_row
);
save_list
();
}
static
void
save_list
()
{
GString
*
data
;
GtkTreeIter
iter
;
data
=
g_string_new
(
""
);
if
(
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
model
),
&
iter
))
{
do
{
GValue
val0
;
GValue
val1
;
GValue
val2
;
GValue
val3
;
val0
.
g_type
=
0
;
val1
.
g_type
=
0
;
val2
.
g_type
=
0
;
val3
.
g_type
=
0
;
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
BAD_COLUMN
,
&
val0
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
GOOD_COLUMN
,
&
val1
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
WORD_ONLY_COLUMN
,
&
val2
);
gtk_tree_model_get_value
(
GTK_TREE_MODEL
(
model
),
&
iter
,
CASE_SENSITIVE_COLUMN
,
&
val3
);
g_string_append_printf
(
data
,
"COMPLETE %d
\n
CASE %d
\n
BAD %s
\n
GOOD %s
\n\n
"
,
g_value_get_boolean
(
&
val2
),
g_value_get_boolean
(
&
val3
),
g_value_get_string
(
&
val0
),
g_value_get_string
(
&
val1
));
g_value_unset
(
&
val0
);
g_value_unset
(
&
val1
);
g_value_unset
(
&
val2
);
g_value_unset
(
&
val3
);
}
while
(
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
model
),
&
iter
));
}
purple_util_write_data_to_config_file
(
"dict"
,
data
->
str
,
-1
);
g_string_free
(
data
,
TRUE
);
}
static
void
on_selection_changed
(
GtkTreeSelection
*
sel
,
gpointer
data
)
{
gint
num_selected
;
num_selected
=
gtk_tree_selection_count_selected_rows
(
sel
);
gtk_widget_set_sensitive
((
GtkWidget
*
)
data
,
(
num_selected
>
0
));
}
static
gboolean
non_empty
(
const
char
*
s
)
{
while
(
*
s
&&
g_ascii_isspace
(
*
s
))
s
++
;
return
*
s
;
}
static
void
on_entry_changed
(
GtkEditable
*
editable
,
gpointer
data
)
{
gtk_widget_set_sensitive
((
GtkWidget
*
)
data
,
non_empty
(
gtk_entry_get_text
(
GTK_ENTRY
(
bad_entry
)))
&&
non_empty
(
gtk_entry_get_text
(
GTK_ENTRY
(
good_entry
))));
}
static
void
whole_words_button_toggled
(
GtkToggleButton
*
complete_toggle
,
GtkToggleButton
*
case_toggle
)
{
gboolean
enabled
=
gtk_toggle_button_get_active
(
complete_toggle
);
gtk_toggle_button_set_active
(
case_toggle
,
!
enabled
);
gtk_widget_set_sensitive
(
GTK_WIDGET
(
case_toggle
),
enabled
);
}
static
GtkWidget
*
get_config_frame
(
PurplePlugin
*
plugin
)
{
GtkWidget
*
ret
,
*
vbox
;
GtkWidget
*
hbox
;
GtkWidget
*
button
;
GtkSizeGroup
*
sg
;
GtkSizeGroup
*
sg2
;
GtkCellRenderer
*
renderer
;
GtkTreeViewColumn
*
column
;
GtkWidget
*
vbox2
;
GtkWidget
*
vbox3
;
ret
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
18
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
ret
),
12
);
vbox
=
pidgin_make_frame
(
ret
,
_
(
"Text Replacements"
));
gtk_container_set_border_width
(
GTK_CONTAINER
(
vbox
),
4
);
gtk_widget_show
(
vbox
);
tree
=
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
model
));
gtk_widget_set_size_request
(
tree
,
-1
,
200
);
renderer
=
gtk_cell_renderer_text_new
();
g_object_set
(
G_OBJECT
(
renderer
),
"editable"
,
TRUE
,
NULL
);
g_signal_connect
(
G_OBJECT
(
renderer
),
"edited"
,
G_CALLBACK
(
on_edited
),
GINT_TO_POINTER
(
0
));
column
=
gtk_tree_view_column_new_with_attributes
(
_
(
"You type"
),
renderer
,
"text"
,
BAD_COLUMN
,
NULL
);
gtk_tree_view_column_set_sizing
(
column
,
GTK_TREE_VIEW_COLUMN_FIXED
);
gtk_tree_view_column_set_fixed_width
(
column
,
150
);
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
tree
),
column
);
renderer
=
gtk_cell_renderer_text_new
();
g_object_set
(
G_OBJECT
(
renderer
),
"editable"
,
TRUE
,
NULL
);
g_signal_connect
(
G_OBJECT
(
renderer
),
"edited"
,
G_CALLBACK
(
on_edited
),
GINT_TO_POINTER
(
1
));
column
=
gtk_tree_view_column_new_with_attributes
(
_
(
"You send"
),
renderer
,
"text"
,
GOOD_COLUMN
,
NULL
);
gtk_tree_view_column_set_sizing
(
column
,
GTK_TREE_VIEW_COLUMN_FIXED
);
gtk_tree_view_column_set_fixed_width
(
column
,
150
);
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
tree
),
column
);
renderer
=
gtk_cell_renderer_toggle_new
();
g_object_set
(
G_OBJECT
(
renderer
),
"activatable"
,
TRUE
,
NULL
);
g_signal_connect
(
G_OBJECT
(
renderer
),
"toggled"
,
G_CALLBACK
(
word_only_toggled
),
NULL
);
column
=
gtk_tree_view_column_new_with_attributes
(
_
(
"Whole words only"
),
renderer
,
"active"
,
WORD_ONLY_COLUMN
,
NULL
);
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
tree
),
column
);
renderer
=
gtk_cell_renderer_toggle_new
();
g_object_set
(
G_OBJECT
(
renderer
),
"activatable"
,
TRUE
,
NULL
);
g_signal_connect
(
G_OBJECT
(
renderer
),
"toggled"
,
G_CALLBACK
(
case_sensitive_toggled
),
NULL
);
column
=
gtk_tree_view_column_new_with_attributes
(
_
(
"Case sensitive"
),
renderer
,
"active"
,
CASE_SENSITIVE_COLUMN
,
NULL
);
gtk_tree_view_column_set_resizable
(
column
,
TRUE
);
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
tree
),
column
);
gtk_tree_selection_set_mode
(
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
tree
)),
GTK_SELECTION_MULTIPLE
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
pidgin_make_scrollable
(
tree
,
GTK_POLICY_NEVER
,
GTK_POLICY_ALWAYS
,
GTK_SHADOW_IN
,
-1
,
-1
),
TRUE
,
TRUE
,
0
);
gtk_widget_show
(
tree
);
hbox
=
gtk_button_box_new
(
GTK_ORIENTATION_HORIZONTAL
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
hbox
,
FALSE
,
FALSE
,
0
);
gtk_widget_show
(
hbox
);
button
=
gtk_button_new_with_mnemonic
(
_
(
"_Delete"
));
g_signal_connect
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
list_delete
),
NULL
);
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
button
,
FALSE
,
FALSE
,
0
);
gtk_widget_set_sensitive
(
button
,
FALSE
);
g_signal_connect
(
G_OBJECT
(
gtk_tree_view_get_selection
(
GTK_TREE_VIEW
(
tree
))),
"changed"
,
G_CALLBACK
(
on_selection_changed
),
button
);
gtk_widget_show
(
button
);
vbox
=
pidgin_make_frame
(
ret
,
_
(
"Add a new text replacement"
));
hbox
=
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
6
);
gtk_box_pack_start
(
GTK_BOX
(
vbox
),
hbox
,
TRUE
,
TRUE
,
0
);
gtk_widget_show
(
hbox
);
vbox2
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
6
);
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
vbox2
,
TRUE
,
TRUE
,
0
);
gtk_widget_show
(
vbox2
);
sg
=
gtk_size_group_new
(
GTK_SIZE_GROUP_HORIZONTAL
);
sg2
=
gtk_size_group_new
(
GTK_SIZE_GROUP_HORIZONTAL
);
bad_entry
=
gtk_entry_new
();
/* Set a minimum size. Since they're in a size group, the other entry will match up. */
gtk_widget_set_size_request
(
bad_entry
,
350
,
-1
);
gtk_size_group_add_widget
(
sg2
,
bad_entry
);
pidgin_add_widget_to_vbox
(
GTK_BOX
(
vbox2
),
_
(
"You _type:"
),
sg
,
bad_entry
,
FALSE
,
NULL
);
good_entry
=
gtk_entry_new
();
gtk_size_group_add_widget
(
sg2
,
good_entry
);
pidgin_add_widget_to_vbox
(
GTK_BOX
(
vbox2
),
_
(
"You _send:"
),
sg
,
good_entry
,
FALSE
,
NULL
);
/* Created here so it can be passed to whole_words_button_toggled. */
case_toggle
=
gtk_check_button_new_with_mnemonic
(
_
(
"_Exact case match (uncheck for automatic case handling)"
));
complete_toggle
=
gtk_check_button_new_with_mnemonic
(
_
(
"Only replace _whole words"
));
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
complete_toggle
),
TRUE
);
g_signal_connect
(
G_OBJECT
(
complete_toggle
),
"clicked"
,
G_CALLBACK
(
whole_words_button_toggled
),
case_toggle
);
gtk_widget_show
(
complete_toggle
);
gtk_box_pack_start
(
GTK_BOX
(
vbox2
),
complete_toggle
,
FALSE
,
FALSE
,
0
);
/* The button is created above so it can be passed to whole_words_button_toggled. */
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
case_toggle
),
FALSE
);
gtk_widget_show
(
case_toggle
);
gtk_box_pack_start
(
GTK_BOX
(
vbox2
),
case_toggle
,
FALSE
,
FALSE
,
0
);
button
=
gtk_button_new_with_mnemonic
(
_
(
"_Add"
));
g_signal_connect
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
list_add_new
),
NULL
);
vbox3
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
0
);
gtk_box_pack_start
(
GTK_BOX
(
hbox
),
vbox3
,
TRUE
,
FALSE
,
0
);
gtk_widget_show
(
vbox3
);
gtk_box_pack_end
(
GTK_BOX
(
vbox3
),
button
,
FALSE
,
FALSE
,
0
);
g_signal_connect
(
G_OBJECT
(
bad_entry
),
"changed"
,
G_CALLBACK
(
on_entry_changed
),
button
);
g_signal_connect
(
G_OBJECT
(
good_entry
),
"changed"
,
G_CALLBACK
(
on_entry_changed
),
button
);
gtk_widget_set_sensitive
(
button
,
FALSE
);
gtk_widget_show
(
button
);
#if 0
vbox = pidgin_make_frame(ret, _("General Text Replacement Options"));
pidgin_prefs_checkbox(_("Enable replacement of last word on send"),
"/plugins/gtk/spellchk/last_word_replace", vbox);
#endif
gtk_widget_show_all
(
ret
);
g_object_unref
(
sg
);
g_object_unref
(
sg2
);
return
ret
;
}
/*
* EXPORTED FUNCTIONS
*/
static
PidginPluginInfo
*
plugin_query
(
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
{
"Eric Warmenhoven <eric@warmenhoven.org>"
,
NULL
};
return
pidgin_plugin_info_new
(
"id"
,
SPELLCHECK_PLUGIN_ID
,
"name"
,
N_
(
"Text replacement"
),
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Utility"
),
"summary"
,
N_
(
"Replaces text in outgoing messages according to user-defined rules."
),
"description"
,
N_
(
"Replaces text in outgoing messages according to user-defined rules."
),
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"gtk-config-frame-cb"
,
get_config_frame
,
NULL
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
void
*
conv_handle
=
purple_conversations_get_handle
();
GList
*
convs
;
#if 0
purple_prefs_add_none("/plugins");
purple_prefs_add_none("/plugins/gtk");
purple_prefs_add_none("/plugins/gtk/spellchk");
purple_prefs_add_bool("/plugins/gtk/spellchk/last_word_replace", TRUE);
#endif
load_conf
();
/* Attach to existing conversations */
for
(
convs
=
purple_conversations_get_all
();
convs
!=
NULL
;
convs
=
convs
->
next
)
{
spellchk_new_attach
((
PurpleConversation
*
)
convs
->
data
);
}
purple_signal_connect
(
conv_handle
,
"conversation-created"
,
plugin
,
PURPLE_CALLBACK
(
spellchk_new_attach
),
NULL
);
return
TRUE
;
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
GList
*
convs
;
/* Detach from existing conversations */
for
(
convs
=
purple_conversations_get_all
();
convs
!=
NULL
;
convs
=
convs
->
next
)
{
PidginConversation
*
gtkconv
=
PIDGIN_CONVERSATION
((
PurpleConversation
*
)
convs
->
data
);
spellchk
*
spell
=
g_object_get_data
(
G_OBJECT
(
gtkconv
->
entry
),
SPELLCHK_OBJECT_KEY
);
g_signal_handlers_disconnect_by_func
(
gtkconv
->
entry
,
message_send_cb
,
spell
);
g_object_set_data
(
G_OBJECT
(
gtkconv
->
entry
),
SPELLCHK_OBJECT_KEY
,
NULL
);
}
return
TRUE
;
}
PURPLE_PLUGIN_INIT
(
spellcheck
,
plugin_query
,
plugin_load
,
plugin_unload
);