Skip to content
Snippets Groups Projects
Commit da6e7e39 authored by Eike Cochu's avatar Eike Cochu
Browse files

fixed data dir resolution

moved filebase implementation from util to cmd, it is analyzer sensitive
moved exceptions to ex package
added high precision time measurements
simplified import command
deleted stopwords.txt, using hardcoded variant
parent 4e3e7131
Branches
No related tags found
No related merge requests found
Showing
with 485 additions and 313 deletions
......@@ -271,6 +271,15 @@
},
"buffers":
[
{
"contents": "1. import all new articles:\n * generate article statistics\n * into database\n * into filebase, using filebase adapter of selected tm library\n2. recreate topic modeling, using selected tm library\n * needs no articles in memory, works completely on files\n3. insert new topic model into database\n * how to interpret tm result?\n * how to relate tm result to articles?\n4. index new articles\n * needs title, processed text and topics\n\nfilebase writes into single file according to tm library\nneeds index where articles are stored in the file\n\nall new articles are held in memory?\n\noriginal text is not needed except for stats (original text length) and for db for ui browsing",
"settings":
{
"buffer_size": 675,
"line_ending": "Unix",
"name": "1. import all new articles:"
}
}
],
"build_system": "",
"build_system_choices":
......@@ -892,8 +901,97 @@
"groups":
[
{
"selected": 0,
"sheets":
[
{
"buffer": 0,
"semi_transient": false,
"settings":
{
"buffer_size": 675,
"regions":
{
},
"selection":
[
[
579,
579
]
],
"settings":
{
"BracketHighlighterBusy": false,
"auto_name": "1. import all new articles:",
"bh_regions":
[
"bh_default",
"bh_default_center",
"bh_default_open",
"bh_default_close",
"bh_default_content",
"bh_square",
"bh_square_center",
"bh_square_open",
"bh_square_close",
"bh_square_content",
"bh_round",
"bh_round_center",
"bh_round_open",
"bh_round_close",
"bh_round_content",
"bh_c_define",
"bh_c_define_center",
"bh_c_define_open",
"bh_c_define_close",
"bh_c_define_content",
"bh_single_quote",
"bh_single_quote_center",
"bh_single_quote_open",
"bh_single_quote_close",
"bh_single_quote_content",
"bh_double_quote",
"bh_double_quote_center",
"bh_double_quote_open",
"bh_double_quote_close",
"bh_double_quote_content",
"bh_angle",
"bh_angle_center",
"bh_angle_open",
"bh_angle_close",
"bh_angle_content",
"bh_tag",
"bh_tag_center",
"bh_tag_open",
"bh_tag_close",
"bh_tag_content",
"bh_regex",
"bh_regex_center",
"bh_regex_open",
"bh_regex_close",
"bh_regex_content",
"bh_unmatched",
"bh_unmatched_center",
"bh_unmatched_open",
"bh_unmatched_close",
"bh_unmatched_content",
"bh_curly",
"bh_curly_center",
"bh_curly_open",
"bh_curly_close",
"bh_curly_content"
],
"incomplete_sync": null,
"syntax": "Packages/Text/Plain text.tmLanguage"
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 0,
"type": "text"
}
]
}
],
......
......@@ -14,7 +14,7 @@ org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
......@@ -22,7 +22,7 @@ org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=49
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
......@@ -31,7 +31,7 @@ org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
......
......@@ -12,10 +12,13 @@ import org.slf4j.LoggerFactory;
import de.vipra.cmd.option.Command;
import de.vipra.cmd.option.DeleteCommand;
import de.vipra.cmd.option.ImportCommand;
import de.vipra.util.StringUtils;
import de.vipra.util.Timer;
public class Main {
public static final Logger log = LoggerFactory.getLogger(Main.class);
public static final Logger out = LoggerFactory.getLogger("shellout");
public static void main(String[] args) {
CommandLineParser parser = new DefaultParser();
......@@ -49,7 +52,11 @@ public class Main {
}
if (c != null) {
Timer t = new Timer();
t.start();
c.run();
long dur = t.stop();
out.info("done in " + StringUtils.timeString(dur));
} else {
options.printHelp(cmd);
}
......
package de.vipra.util.ex;
package de.vipra.cmd.ex;
public class FilebaseException extends Exception {
......
package de.vipra.cmd.ex;
public class ImportException extends Exception {
private static final long serialVersionUID = 1L;
private final String id;
public ImportException(String msg, String id) {
super(msg);
this.id = id;
}
public ImportException(Exception e, String id) {
super(e);
this.id = id;
}
public String getId() {
return id;
}
}
package de.vipra.cmd.lda;
package de.vipra.cmd.ex;
public class LDAAnalyzerException extends Exception {
......
package de.vipra.cmd.text;
package de.vipra.cmd.ex;
public class PreprocessorException extends Exception {
......
package de.vipra.cmd.file;
import java.io.File;
import java.io.IOException;
import de.vipra.cmd.ex.FilebaseException;
import de.vipra.cmd.model.Article;
import de.vipra.util.Config;
import de.vipra.util.Config.Key;
import de.vipra.util.ex.ConfigException;
public abstract class Filebase {
private final File dataDir;
private final FilebaseIndex index;
public Filebase(File dataDir) throws FilebaseException {
this.dataDir = dataDir;
try {
this.index = new FilebaseIndex(new File(dataDir, "asd"));
} catch (IOException e) {
throw new FilebaseException("could not read index: " + e.getMessage());
}
}
public File getDataDir() {
return dataDir;
}
public void writeIndex() throws IOException {
index.write();
}
public void remove(Article article) throws FilebaseException {
remove(article.getId());
}
public abstract void add(Article article) throws FilebaseException;
public abstract void remove(String id) throws FilebaseException;
public abstract void write() throws IOException;
public static Filebase getFilebase(Config config) throws FilebaseException, ConfigException {
File dataDir = config.getDataDirectory();
switch (config.getString(Key.ANALYZER).toLowerCase()) {
case "ldac":
return new LdacFilebase(dataDir);
case "jgibb":
default:
return new JGibbFilebase(dataDir);
}
}
}
package de.vipra.cmd.file;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.vipra.util.Constants;
import de.vipra.util.FileUtils;
public class FilebaseIndex {
private final File file;
private final List<String> index;
public FilebaseIndex(File file) throws IOException {
this.file = file;
if (file.exists()) {
index = new ArrayList<>(FileUtils.readFile(file));
} else {
index = new ArrayList<>();
}
}
public void write() throws IOException {
FileUtils.writeLines(file, Constants.FB_ENCODING.name(), index, null, false);
}
public int add(String id) {
int i = indexOf(id);
if (i == -1) {
index.add(id);
i = index.size() - 1;
}
return i;
}
public int indexOf(String id) {
return index.indexOf(id);
}
public boolean remove(String id) {
return index.remove(id);
}
}
package de.vipra.cmd.file;
import java.io.File;
import java.io.IOException;
import de.vipra.cmd.ex.FilebaseException;
import de.vipra.cmd.model.Article;
public class JGibbFilebase extends Filebase {
public JGibbFilebase(File dataDir) throws FilebaseException {
super(dataDir);
// TODO Auto-generated constructor stub
}
@Override
public void add(Article article) {
// TODO Auto-generated method stub
}
@Override
public void remove(String id) {
// TODO Auto-generated method stub
}
@Override
public void write() throws IOException {
writeIndex();
}
}
package de.vipra.cmd.file;
import java.io.File;
import java.io.IOException;
import de.vipra.cmd.ex.FilebaseException;
import de.vipra.cmd.model.Article;
public class LdacFilebase extends Filebase {
public LdacFilebase(File dataDir) throws FilebaseException {
super(dataDir);
// TODO Auto-generated constructor stub
}
@Override
public void add(Article article) {
// TODO Auto-generated method stub
}
@Override
public void remove(String id) {
// TODO Auto-generated method stub
}
@Override
public void write() throws IOException {
writeIndex();
}
}
package de.vipra.cmd.lda;
import de.vipra.cmd.model.Article;
import de.vipra.cmd.ex.LDAAnalyzerException;
public class JGibbLDAAnalyzer implements LDAAnalyzer {
public class JGibbLDAAnalyzer extends LDAAnalyzer {
@Override
public Object analyze(Article article) throws LDAAnalyzerException {
public String getName() {
return "JGibb Analyzer";
}
@Override
public void analyze() throws LDAAnalyzerException {
// TODO Auto-generated method stub
return null;
}
}
package de.vipra.cmd.lda;
import de.vipra.cmd.model.Article;
import de.vipra.cmd.ex.LDAAnalyzerException;
import de.vipra.util.Config;
import de.vipra.util.Config.Key;
public interface LDAAnalyzer {
public abstract class LDAAnalyzer {
public Object analyze(Article article) throws LDAAnalyzerException;
public abstract String getName();
public abstract void analyze() throws LDAAnalyzerException;
public static LDAAnalyzer getAnalyzer(Config config) {
switch (config.getString(Key.ANALYZER).toLowerCase()) {
case "ldac":
return new LdacLDAAnalyzer();
case "jgibb":
default:
return new JGibbLDAAnalyzer();
}
}
}
package de.vipra.cmd.lda;
import de.vipra.cmd.model.Article;
import de.vipra.cmd.ex.LDAAnalyzerException;
public class LdacLDAAnalyzer implements LDAAnalyzer {
public class LdacLDAAnalyzer extends LDAAnalyzer {
@Override
public Object analyze(Article article) throws LDAAnalyzerException {
public String getName() {
return "lda-c Analyzer";
}
@Override
public void analyze() throws LDAAnalyzerException {
// TODO Auto-generated method stub
return null;
}
}
......@@ -9,14 +9,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.vipra.cmd.ExecutionException;
import de.vipra.cmd.ex.FilebaseException;
import de.vipra.cmd.file.Filebase;
import de.vipra.cmd.model.Article;
import de.vipra.util.Config;
import de.vipra.util.ConfigException;
import de.vipra.util.Constants;
import de.vipra.util.ex.ConfigException;
import de.vipra.util.ex.DatabaseException;
import de.vipra.util.ex.FilebaseException;
import de.vipra.util.service.DatabaseService;
import de.vipra.util.service.FilebaseService;
public class DeleteCommand implements Command {
......@@ -26,7 +26,7 @@ public class DeleteCommand implements Command {
private ArrayList<String> ids = new ArrayList<>();
private Config config;
private DatabaseService<Article> dbArticles;
private FilebaseService<Article> fbArticles;
private Filebase filebase;
DeleteCommand() {}
......@@ -56,7 +56,7 @@ public class DeleteCommand implements Command {
try {
// 2. delete file
fbArticles.deleteSingle(id);
filebase.remove(id);
} catch (FilebaseException e) {
errors.add(e);
}
......@@ -72,10 +72,10 @@ public class DeleteCommand implements Command {
@Override
public void run() throws ExecutionException {
try {
config = new Config();
dbArticles = config.getDatabaseService(Constants.Collection.ARTICLES, Article.class);
fbArticles = config.getFilebaseService(Article.class);
} catch (IOException | ConfigException e) {
config = Config.getConfig();
dbArticles = DatabaseService.getDatabaseService(config, Constants.Collection.ARTICLES, Article.class);
filebase = Filebase.getFilebase(config);
} catch (IOException | FilebaseException | ConfigException e) {
throw new ExecutionException(e);
}
......
package de.vipra.cmd.option;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
......@@ -10,45 +11,25 @@ import java.util.List;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.vipra.cmd.ExecutionException;
import de.vipra.cmd.ex.ImportException;
import de.vipra.cmd.file.Filebase;
import de.vipra.cmd.lda.LDAAnalyzer;
import de.vipra.cmd.model.Article;
import de.vipra.cmd.text.LucenePreprocessor;
import de.vipra.cmd.text.Preprocessor;
import de.vipra.util.Config;
import de.vipra.util.ConfigException;
import de.vipra.util.Constants;
import de.vipra.util.StringUtils;
import de.vipra.util.Timer;
import de.vipra.util.model.ArticleStats;
import de.vipra.util.service.DatabaseService;
import de.vipra.util.service.FilebaseService;
public class ImportCommand implements Command {
public class ImportException extends Exception {
private static final long serialVersionUID = 1L;
private final String id;
public ImportException(String msg, String id) {
super(msg);
this.id = id;
}
public ImportException(Exception e, String id) {
super(e);
this.id = id;
}
public String getId() {
return id;
}
}
public static final Logger log = LoggerFactory.getLogger(ImportCommand.class);
public static final Logger out = LoggerFactory.getLogger("shellout");
......@@ -56,7 +37,9 @@ public class ImportCommand implements Command {
private JSONParser parser = new JSONParser();
private Config config;
private DatabaseService<Article> dbArticles;
private FilebaseService<Article> fbArticles;
private Filebase filebase;
private Preprocessor preprocessor;
private LDAAnalyzer analyzer;
ImportCommand() {}
......@@ -95,91 +78,101 @@ public class ImportCommand implements Command {
}
}
private void importFile(File file) throws Exception {
Object data = parser.parse(new FileReader(file));
try {
importArticles((JSONArray) data);
} catch (ClassCastException e) {
try {
importArticle((JSONObject) data);
} catch (ClassCastException e2) {
throw new ExecutionException("invalid json file format: " + file.getAbsolutePath());
}
}
}
private void importArticles(JSONArray array) throws ExecutionException {
List<Exception> errors = new ArrayList<>();
for (Object object : array) {
try {
importArticle((JSONObject) object);
} catch (ImportException e) {
revertImport(e.getId());
errors.add(e);
} catch (Exception e) {
errors.add(e);
}
}
if (errors.size() > 0) {
throw new ExecutionException(errors);
}
}
void importArticle(JSONObject obj) throws ImportException {
/**
* import a single article into the database and filebase
*
* @param obj
* @return
* @throws ImportException
*/
Article importArticle(JSONObject obj) throws ImportException {
out.info("importing \"" + StringUtils.ellipsize(obj.get("title").toString(), 80) + "\"");
Article article = new Article();
article.fromJSON(obj);
try {
// 1. preprocess text
// process text before topic modeling
Preprocessor preprocessor = new LucenePreprocessor();
String processedText = preprocessor.preprocess(article.getText());
// preprocess text and generate text statistics
String preprocessedText = preprocessor.preprocess(article.getText());
ArticleStats articleStats = ArticleStats.generateFromText(preprocessedText);
// 2. generate word statistics
article.setStats(ArticleStats.generateFromText(processedText));
// 3. add article to mongodb
// this generates a unique object id
// add article to mongodb
article.setStats(articleStats);
article = dbArticles.createSingle(article);
// 4. add article to filebase
// topic modeling works on files
article.setText(processedText);
fbArticles.createSingle(article);
// add article to filebase
article.setText(preprocessedText);
filebase.add(article);
return article;
} catch (Exception e) {
throw new ImportException(e, article.getId());
}
}
private void revertImport(String id) throws ExecutionException {
if (id != null) {
DeleteCommand cmd = new DeleteCommand();
cmd.deleteEntry(id);
/**
* Imports a file into the database and the filebase
*
* @param file
* @throws ParseException
* @throws IOException
* @throws FileNotFoundException
* @throws ImportException
* @throws Exception
*/
private List<Article> importFile(File file)
throws FileNotFoundException, IOException, ParseException, ImportException {
Object data = parser.parse(new FileReader(file));
List<Article> articles = new ArrayList<Article>();
if (data instanceof JSONArray) {
for (Object object : (JSONArray) data) {
articles.add(importArticle((JSONObject) object));
}
} else if (data instanceof JSONObject) {
articles.add(importArticle((JSONObject) data));
}
return articles;
}
@Override
public void run() throws ExecutionException {
try {
config = new Config();
dbArticles = config.getDatabaseService(Constants.Collection.ARTICLES, Article.class);
fbArticles = config.getFilebaseService(Article.class);
} catch (IOException | ConfigException e) {
throw new ExecutionException(e);
}
config = Config.getConfig();
dbArticles = DatabaseService.getDatabaseService(config, Constants.Collection.ARTICLES, Article.class);
filebase = Filebase.getFilebase(config);
preprocessor = Preprocessor.getPreprocessor(config);
analyzer = LDAAnalyzer.getAnalyzer(config);
out.info("using data directory: " + filebase.getDataDir().getAbsolutePath());
out.info("using preprocessor: " + preprocessor.getName());
out.info("using analyzer: " + analyzer.getName());
Timer timer = new Timer();
timer.start();
List<Exception> ex = new ArrayList<>();
// import files into database and filebase
List<Article> articles = new ArrayList<>();
for (File file : files) {
try {
importFile(file);
} catch (Exception e) {
ex.add(e);
}
if (file.isFile() && file.exists())
articles.addAll(importFile(file));
}
if (ex.size() > 0) {
throw new ExecutionException(ex);
long durImport = timer.lap();
// do topic modeling
analyzer.analyze();
long durAnalyze = timer.lap();
// write file index
filebase.writeIndex();
long durIndex = timer.lap();
out.info("imported " + articles.size() + " " + (articles.size() == 1 ? "article" : "articles"));
out.info("import: " + StringUtils.timeString(durImport) + ", analyze: " + StringUtils.timeString(durAnalyze)
+ ", reindex: " + StringUtils.timeString(durIndex));
} catch (Exception e) {
throw new ExecutionException(e);
}
}
......
package de.vipra.cmd.text;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CustomPreprocessor implements Preprocessor {
public static final HashSet<String> STOPWORDS = new HashSet<>(Arrays.asList(new String[] { "a", "about", "above",
"after", "again", "against", "all", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because",
"been", "before", "being", "below", "between", "both", "but", "by", "can't", "cannot", "could", "couldn't",
"did", "didn't", "do", "does", "doesn't", "doing", "don't", "down", "during", "each", "few", "for", "from",
"further", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "he's",
"her", "here", "here's", "hers", "herself", "him", "himself", "his", "how", "how's", "i", "i'd", "i'll",
"i'm", "i've", "if", "in", "into", "is", "isn't", "it", "it's", "its", "itself", "let's", "me", "more",
"most", "mustn't", "my", "myself", "no", "nor", "not", "of", "off", "on", "once", "only", "or", "other",
"ought", "our", "ours ourselves", "out", "over", "own", "same", "shan't", "she", "she'd", "she'll",
"she's", "should", "shouldn't", "so", "some", "such", "than", "that", "that's", "the", "their", "theirs",
"them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're",
"they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "wasn't", "we",
"we'd", "we'll", "we're", "we've", "were", "weren't", "what", "what's", "when", "when's", "where",
"where's", "which", "while", "who", "who's", "whom", "why", "why's", "with", "won't", "would", "wouldn't",
"you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself", "yourselves" }));
public class CustomPreprocessor extends Preprocessor {
private final Set<String> stopWords;
public CustomPreprocessor(List<String> stopWordsList) {
this.stopWords = new HashSet<>(stopWordsList);
}
private String removeStopWords(String text) {
String[] words = text.split("\\s+");
StringBuilder sb = new StringBuilder();
for (String word : words) {
if (STOPWORDS.contains(word)) {
if (stopWords.contains(word)) {
continue;
}
sb.append(word).append(" ");
......@@ -33,6 +24,11 @@ public class CustomPreprocessor implements Preprocessor {
return sb.toString().trim();
}
@Override
public String getName() {
return "Custom Preprocessor";
}
@Override
public String preprocess(String input) {
input = input.toLowerCase();
......
......@@ -3,6 +3,7 @@ package de.vipra.cmd.text;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.lucene.analysis.Analyzer;
......@@ -12,14 +13,27 @@ import org.apache.lucene.analysis.miscellaneous.TrimFilter;
import org.apache.lucene.analysis.pattern.PatternReplaceFilter;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.util.CharArraySet;
import de.vipra.cmd.ex.PreprocessorException;
import de.vipra.util.StringUtils;
public class LucenePreprocessor implements Preprocessor {
public class LucenePreprocessor extends Preprocessor {
private final CharArraySet stopWords;
public LucenePreprocessor(List<String> stopWords) {
this.stopWords = new CharArraySet(stopWords, false);
}
@Override
public String getName() {
return "Lucene Preprocessor";
}
@Override
public String preprocess(String input) throws PreprocessorException {
Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new StandardAnalyzer(stopWords);
TokenStream stream = analyzer.tokenStream(null, new StringReader(input));
try {
stream.reset();
......
package de.vipra.cmd.text;
public interface Preprocessor {
import java.util.Arrays;
import java.util.List;
String preprocess(String input) throws PreprocessorException;
import de.vipra.cmd.ex.PreprocessorException;
import de.vipra.util.Config;
import de.vipra.util.Constants;
import de.vipra.util.Config.Key;
public abstract class Preprocessor {
public abstract String getName();
public abstract String preprocess(String input) throws PreprocessorException;
public static Preprocessor getPreprocessor(Config config) {
List<String> stopWords = Arrays.asList(config.getString(Key.STOPWORDS).toLowerCase().split(","));
if (stopWords.size() == 0) {
stopWords = Constants.STOPWORDS;
}
switch (config.getString(Key.PREPROCESSOR)) {
case "custom":
return new CustomPreprocessor(stopWords);
case "lucene":
default:
return new LucenePreprocessor(stopWords);
}
}
}
a
about
above
after
again
against
all
am
an
and
any
are
aren't
as
at
be
because
been
before
being
below
between
both
but
by
can't
cannot
could
couldn't
did
didn't
do
does
doesn't
doing
don't
down
during
each
few
for
from
further
had
hadn't
has
hasn't
have
haven't
having
he
he'd
he'll
he's
her
here
here's
hers
herself
him
himself
his
how
how's
i
i'd
i'll
i'm
i've
if
in
into
is
isn't
it
it's
its
itself
let's
me
more
most
mustn't
my
myself
no
nor
not
of
off
on
once
only
or
other
ought
our
ours ourselves
out
over
own
same
shan't
she
she'd
she'll
she's
should
shouldn't
so
some
such
than
that
that's
the
their
theirs
them
themselves
then
there
there's
these
they
they'd
they'll
they're
they've
this
those
through
to
too
under
until
up
very
was
wasn't
we
we'd
we'll
we're
we've
were
weren't
what
what's
when
when's
where
where's
which
while
who
who's
whom
why
why's
with
won't
would
wouldn't
you
you'd
you'll
you're
you've
your
yours
yourself
yourselves
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment