diff --git a/fw/README.md b/fw/README.md index fae3c6f..fc1fb60 100644 --- a/fw/README.md +++ b/fw/README.md @@ -6,8 +6,6 @@ As of May 2021, it's only been tested on various RP2040 dev boards. Board-agnostic code lives in the [core](./core) directory. Board-specific code - for things like driving indicator LEDs, GPIO mappings - are in other folders. -Word libraries are also in these individual directories for now, as certain dev boards have less flash space. -Those boards have smaller default libraries. Currently supported boards: * [Pimoroni Tiny2040](./tiny2040) * [Raspberry Pi Pico](./pico) @@ -23,12 +21,13 @@ tested natively on desktop. *For key press detection on Mac, you'll need to give 2. Find the directory with your board's name in the `bundle` directory. Copy all files/subdirectories onto your CircuitPython device. 3. If your board requires third-party libraries to run this code (most do), you may have to manually copy them. Each board's `bundle` directory will contain a README listing all of the required dependencies. Official CircuitPython libraries available [here](https://circuitpython.org/libraries). As of May 2021, I have been using Bundle version 6.x. 4. If you're using one of the desktop versions, execute `python3 code.py` from the `bundle/[macos/win32]` directory. You'll have to `pip3 install pynput` as well. +5. There is now a `test` target that should run on any machine. This is just a script that simulates the typing of a single word. Execute `python3 code.py` from the `bundle/test` directory to run. ## Customizing the keypad layout -You can customize which letters get attached to each key by changing the `keypad_dict` dictionary in `code.py`. The default is: +You can customize which letters get attached to each key by changing the `key_map` dictionary in `key_map.py`. The default for English is something like: ```python -keypad_dict = { +key_map = { '1' : ['1'], '2' : ['a', 'b', 'c'], '3' : ['d', 'e', 'f'], @@ -44,7 +43,7 @@ keypad_dict = { ``` But as [Ben Torvaney discovered](https://torvaney.github.io/projects/t9-optimised.html), you can optimize your typing even further by using something like: ```python -keypad_dict = { +key_map = { '1' : ['1'], '2' : ['a', 'm', 'r'], '3' : ['c', 'd', 'f', 'p', 'u'], diff --git a/fw/ada-macropad/library.t9l b/fw/ada-macropad/library.t9l deleted file mode 100644 index 8a1f320..0000000 Binary files a/fw/ada-macropad/library.t9l and /dev/null differ diff --git a/fw/core/character_map.py b/fw/core/character_map.py new file mode 100644 index 0000000..03f4ade --- /dev/null +++ b/fw/core/character_map.py @@ -0,0 +1 @@ +character_map = {"a" : 0,"b" : 1,"c" : 2,"d" : 3,"e" : 4,"f" : 5,"g" : 6,"h" : 7,"i" : 8,"j" : 9,"k" : 10,"l" : 11,"m" : 12,"n" : 13,"o" : 14,"p" : 15,"q" : 16,"r" : 17,"s" : 18,"t" : 19,"u" : 20,"v" : 21,"w" : 22,"x" : 23,"y" : 24,"z" : 25,"\'" : 26,"-" : 27,"\u00DF" : 28,"\u00E0" : 29,"\u00E1" : 30,"\u00E2" : 31,"\u00E3" : 32,"\u00E4" : 33,"\u00E5" : 34,"\u00E6" : 35,"\u00E7" : 36,"\u00E8" : 37,"\u00E9" : 38,"\u00EA" : 39,"\u00EB" : 40,"\u00EC" : 41,"\u00ED" : 42,"\u00EE" : 43,"\u00EF" : 44,"\u00F0" : 45,"\u00F1" : 46,"\u00F2" : 47,"\u00F3" : 48,"\u00F4" : 49,"\u00F5" : 50,"\u00F6" : 51,"\u00F8" : 52,"\u00F9" : 53,"\u00FA" : 54,"\u00FC" : 55,"\u00FE" : 56,"\u0161" : 57} \ No newline at end of file diff --git a/fw/core/code.py b/fw/core/code.py index e1e8541..f2ff961 100644 --- a/fw/core/code.py +++ b/fw/core/code.py @@ -1,13 +1,16 @@ import time from led import Led from t9_keypad import Keypad -from keyboard import Keyboard -from keyboard import Keycode +from t9_keyboard import Keyboard +from t9_keyboard import Keycode from t9_display import Display +from key_map import key_map +from character_map import character_map NO_WORD = 0 PARTIAL_WORD = 1 WORD = 2 +NODE_HEADER_LEN = 3 CACHE_SIZE = 8000 # Used to store Trie node locations @@ -92,20 +95,6 @@ def __init__(self, keys, words, pres): def __str__(self): return f'keys: {self.keys}, words: {self.words}, pres: {self.pres}' -keypad_dict = { - '1' : ['1'], - '2' : ['a', 'b', 'c'], - '3' : ['d', 'e', 'f'], - '4' : ['g', 'h', 'i'], - '5' : ['j', 'k', 'l'], - '6' : ['m', 'n', 'o'], - '7' : ['p', 'q', 'r', 's'], - '8' : ['t', 'u', 'v'], - '9' : ['w', 'x', 'y', 'z'], - '0' : [' ', '0', '\n'], - '#' : ['.', ',', '?', '!'] -} - def error_mode(): print("ERROR!") while True: @@ -113,7 +102,7 @@ def error_mode(): pass reverse_key_dict = { } -for k, l in keypad_dict.items(): +for k, l in key_map.items(): for c in l: reverse_key_dict[c] = k @@ -146,13 +135,17 @@ def error_mode(): # Flag to indicate to our main loop that we want to start a new word force_break_word = False +def read_int(file, offset, len): + file.seek(offset) + return int.from_bytes(file.read(len), 'big') + # given a file and location in that file, read a 24bit unsigned int -def read_int(file, offset): +def read_address(file, offset): if (offset < CACHE_SIZE): cached = file_cache[offset] if cached >= 0: return cached - file.seek(offset * 3) + file.seek(offset) x = int.from_bytes(file.read(3), 'big') if (offset < CACHE_SIZE): file_cache[offset] = x @@ -162,11 +155,22 @@ def read_int(file, offset): def search(file, offset, s: str): poll_keys() if len(s) == 0: - file_val = read_int(file, offset) - return WORD if file_val == 1 else PARTIAL_WORD + word_flag = read_int(file, offset * 3, 1) + return WORD if word_flag == 1 else PARTIAL_WORD else: - ch = ord(s[0]) - ord('a') - file_val = read_int(file, offset + 1 + ch) + ch = character_map[s[0]] + ch_bitmap = read_int(file, (offset * 3) + 1, 8) + if (ch_bitmap & (1 << ch) == 0): + return NO_WORD + ch_index = 0 + shift_count = 0 + while(ch_bitmap != 0 and shift_count < ch): + if ch_bitmap & 1: + ch_index += 1 + ch_bitmap >>= 1 + shift_count += 1 + + file_val = read_address(file, (offset + NODE_HEADER_LEN + ch_index) * 3) if file_val == 0xFFFFFF: return WORD if len(s) == 1 else NO_WORD elif file_val > 0: @@ -176,7 +180,7 @@ def search(file, offset, s: str): # Given an open file, a key, and a list of valid prefixes, find all possible words/prefixes def get_words(file, input, last_result): # Note that each key has up to 4 possible chars, so we'll need to try all of them - chars = keypad_dict[input] + chars = key_map[input] output_words = [] output_prefixes = [] for prefix in (last_result.words + last_result.pres): @@ -253,7 +257,7 @@ def poll_keys_modified(current_keys): force_break_word = True held_modified_keys.append(k) now = time.monotonic() - key_dict = keypad_dict[k] + key_dict = key_map[k] if k is not last_modified_key or (now - last_modified_time > 0.6): flush_last_modified() emit_raw_text(key_dict[0]) @@ -304,7 +308,7 @@ def poll_keys(): key_queue.append(hk) ## MAIN LOOP -with open("library.t9l", "rb") as fp: +with open("library.t9l2", "rb") as fp: while True: word_index = 0 current_word = "" @@ -355,8 +359,8 @@ def poll_keys(): elif c < '2' or c > '9': break # emit for any number keys that don't have letters (if user has customized layout) - elif ord(keypad_dict[c][0]) < ord('a'): - emit_raw_text(keypad_dict[c][0]) + elif ord(key_map[c][0]) < ord('a'): + emit_raw_text(key_map[c][0]) break else: # search the dictionary! diff --git a/fw/core/key_map.py b/fw/core/key_map.py new file mode 100644 index 0000000..0e5dedb --- /dev/null +++ b/fw/core/key_map.py @@ -0,0 +1 @@ +key_map = {'1':["1"],'2':["a","b","c"],'3':["d","e","f"],'4':["g","h","i"],'5':["j","k","l"],'6':["m","n","o"],'7':["p","q","r","s"],'8':["t","u","v"],'9':["w","x","y","z"],'0':[" ","0","\n"],'#':[".",",","?","!"]} \ No newline at end of file diff --git a/fw/core/library.t9l2 b/fw/core/library.t9l2 new file mode 100644 index 0000000..33f78af Binary files /dev/null and b/fw/core/library.t9l2 differ diff --git a/fw/core/version.txt b/fw/core/version.txt new file mode 100644 index 0000000..359a5b9 --- /dev/null +++ b/fw/core/version.txt @@ -0,0 +1 @@ +2.0.0 \ No newline at end of file diff --git a/fw/macos/library.t9l b/fw/macos/library.t9l deleted file mode 100644 index 8a1f320..0000000 Binary files a/fw/macos/library.t9l and /dev/null differ diff --git a/fw/macos/keyboard.py b/fw/macos/t9_keyboard.py similarity index 100% rename from fw/macos/keyboard.py rename to fw/macos/t9_keyboard.py diff --git a/fw/pico/README.md b/fw/pico/README.md index a097243..e3225a3 100644 --- a/fw/pico/README.md +++ b/fw/pico/README.md @@ -5,7 +5,7 @@ * `adafruit_hid/consumer_control_code.mpy` * `adafruit_hid/consumer_control.mpy` * `adafruit_hid/gamepad.mpy` - * `adafruit_hid/keyboard_layout_us.mpy` + * `adafruit_hid/keyboard_layout.mpy` (It may be called `keyboard_layout_us.py` - if so, rename it without the `_us`) * `adafruit_hid/keyboard.mpy` * `adafruit_hid/keycode.mpy` * `adafruit_hid/mouse.mpy` diff --git a/fw/pico/library.t9l b/fw/pico/library.t9l deleted file mode 100644 index 6ad4d06..0000000 Binary files a/fw/pico/library.t9l and /dev/null differ diff --git a/fw/qtpy2040/keyboard.py b/fw/pico/t9_keyboard.py old mode 100644 new mode 100755 similarity index 77% rename from fw/qtpy2040/keyboard.py rename to fw/pico/t9_keyboard.py index ba7e817..d4dce52 --- a/fw/qtpy2040/keyboard.py +++ b/fw/pico/t9_keyboard.py @@ -1,12 +1,12 @@ import usb_hid import adafruit_hid.keyboard -from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS +from adafruit_hid.keyboard_layout import KeyboardLayout import adafruit_hid.keycode class Keyboard(): def __init__(self): self.keyboard = adafruit_hid.keyboard.Keyboard(usb_hid.devices) - self.keyboard_layout = KeyboardLayoutUS(self.keyboard) + self.keyboard_layout = KeyboardLayout(self.keyboard) def press(self, key): self.keyboard.press(key) diff --git a/fw/qtpy2040/README.md b/fw/qtpy2040/README.md index 290fbcc..eacdbe6 100644 --- a/fw/qtpy2040/README.md +++ b/fw/qtpy2040/README.md @@ -5,7 +5,7 @@ * `adafruit_hid/consumer_control_code.mpy` * `adafruit_hid/consumer_control.mpy` * `adafruit_hid/gamepad.mpy` - * `adafruit_hid/keyboard_layout_us.mpy` + * `adafruit_hid/keyboard_layout.mpy` (It may be called `keyboard_layout_us.py` - if so, rename it without the `_us`) * `adafruit_hid/keyboard.mpy` * `adafruit_hid/keycode.mpy` * `adafruit_hid/mouse.mpy` diff --git a/fw/qtpy2040/library.t9l b/fw/qtpy2040/library.t9l deleted file mode 100644 index 8a1f320..0000000 Binary files a/fw/qtpy2040/library.t9l and /dev/null differ diff --git a/fw/tiny2040/keyboard.py b/fw/qtpy2040/t9_keyboard.py similarity index 77% rename from fw/tiny2040/keyboard.py rename to fw/qtpy2040/t9_keyboard.py index ba7e817..d4dce52 100644 --- a/fw/tiny2040/keyboard.py +++ b/fw/qtpy2040/t9_keyboard.py @@ -1,12 +1,12 @@ import usb_hid import adafruit_hid.keyboard -from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS +from adafruit_hid.keyboard_layout import KeyboardLayout import adafruit_hid.keycode class Keyboard(): def __init__(self): self.keyboard = adafruit_hid.keyboard.Keyboard(usb_hid.devices) - self.keyboard_layout = KeyboardLayoutUS(self.keyboard) + self.keyboard_layout = KeyboardLayout(self.keyboard) def press(self, key): self.keyboard.press(key) diff --git a/fw/test/led.py b/fw/test/led.py new file mode 100644 index 0000000..ca05685 --- /dev/null +++ b/fw/test/led.py @@ -0,0 +1,15 @@ +class Led(): + def __init__(self): + self.color = None + + def show_red(self): + print("set led to red") + self.color = 'r' + + def show_green(self): + print("set led to green") + self.color = 'g' + + def show_blue(self): + print("set led to blue") + self.color = 'b' \ No newline at end of file diff --git a/fw/test/t9_display.py b/fw/test/t9_display.py new file mode 100644 index 0000000..24df7a2 --- /dev/null +++ b/fw/test/t9_display.py @@ -0,0 +1,6 @@ +class Display(): + def __init__(self): + pass + + def display_results(self, result, index): + pass \ No newline at end of file diff --git a/fw/test/t9_keyboard.py b/fw/test/t9_keyboard.py new file mode 100644 index 0000000..64c200f --- /dev/null +++ b/fw/test/t9_keyboard.py @@ -0,0 +1,30 @@ +class Keyboard(): + def __init__(self): + self.buffer = "" + + def press(self, key): + if key == Keycode.BACKSPACE: + self.buffer = self.buffer[:-1] + + def release_all(self): + pass + + def write(self, text): + self.buffer = self.buffer + text + # pynput virtual typing doesn't seem to work on Mavericks, so just print the output + print("buffer:", self.buffer) + +class Keycode(): + BACKSPACE = "backspace" + F1 = "F1" + F2 = "F2" + F3 = "F3" + F4 = "F4" + F5 = "F5" + F6 = "F6" + F7 = "F7" + F8 = "F8" + F9 = "F9" + F10 = "F10" + F11 = "F11" + F12 = "F12" \ No newline at end of file diff --git a/fw/test/t9_keypad.py b/fw/test/t9_keypad.py new file mode 100644 index 0000000..f151477 --- /dev/null +++ b/fw/test/t9_keypad.py @@ -0,0 +1,55 @@ +import threading +import time +import sys + +test_word = "actual" + +class Keypad(): + def __init__(self, keys): + self.pressed_keys = set() + threading.Thread(target=self.scripted_keys).start() + + def scripted_keys(self): + time.sleep(3) + for c in test_word: + k = key_map[c] + self.pressed_keys.add(k) + time.sleep(0.5) + self.pressed_keys.remove(k) + time.sleep(0.5) + +key_map = { + 'b' : '2', + 'a' : '2', + 'c' : '2', + 'ç' : '2', + 'á' : '2', + 'd' : '3', + 'e' : '3', + 'é' : '3', + 'f' : '3', + 'g' : '4', + 'h' : '4', + 'i' : '4', + 'í' : '4', + 'j' : '5', + 'k' : '5', + 'l' : '5', + 'm' : '6', + 'n' : '6', + 'o' : '6', + 'ó' : '6', + 'p' : '7', + 'q' : '7', + 'r' : '7', + 's' : '7', + 't' : '8', + 'u' : '8', + 'ü' : '8', + 'ú' : '8', + 'v' : '8', + 'w' : '9', + 'x' : '9', + 'y' : '9', + 'z' : '9' + } \ No newline at end of file diff --git a/fw/tiny2040/README.md b/fw/tiny2040/README.md index a097243..e3225a3 100644 --- a/fw/tiny2040/README.md +++ b/fw/tiny2040/README.md @@ -5,7 +5,7 @@ * `adafruit_hid/consumer_control_code.mpy` * `adafruit_hid/consumer_control.mpy` * `adafruit_hid/gamepad.mpy` - * `adafruit_hid/keyboard_layout_us.mpy` + * `adafruit_hid/keyboard_layout.mpy` (It may be called `keyboard_layout_us.py` - if so, rename it without the `_us`) * `adafruit_hid/keyboard.mpy` * `adafruit_hid/keycode.mpy` * `adafruit_hid/mouse.mpy` diff --git a/fw/tiny2040/library.t9l b/fw/tiny2040/library.t9l deleted file mode 100644 index 8a1f320..0000000 Binary files a/fw/tiny2040/library.t9l and /dev/null differ diff --git a/fw/pico/keyboard.py b/fw/tiny2040/t9_keyboard.py old mode 100755 new mode 100644 similarity index 77% rename from fw/pico/keyboard.py rename to fw/tiny2040/t9_keyboard.py index ba7e817..d4dce52 --- a/fw/pico/keyboard.py +++ b/fw/tiny2040/t9_keyboard.py @@ -1,12 +1,12 @@ import usb_hid import adafruit_hid.keyboard -from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS +from adafruit_hid.keyboard_layout import KeyboardLayout import adafruit_hid.keycode class Keyboard(): def __init__(self): self.keyboard = adafruit_hid.keyboard.Keyboard(usb_hid.devices) - self.keyboard_layout = KeyboardLayoutUS(self.keyboard) + self.keyboard_layout = KeyboardLayout(self.keyboard) def press(self, key): self.keyboard.press(key) diff --git a/fw/win32/library.t9l b/fw/win32/library.t9l deleted file mode 100644 index 8a1f320..0000000 Binary files a/fw/win32/library.t9l and /dev/null differ diff --git a/fw/win32/keyboard.py b/fw/win32/t9_keyboard.py similarity index 100% rename from fw/win32/keyboard.py rename to fw/win32/t9_keyboard.py diff --git a/library_generator/.gitignore b/library_generator/.gitignore index 1b9df47..0d9382b 100644 --- a/library_generator/.gitignore +++ b/library_generator/.gitignore @@ -1,5 +1,5 @@ -library.t9l .gradle/ build/ +output/ .idea/ local.properties \ No newline at end of file diff --git a/library_generator/build.gradle b/library_generator/build.gradle index 9068b90..2458150 100644 --- a/library_generator/build.gradle +++ b/library_generator/build.gradle @@ -1,39 +1,40 @@ buildscript { - ext.kotlin_version = '1.5.10' - ext.ktor_version = '1.6.1' - ext.appengine_version = '1.9.60' - ext.appengine_plugin_version = '2.4.1' + ext.kotlin_version = '1.6.20' } plugins { id 'org.jetbrains.kotlin.jvm' version "$kotlin_version" - id 'com.google.cloud.tools.appengine' version "$appengine_plugin_version" + id 'com.google.cloud.tools.appengine' version "2.4.1" } apply plugin: 'war' apply plugin: 'com.google.cloud.tools.appengine' group 'com.dupontgu' -version '0.0.5' +version '2.0.0' repositories { mavenCentral() } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib" - implementation 'org.slf4j:slf4j-log4j12:1.7.29' - compile "io.ktor:ktor-server-servlet:$ktor_version" - compile "io.ktor:ktor-html-builder:$ktor_version" - providedCompile "com.google.appengine:appengine:$appengine_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'org.slf4j:slf4j-log4j12:1.7.36' + implementation 'org.apache.commons:commons-text:1.9' + implementation 'org.zeroturnaround:zt-zip:1.15' + compile "io.ktor:ktor-server-servlet:1.6.8" + compile "io.ktor:ktor-html-builder:1.6.8" + providedCompile "com.google.appengine:appengine:1.9.96" } appengine { // App Engine tasks configuration deploy { // deploy configuration projectId = 'GCLOUD_CONFIG' - version = '1' + version = '2' + stopPreviousVersion = false + promote = false } } diff --git a/library_generator/src/main/kotlin/com/dupontgu/t9/Languages.kt b/library_generator/src/main/kotlin/com/dupontgu/t9/Languages.kt new file mode 100644 index 0000000..27c5abd --- /dev/null +++ b/library_generator/src/main/kotlin/com/dupontgu/t9/Languages.kt @@ -0,0 +1,134 @@ +package com.dupontgu.t9 + +enum class Languages(val languageCode: String, val librarySourceUrl: String) { + ENGLISH( + "en", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/english.txt" + ), + SPANISH( + "es", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/spanish.txt" + ), + ITALIAN( + "it", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/italian.txt" + ), + SWEDISH( + "sw", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/swedish.txt" + ), + GERMAN( + "de", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/german.txt" + ), + FRENCH( + "fr", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/french.txt" + ), + DUTCH( + "nl", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/dutch.txt" + ), + DANISH( + "da", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/danish.txt" + ), + PORTUGUESE( + "pt", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/portuguese.txt" + ), + NORWEGIAN( + "nb", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/norwegian.txt" + ), + ALBANIAN( + "sq", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/albanian.txt" + ), + CATALAN( + "ca", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/catalan.txt" + ), + ESTONIAN( + "et", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/estonian.txt" + ), + FINNISH( + "fi", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/finnish.txt" + ), + INDONESIAN( + "id", + "https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/indonesian.txt" + ), +} + +/** + * Map of physical T9 buttons to set of type-able characters + * Note - each language should only keep the characters it needs. + * Keeping extra characters around will slow down search time. + */ +val globalKeyMap = mapOf( + '1' to listOf('1'), + '2' to listOf('a', 'b', 'c', 'à', 'á', 'â', 'ä', 'æ', 'ã', 'å', 'ā', 'ç', 'ć', 'č'), + '3' to listOf('d', 'e', 'f', 'ð', 'è', 'é', 'ê', 'ë', 'ē', 'ė', 'ę'), + '4' to listOf('g', 'h', 'i', 'î', 'ï', 'í', 'ī', 'į', 'ì'), + '5' to listOf('j', 'k', 'l', '\'', '-'), + '6' to listOf('m', 'n', 'o', 'ñ', 'ń', 'ô', 'ö', 'ò', 'ó', 'œ', 'ø', 'ō', 'õ'), + '7' to listOf('p', 'q', 'r', 's', 'ß', 'ś', 'š'), + '8' to listOf('t', 'u', 'v', 'þ', 'û', 'ü', 'ù', 'ú', 'ū'), + '9' to listOf('w', 'x', 'y', 'z'), + '0' to listOf(' ', '0', '\n'), + '#' to listOf('.', ',', '?', '!') +) + +// These characters should be available in every language +val universalCharacters = listOf(globalKeyMap['1']!!, globalKeyMap['0']!!, globalKeyMap['#']!!).flatten() + +// IMPORTANT - do not change the order of this between releases +// any new characters should be appended to the end +val charMap = ( + ('a'..'z') + listOf( + 'ü', + 'é', + 'ç', + 'á', + 'í', + 'ó', + 'ú', + 'ñ', + 'à', + 'è', + 'ì', + 'ù', + 'ò', + 'õ', + 'ð', + 'š', + 'þ', + 'ê', + 'î', + 'ï', + 'ã', + 'ä', + 'ö', + 'ô', + 'å', + 'â', + 'ß', + 'ë', + 'ø', + 'æ', + '\'', + '-' + ).sorted()) + .mapIndexed { i, c -> c to i } + .toMap() + .onEach { (key, _) -> + if(globalKeyMap.none { it.value.contains(key)}) { + throw RuntimeException("Missing key mapping for character: $key!") + } + } + + + diff --git a/library_generator/src/main/kotlin/com/dupontgu/t9/Main.kt b/library_generator/src/main/kotlin/com/dupontgu/t9/Main.kt index 34bdced..3be2a8d 100644 --- a/library_generator/src/main/kotlin/com/dupontgu/t9/Main.kt +++ b/library_generator/src/main/kotlin/com/dupontgu/t9/Main.kt @@ -1,272 +1,87 @@ +import com.dupontgu.t9.* +import org.apache.commons.text.StringEscapeUtils +import java.io.BufferedInputStream import java.io.File import java.io.FileOutputStream -import java.io.InputStream -import java.io.OutputStream -import java.util.* +import java.net.URL -// Each pointer is a 24 bit address -private const val ADDRESS_LENGTH_BYTES = 3 - -// newline delimited list of words for your T9 dictionary -private const val DICT_FILE = "/dict.txt" - -// where the custom library file will be written -private const val OUT_FILE = "library.t9l" - -// a-z -private const val ALPHA_COUNT = 26 - -// helpers to check if a library entry matches our supported alphabet -private val alphabetRegex = Regex("^[a-zA-Z]*\$") -private fun String.isValid() = matches(alphabetRegex) - -private const val MAX_LINE_LEN = 25 -private fun String.hasValidLength() = length <= MAX_LINE_LEN - -sealed class LibraryResult : Throwable() { - data class Success(val numBytesWritten: Int) : LibraryResult() - sealed class Error(override val message: String) : LibraryResult() { - data class LineTooLongError(val line: String) : Error("Error: this file contains a line that is too long: ${line.take(25)}") - data class InvalidLineError(val line: String) : Error("Error: this file contains a line that contains invalid characters: ${line.take(25)}") - } -} - -fun serializeLibraryFile(input: InputStream, output: OutputStream): LibraryResult { - val tree = try { - input - .bufferedReader() - .lineSequence() - // clean each line - .map { line -> - if (!line.isValid()) throw LibraryResult.Error.InvalidLineError(line) - if (!line.hasValidLength()) throw LibraryResult.Error.LineTooLongError(line) - line.trim().lowercase(Locale.getDefault()).filter { it.isLetter() } - } - // insert each word into the Trie - .fold(NullNode) { acc, s -> acc.insert(s) } - } catch (err: LibraryResult.Error) { - return err - } - - // serialize the tree - val queue = ArrayDeque().apply { addFirst(tree) } - val serializedTreeAddresses = mutableListOf() - var offset = 0u - while (!queue.isEmpty()) { - val node = queue.pollFirst() - val size = node.flattenAddresses(offset, queue, serializedTreeAddresses) - offset += size - } - - // convert UInts to 3 byte addresses - val flatList = serializedTreeAddresses.flatMap { it.toBytes() } - // write to output - output.use { it.write(flatList.toByteArray()) } - return LibraryResult.Success(flatList.size) -} - -fun main() { - val input = {}.javaClass.getResource(DICT_FILE).openStream() - val output = FileOutputStream(File(OUT_FILE)) - val result = serializeLibraryFile(input, output) - println( - when (result) { - is LibraryResult.Success -> "Wrote to file $OUT_FILE, size: ${result.numBytesWritten} bytes" - is LibraryResult.Error.LineTooLongError -> "ERROR! Line was too long: ${result.line.take(25)}(...)" - is LibraryResult.Error.InvalidLineError -> "ERROR! Line contains invalid characters: ${result.line.take(25)}(...)" - } - ) -} - -sealed class TrieNode { - abstract fun fetch(char: Char): TrieNode - - private fun fetch(string: String): TrieNode { - if (string.isEmpty()) return this - return when (val next = fetch(string.first())) { - is ParentNode -> next.fetch(string.rest) - is OnlyWordNode -> if (string.length > 1) { - NullNode - } else { - OnlyWordNode - } - is NullNode -> NullNode - } - } - - abstract fun insert(string: String): TrieNode - - fun contains(string: String): Boolean { - return when (fetch(string)) { - is WordParentNode -> true - is OnlyParentNode -> false - OnlyWordNode -> true - NullNode -> false - } - } - - open fun flattenAddresses(offset: UInt, queue: Queue, collector: MutableCollection): UInt { - return 0u - } - - abstract val trieSize: Int -} - -val Char.alphaIndex: Int - get() { - val alpha = this - 'a' - if (alpha < 0) error("unable to insert: $this") - return alpha - } - -val String.rest: String - get() = removeRange(0, 1) - -/** - * Base class for nodes that have children - * In the context of the dictionary trie - a node that represents a partial word - */ -sealed class ParentNode( - protected val chars: MutableList = MutableList(ALPHA_COUNT) { NullNode } -) : TrieNode() { - - override fun fetch(char: Char): TrieNode { - return chars.getOrElse(char.alphaIndex) { NullNode } - } - - fun insertChar(char: Char) { - chars[char.alphaIndex] = OnlyWordNode - } - - abstract val name: String - abstract val isWord: Boolean - - override fun toString(): String { - return "$name(\n" + - chars.joinToString(separator = "\n") { s -> - s.toString().lines().joinToString("\n") { " $it" } - } + - "\n)" - } - - override val trieSize: Int = ALPHA_COUNT + 1 - - override fun flattenAddresses(offset: UInt, queue: Queue, collector: MutableCollection): UInt { - val sizes = chars.scan(0u) { acc, trieNode -> acc + trieNode.trieSize.toUInt() } - val thisRow = chars.mapIndexed { index, node -> - return@mapIndexed when (node) { - is ParentNode -> offset + chars.size.toUInt() + 1u + sizes[index] - OnlyWordNode -> 0xFFFFFFu - NullNode -> 0x00u - } - } - queue.addAll(chars) - collector.add(if (isWord) 1u else 0u) - collector.addAll(thisRow) - return sizes.last().toUInt() - } -} - -/** - * A trie node that represents a valid word, and is also the prefix for at least one other word - */ -class WordParentNode( - chars: MutableList = MutableList(ALPHA_COUNT) { NullNode } -) : ParentNode(chars) { - override fun insert(string: String): TrieNode { - if (string.isNotEmpty()) { - val first = string.first() - chars[first.alphaIndex] = fetch(first).insert(string.rest) - } - return this - } - - override val name: String = "WordParent" - - override val isWord: Boolean = true -} +private const val OUT_DIR = "output" +private const val GLOBAL_CHAR_MAP_FILE = "character_map.py" +const val KEY_MAP_FILE = "key_map.py" /** - * A trie node that represents a prefix for at least one other word + * Downloads a default list of words for each of the supported [Languages], + * and generates T9 library files and accompanying key map files. + * + * Also generates the global character map file, which is used directly by the firmware. */ -class OnlyParentNode( - chars: MutableList = MutableList(ALPHA_COUNT) { NullNode } -) : ParentNode(chars) { - override fun insert(string: String): TrieNode { - if (string.isNotEmpty()) { - val first = string.first() - chars[first.alphaIndex] = fetch(first).insert(string.rest) - return this +fun main() { + val outputDir = File(OUT_DIR).apply { + if (!exists()) { + mkdir() } - return WordParentNode(chars) } - override val name: String = "OnlyParent" - - override val isWord: Boolean = false -} - -/** - * A trie node that represents a valid word that is NOT a prefix for any other words - */ -object OnlyWordNode : TrieNode() { - override fun fetch(char: Char): TrieNode = NullNode - - override fun insert(string: String): TrieNode { - if (string.isEmpty()) return OnlyWordNode - val first = string.first() - val newParent = WordParentNode() - if (string.length == 1) { - newParent.insertChar(first) - } else { - newParent.insert(string) + Languages.values().forEach { + val languageDir = File(outputDir, it.languageCode).apply { + if (!exists()) { + mkdir() + } } - return newParent - } - - override fun toString(): String = "ChildNode" - - override val trieSize: Int = 0 -} - -/** - * A trie node that is neither a word, or a prefix for a word. A dead end. - */ -object NullNode : TrieNode() { - override fun fetch(char: Char): TrieNode = NullNode - - override fun insert(string: String): TrieNode { - if (string.isEmpty()) { - return OnlyWordNode + val tempFile = kotlin.io.path.createTempFile("library-${it.languageCode}").toFile() + URL(it.librarySourceUrl).downloadFileTo(tempFile) + val libraryOutputFile = File(languageDir, "library.t9l2") + val result = serializeLibraryFile( + tempFile.inputStream(), + FileOutputStream(libraryOutputFile), + removeInvalidLines = true + ) + when (result) { + is LibraryResult.Success -> { + println( + """ + Wrote to file $libraryOutputFile, size: ${result.numBytesWritten} bytes + ${result.charSet} (${result.charSet.size}) + skipped: ${result.skippedWords} + """.trimIndent() + ) + writeKeyMapFile(result, File(languageDir, KEY_MAP_FILE)) + } + is LibraryResult.Error.LineTooLongError -> println("ERROR! Line was too long: ${result.line.take(25)}") + is LibraryResult.Error.InvalidLineError -> println( + "ERROR! Line contains invalid characters: ${result.line.take(25)}" + ) } - return OnlyParentNode().insert(string) + println() + } + + /** + * Write global character_map Python file, which can be loaded by T9 FW + * The character_map is provides the index of each character's flag within a node header's bitset + */ + File(outputDir, GLOBAL_CHAR_MAP_FILE).outputStream().bufferedWriter().use { writer -> + val mappings = charMap + .map { + // take care of any characters that might not get written to a string properly + val unescapedKey = StringEscapeUtils.escapeEcmaScript(it.key.toString()) + "\"$unescapedKey\" : ${it.value}" + } + .joinToString(",") + writer.write("character_map = {$mappings}") } - - override fun toString(): String = "Null" - - override val trieSize: Int = 0 } -/** - * Convert UInt into a byte array - */ -fun UInt.toBytes(isBigEndian: Boolean = true, wordLength: Int = ADDRESS_LENGTH_BYTES): List { - val bytes = mutableListOf() - var n = this - if (n == 0x00u) { - bytes += n.toByte() - } else { - while (n != 0x00u) { - bytes += n.toByte() - n = n.shr(Byte.SIZE_BITS) +fun URL.downloadFileTo(file: File) { + openStream().use { inp -> + BufferedInputStream(inp).use { bis -> + file.outputStream().use { fos -> + val data = ByteArray(1024) + var count: Int + while (bis.read(data, 0, 1024).also { count = it } != -1) { + fos.write(data, 0, count) + } + } } } - - val paddings = if (bytes.size > wordLength) { - emptyList() - } else { - List(wordLength - bytes.size) { 0x00 } - } - return paddings + if (isBigEndian) bytes.reversed() else bytes } diff --git a/library_generator/src/main/kotlin/com/dupontgu/t9/T9.kt b/library_generator/src/main/kotlin/com/dupontgu/t9/T9.kt new file mode 100644 index 0000000..e5aff26 --- /dev/null +++ b/library_generator/src/main/kotlin/com/dupontgu/t9/T9.kt @@ -0,0 +1,321 @@ +package com.dupontgu.t9 + +import org.apache.commons.text.StringEscapeUtils +import java.io.BufferedInputStream +import java.io.File +import java.io.InputStream +import java.io.OutputStream +import java.net.URL +import java.util.* + +// Each pointer is a 24 bit address +private const val ADDRESS_LENGTH_BYTES = 3 + +// Each node will have a header with "metadata", 9 bytes long +private const val HEADER_LENGTH_WORDS = 3 +private const val HEADER_LENGTH_BYTES = HEADER_LENGTH_WORDS * ADDRESS_LENGTH_BYTES + +private fun String.isValid() = all { charMap.containsKey(it.lowercaseChar()) } + +private const val MAX_LINE_LEN = 30 +private fun String.hasValidLength() = length <= MAX_LINE_LEN + +val Char.alphaIndex: Int + // safe because we should be pre-checking all words for invalid chars + get() = charMap[this]!! + +sealed class LibraryResult : Throwable() { + data class Success( + val numBytesWritten: Long, + val charSet: Set, + val skippedWords: Set + ) : LibraryResult() + + sealed class Error(override val message: String) : LibraryResult() { + data class LineTooLongError(val line: String) : + Error("Error: this file contains a line that is too long: ${line.take(25)}") + + data class InvalidLineError(val line: String) : + Error("Error: this file contains a line that contains invalid characters: ${line.take(25)}.\nSupported characters are:\n${charMap.keys}") + } +} + +fun serializeLibraryFile(input: InputStream, output: OutputStream, removeInvalidLines: Boolean = false): LibraryResult { + val charSet = mutableSetOf() + val skippedWords = mutableSetOf() + val tree = try { + input + .bufferedReader() + .lineSequence() + .filter { word -> + if (!removeInvalidLines) return@filter true + word.isValid().also { if (!it) skippedWords.add(word) } + } + .map { line -> + if (!line.isValid()) throw LibraryResult.Error.InvalidLineError(line) + if (!line.hasValidLength()) throw LibraryResult.Error.LineTooLongError(line) + line.trim().lowercase(Locale.getDefault()).onEach(charSet::add) + } + // insert each word into the Trie + .fold(NullNode) { acc, s -> acc.insert(s) } + } catch (err: LibraryResult.Error) { + return err + } + + val queue = ArrayDeque().apply { addFirst(tree) } + + var offset = queue.peekFirst().nodeSize.toUInt() + output.use { stream -> + while (!queue.isEmpty()) { + val node = queue.pollFirst() + val size = node.serializeTo(offset, queue) { stream.write(it.toByteArray()) } + offset += size + } + } + + return LibraryResult.Success((offset.toLong() * ADDRESS_LENGTH_BYTES), charSet, skippedWords) +} + +/** + * The first [HEADER_LENGTH_BYTES] bytes of every node + * Contains 1 byte indicating whether the node marks the end of a valid word in the library + * Followed by a bitset, where each bit represents the presence of a child node. + * The indices of the bits correspond to the value set of the global [charMap]. + */ +class NodeHeader( + private val nodeIsWord: Boolean +) { + private val flags = BitSet() + fun serializeTo(output: SerializedOutput) { + val bytes = MutableList(HEADER_LENGTH_BYTES) { 0 } + bytes[0] = if (nodeIsWord) 1 else 0 + var i = HEADER_LENGTH_BYTES - 1 + flags.toByteArray().forEach { bytes[i--] = it } + output.write(bytes) + } + + operator fun set(index: Int, value: Boolean) { + flags[index] = value + } +} + +fun interface SerializedOutput { + fun write(bytes: Collection) +} + +sealed class TrieNode { + abstract fun fetch(char: Char): TrieNode + + private fun fetch(string: String): TrieNode { + if (string.isEmpty()) return this + return when (val next = fetch(string.first())) { + is ParentNode -> next.fetch(string.rest) + is OnlyWordNode -> if (string.length > 1) { + NullNode + } else { + OnlyWordNode + } + is NullNode -> NullNode + } + } + + abstract fun insert(string: String): TrieNode + + fun contains(string: String): Boolean { + return when (fetch(string)) { + is WordParentNode -> true + is OnlyParentNode -> false + is OnlyWordNode -> true + is NullNode -> false + } + } + + open fun serializeTo(offset: UInt, queue: Queue, output: SerializedOutput): UInt { + return 0u + } + + abstract val nodeSize: Int +} + +val String.rest: String + get() = removeRange(0, 1) + +/** + * Base class for nodes that have children + * In the context of the dictionary trie - a node that represents a partial word + */ +sealed class ParentNode( + protected val chars: MutableList = MutableList(charMap.size) { NullNode } +) : TrieNode() { + + override fun fetch(char: Char): TrieNode { + return chars.getOrElse(char.alphaIndex) { NullNode } + } + + fun insertChar(char: Char) { + chars[char.alphaIndex] = OnlyWordNode + } + + abstract val name: String + abstract val isWord: Boolean + + override fun toString(): String { + return "$name(\n" + + chars.joinToString(separator = "\n") { s -> + s.toString().lines().joinToString("\n") { " $it" } + } + + "\n)" + } + + private val populatedChars + get() = chars.count { it !is NullNode } + + override val nodeSize: Int + get() = populatedChars + HEADER_LENGTH_WORDS + + override fun serializeTo(offset: UInt, queue: Queue, output: SerializedOutput): UInt { + val header = NodeHeader(isWord) + val sizes = chars.scan(0u) { acc, trieNode -> acc + trieNode.nodeSize.toUInt() } + val thisRow = chars.flatMapIndexed { index, node -> + val address = when (node) { + is ParentNode -> (offset + sizes[index]) + is OnlyWordNode -> 0xFFFFFFu + is NullNode -> null + } + header[index] = address != null + return@flatMapIndexed address?.toBytes().orEmpty() + } + queue.addAll(chars) + header.serializeTo(output) + output.write(thisRow) + return sizes.last() + } +} + +/** + * A trie node that represents a valid word, and is also the prefix for at least one other word + */ +class WordParentNode( + chars: MutableList = MutableList(charMap.size) { NullNode } +) : ParentNode(chars) { + override fun insert(string: String): TrieNode { + if (string.isNotEmpty()) { + val first = string.first() + chars[first.alphaIndex] = fetch(first).insert(string.rest) + } + return this + } + + override val name: String = "WordParent" + + override val isWord: Boolean = true +} + +/** + * A trie node that represents a prefix for at least one other word + */ +class OnlyParentNode( + chars: MutableList = MutableList(charMap.size) { NullNode } +) : ParentNode(chars) { + override fun insert(string: String): TrieNode { + if (string.isNotEmpty()) { + val first = string.first() + chars[first.alphaIndex] = fetch(first).insert(string.rest) + return this + } + return WordParentNode(chars) + } + + override val name: String = "OnlyParent" + + override val isWord: Boolean = false +} + +/** + * A trie node that represents a valid word that is NOT a prefix for any other words + */ +object OnlyWordNode : TrieNode() { + override fun fetch(char: Char): TrieNode = NullNode + + override fun insert(string: String): TrieNode { + if (string.isEmpty()) return this + val first = string.first() + val newParent = WordParentNode() + if (string.length == 1) { + newParent.insertChar(first) + } else { + newParent.insert(string) + } + return newParent + } + + override fun toString(): String = "ChildNode" + + override val nodeSize: Int = 0 +} + +/** + * A trie node that is neither a word, or a prefix for a word. A dead end. + */ +object NullNode : TrieNode() { + override fun fetch(char: Char): TrieNode = NullNode + + override fun insert(string: String): TrieNode { + if (string.isEmpty()) { + return OnlyWordNode + } + return OnlyParentNode().insert(string) + } + + override fun toString(): String = "Null" + + override val nodeSize: Int = 0 +} + +/** + * Convert UInt into a byte array + */ +fun UInt.toBytes(isBigEndian: Boolean = true, wordLength: Int = ADDRESS_LENGTH_BYTES): List { + val bytes = mutableListOf() + var n = this + if (n == 0x00u) { + bytes += n.toByte() + } else { + while (n != 0x00u) { + bytes += n.toByte() + n = n.shr(Byte.SIZE_BITS) + } + } + + val paddings = if (bytes.size > wordLength) { + emptyList() + } else { + List(wordLength - bytes.size) { 0x00 } + } + return paddings + if (isBigEndian) bytes.reversed() else bytes +} + +/** + * Each language has a key_map file, which maps the T9 buttons (1, 2, 3...) to an array of type-able characters + * These maps should only contain the characters relevant to that language. The set of characters is + * collected as a part of [serializeLibraryFile] and then passed here. + * + * As a shortcut, we write a valid Python dictionary file that can be imported directly by the T9 FW. + */ +internal fun writeKeyMapFile(libraryResult: LibraryResult.Success, outputFile: File) { + val languageCharacterSet = libraryResult.charSet + universalCharacters + val filteredKeyMap = globalKeyMap + .mapValues { (_, value) -> value.filter { languageCharacterSet.contains(it) } } + .map { (key, value) -> + val escapedList = value.joinToString(",") { + val escapedChar = StringEscapeUtils.escapeEcmaScript(it.toString()) + "\"$escapedChar\"" + } + "\'$key\':[$escapedList]" + } + .let { "key_map = {${it.joinToString(",")}}" } + + outputFile.outputStream().bufferedWriter().use { writer -> + writer.write(filteredKeyMap) + } +} \ No newline at end of file diff --git a/library_generator/src/main/kotlin/com/dupontgu/t9/web/GCloudMain.kt b/library_generator/src/main/kotlin/com/dupontgu/t9/web/GCloudMain.kt index 7545ebe..12a24e2 100644 --- a/library_generator/src/main/kotlin/com/dupontgu/t9/web/GCloudMain.kt +++ b/library_generator/src/main/kotlin/com/dupontgu/t9/web/GCloudMain.kt @@ -1,7 +1,9 @@ package com.dupontgu.t9.web -import LibraryResult +import KEY_MAP_FILE +import com.dupontgu.t9.* import com.dupontgu.t9.web.DevBoard.* +import com.dupontgu.t9.writeKeyMapFile import io.ktor.application.* import io.ktor.features.* import io.ktor.html.* @@ -12,12 +14,13 @@ import io.ktor.response.* import io.ktor.routing.* import kotlinx.html.* import org.apache.log4j.BasicConfigurator -import serializeLibraryFile +import org.zeroturnaround.zip.ZipUtil import java.lang.IllegalArgumentException -import java.util.* import kotlin.io.path.createTempFile -private const val LIB_FILE_NAME = "library.t9l" +private const val ARCHIVE_NAME = "t9_library.zip" +private const val LIB_FILE_NAME = "library.t9l2" +private const val VERSION_FILE_NAME = "version.txt" private enum class DevBoard( val displayName: String @@ -67,20 +70,38 @@ fun Application.main() { call.respondHtml(HttpStatusCode.OK) { renderFirmwarePage(devBoard) } } + get("/fw-update/{board}") { + val devBoard = call.parseDevBoard() ?: return@get call.respond(HttpStatusCode.NotFound) + call.respondHtml(HttpStatusCode.OK) { renderFirmwareUpdatePage(devBoard) } + } + + val keyMapPrefix = "keyMap" + val libraryPrefix = "library" post("/upload") { _ -> val multipart = call.receiveMultipart() var responded = false multipart.forEachPart { part -> if (part is PartData.FileItem) { - val tempFile = createTempFile(prefix = UUID.randomUUID().toString()).toFile() - val result = serializeLibraryFile(part.streamProvider(), tempFile.outputStream()) + val libraryFile = createTempFile(prefix = libraryPrefix).toFile() + val result = serializeLibraryFile(part.streamProvider(), libraryFile.outputStream()) if (result is LibraryResult.Error) { call.respond(HttpStatusCode.UnprocessableEntity, result.message) - } else { - call.response.header("Content-Disposition", "attachment; filename=\"$LIB_FILE_NAME\"") - call.respondFile(tempFile) + responded = true + } else if (result is LibraryResult.Success) { + val keyMapFile = createTempFile(prefix = keyMapPrefix).toFile() + val archive = createTempFile(prefix = "archive").toFile() + writeKeyMapFile(result, keyMapFile) + ZipUtil.packEntries(arrayOf(libraryFile, keyMapFile), archive) { + when { + it.startsWith(keyMapPrefix) -> KEY_MAP_FILE + it.startsWith(libraryPrefix) -> LIB_FILE_NAME + else -> it + } + } + call.response.header("Content-Disposition", "attachment; filename=\"$ARCHIVE_NAME\"") + call.respondFile(archive) + responded = true } - responded = true } part.dispose() } @@ -91,7 +112,6 @@ fun Application.main() { ) } } - } } @@ -102,16 +122,37 @@ fun HTML.renderRootPage() { body { h1 { +"Standalone T9 Keypad" } h2 { +"By Guy Dupont" } - +"Read the usage instructions "; a("/usage") { +"here." }; br() - +"Generate your own custom T9 library "; a("/library") { +"here." }; br() - +"Purchase "; a("https://www.etsy.com/shop/EsotericGadgetsByGuy?ele=shop_open") { +"here!!" }; +" (limited supply)"; br(); - +"If you have the DIY kit (or just the PCB), assembly instructions are "; a("/board?destination=assembly") { +"here." }; br(); - +"If you need to install the T9 firmware, check "; a("/board?destination=firmware") { +"here." }; br(); - +"Follow Guy on Twitter "; a("https://twitter.com/gvy_dvpont") { +"here." }; br() - +"Email Guy at "; a("mailto:gvy.dvpont@gmail.com") { +"gvy.dvpont@gmail.com." }; br() - +"Watch the YouTube video "; a("https://youtu.be/6cbBSEbwLUI") { +"here." }; br() - +"See the Hackaday.io project page "; a("https://hackaday.io/project/179977-standalone-t9-predictive-keyboard") { +"here." }; br() - +"Find the source code "; a("https://github.com/dupontgu/t9-macropad-circuitpython") { +"here." }; br() + h3 { +"If you already have a working T9 Keypad:" } + ul { + li { +"Read the usage instructions "; a("/usage") { +"here." }; } + li { +"Generate your own custom T9 library "; a("/library") { +"here." }; } + li { +"Update to the latest version of the firmware "; a("/board?destination=fw-update") { +"here." }; } + } + h3 { +"If you do not yet have a T9 Keypad:" } + ul { + li { + +"Purchase "; a("https://www.etsy.com/shop/EsotericGadgetsByGuy?ele=shop_open") { +"here!!" }; +" (kits available as well)"; + } + } + h3 { +"If you have a kit, or are building on your own:" } + ul { + li { +"Assembly instructions are "; a("/board?destination=assembly") { +"here." }; } + li { +"If you need to install the T9 firmware, check "; a("/board?destination=firmware") { +"here." }; } + } + + h3 { +"If you want to get in touch with Guy:" } + ul { + li { +"Follow Guy on Twitter "; a("https://twitter.com/gvy_dvpont") { +"here." }; } + li { +"Email Guy at "; a("mailto:gvy.dvpont@gmail.com") { +"gvy.dvpont@gmail.com." }; } + } + + h3 { +"If want to learn more about the project:" } + ul { + li { +"Watch the YouTube video "; a("https://youtu.be/6cbBSEbwLUI") { +"here." }; } + li { +"See the Hackaday.io project page "; a("https://hackaday.io/project/179977-standalone-t9-predictive-keyboard") { +"here." }; } + li { +"Find the source code "; a("https://github.com/dupontgu/t9-macropad-circuitpython") { +"here." }; } + } + } } @@ -153,9 +194,11 @@ private fun HTML.renderKitInstructionsPage(devBoard: DevBoard) { title { +"T9 Keypad Assembly" } style { unsafe { - raw(""" + raw( + """ img { max-width: 800px; } - """) + """ + ) } } } @@ -231,7 +274,7 @@ private fun HTML.renderFirmwarePage(devBoard: DevBoard) { li { +"Dowload the latest version of CircuitPython for the " a(devBoard.circuitPythonLink) { +"${devBoard.displayName}." } - +" As of July 2021, version 6.3.0 works great on all boards." + +" As of April 2022, version 7.2.5 works great on all boards." } li { +"On your development board, hold the button labeled 'boot', and plug it into your computer." @@ -251,7 +294,7 @@ private fun HTML.renderFirmwarePage(devBoard: DevBoard) { } li { +"Find the latest T9 firmware release on the " - a("https://github.com/dupontgu/t9-macropad-circuitpython/releases"){ +"GitHub releases page." } + a("https://github.com/dupontgu/t9-macropad-circuitpython/releases") { +"GitHub releases page. " } +""" Each release should have a list of .zip files associated with it. Find the one that matches your dev board. This board's zip file should be called: ${devBoard.fwZipName}.zip. Download and unzip it. @@ -269,7 +312,7 @@ private fun HTML.renderFirmwarePage(devBoard: DevBoard) { Download the CircuitPython library bundle that matches the CircuitPython version that you installed. You can find all versions of the bundle """.trimIndent() - a("https://circuitpython.org/libraries"){ +"here." } + a("https://circuitpython.org/libraries") { +"here." } } li { +""" @@ -295,6 +338,49 @@ private fun HTML.renderFirmwarePage(devBoard: DevBoard) { } } +private fun HTML.renderFirmwareUpdatePage(devBoard: DevBoard) { + head { + title { +"T9 Firmware Update Instructions" } + } + body { + h1 { +"Updating T9 CircuitPython Firmware" } + h2 { +"Note - only follow these steps if you already have a working T9 Keypad." } + h3 { a("/") { +"(Project Root)" } } + narrowDiv { + ol { + li { + +""" + Plug your T9 keypad into your computer. Your computer should recognize it as both a + keyboard and a mass storage device. The storage device is likely named: 'CIRCUITPY'. + """.trimIndent() + } + li { + +"Find the latest T9 firmware release on the " + a("https://github.com/dupontgu/t9-macropad-circuitpython/releases") { +"GitHub releases page. " } + +""" + Each release should have a list of .zip files associated with it. Find the one that matches your dev board. + This board's zip file should be called: ${devBoard.fwZipName}.zip. Download and unzip it. + """.trimIndent() + } + li { + +""" + Copy all of the files from the extracted ${devBoard.fwZipName} folder onto your dev board, + which should still be mounted on your computer as 'CIRCUITPY'. Overwrite any conflicting files. + This may take a minute. Do not delete any existing files! + """.trimIndent() + } + li { + +""" + The board should automatically reboot + and the light should turn blue after ~5 seconds. You're good to go! Check out the full usage instructions + """.trimIndent() + a("/usage") { +"here!" } + } + } + } + } +} + fun HTML.renderUsageInstructionsPage() { head { title { +"T9 Keypad Usage Instructions" } @@ -331,6 +417,17 @@ fun HTML.renderLibraryGeneratorPage() { } body { h1 { +"Guy's T9 Library Generator" } + h2 { +"IMPORTANT! Library files generated by this page will only work with keypads running (at least) version 2 of the firmware." } + narrowDiv { + +""" + If you are unsure which version of the firmware you are running, plug your keypad into a computer. + Open the CIRCUITPY drive in your file explorer. + Look for a file named $VERSION_FILE_NAME. If the file does not exist, you are running version 1 and need to update. + Otherwise, the file will tell you which version is currently running. + If you need to update, follow the instructions + """.trimIndent() + a("/board?destination=fw-update") { +"here." }; + } h3 { a("/") { +"(Project Root)" } } unsafe { +"" @@ -341,15 +438,18 @@ fun HTML.renderLibraryGeneratorPage() { }; br() +"Use the form below to upload a text file containing the words you'd like available on your keyboard."; br() +"The file should be a plain .txt file, and each line should contain exactly one word."; br() - +"Currently, words can only contain the letters A-Z (upper or lowercase), and can only be 25 characters long."; br() - a("https://raw.githubusercontent.com/dupontgu/t9-macropad-circuitpython/main/library_generator/src/main/resources/dict.txt") { +"Here" } - +" you can find my default list of words. Feel free to download this file (File -> Save As) and add or remove words as you see fit!" + +"The T9 algorithm is language agnostic, but only the following characters are currently supported:"; br() + +"${charMap.keys}"; br() + a("https://raw.githubusercontent.com/oprogramador/most-common-words-by-language/master/src/resources/english.txt") { +"Here" } + +" you can find a default list of English words. Feel free to download this file (File -> Save As) and add or remove words as you see fit!"; br() + +"For other languages, check " + a("https://github.com/oprogramador/most-common-words-by-language/tree/master/src/resources") { +"here." } br(); br() +"When you successfully upload a word library file using the \"Browse\" button below, you will be given the option to download a new file, named " - b { +LIB_FILE_NAME }; +"."; br() - +"Drag and drop this .t9l file on to your T9 keyboard drive (likely named CIRCUITPY) and replace the existing file with the same name."; br() - +"Back up the old file first if you want to save it! You can name it anything, but the keyboard will only use the file named $LIB_FILE_NAME as it's current library. "; br() - +"Once the new file has loaded (it may take a minute or so), the keyboard will reboot and your new library will be loaded!" + b { +ARCHIVE_NAME }; +"."; br() + +"Extract all files from this archive, them drag-and-drop them on to your T9 keyboard drive (likely named CIRCUITPY). Replace the existing files with the same name."; br() + b { +"Back up the old files first if you want to save them!"; br() } + +"Once the new files have loaded (it may take a minute or so), the keyboard will reboot and your new library will be loaded!" br(); br() form(action = "upload", method = FormMethod.post) { input(InputType.file, formEncType = InputFormEncType.multipartFormData, name = "File here!") @@ -361,3 +461,4 @@ fun HTML.renderLibraryGeneratorPage() { } } } + diff --git a/library_generator/src/main/resources/dict.txt b/library_generator/src/main/resources/dict.txt deleted file mode 100644 index 368143d..0000000 --- a/library_generator/src/main/resources/dict.txt +++ /dev/null @@ -1,10000 +0,0 @@ -a -aa -aaa -aaron -ab -abandoned -abc -aberdeen -abilities -ability -able -aboriginal -abortion -about -above -abraham -abroad -abs -absence -absent -absolute -absolutely -absorption -abstract -abstracts -abu -abuse -ac -academic -academics -academy -acc -accent -accept -acceptable -acceptance -accepted -accepting -accepts -access -accessed -accessibility -accessible -accessing -accessories -accessory -accident -accidents -accommodate -accommodation -accommodations -accompanied -accompanying -accomplish -accomplished -accordance -according -accordingly -account -accountability -accounting -accounts -accreditation -accredited -accuracy -accurate -accurately -accused -acdbentity -ace -acer -achieve -achieved -achievement -achievements -achieving -acid -acids -acknowledge -acknowledged -acm -acne -acoustic -acquire -acquired -acquisition -acquisitions -acre -acres -acrobat -across -acrylic -act -acting -action -actions -activated -activation -active -actively -activists -activities -activity -actor -actors -actress -acts -actual -actually -acute -ad -ada -adam -adams -adaptation -adapted -adapter -adapters -adaptive -adaptor -add -added -addiction -adding -addition -additional -additionally -additions -address -addressed -addresses -addressing -adds -adelaide -adequate -adidas -adipex -adjacent -adjust -adjustable -adjusted -adjustment -adjustments -admin -administered -administration -administrative -administrator -administrators -admission -admissions -admit -admitted -adobe -adolescent -adopt -adopted -adoption -adrian -ads -adsl -adult -adults -advance -advanced -advancement -advances -advantage -advantages -adventure -adventures -adverse -advert -advertise -advertisement -advertisements -advertiser -advertisers -advertising -advice -advise -advised -advisor -advisors -advisory -advocacy -advocate -adware -ae -aerial -aerospace -af -affair -affairs -affect -affected -affecting -affects -affiliate -affiliated -affiliates -affiliation -afford -affordable -afghanistan -afraid -africa -african -after -afternoon -afterwards -ag -again -against -age -aged -agencies -agency -agenda -agent -agents -ages -aggregate -aggressive -aging -ago -agree -agreed -agreement -agreements -agrees -agricultural -agriculture -ah -ahead -ai -aid -aids -aim -aimed -aims -air -aircraft -airfare -airline -airlines -airplane -airport -airports -aj -ak -aka -al -ala -alabama -alan -alarm -alaska -albania -albany -albert -alberta -album -albums -albuquerque -alcohol -alert -alerts -alex -alexander -alexandria -alfred -algebra -algeria -algorithm -algorithms -ali -alias -alice -alien -align -alignment -alike -alive -all -allah -allan -alleged -allen -allergy -alliance -allied -allocated -allocation -allow -allowance -allowed -allowing -allows -alloy -almost -alone -along -alot -alpha -alphabetical -alpine -already -also -alt -alter -altered -alternate -alternative -alternatively -alternatives -although -alto -aluminium -aluminum -alumni -always -am -amanda -amateur -amazing -amazon -amazoncom -amazoncouk -ambassador -amber -ambien -ambient -amd -amend -amended -amendment -amendments -amenities -america -american -americans -americas -amino -among -amongst -amount -amounts -amp -ampland -amplifier -amsterdam -amy -an -ana -anaheim -anal -analog -analyses -analysis -analyst -analysts -analytical -analyze -analyzed -anatomy -anchor -ancient -and -andale -anderson -andorra -andrea -andreas -andrew -andrews -andy -angel -angela -angeles -angels -anger -angle -angola -angry -animal -animals -animated -animation -anime -ann -anna -anne -annex -annie -anniversary -annotated -annotation -announce -announced -announcement -announcements -announces -annoying -annual -annually -anonymous -another -answer -answered -answering -answers -ant -antarctica -antenna -anthony -anthropology -anti -antibodies -antibody -anticipated -antigua -antique -antiques -antivirus -antonio -anxiety -any -anybody -anymore -anyone -anything -anytime -anyway -anywhere -aol -ap -apache -apart -apartment -apartments -api -apnic -apollo -app -apparatus -apparel -apparent -apparently -appeal -appeals -appear -appearance -appeared -appearing -appears -appendix -apple -appliance -appliances -applicable -applicant -applicants -application -applications -applied -applies -apply -applying -appointed -appointment -appointments -appraisal -appreciate -appreciated -appreciation -approach -approaches -appropriate -appropriations -approval -approve -approved -approx -approximate -approximately -apps -apr -april -apt -aqua -aquarium -aquatic -ar -arab -arabia -arabic -arbitrary -arbitration -arc -arcade -arch -architect -architects -architectural -architecture -archive -archived -archives -arctic -are -area -areas -arena -arg -argentina -argue -argued -argument -arguments -arise -arising -arizona -arkansas -arlington -arm -armed -armenia -armor -arms -armstrong -army -arnold -around -arrange -arranged -arrangement -arrangements -array -arrest -arrested -arrival -arrivals -arrive -arrived -arrives -arrow -art -arthritis -arthur -article -articles -artificial -artist -artistic -artists -arts -artwork -aruba -as -asbestos -ascii -ash -ashley -asia -asian -aside -asin -ask -asked -asking -asks -asn -asp -aspect -aspects -aspnet -ass -assault -assembled -assembly -assess -assessed -assessing -assessment -assessments -asset -assets -assign -assigned -assignment -assignments -assist -assistance -assistant -assisted -assists -associate -associated -associates -association -associations -assume -assumed -assumes -assuming -assumption -assumptions -assurance -assure -assured -asthma -astrology -astronomy -asus -at -ata -ate -athens -athletes -athletic -athletics -ati -atlanta -atlantic -atlas -atm -atmosphere -atmospheric -atom -atomic -attach -attached -attachment -attachments -attack -attacked -attacks -attempt -attempted -attempting -attempts -attend -attendance -attended -attending -attention -attitude -attitudes -attorney -attorneys -attract -attraction -attractions -attractive -attribute -attributes -au -auburn -auckland -auction -auctions -aud -audi -audience -audio -audit -auditor -aug -august -aurora -aus -austin -australia -australian -austria -authentic -authentication -author -authorities -authority -authorization -authorized -authors -auto -automated -automatic -automatically -automation -automobile -automobiles -automotive -autos -autumn -av -availability -available -avatar -ave -avenue -average -avg -avi -aviation -avoid -avoiding -avon -aw -award -awarded -awards -aware -awareness -away -awesome -awful -axis -aye -az -azerbaijan -b -ba -babe -babes -babies -baby -bachelor -back -backed -background -backgrounds -backing -backup -bacon -bacteria -bacterial -bad -badge -badly -bag -baghdad -bags -bahamas -bahrain -bailey -baker -baking -balance -balanced -bald -bali -ball -ballet -balloon -ballot -balls -baltimore -ban -banana -band -bands -bandwidth -bang -bangbus -bangkok -bangladesh -bank -banking -bankruptcy -banks -banned -banner -banners -baptist -bar -barbados -barbara -barbie -barcelona -bare -barely -bargain -bargains -barn -barnes -barrel -barrier -barriers -barry -bars -base -baseball -based -baseline -basement -basename -bases -basic -basically -basics -basin -basis -basket -basketball -baskets -bass -bat -batch -bath -bathroom -bathrooms -baths -batman -batteries -battery -battle -battlefield -bay -bb -bbc -bbs -bbw -bc -bd -bdsm -be -beach -beaches -beads -beam -bean -beans -bear -bearing -bears -beast -beastality -beastiality -beat -beatles -beats -beautiful -beautifully -beauty -beaver -became -because -become -becomes -becoming -bed -bedding -bedford -bedroom -bedrooms -beds -bee -beef -been -beer -before -began -begin -beginner -beginners -beginning -begins -begun -behalf -behavior -behavioral -behaviour -behind -beijing -being -beings -belarus -belfast -belgium -belief -beliefs -believe -believed -believes -belize -belkin -bell -belle -belly -belong -belongs -below -belt -belts -ben -bench -benchmark -bend -beneath -beneficial -benefit -benefits -benjamin -bennett -benz -berkeley -berlin -bermuda -bernard -berry -beside -besides -best -bestiality -bestsellers -bet -beta -beth -better -betting -betty -between -beverage -beverages -beverly -beyond -bg -bhutan -bi -bias -bible -biblical -bibliographic -bibliography -bicycle -bid -bidder -bidding -bids -big -bigger -biggest -bike -bikes -bikini -bill -billing -billion -bills -billy -bin -binary -bind -binding -bingo -bio -biodiversity -biographies -biography -biol -biological -biology -bios -biotechnology -bird -birds -birmingham -birth -birthday -bishop -bit -bitch -bite -bits -biz -bizarre -bizrate -bk -bl -black -blackberry -blackjack -blacks -blade -blades -blah -blair -blake -blame -blank -blanket -blast -bleeding -blend -bless -blessed -blind -blink -block -blocked -blocking -blocks -blog -blogger -bloggers -blogging -blogs -blond -blonde -blood -bloody -bloom -bloomberg -blow -blowing -blowjob -blowjobs -blue -blues -bluetooth -blvd -bm -bmw -bo -board -boards -boat -boating -boats -bob -bobby -boc -bodies -body -bold -bolivia -bolt -bomb -bon -bond -bondage -bonds -bone -bones -bonus -boob -boobs -book -booking -bookings -bookmark -bookmarks -books -bookstore -bool -boolean -boom -boost -boot -booth -boots -booty -border -borders -bored -boring -born -borough -bosnia -boss -boston -both -bother -botswana -bottle -bottles -bottom -bought -boulder -boulevard -bound -boundaries -boundary -bouquet -boutique -bow -bowl -bowling -box -boxed -boxes -boxing -boy -boys -bp -br -bra -bracelet -bracelets -bracket -brad -bradford -bradley -brain -brake -brakes -branch -branches -brand -brandon -brands -bras -brass -brave -brazil -brazilian -breach -bread -break -breakdown -breakfast -breaking -breaks -breast -breasts -breath -breathing -breed -breeding -breeds -brian -brick -bridal -bride -bridge -bridges -brief -briefing -briefly -briefs -bright -brighton -brilliant -bring -bringing -brings -brisbane -bristol -britain -britannica -british -britney -broad -broadband -broadcast -broadcasting -broader -broadway -brochure -brochures -broke -broken -broker -brokers -bronze -brook -brooklyn -brooks -bros -brother -brothers -brought -brown -browse -browser -browsers -browsing -bruce -brunei -brunette -brunswick -brush -brussels -brutal -bryan -bryant -bs -bt -bubble -buck -bucks -budapest -buddy -budget -budgets -buf -buffalo -buffer -bufing -bug -bugs -build -builder -builders -building -buildings -builds -built -bukkake -bulgaria -bulgarian -bulk -bull -bullet -bulletin -bumper -bunch -bundle -bunny -burden -bureau -buried -burke -burlington -burn -burner -burning -burns -burst -burton -bus -buses -bush -business -businesses -busty -busy -but -butler -butt -butter -butterfly -button -buttons -butts -buy -buyer -buyers -buying -buys -buzz -bw -by -bye -byte -bytes -c -ca -cab -cabin -cabinet -cabinets -cable -cables -cache -cached -cad -cadillac -cafe -cage -cake -cakes -cal -calcium -calculate -calculated -calculation -calculations -calculator -calculators -calendar -calendars -calgary -calibration -calif -california -call -called -calling -calls -calm -calvin -cam -cambodia -cambridge -camcorder -camcorders -came -camel -camera -cameras -cameron -cameroon -camp -campaign -campaigns -campbell -camping -camps -campus -cams -can -canada -canadian -canal -canberra -cancel -cancellation -cancelled -cancer -candidate -candidates -candle -candles -candy -cannon -canon -cant -canvas -canyon -cap -capabilities -capability -capable -capacity -cape -capital -capitol -caps -captain -capture -captured -car -carb -carbon -card -cardiac -cardiff -cardiovascular -cards -care -career -careers -careful -carefully -carey -cargo -caribbean -caring -carl -carlo -carlos -carmen -carnival -carol -carolina -caroline -carpet -carried -carrier -carriers -carries -carroll -carry -carrying -cars -cart -carter -cartoon -cartoons -cartridge -cartridges -cas -casa -case -cases -casey -cash -cashiers -casino -casinos -casio -cassette -cast -casting -castle -casual -cat -catalog -catalogs -catalogue -catalyst -catch -categories -category -catering -cathedral -catherine -catholic -cats -cattle -caught -cause -caused -causes -causing -caution -cave -cayman -cb -cbs -cc -ccd -cd -cdna -cds -cdt -ce -cedar -ceiling -celebrate -celebration -celebrities -celebrity -celebs -cell -cells -cellular -celtic -cement -cemetery -census -cent -center -centered -centers -central -centre -centres -cents -centuries -century -ceo -ceramic -ceremony -certain -certainly -certificate -certificates -certification -certified -cest -cet -cf -cfr -cg -cgi -ch -chad -chain -chains -chair -chairman -chairs -challenge -challenged -challenges -challenging -chamber -chambers -champagne -champion -champions -championship -championships -chan -chance -chancellor -chances -change -changed -changelog -changes -changing -channel -channels -chaos -chapel -chapter -chapters -char -character -characteristic -characteristics -characterization -characterized -characters -charge -charged -charger -chargers -charges -charging -charitable -charity -charles -charleston -charlie -charlotte -charm -charming -charms -chart -charter -charts -chase -chassis -chat -cheap -cheaper -cheapest -cheat -cheats -check -checked -checking -checklist -checkout -checks -cheers -cheese -chef -chelsea -chem -chemical -chemicals -chemistry -chen -cheque -cherry -chess -chest -chester -chevrolet -chevy -chi -chicago -chick -chicken -chicks -chief -child -childhood -children -childrens -chile -china -chinese -chip -chips -cho -chocolate -choice -choices -choir -cholesterol -choose -choosing -chorus -chose -chosen -chris -christ -christian -christianity -christians -christina -christine -christmas -christopher -chrome -chronic -chronicle -chronicles -chrysler -chubby -chuck -church -churches -ci -cia -cialis -ciao -cigarette -cigarettes -cincinnati -cindy -cinema -cingular -cio -cir -circle -circles -circuit -circuits -circular -circulation -circumstances -circus -cisco -citation -citations -cite -cited -cities -citizen -citizens -citizenship -city -citysearch -civic -civil -civilian -civilization -cj -cl -claim -claimed -claims -claire -clan -clara -clarity -clark -clarke -class -classes -classic -classical -classics -classification -classified -classifieds -classroom -clause -clay -clean -cleaner -cleaners -cleaning -cleanup -clear -clearance -cleared -clearing -clearly -clerk -cleveland -click -clicking -clicks -client -clients -cliff -climate -climb -climbing -clinic -clinical -clinics -clinton -clip -clips -clock -clocks -clone -close -closed -closely -closer -closes -closest -closing -closure -cloth -clothes -clothing -cloud -clouds -cloudy -club -clubs -cluster -clusters -cm -cms -cn -cnet -cnetcom -cnn -co -coach -coaches -coaching -coal -coalition -coast -coastal -coat -coated -coating -cock -cocks -cod -code -codes -coding -coffee -cognitive -cohen -coin -coins -col -cold -cole -coleman -colin -collaboration -collaborative -collapse -collar -colleague -colleagues -collect -collectables -collected -collectible -collectibles -collecting -collection -collections -collective -collector -collectors -college -colleges -collins -cologne -colombia -colon -colonial -colony -color -colorado -colored -colors -colour -colours -columbia -columbus -column -columnists -columns -com -combat -combination -combinations -combine -combined -combines -combining -combo -come -comedy -comes -comfort -comfortable -comic -comics -coming -comm -command -commander -commands -comment -commentary -commented -comments -commerce -commercial -commission -commissioner -commissioners -commissions -commit -commitment -commitments -committed -committee -committees -commodities -commodity -common -commonly -commons -commonwealth -communicate -communication -communications -communist -communities -community -comp -compact -companies -companion -company -compaq -comparable -comparative -compare -compared -comparing -comparison -comparisons -compatibility -compatible -compensation -compete -competent -competing -competition -competitions -competitive -competitors -compilation -compile -compiled -compiler -complaint -complaints -complement -complete -completed -completely -completing -completion -complex -complexity -compliance -compliant -complicated -complications -complimentary -comply -component -components -composed -composer -composite -composition -compound -compounds -comprehensive -compressed -compression -compromise -computation -computational -compute -computed -computer -computers -computing -con -concentrate -concentration -concentrations -concept -concepts -conceptual -concern -concerned -concerning -concerns -concert -concerts -conclude -concluded -conclusion -conclusions -concord -concrete -condition -conditional -conditioning -conditions -condo -condos -conduct -conducted -conducting -conf -conference -conferences -conferencing -confidence -confident -confidential -confidentiality -config -configuration -configure -configured -configuring -confirm -confirmation -confirmed -conflict -conflicts -confused -confusion -congo -congratulations -congress -congressional -conjunction -connect -connected -connecticut -connecting -connection -connections -connectivity -connector -connectors -cons -conscious -consciousness -consecutive -consensus -consent -consequence -consequences -consequently -conservation -conservative -consider -considerable -consideration -considerations -considered -considering -considers -consist -consistency -consistent -consistently -consisting -consists -console -consoles -consolidated -consolidation -consortium -conspiracy -const -constant -constantly -constitute -constitutes -constitution -constitutional -constraint -constraints -construct -constructed -construction -consult -consultancy -consultant -consultants -consultation -consulting -consumer -consumers -consumption -contact -contacted -contacting -contacts -contain -contained -container -containers -containing -contains -contamination -contemporary -content -contents -contest -contests -context -continent -continental -continually -continue -continued -continues -continuing -continuity -continuous -continuously -contract -contracting -contractor -contractors -contracts -contrary -contrast -contribute -contributed -contributing -contribution -contributions -contributor -contributors -control -controlled -controller -controllers -controlling -controls -controversial -controversy -convenience -convenient -convention -conventional -conventions -convergence -conversation -conversations -conversion -convert -converted -converter -convertible -convicted -conviction -convinced -cook -cookbook -cooked -cookie -cookies -cooking -cool -cooler -cooling -cooper -cooperation -cooperative -coordinate -coordinated -coordinates -coordination -coordinator -cop -cope -copied -copies -copper -copy -copying -copyright -copyrighted -copyrights -coral -cord -cordless -core -cork -corn -cornell -corner -corners -cornwall -corp -corporate -corporation -corporations -corps -corpus -correct -corrected -correction -corrections -correctly -correlation -correspondence -corresponding -corruption -cos -cosmetic -cosmetics -cost -costa -costs -costume -costumes -cottage -cottages -cotton -could -council -councils -counsel -counseling -count -counted -counter -counters -counties -counting -countries -country -counts -county -couple -coupled -couples -coupon -coupons -courage -courier -course -courses -court -courtesy -courts -cove -cover -coverage -covered -covering -covers -cow -cowboy -cox -cp -cpu -cr -crack -cradle -craft -crafts -craig -crap -craps -crash -crawford -crazy -cream -create -created -creates -creating -creation -creations -creative -creativity -creator -creature -creatures -credit -credits -creek -crest -crew -cricket -crime -crimes -criminal -crisis -criteria -criterion -critical -criticism -critics -crm -croatia -crop -crops -cross -crossing -crossword -crowd -crown -crucial -crude -cruise -cruises -cruz -cry -crystal -cs -css -cst -ct -cu -cuba -cube -cubic -cuisine -cult -cultural -culture -cultures -cum -cumshot -cumshots -cumulative -cunt -cup -cups -cure -curious -currencies -currency -current -currently -curriculum -cursor -curtis -curve -curves -custody -custom -customer -customers -customise -customize -customized -customs -cut -cute -cuts -cutting -cv -cvs -cw -cyber -cycle -cycles -cycling -cylinder -cyprus -cz -czech -d -da -dad -daddy -daily -dairy -daisy -dakota -dale -dallas -dam -damage -damaged -damages -dame -damn -dan -dana -dance -dancing -danger -dangerous -daniel -danish -danny -dans -dare -dark -darkness -darwin -das -dash -dat -data -database -databases -date -dated -dates -dating -daughter -daughters -dave -david -davidson -davis -dawn -day -days -dayton -db -dc -dd -ddr -de -dead -deadline -deadly -deaf -deal -dealer -dealers -dealing -deals -dealt -dealtime -dean -dear -death -deaths -debate -debian -deborah -debt -debug -debut -dec -decade -decades -december -decent -decide -decided -decimal -decision -decisions -deck -declaration -declare -declared -decline -declined -decor -decorating -decorative -decrease -decreased -dedicated -dee -deemed -deep -deeper -deeply -deer -def -default -defeat -defects -defence -defend -defendant -defense -defensive -deferred -deficit -define -defined -defines -defining -definitely -definition -definitions -degree -degrees -del -delaware -delay -delayed -delays -delegation -delete -deleted -delhi -delicious -delight -deliver -delivered -delivering -delivers -delivery -dell -delta -deluxe -dem -demand -demanding -demands -demo -democracy -democrat -democratic -democrats -demographic -demonstrate -demonstrated -demonstrates -demonstration -den -denial -denied -denmark -dennis -dense -density -dental -dentists -denver -deny -department -departmental -departments -departure -depend -dependence -dependent -depending -depends -deployment -deposit -deposits -depot -depression -dept -depth -deputy -der -derby -derek -derived -des -descending -describe -described -describes -describing -description -descriptions -desert -deserve -design -designated -designation -designed -designer -designers -designing -designs -desirable -desire -desired -desk -desktop -desktops -desperate -despite -destination -destinations -destiny -destroy -destroyed -destruction -detail -detailed -details -detect -detected -detection -detective -detector -determination -determine -determined -determines -determining -detroit -deutsch -deutsche -deutschland -dev -devel -develop -developed -developer -developers -developing -development -developmental -developments -develops -deviant -deviation -device -devices -devil -devon -devoted -df -dg -dh -di -diabetes -diagnosis -diagnostic -diagram -dial -dialog -dialogue -diameter -diamond -diamonds -diana -diane -diary -dice -dick -dicke -dicks -dictionaries -dictionary -did -die -died -diego -dies -diesel -diet -dietary -diff -differ -difference -differences -different -differential -differently -difficult -difficulties -difficulty -diffs -dig -digest -digit -digital -dildo -dildos -dim -dimension -dimensional -dimensions -dining -dinner -dip -diploma -dir -direct -directed -direction -directions -directive -directly -director -directories -directors -directory -dirt -dirty -dis -disabilities -disability -disable -disabled -disagree -disappointed -disaster -disc -discharge -disciplinary -discipline -disciplines -disclaimer -disclaimers -disclose -disclosure -disco -discount -discounted -discounts -discover -discovered -discovery -discrete -discretion -discrimination -discs -discuss -discussed -discusses -discussing -discussion -discussions -disease -diseases -dish -dishes -disk -disks -disney -disorder -disorders -dispatch -dispatched -display -displayed -displaying -displays -disposal -disposition -dispute -disputes -dist -distance -distances -distant -distinct -distinction -distinguished -distribute -distributed -distribution -distributions -distributor -distributors -district -districts -disturbed -div -dive -diverse -diversity -divide -divided -dividend -divine -diving -division -divisions -divorce -divx -diy -dj -dk -dl -dm -dna -dns -do -doc -dock -docs -doctor -doctors -doctrine -document -documentary -documentation -documented -documents -dod -dodge -doe -does -dog -dogs -doing -doll -dollar -dollars -dolls -dom -domain -domains -dome -domestic -dominant -dominican -don -donald -donate -donated -donation -donations -done -donna -donor -donors -dont -doom -door -doors -dos -dosage -dose -dot -double -doubt -doug -douglas -dover -dow -down -download -downloadable -downloadcom -downloaded -downloading -downloads -downtown -dozen -dozens -dp -dpi -dr -draft -drag -dragon -drain -drainage -drama -dramatic -dramatically -draw -drawing -drawings -drawn -draws -dream -dreams -dress -dressed -dresses -dressing -drew -dried -drill -drilling -drink -drinking -drinks -drive -driven -driver -drivers -drives -driving -drop -dropped -drops -drove -drug -drugs -drum -drums -drunk -dry -dryer -ds -dsc -dsl -dt -dts -du -dual -dubai -dublin -duck -dude -due -dui -duke -dumb -dump -duncan -duo -duplicate -durable -duration -durham -during -dust -dutch -duties -duty -dv -dvd -dvds -dx -dying -dylan -dynamic -dynamics -e -ea -each -eagle -eagles -ear -earl -earlier -earliest -early -earn -earned -earning -earnings -earrings -ears -earth -earthquake -ease -easier -easily -east -easter -eastern -easy -eat -eating -eau -ebay -ebony -ebook -ebooks -ec -echo -eclipse -eco -ecological -ecology -ecommerce -economic -economics -economies -economy -ecuador -ed -eddie -eden -edgar -edge -edges -edinburgh -edit -edited -editing -edition -editions -editor -editorial -editorials -editors -edmonton -eds -edt -educated -education -educational -educators -edward -edwards -ee -ef -effect -effective -effectively -effectiveness -effects -efficiency -efficient -efficiently -effort -efforts -eg -egg -eggs -egypt -egyptian -eh -eight -either -ejaculation -el -elder -elderly -elect -elected -election -elections -electoral -electric -electrical -electricity -electro -electron -electronic -electronics -elegant -element -elementary -elements -elephant -elevation -eleven -eligibility -eligible -eliminate -elimination -elite -elizabeth -ellen -elliott -ellis -else -elsewhere -elvis -em -emacs -email -emails -embassy -embedded -emerald -emergency -emerging -emily -eminem -emirates -emission -emissions -emma -emotional -emotions -emperor -emphasis -empire -empirical -employ -employed -employee -employees -employer -employers -employment -empty -en -enable -enabled -enables -enabling -enb -enclosed -enclosure -encoding -encounter -encountered -encourage -encouraged -encourages -encouraging -encryption -encyclopedia -end -endangered -ended -endif -ending -endless -endorsed -endorsement -ends -enemies -enemy -energy -enforcement -eng -engage -engaged -engagement -engaging -engine -engineer -engineering -engineers -engines -england -english -enhance -enhanced -enhancement -enhancements -enhancing -enjoy -enjoyed -enjoying -enlarge -enlargement -enormous -enough -enquiries -enquiry -enrolled -enrollment -ensemble -ensure -ensures -ensuring -ent -enter -entered -entering -enterprise -enterprises -enters -entertaining -entertainment -entire -entirely -entities -entitled -entity -entrance -entrepreneur -entrepreneurs -entries -entry -envelope -environment -environmental -environments -enzyme -eos -ep -epa -epic -epinions -epinionscom -episode -episodes -epson -eq -equal -equality -equally -equation -equations -equilibrium -equipment -equipped -equity -equivalent -er -era -eric -ericsson -erik -erotic -erotica -erp -error -errors -es -escape -escort -escorts -especially -espn -essay -essays -essence -essential -essentially -essentials -essex -est -establish -established -establishing -establishment -estate -estates -estimate -estimated -estimates -estimation -estonia -et -etc -eternal -ethernet -ethical -ethics -ethiopia -ethnic -eu -eugene -eur -euro -europe -european -euros -ev -eva -eval -evaluate -evaluated -evaluating -evaluation -evaluations -evanescence -evans -eve -even -evening -event -events -eventually -ever -every -everybody -everyday -everyone -everything -everywhere -evidence -evident -evil -evolution -ex -exact -exactly -exam -examination -examinations -examine -examined -examines -examining -example -examples -exams -exceed -excel -excellence -excellent -except -exception -exceptional -exceptions -excerpt -excess -excessive -exchange -exchanges -excited -excitement -exciting -exclude -excluded -excluding -exclusion -exclusive -exclusively -excuse -exec -execute -executed -execution -executive -executives -exempt -exemption -exercise -exercises -exhaust -exhibit -exhibition -exhibitions -exhibits -exist -existed -existence -existing -exists -exit -exotic -exp -expand -expanded -expanding -expansion -expansys -expect -expectations -expected -expects -expedia -expenditure -expenditures -expense -expenses -expensive -experience -experienced -experiences -experiencing -experiment -experimental -experiments -expert -expertise -experts -expiration -expired -expires -explain -explained -explaining -explains -explanation -explicit -explicitly -exploration -explore -explorer -exploring -explosion -expo -export -exports -exposed -exposure -express -expressed -expression -expressions -ext -extend -extended -extending -extends -extension -extensions -extensive -extent -exterior -external -extra -extract -extraction -extraordinary -extras -extreme -extremely -eye -eyed -eyes -ez -f -fa -fabric -fabrics -fabulous -face -faced -faces -facial -facilitate -facilities -facility -facing -fact -factor -factors -factory -facts -faculty -fail -failed -failing -fails -failure -failures -fair -fairfield -fairly -fairy -faith -fake -fall -fallen -falling -falls -false -fame -familiar -families -family -famous -fan -fancy -fans -fantastic -fantasy -faq -faqs -far -fare -fares -farm -farmer -farmers -farming -farms -fascinating -fashion -fast -faster -fastest -fat -fatal -fate -father -fathers -fatty -fault -favor -favorite -favorites -favors -favour -favourite -favourites -fax -fbi -fc -fcc -fd -fda -fe -fear -fears -feat -feature -featured -features -featuring -feb -february -fed -federal -federation -fee -feed -feedback -feeding -feeds -feel -feeling -feelings -feels -fees -feet -fell -fellow -fellowship -felt -female -females -fence -feof -ferrari -ferry -festival -festivals -fetish -fever -few -fewer -ff -fg -fi -fiber -fibre -fiction -field -fields -fifteen -fifth -fifty -fig -fight -fighter -fighters -fighting -figure -figured -figures -fiji -file -filed -filename -files -filing -fill -filled -filling -film -filme -films -filter -filtering -filters -fin -final -finally -finals -finance -finances -financial -financing -find -findarticles -finder -finding -findings -findlaw -finds -fine -finest -finger -fingering -fingers -finish -finished -finishing -finite -finland -finnish -fioricet -fire -fired -firefox -fireplace -fires -firewall -firewire -firm -firms -firmware -first -fiscal -fish -fisher -fisheries -fishing -fist -fisting -fit -fitness -fits -fitted -fitting -five -fix -fixed -fixes -fixtures -fl -fla -flag -flags -flame -flash -flashers -flashing -flat -flavor -fleece -fleet -flesh -flex -flexibility -flexible -flickr -flight -flights -flip -float -floating -flood -floor -flooring -floors -floppy -floral -florence -florida -florist -florists -flour -flow -flower -flowers -flows -floyd -flu -fluid -flush -flux -fly -flyer -flying -fm -fo -foam -focal -focus -focused -focuses -focusing -fog -fold -folder -folders -folding -folk -folks -follow -followed -following -follows -font -fonts -foo -food -foods -fool -foot -footage -football -footwear -for -forbes -forbidden -force -forced -forces -ford -forecast -forecasts -foreign -forest -forestry -forests -forever -forge -forget -forgot -forgotten -fork -form -formal -format -formation -formats -formatting -formed -former -formerly -forming -forms -formula -fort -forth -fortune -forty -forum -forums -forward -forwarding -fossil -foster -foto -fotos -fought -foul -found -foundation -foundations -founded -founder -fountain -four -fourth -fox -fp -fr -fraction -fragrance -fragrances -frame -framed -frames -framework -framing -france -franchise -francis -francisco -frank -frankfurt -franklin -fraser -fraud -fred -frederick -free -freebsd -freedom -freelance -freely -freeware -freeze -freight -french -frequencies -frequency -frequent -frequently -fresh -fri -friday -fridge -friend -friendly -friends -friendship -frog -from -front -frontier -frontpage -frost -frozen -fruit -fruits -fs -ft -ftp -fu -fuck -fucked -fucking -fuel -fuji -fujitsu -full -fully -fun -function -functional -functionality -functioning -functions -fund -fundamental -fundamentals -funded -funding -fundraising -funds -funeral -funk -funky -funny -fur -furnished -furnishings -furniture -further -furthermore -fusion -future -futures -fuzzy -fw -fwd -fx -fy -g -ga -gabriel -gadgets -gage -gain -gained -gains -galaxy -gale -galleries -gallery -gambling -game -gamecube -games -gamespot -gaming -gamma -gang -gangbang -gap -gaps -garage -garbage -garcia -garden -gardening -gardens -garlic -garmin -gary -gas -gasoline -gate -gates -gateway -gather -gathered -gathering -gauge -gave -gay -gays -gazette -gb -gba -gbp -gc -gcc -gd -gdp -ge -gear -geek -gel -gem -gen -gender -gene -genealogy -general -generally -generate -generated -generates -generating -generation -generations -generator -generators -generic -generous -genes -genesis -genetic -genetics -geneva -genius -genome -genre -genres -gentle -gentleman -gently -genuine -geo -geographic -geographical -geography -geological -geology -geometry -george -georgia -gerald -german -germany -get -gets -getting -gg -ghana -ghost -ghz -gi -giant -giants -gibraltar -gibson -gif -gift -gifts -gig -gilbert -girl -girlfriend -girls -gis -give -given -gives -giving -gl -glad -glance -glasgow -glass -glasses -glen -glenn -global -globe -glory -glossary -gloves -glow -glucose -gm -gmbh -gmc -gmt -gnome -gnu -go -goal -goals -goat -god -gods -goes -going -gold -golden -golf -gone -gonna -good -goods -google -gordon -gore -gorgeous -gospel -gossip -got -gothic -goto -gotta -gotten -gourmet -gov -governance -governing -government -governmental -governments -governor -govt -gp -gpl -gps -gr -grab -grace -grad -grade -grades -gradually -graduate -graduated -graduates -graduation -graham -grain -grammar -grams -grand -grande -granny -grant -granted -grants -graph -graphic -graphical -graphics -graphs -gras -grass -grateful -gratis -gratuit -grave -gravity -gray -great -greater -greatest -greatly -greece -greek -green -greene -greenhouse -greensboro -greeting -greetings -greg -gregory -grenada -grew -grey -grid -griffin -grill -grip -grocery -groove -gross -ground -grounds -groundwater -group -groups -grove -grow -growing -grown -grows -growth -gs -gsm -gst -gt -gtk -guam -guarantee -guaranteed -guarantees -guard -guardian -guards -guatemala -guess -guest -guestbook -guests -gui -guidance -guide -guided -guidelines -guides -guild -guilty -guinea -guitar -guitars -gulf -gun -guns -guru -guy -guyana -guys -gym -gzip -h -ha -habitat -habits -hack -hacker -had -hair -hairy -haiti -half -halfcom -halifax -hall -halloween -halo -ham -hamburg -hamilton -hammer -hampshire -hampton -hand -handbags -handbook -handed -handheld -handhelds -handjob -handjobs -handle -handled -handles -handling -handmade -hands -handy -hang -hanging -hans -hansen -happen -happened -happening -happens -happiness -happy -harassment -harbor -harbour -hard -hardcore -hardcover -harder -hardly -hardware -hardwood -harley -harm -harmful -harmony -harold -harper -harris -harrison -harry -hart -hartford -harvard -harvest -harvey -has -hash -hat -hate -hats -have -haven -having -hawaii -hawaiian -hawk -hay -hayes -hazard -hazardous -hazards -hb -hc -hd -hdtv -he -head -headed -header -headers -heading -headline -headlines -headphones -headquarters -heads -headset -healing -health -healthcare -healthy -hear -heard -hearing -hearings -heart -hearts -heat -heated -heater -heath -heather -heating -heaven -heavily -heavy -hebrew -heel -height -heights -held -helen -helena -helicopter -hell -hello -helmet -help -helped -helpful -helping -helps -hence -henderson -henry -hentai -hepatitis -her -herald -herb -herbal -herbs -here -hereby -herein -heritage -hero -heroes -herself -hewlett -hey -hh -hi -hidden -hide -hierarchy -high -higher -highest -highland -highlight -highlighted -highlights -highly -highs -highway -highways -hiking -hill -hills -hilton -him -himself -hindu -hint -hints -hip -hire -hired -hiring -his -hispanic -hist -historic -historical -history -hit -hitachi -hits -hitting -hiv -hk -hl -ho -hobbies -hobby -hockey -hold -holdem -holder -holders -holding -holdings -holds -hole -holes -holiday -holidays -holland -hollow -holly -hollywood -holmes -holocaust -holy -home -homeland -homeless -homepage -homes -hometown -homework -hon -honda -honduras -honest -honey -hong -honolulu -honor -honors -hood -hook -hop -hope -hoped -hopefully -hopes -hoping -hopkins -horizon -horizontal -hormone -horn -horny -horrible -horror -horse -horses -hose -hospital -hospitality -hospitals -host -hosted -hostel -hostels -hosting -hosts -hot -hotel -hotels -hotelscom -hotmail -hottest -hour -hourly -hours -house -household -households -houses -housewares -housewives -housing -houston -how -howard -however -howto -hp -hq -hr -href -hrs -hs -ht -html -http -hu -hub -hudson -huge -hugh -hughes -hugo -hull -human -humanitarian -humanities -humanity -humans -humidity -humor -hundred -hundreds -hung -hungarian -hungary -hunger -hungry -hunt -hunter -hunting -huntington -hurricane -hurt -husband -hwy -hybrid -hydraulic -hydrocodone -hydrogen -hygiene -hypothesis -hypothetical -hyundai -hz -i -ia -ian -ibm -ic -ice -iceland -icon -icons -icq -ict -id -idaho -ide -idea -ideal -ideas -identical -identification -identified -identifier -identifies -identify -identifying -identity -idle -idol -ids -ie -ieee -if -ignore -ignored -ii -iii -il -ill -illegal -illinois -illness -illustrated -illustration -illustrations -im -ima -image -images -imagination -imagine -imaging -img -immediate -immediately -immigrants -immigration -immune -immunology -impact -impacts -impaired -imperial -implement -implementation -implemented -implementing -implications -implied -implies -import -importance -important -importantly -imported -imports -impose -imposed -impossible -impressed -impression -impressive -improve -improved -improvement -improvements -improving -in -inappropriate -inbox -inc -incentive -incentives -incest -inch -inches -incidence -incident -incidents -incl -include -included -includes -including -inclusion -inclusive -income -incoming -incomplete -incorporate -incorporated -incorrect -increase -increased -increases -increasing -increasingly -incredible -incurred -ind -indeed -independence -independent -independently -index -indexed -indexes -india -indian -indiana -indianapolis -indians -indicate -indicated -indicates -indicating -indication -indicator -indicators -indices -indie -indigenous -indirect -individual -individually -individuals -indonesia -indonesian -indoor -induced -induction -industrial -industries -industry -inexpensive -inf -infant -infants -infected -infection -infections -infectious -infinite -inflation -influence -influenced -influences -info -inform -informal -information -informational -informative -informed -infrared -infrastructure -ing -ingredients -inherited -initial -initially -initiated -initiative -initiatives -injection -injured -injuries -injury -ink -inkjet -inline -inn -inner -innocent -innovation -innovations -innovative -inns -input -inputs -inquire -inquiries -inquiry -ins -insects -insert -inserted -insertion -inside -insider -insight -insights -inspection -inspections -inspector -inspiration -inspired -install -installation -installations -installed -installing -instance -instances -instant -instantly -instead -institute -institutes -institution -institutional -institutions -instruction -instructional -instructions -instructor -instructors -instrument -instrumental -instrumentation -instruments -insulin -insurance -insured -int -intake -integer -integral -integrate -integrated -integrating -integration -integrity -intel -intellectual -intelligence -intelligent -intend -intended -intense -intensity -intensive -intent -intention -inter -interact -interaction -interactions -interactive -interest -interested -interesting -interests -interface -interfaces -interference -interim -interior -intermediate -internal -international -internationally -internet -internship -interpretation -interpreted -interracial -intersection -interstate -interval -intervals -intervention -interventions -interview -interviews -intimate -intl -into -intranet -intro -introduce -introduced -introduces -introducing -introduction -introductory -invalid -invasion -invention -inventory -invest -investigate -investigated -investigation -investigations -investigator -investigators -investing -investment -investments -investor -investors -invisible -invision -invitation -invitations -invite -invited -invoice -involve -involved -involvement -involves -involving -io -ion -iowa -ip -ipaq -ipod -ips -ir -ira -iran -iraq -iraqi -irc -ireland -irish -iron -irrigation -irs -is -isa -isaac -isbn -islam -islamic -island -islands -isle -iso -isolated -isolation -isp -israel -israeli -issn -issue -issued -issues -ist -istanbul -it -italia -italian -italiano -italic -italy -item -items -its -itsa -itself -itunes -iv -ivory -ix -j -ja -jack -jacket -jackets -jackie -jackson -jacksonville -jacob -jade -jaguar -jail -jake -jam -jamaica -james -jamie -jan -jane -janet -january -japan -japanese -jar -jason -java -javascript -jay -jazz -jc -jd -je -jean -jeans -jeep -jeff -jefferson -jeffrey -jelsoft -jennifer -jenny -jeremy -jerry -jersey -jerusalem -jesse -jessica -jesus -jet -jets -jewel -jewellery -jewelry -jewish -jews -jill -jim -jimmy -jj -jm -jo -joan -job -jobs -joe -joel -john -johnny -johns -johnson -johnston -join -joined -joining -joins -joint -joke -jokes -jon -jonathan -jones -jordan -jose -joseph -josh -joshua -journal -journalism -journalist -journalists -journals -journey -joy -joyce -jp -jpeg -jpg -jr -js -juan -judge -judges -judgment -judicial -judy -juice -jul -julia -julian -julie -july -jump -jumps -jumping -jun -junction -june -jungle -junior -junk -jurisdiction -jury -just -justice -justify -justin -juvenile -jvc -k -ka -kai -kansas -karaoke -karen -karl -karma -kate -kathy -katie -katrina -kay -kazakhstan -kb -kde -keen -keep -keeping -keeps -keith -kelkoo -kelly -ken -kennedy -kenneth -kenny -keno -kent -kentucky -kenya -kept -kernel -kerry -kevin -key -keyboard -keyboards -keys -keyword -keywords -kg -kick -kid -kidney -kids -kijiji -kill -killed -killer -killing -kills -kilometers -kim -kinase -kind -kinda -kinds -king -kingdom -kings -kingston -kirk -kiss -kissing -kit -kitchen -kits -kitty -klein -km -knee -knew -knife -knight -knights -knit -knitting -knives -knock -know -knowing -knowledge -knowledgestorm -known -knows -ko -kodak -kong -korea -korean -kruger -ks -kurt -kuwait -kw -ky -kyle -l -la -lab -label -labeled -labels -labor -laboratories -laboratory -labour -labs -lace -lack -ladder -laden -ladies -lady -lafayette -laid -lake -lakes -lamb -lambda -lamp -lamps -lan -lancaster -lance -land -landing -lands -landscape -landscapes -lane -lanes -lang -language -languages -lanka -lap -laptop -laptops -large -largely -larger -largest -larry -las -laser -last -lasting -lat -late -lately -later -latest -latex -latin -latina -latinas -latino -latitude -latter -latvia -lauderdale -laugh -laughing -launch -launched -launches -laundry -laura -lauren -law -lawn -lawrence -laws -lawsuit -lawyer -lawyers -lay -layer -layers -layout -lazy -lb -lbs -lc -lcd -ld -le -lead -leader -leaders -leadership -leading -leads -leaf -league -lean -learn -learned -learners -learning -lease -leasing -least -leather -leave -leaves -leaving -lebanon -lecture -lectures -led -lee -leeds -left -leg -legacy -legal -legally -legend -legendary -legends -legislation -legislative -legislature -legitimate -legs -leisure -lemon -len -lender -lenders -lending -length -lens -lenses -leo -leon -leonard -leone -les -lesbian -lesbians -leslie -less -lesser -lesson -lessons -let -lets -letter -letters -letting -leu -level -levels -levitra -levy -lewis -lexington -lexmark -lexus -lf -lg -li -liabilities -liability -liable -lib -liberal -liberia -liberty -librarian -libraries -library -libs -licence -license -licensed -licenses -licensing -licking -lid -lie -liechtenstein -lies -life -lifestyle -lifetime -lift -light -lighter -lighting -lightning -lights -lightweight -like -liked -likelihood -likely -likes -likewise -lil -lime -limit -limitation -limitations -limited -limiting -limits -limousines -lincoln -linda -lindsay -line -linear -lined -lines -lingerie -link -linked -linking -links -linux -lion -lions -lip -lips -liquid -lisa -list -listed -listen -listening -listing -listings -listprice -lists -lit -lite -literacy -literally -literary -literature -lithuania -litigation -little -live -livecam -lived -liver -liverpool -lives -livesex -livestock -living -liz -ll -llc -lloyd -llp -lm -ln -lo -load -loaded -loading -loads -loan -loans -lobby -loc -local -locale -locally -locate -located -location -locations -locator -lock -locked -locking -locks -lodge -lodging -log -logan -logged -logging -logic -logical -login -logistics -logitech -logo -logos -logs -lol -lolita -london -lone -lonely -long -longer -longest -longitude -look -looked -looking -looks -looksmart -lookup -loop -loops -loose -lopez -lord -los -lose -losing -loss -losses -lost -lot -lots -lottery -lotus -lou -loud -louis -louise -louisiana -louisville -lounge -love -loved -lovely -lover -lovers -loves -loving -low -lower -lowest -lows -lp -ls -lt -ltd -lu -lucas -lucia -luck -lucky -lucy -luggage -luis -luke -lunch -lung -luther -luxembourg -luxury -lycos -lying -lynn -lyric -lyrics -m -ma -mac -macedonia -machine -machinery -machines -macintosh -macro -macromedia -mad -madagascar -made -madison -madness -madonna -madrid -mae -mag -magazine -magazines -magic -magical -magnet -magnetic -magnificent -magnitude -mai -maiden -mail -mailed -mailing -mailman -mails -mailto -main -maine -mainland -mainly -mainstream -maintain -maintained -maintaining -maintains -maintenance -major -majority -make -maker -makers -makes -makeup -making -malawi -malaysia -maldives -male -males -mali -mall -malpractice -malta -mambo -man -manage -managed -management -manager -managers -managing -manchester -mandate -mandatory -manga -manhattan -manitoba -manner -manor -manual -manually -manuals -manufacture -manufactured -manufacturer -manufacturers -manufacturing -many -map -maple -mapping -maps -mar -marathon -marble -marc -march -marco -marcus -mardi -margaret -margin -maria -mariah -marie -marijuana -marilyn -marina -marine -mario -marion -maritime -mark -marked -marker -markers -market -marketing -marketplace -markets -marking -marks -marriage -married -marriott -mars -marshall -mart -martha -martial -martin -marvel -mary -maryland -mas -mask -mason -mass -massachusetts -massage -massive -master -mastercard -masters -masturbating -masturbation -mat -match -matched -matches -matching -mate -material -materials -maternity -math -mathematical -mathematics -mating -matrix -mats -matt -matter -matters -matthew -mattress -mature -maui -mauritius -max -maximize -maximum -may -maybe -mayor -mazda -mb -mba -mc -mcdonald -md -me -meal -meals -mean -meaning -meaningful -means -meant -meanwhile -measure -measured -measurement -measurements -measures -measuring -meat -mechanical -mechanics -mechanism -mechanisms -med -medal -media -median -medicaid -medical -medicare -medication -medications -medicine -medicines -medieval -meditation -mediterranean -medium -medline -meet -meeting -meetings -meets -meetup -mega -mel -melbourne -melissa -mem -member -members -membership -membrane -memo -memorabilia -memorial -memories -memory -memphis -men -mens -ment -mental -mention -mentioned -mentor -menu -menus -mercedes -merchandise -merchant -merchants -mercury -mercy -mere -merely -merge -merger -merit -merry -mesa -mesh -mess -message -messages -messaging -messenger -met -meta -metabolism -metadata -metal -metallic -metallica -metals -meter -meters -method -methodology -methods -metres -metric -metro -metropolitan -mexican -mexico -meyer -mf -mfg -mg -mh -mhz -mi -mia -miami -mic -mice -michael -michel -michelle -michigan -micro -microphone -microsoft -microwave -mid -middle -midi -midlands -midnight -midwest -might -mighty -migration -mike -mil -milan -mild -mile -mileage -miles -milf -milfhunter -milfs -military -milk -mill -millennium -miller -million -millions -mills -milton -milwaukee -mime -min -mind -minds -mine -mineral -minerals -mines -mini -miniature -minimal -minimize -minimum -mining -minister -ministers -ministries -ministry -minneapolis -minnesota -minolta -minor -minority -mins -mint -minus -minute -minutes -miracle -mirror -mirrors -misc -miscellaneous -miss -missed -missile -missing -mission -missions -mississippi -missouri -mistake -mistakes -mistress -mit -mitchell -mitsubishi -mix -mixed -mixer -mixing -mixture -mj -ml -mlb -mls -mm -mn -mo -mobile -mobiles -mobility -mod -mode -model -modeling -modelling -models -modem -modems -moderate -moderator -moderators -modern -modes -modification -modifications -modified -modify -mods -modular -module -modules -moisture -mold -moldova -molecular -molecules -mom -moment -moments -momentum -moms -mon -monaco -monday -monetary -money -mongolia -monica -monitor -monitored -monitoring -monitors -monkey -mono -monroe -monster -montana -monte -montgomery -month -monthly -months -montreal -mood -moon -moore -moral -more -moreover -morgan -morning -morocco -morris -morrison -mortality -mortgage -mortgages -moscow -moses -moss -most -mostly -motel -motels -mother -motherboard -mothers -motion -motivated -motivation -motor -motorcycle -motorcycles -motorola -motors -mount -mountain -mountains -mounted -mounting -mounts -mouse -mouth -move -moved -movement -movements -movers -moves -movie -movies -moving -mozambique -mozilla -mp -mpeg -mpegs -mpg -mph -mr -mrna -mrs -ms -msg -msgid -msgstr -msie -msn -mt -mtv -mu -much -mud -mug -multi -multimedia -multiple -mumbai -munich -municipal -municipality -murder -murphy -murray -muscle -muscles -museum -museums -music -musical -musician -musicians -muslim -muslims -must -mustang -mutual -muze -mv -mw -mx -my -myanmar -myers -myrtle -myself -mysimon -myspace -mysql -mysterious -mystery -myth -n -na -nail -nails -naked -nam -name -named -namely -names -namespace -namibia -nancy -nano -naples -narrative -narrow -nasa -nascar -nasdaq -nashville -nasty -nat -nathan -nation -national -nationally -nations -nationwide -native -nato -natural -naturally -naturals -nature -naughty -nav -naval -navigate -navigation -navigator -navy -nb -nba -nbc -nc -ncaa -nd -ne -near -nearby -nearest -nearly -nebraska -nec -necessarily -necessary -necessity -neck -necklace -need -needed -needle -needs -negative -negotiation -negotiations -neighbor -neighborhood -neighbors -neil -neither -nelson -neo -neon -nepal -nerve -nervous -nest -nested -net -netherlands -netscape -network -networking -networks -neural -neutral -nevada -never -nevertheless -new -newark -newbie -newcastle -newer -newest -newfoundland -newly -newport -news -newscom -newsletter -newsletters -newspaper -newspapers -newton -next -nextel -nfl -ng -nh -nhl -nhs -ni -niagara -nicaragua -nice -nicholas -nick -nickel -nickname -nicole -niger -nigeria -night -nightlife -nightmare -nights -nike -nikon -nil -nine -nintendo -nipple -nipples -nirvana -nissan -nitrogen -nj -nl -nm -nn -no -noble -nobody -node -nodes -noise -nokia -nominated -nomination -nominations -non -none -nonprofit -noon -nor -norfolk -norm -normal -normally -norman -north -northeast -northern -northwest -norton -norway -norwegian -nos -nose -not -note -notebook -notebooks -noted -notes -nothing -notice -noticed -notices -notification -notifications -notified -notify -notion -notre -nottingham -nov -nova -novel -novels -novelty -november -now -nowhere -np -nr -ns -nsw -nt -ntsc -nu -nuclear -nude -nudist -nudity -nuke -null -number -numbers -numeric -numerical -numerous -nurse -nursery -nurses -nursing -nut -nutrition -nutritional -nuts -nutten -nv -nvidia -nw -ny -nyc -nylon -nz -o -oak -oakland -oaks -oasis -ob -obesity -obituaries -obj -object -objective -objectives -objects -obligation -obligations -observation -observations -observe -observed -observer -obtain -obtained -obtaining -obvious -obviously -oc -occasion -occasional -occasionally -occasions -occupation -occupational -occupations -occupied -occur -occurred -occurrence -occurring -occurs -ocean -oclc -oct -october -odd -odds -oe -oecd -oem -of -off -offense -offensive -offer -offered -offering -offerings -offers -office -officer -officers -offices -official -officially -officials -offline -offset -offshore -often -og -oh -ohio -oil -oils -ok -okay -oklahoma -ol -old -older -oldest -olive -oliver -olympic -olympics -olympus -om -omaha -oman -omega -omissions -on -once -one -ones -ongoing -onion -online -only -ons -ontario -onto -oo -ooo -oops -op -open -opened -opening -openings -opens -opera -operate -operated -operates -operating -operation -operational -operations -operator -operators -opinion -opinions -opponent -opponents -opportunities -opportunity -opposed -opposite -opposition -opt -optical -optics -optimal -optimization -optimize -optimum -option -optional -options -or -oracle -oral -orange -orbit -orchestra -order -ordered -ordering -orders -ordinance -ordinary -oregon -org -organ -organic -organisation -organisations -organised -organisms -organization -organizational -organizations -organize -organized -organizer -organizing -orgasm -orgy -oriental -orientation -oriented -origin -original -originally -origins -orlando -orleans -os -oscar -ot -other -others -otherwise -ottawa -ou -ought -our -ours -ourselves -out -outcome -outcomes -outdoor -outdoors -outer -outlet -outline -outlined -outlook -output -outputs -outreach -outside -outsourcing -outstanding -oval -oven -over -overall -overcome -overhead -overnight -overseas -overview -owen -own -owned -owner -owners -ownership -owns -oxford -oxide -oxygen -oz -ozone -p -pa -pac -pace -pacific -pack -package -packages -packaging -packard -packed -packet -packets -packing -packs -pad -pads -page -pages -paid -pain -painful -paint -paintball -painted -painting -paintings -pair -pairs -pakistan -pal -palace -pale -palestine -palestinian -palm -palmer -pam -pamela -pan -panama -panasonic -panel -panels -panic -panties -pants -pantyhose -paper -paperback -paperbacks -papers -papua -par -para -parade -paradise -paragraph -paragraphs -paraguay -parallel -parameter -parameters -parcel -parent -parental -parenting -parents -paris -parish -park -parker -parking -parks -parliament -parliamentary -part -partial -partially -participant -participants -participate -participated -participating -participation -particle -particles -particular -particularly -parties -partition -partly -partner -partners -partnership -partnerships -parts -party -pas -paso -pass -passage -passed -passenger -passengers -passes -passing -passion -passive -passport -password -passwords -past -pasta -paste -pastor -pat -patch -patches -patent -patents -path -pathology -paths -patient -patients -patio -patricia -patrick -patrol -pattern -patterns -paul -pavilion -paxil -pay -payable -payday -paying -payment -payments -paypal -payroll -pays -pb -pc -pci -pcs -pct -pd -pda -pdas -pdf -pdt -pe -peace -peaceful -peak -pearl -peas -pediatric -pee -peeing -peer -peers -pen -penalties -penalty -pencil -pendant -pending -penetration -penguin -peninsula -penis -penn -pennsylvania -penny -pens -pension -pensions -pentium -people -peoples -pepper -per -perceived -percent -percentage -perception -perfect -perfectly -perform -performance -performances -performed -performer -performing -performs -perfume -perhaps -period -periodic -periodically -periods -peripheral -peripherals -perl -permalink -permanent -permission -permissions -permit -permits -permitted -perry -persian -persistent -person -personal -personality -personalized -personally -personals -personnel -persons -perspective -perspectives -perth -peru -pest -pet -pete -peter -petersburg -peterson -petite -petition -petroleum -pets -pf -pg -pgp -ph -phantom -pharmaceutical -pharmaceuticals -pharmacies -pharmacology -pharmacy -phase -phases -phd -phenomenon -phentermine -phi -phil -philadelphia -philip -philippines -philips -phillips -philosophy -phoenix -phone -phones -photo -photograph -photographer -photographers -photographic -photographs -photography -photos -photoshop -php -phpbb -phrase -phrases -phys -physical -physically -physician -physicians -physics -physiology -pi -piano -pic -pichunter -pick -picked -picking -picks -pickup -picnic -pics -picture -pictures -pie -piece -pieces -pierce -pierre -pig -pike -pill -pillow -pills -pilot -pin -pine -ping -pink -pins -pioneer -pipe -pipeline -pipes -pirates -piss -pissing -pit -pitch -pittsburgh -pix -pixel -pixels -pizza -pj -pk -pl -place -placed -placement -places -placing -plain -plains -plaintiff -plan -plane -planes -planet -planets -planned -planner -planners -planning -plans -plant -plants -plasma -plastic -plastics -plate -plates -platform -platforms -platinum -play -playback -playboy -played -player -players -playing -playlist -plays -playstation -plaza -plc -pleasant -please -pleased -pleasure -pledge -plenty -plot -plots -plug -plugin -plugins -plumbing -plus -plymouth -pm -pmc -pmid -pn -po -pocket -pockets -pod -podcast -podcasts -poem -poems -poet -poetry -point -pointed -pointer -pointing -points -pokemon -poker -poland -polar -pole -police -policies -policy -polish -polished -political -politicians -politics -poll -polls -pollution -polo -poly -polyester -polymer -polyphonic -pond -pontiac -pool -pools -poor -pop -pope -popular -popularity -population -populations -por -porcelain -pork -porn -porno -porsche -port -portable -portal -porter -portfolio -portion -portions -portland -portrait -portraits -ports -portsmouth -portugal -portuguese -pos -pose -posing -position -positioning -positions -positive -possess -possession -possibilities -possibility -possible -possibly -post -postage -postal -postcard -postcards -posted -poster -posters -posting -postings -postposted -posts -pot -potato -potatoes -potential -potentially -potter -pottery -poultry -pound -pounds -pour -poverty -powder -powell -power -powered -powerful -powerpoint -powers -powerseller -pp -ppc -ppm -pr -practical -practice -practices -practitioner -practitioners -prague -prairie -praise -pray -prayer -prayers -pre -preceding -precious -precipitation -precise -precisely -precision -predict -predicted -prediction -predictions -prefer -preference -preferences -preferred -prefers -prefix -pregnancy -pregnant -preliminary -premier -premiere -premises -premium -prep -prepaid -preparation -prepare -prepared -preparing -prerequisite -prescribed -prescription -presence -present -presentation -presentations -presented -presenting -presently -presents -preservation -preserve -president -presidential -press -pressed -pressing -pressure -preston -pretty -prev -prevent -preventing -prevention -preview -previews -previous -previously -price -priced -prices -pricing -pride -priest -primarily -primary -prime -prince -princess -princeton -principal -principle -principles -print -printable -printed -printer -printers -printing -prints -prior -priorities -priority -prison -prisoner -prisoners -privacy -private -privilege -privileges -prix -prize -prizes -pro -probability -probably -probe -problem -problems -proc -procedure -procedures -proceed -proceeding -proceedings -proceeds -process -processed -processes -processing -processor -processors -procurement -produce -produced -producer -producers -produces -producing -product -production -productions -productive -productivity -products -prof -profession -professional -professionals -professor -profile -profiles -profit -profits -program -programme -programmer -programmers -programmes -programming -programs -progress -progressive -prohibited -project -projected -projection -projector -projectors -projects -prominent -promise -promised -promises -promising -promo -promote -promoted -promotes -promoting -promotion -promotional -promotions -prompt -promptly -proof -propecia -proper -properly -properties -property -prophet -proportion -proposal -proposals -propose -proposed -proposition -proprietary -pros -prospect -prospective -prospects -prostate -prostores -prot -protect -protected -protecting -protection -protective -protein -proteins -protest -protocol -protocols -prototype -proud -proudly -prove -proved -proven -provide -provided -providence -provider -providers -provides -providing -province -provinces -provincial -provision -provisions -proxy -prozac -ps -psi -psp -pst -psychiatry -psychological -psychology -pt -pts -pty -pub -public -publication -publications -publicity -publicly -publish -published -publisher -publishers -publishing -pubmed -pubs -puerto -pull -pulled -pulling -pulse -pump -pumps -punch -punishment -punk -pupils -puppy -purchase -purchased -purchases -purchasing -pure -purple -purpose -purposes -purse -pursuant -pursue -pursuit -push -pushed -pushing -pussy -put -puts -putting -puzzle -puzzles -pvc -python -q -qatar -qc -qld -qt -qty -quad -qualification -qualifications -qualified -qualify -qualifying -qualities -quality -quantitative -quantities -quantity -quantum -quarter -quarterly -quarters -que -quebec -queen -queens -queensland -queries -query -quest -question -questionnaire -questions -queue -qui -quick -quickly -quiet -quilt -quit -quite -quiz -quizzes -quotations -quote -quoted -quotes -r -ra -rabbit -race -races -rachel -racial -racing -rack -racks -radar -radiation -radical -radio -radios -radius -rage -raid -rail -railroad -railway -rain -rainbow -raise -raised -raises -raising -raleigh -rally -ralph -ram -ran -ranch -rand -random -randy -range -rangers -ranges -ranging -rank -ranked -ranking -rankings -ranks -rap -rape -rapid -rapidly -rapids -rare -rarely -rat -rate -rated -rates -rather -rating -ratings -ratio -rational -ratios -rats -raw -ray -raymond -rays -rb -rc -rca -rd -re -reach -reached -reaches -reaching -reaction -reactions -read -reader -readers -readily -reading -readings -reads -ready -real -realistic -reality -realize -realized -really -realm -realtor -realtors -realty -rear -reason -reasonable -reasonably -reasoning -reasons -rebate -rebates -rebecca -rebel -rebound -rec -recall -receipt -receive -received -receiver -receivers -receives -receiving -recent -recently -reception -receptor -receptors -recipe -recipes -recipient -recipients -recognised -recognition -recognize -recognized -recommend -recommendation -recommendations -recommended -recommends -reconstruction -record -recorded -recorder -recorders -recording -recordings -records -recover -recovered -recovery -recreation -recreational -recruiting -recruitment -recycling -red -redeem -redhead -reduce -reduced -reduces -reducing -reduction -reductions -reed -reef -reel -ref -refer -reference -referenced -references -referral -referrals -referred -referring -refers -refinance -refine -refined -reflect -reflected -reflection -reflections -reflects -reform -reforms -refresh -refrigerator -refugees -refund -refurbished -refuse -refused -reg -regard -regarded -regarding -regardless -regards -reggae -regime -region -regional -regions -register -registered -registrar -registration -registry -regression -regular -regularly -regulated -regulation -regulations -regulatory -rehab -rehabilitation -reid -reject -rejected -rel -relate -related -relates -relating -relation -relations -relationship -relationships -relative -relatively -relatives -relax -relaxation -relay -release -released -releases -relevance -relevant -reliability -reliable -reliance -relief -religion -religions -religious -reload -relocation -rely -relying -remain -remainder -remained -remaining -remains -remark -remarkable -remarks -remedies -remedy -remember -remembered -remind -reminder -remix -remote -removable -removal -remove -removed -removing -renaissance -render -rendered -rendering -renew -renewable -renewal -reno -rent -rental -rentals -rentcom -rep -repair -repairs -repeat -repeated -replace -replaced -replacement -replacing -replica -replication -replied -replies -reply -report -reported -reporter -reporters -reporting -reports -repository -represent -representation -representations -representative -representatives -represented -representing -represents -reprint -reprints -reproduce -reproduced -reproduction -reproductive -republic -republican -republicans -reputation -request -requested -requesting -requests -require -required -requirement -requirements -requires -requiring -res -rescue -research -researcher -researchers -reseller -reservation -reservations -reserve -reserved -reserves -reservoir -reset -residence -resident -residential -residents -resist -resistance -resistant -resolution -resolutions -resolve -resolved -resort -resorts -resource -resources -respect -respected -respective -respectively -respiratory -respond -responded -respondent -respondents -responding -response -responses -responsibilities -responsibility -responsible -rest -restaurant -restaurants -restoration -restore -restored -restrict -restricted -restriction -restrictions -restructuring -result -resulted -resulting -results -resume -resumes -retail -retailer -retailers -retain -retained -retention -retired -retirement -retreat -retrieval -retrieve -retrieved -retro -return -returned -returning -returns -reunion -reuters -rev -reveal -revealed -reveals -revelation -revenge -revenue -revenues -reverse -review -reviewed -reviewer -reviewing -reviews -revised -revision -revisions -revolution -revolutionary -reward -rewards -reynolds -rf -rfc -rg -rh -rhode -rhythm -ri -ribbon -rica -rice -rich -richard -richards -richardson -richmond -rick -rico -rid -ride -rider -riders -rides -ridge -riding -right -rights -rim -ring -rings -ringtone -ringtones -rio -rip -ripe -rise -rising -risk -risks -river -rivers -riverside -rj -rl -rm -rn -rna -ro -road -roads -rob -robert -roberts -robertson -robin -robinson -robot -robots -robust -rochester -rock -rocket -rocks -rocky -rod -roger -rogers -roland -role -roles -roll -rolled -roller -rolling -rolls -rom -roman -romance -romania -romantic -rome -ron -ronald -roof -room -roommate -roommates -rooms -root -roots -rope -rosa -rose -roses -ross -roster -rotary -rotation -rouge -rough -roughly -roulette -round -rounds -route -router -routers -routes -routine -routines -routing -rover -row -rows -roy -royal -royalty -rp -rpg -rpm -rr -rrp -rs -rss -rt -ru -rubber -ruby -rug -rugby -rugs -rule -ruled -rules -ruling -run -runner -running -runs -runtime -rural -rush -russell -russia -russian -ruth -rv -rw -rwanda -rx -ryan -s -sa -sacramento -sacred -sacrifice -sad -saddam -safari -safe -safely -safer -safety -sage -sagem -said -sail -sailing -saint -saints -sake -salad -salaries -salary -sale -salem -sales -sally -salmon -salon -salt -salvador -salvation -sam -samba -same -samoa -sample -samples -sampling -samsung -samuel -san -sand -sandra -sandwich -sandy -sans -santa -sanyo -sao -sap -sapphire -sara -sarah -sas -saskatchewan -sat -satellite -satin -satisfaction -satisfactory -satisfied -satisfy -saturday -saturn -sauce -saudi -savage -savannah -save -saved -saver -saves -saving -savings -saw -say -saying -says -sb -sbjct -sc -scale -scales -scan -scanned -scanner -scanners -scanning -scary -scenario -scenarios -scene -scenes -scenic -schedule -scheduled -schedules -scheduling -schema -scheme -schemes -scholar -scholars -scholarship -scholarships -school -schools -sci -science -sciences -scientific -scientist -scientists -scoop -scope -score -scored -scores -scoring -scotia -scotland -scott -scottish -scout -scratch -screen -screening -screens -screensaver -screensavers -screenshot -screenshots -screw -script -scripting -scripts -scroll -scsi -scuba -sculpture -sd -se -sea -seafood -seal -sealed -sean -search -searchcom -searched -searches -searching -seas -season -seasonal -seasons -seat -seating -seats -seattle -sec -second -secondary -seconds -secret -secretariat -secretary -secrets -section -sections -sector -sectors -secure -secured -securely -securities -security -see -seed -seeds -seeing -seek -seeker -seekers -seeking -seeks -seem -seemed -seems -seen -sees -sega -segment -segments -select -selected -selecting -selection -selections -selective -self -sell -seller -sellers -selling -sells -semester -semi -semiconductor -seminar -seminars -sen -senate -senator -senators -send -sender -sending -sends -senegal -senior -seniors -sense -sensitive -sensitivity -sensor -sensors -sent -sentence -sentences -seo -sep -separate -separated -separately -separation -sept -september -seq -sequence -sequences -ser -serbia -serial -series -serious -seriously -serum -serve -served -server -servers -serves -service -services -serving -session -sessions -set -sets -setting -settings -settle -settled -settlement -setup -seven -seventh -several -severe -sewing -sex -sexcam -sexo -sexual -sexuality -sexually -sexy -sf -sg -sh -shade -shades -shadow -shadows -shaft -shake -shakespeare -shakira -shall -shame -shanghai -shannon -shape -shaped -shapes -share -shared -shareholders -shares -shareware -sharing -shark -sharon -sharp -shaved -shaw -she -shed -sheep -sheer -sheet -sheets -sheffield -shelf -shell -shelter -shemale -shemales -shepherd -sheriff -sherman -shield -shift -shine -ship -shipment -shipments -shipped -shipping -ships -shirt -shirts -shit -shock -shoe -shoes -shoot -shooting -shop -shopper -shoppercom -shoppers -shopping -shoppingcom -shops -shopzilla -shore -short -shortcuts -shorter -shortly -shorts -shot -shots -should -shoulder -show -showcase -showed -shower -showers -showing -shown -shows -showtimes -shut -shuttle -si -sic -sick -side -sides -sie -siemens -sierra -sig -sight -sigma -sign -signal -signals -signature -signatures -signed -significance -significant -significantly -signing -signs -signup -silence -silent -silicon -silk -silly -silver -sim -similar -similarly -simon -simple -simplified -simply -simpson -simpsons -sims -simulation -simulations -simultaneously -sin -since -sing -singapore -singer -singh -singing -single -singles -sink -sip -sir -sister -sisters -sit -site -sitemap -sites -sitting -situated -situation -situations -six -sixth -size -sized -sizes -sk -skating -ski -skiing -skill -skilled -skills -skin -skins -skip -skirt -skirts -sku -sky -skype -sl -slave -sleep -sleeping -sleeps -sleeve -slide -slides -slideshow -slight -slightly -slim -slip -slope -slot -slots -slovak -slovakia -slovenia -slow -slowly -slut -sluts -sm -small -smaller -smart -smell -smile -smilies -smith -smithsonian -smoke -smoking -smooth -sms -smtp -sn -snake -snap -snapshot -snow -snowboard -so -soa -soap -soc -soccer -social -societies -society -sociology -socket -socks -sodium -sofa -soft -softball -software -soil -sol -solar -solaris -sold -soldier -soldiers -sole -solely -solid -solo -solomon -solution -solutions -solve -solved -solving -soma -somalia -some -somebody -somehow -someone -somerset -something -sometimes -somewhat -somewhere -son -song -songs -sonic -sons -sony -soon -soonest -sophisticated -sorry -sort -sorted -sorts -sought -soul -souls -sound -sounds -soundtrack -soup -source -sources -south -southampton -southeast -southern -southwest -soviet -sox -sp -spa -space -spaces -spain -spam -span -spanish -spank -spanking -sparc -spare -spas -spatial -speak -speaker -speakers -speaking -speaks -spears -spec -special -specialist -specialists -specialized -specializing -specially -specials -specialties -specialty -species -specific -specifically -specification -specifications -specifics -specified -specifies -specify -specs -spectacular -spectrum -speech -speeches -speed -speeds -spell -spelling -spencer -spend -spending -spent -sperm -sphere -spice -spider -spies -spin -spine -spirit -spirits -spiritual -spirituality -split -spoke -spoken -spokesman -sponsor -sponsored -sponsors -sponsorship -sport -sporting -sports -spot -spotlight -spots -spouse -spray -spread -spreading -spring -springer -springfield -springs -sprint -spy -spyware -sq -sql -squad -square -squirt -squirting -sr -src -sri -ss -ssl -st -stability -stable -stack -stadium -staff -staffing -stage -stages -stainless -stakeholders -stamp -stamps -stan -stand -standard -standards -standing -standings -stands -stanford -stanley -star -starring -stars -starsmerchant -start -started -starter -starting -starts -startup -stat -state -stated -statement -statements -states -statewide -static -stating -station -stationery -stations -statistical -statistics -stats -status -statute -statutes -statutory -stay -stayed -staying -stays -std -ste -steady -steal -steam -steel -steering -stem -step -stephanie -stephen -steps -stereo -sterling -steve -steven -stevens -stewart -stick -sticker -stickers -sticks -sticky -still -stock -stockholm -stockings -stocks -stolen -stomach -stone -stones -stood -stop -stopped -stopping -stops -storage -store -stored -stores -stories -storm -story -str -straight -strain -strand -strange -stranger -strap -strategic -strategies -strategy -stream -streaming -streams -street -streets -strength -strengthen -strengthening -strengths -stress -stretch -strict -strictly -strike -strikes -striking -string -strings -strip -stripes -strips -stroke -strong -stronger -strongly -struck -struct -structural -structure -structured -structures -struggle -stuart -stuck -stud -student -students -studied -studies -studio -studios -study -studying -stuff -stuffed -stunning -stupid -style -styles -stylish -stylus -su -sub -subaru -subcommittee -subdivision -subject -subjects -sublime -sublimedirectory -submission -submissions -submit -submitted -submitting -subscribe -subscriber -subscribers -subscription -subscriptions -subsection -subsequent -subsequently -subsidiaries -subsidiary -substance -substances -substantial -substantially -substitute -subtle -suburban -succeed -success -successful -successfully -such -suck -sucking -sucks -sudan -sudden -suddenly -sue -suffer -suffered -suffering -sufficient -sufficiently -sugar -suggest -suggested -suggesting -suggestion -suggestions -suggests -suicide -suit -suitable -suite -suited -suites -suits -sullivan -sum -summaries -summary -summer -summit -sun -sunday -sunglasses -sunny -sunrise -sunset -sunshine -super -superb -superintendent -superior -supervision -supervisor -supervisors -supplement -supplemental -supplements -supplied -supplier -suppliers -supplies -supply -support -supported -supporters -supporting -supports -suppose -supposed -supreme -sur -sure -surely -surf -surface -surfaces -surfing -surge -surgeon -surgeons -surgery -surgical -surname -surplus -surprise -surprised -surprising -surrey -surround -surrounded -surrounding -surveillance -survey -surveys -survival -survive -survivor -survivors -susan -suse -suspect -suspected -suspended -suspension -sussex -sustainability -sustainable -sustained -suzuki -sv -sw -swap -sweden -swedish -sweet -swift -swim -swimming -swing -swingers -swiss -switch -switched -switches -switching -switzerland -sword -sydney -symantec -symbol -symbols -sympathy -symphony -symposium -symptoms -sync -syndicate -syndication -syndrome -synopsis -syntax -synthesis -synthetic -syracuse -syria -sys -system -systematic -systems -t -ta -tab -table -tables -tablet -tablets -tabs -tackle -tactics -tag -tagged -tags -tahoe -tail -taiwan -take -taken -takes -taking -tale -talent -talented -tales -talk -talked -talking -talks -tall -tamil -tampa -tan -tank -tanks -tanzania -tap -tape -tapes -tar -target -targeted -targets -tariff -task -tasks -taste -tattoo -taught -tax -taxation -taxes -taxi -taylor -tb -tba -tc -tcp -td -te -tea -teach -teacher -teachers -teaches -teaching -team -teams -tear -tears -tech -technical -technician -technique -techniques -techno -technological -technologies -technology -techrepublic -ted -teddy -tee -teen -teenage -teens -teeth -tel -telecharger -telecom -telecommunications -telephone -telephony -telescope -television -televisions -tell -telling -tells -temp -temperature -temperatures -template -templates -temple -temporal -temporarily -temporary -ten -tenant -tend -tender -tennessee -tennis -tension -tent -term -terminal -terminals -termination -terminology -terms -terrace -terrain -terrible -territories -territory -terror -terrorism -terrorist -terrorists -terry -test -testament -tested -testimonials -testimony -testing -tests -tex -texas -text -textbook -textbooks -textile -textiles -texts -texture -tf -tft -tgp -th -thai -thailand -than -thank -thanks -thanksgiving -that -thats -the -theater -theaters -theatre -thee -theft -thehun -their -them -theme -themes -themselves -then -theology -theorem -theoretical -theories -theory -therapeutic -therapist -therapy -there -thereafter -thereby -therefore -thereof -thermal -thesaurus -these -thesis -they -thick -thickness -thin -thing -things -think -thinking -thinkpad -thinks -third -thirty -this -thomas -thompson -thomson -thong -thongs -thorough -thoroughly -those -thou -though -thought -thoughts -thousand -thousands -thread -threaded -threads -threat -threatened -threatening -threats -three -threesome -threshold -thriller -throat -through -throughout -throw -throwing -thrown -throws -thru -thu -thumb -thumbnail -thumbnails -thumbs -thumbzilla -thunder -thursday -thus -thy -ti -ticket -tickets -tide -tie -tied -tier -ties -tiffany -tiger -tigers -tight -til -tile -tiles -till -tim -timber -time -timeline -timely -timer -times -timing -timothy -tin -tiny -tion -tions -tip -tips -tire -tired -tires -tissue -tit -titanium -titans -title -titled -titles -tits -titten -tm -tmp -tn -to -tobacco -tobago -today -todd -toddler -toe -together -toilet -token -tokyo -told -tolerance -toll -tom -tomato -tomatoes -tommy -tomorrow -ton -tone -toner -tones -tongue -tonight -tons -tony -too -took -tool -toolbar -toolbox -toolkit -tools -tooth -top -topic -topics -topless -tops -toronto -torture -toshiba -total -totally -totals -touch -touched -tough -tour -touring -tourism -tourist -tournament -tournaments -tours -toward -towards -tower -towers -town -towns -township -toxic -toy -toyota -toys -tp -tr -trace -track -trackback -trackbacks -tracked -tracker -tracking -tracks -tract -tractor -tracy -trade -trademark -trademarks -trader -trades -trading -tradition -traditional -traditions -traffic -tragedy -trail -trailer -trailers -trails -train -trained -trainer -trainers -training -trains -tramadol -trance -tranny -trans -transaction -transactions -transcript -transcription -transcripts -transexual -transexuales -transfer -transferred -transfers -transform -transformation -transit -transition -translate -translated -translation -translations -translator -transmission -transmit -transmitted -transparency -transparent -transport -transportation -transsexual -trap -trash -trauma -travel -traveler -travelers -traveling -traveller -travelling -travels -travesti -travis -tray -treasure -treasurer -treasures -treasury -treat -treated -treating -treatment -treatments -treaty -tree -trees -trek -trembl -tremendous -trend -trends -treo -tri -trial -trials -triangle -tribal -tribe -tribes -tribunal -tribune -tribute -trick -tricks -tried -tries -trigger -trim -trinidad -trinity -trio -trip -tripadvisor -triple -trips -triumph -trivia -troops -tropical -trouble -troubleshooting -trout -troy -truck -trucks -true -truly -trunk -trust -trusted -trustee -trustees -trusts -truth -try -trying -ts -tsunami -tt -tu -tub -tube -tubes -tucson -tue -tuesday -tuition -tulsa -tumor -tune -tuner -tunes -tuning -tunisia -tunnel -turbo -turkey -turkish -turn -turned -turner -turning -turns -turtle -tutorial -tutorials -tv -tvcom -tvs -twelve -twenty -twice -twiki -twin -twinks -twins -twist -twisted -two -tx -ty -tyler -type -types -typical -typically -typing -u -uc -uganda -ugly -uh -ui -uk -ukraine -ul -ultimate -ultimately -ultra -ultram -um -un -una -unable -unauthorized -unavailable -uncertainty -uncle -und -undefined -under -undergraduate -underground -underlying -understand -understanding -understood -undertake -undertaken -underwear -undo -une -unemployment -unexpected -unfortunately -uni -unified -uniform -union -unions -uniprotkb -unique -unit -united -units -unity -univ -universal -universe -universities -university -unix -unknown -unless -unlike -unlikely -unlimited -unlock -unnecessary -unsigned -unsubscribe -until -untitled -unto -unusual -unwrap -up -upc -upcoming -update -updated -updates -updating -upgrade -upgrades -upgrading -upload -uploaded -upon -upper -ups -upset -upskirt -upskirts -ur -urban -urge -urgent -uri -url -urls -uruguay -urw -us -usa -usage -usb -usc -usd -usda -use -used -useful -user -username -users -uses -usgs -using -usps -usr -usual -usually -ut -utah -utc -utilities -utility -utilization -utilize -utils -uv -uw -uzbekistan -v -va -vacancies -vacation -vacations -vaccine -vacuum -vagina -val -valentine -valid -validation -validity -valium -valley -valuable -valuation -value -valued -values -valve -valves -vampire -van -vancouver -vanilla -var -variable -variables -variance -variation -variations -varied -varies -variety -various -vary -varying -vast -vat -vatican -vault -vb -vbulletin -vc -vcr -ve -vector -vegas -vegetable -vegetables -vegetarian -vegetation -vehicle -vehicles -velocity -velvet -vendor -vendors -venezuela -venice -venture -ventures -venue -venues -ver -verbal -verde -verification -verified -verify -verizon -vermont -vernon -verse -version -versions -versus -vertex -vertical -very -verzeichnis -vessel -vessels -veteran -veterans -veterinary -vg -vhs -vi -via -viagra -vibrator -vibrators -vic -vice -victim -victims -victor -victoria -victorian -victory -vid -video -videos -vids -vienna -vietnam -vietnamese -view -viewed -viewer -viewers -viewing -viewpicture -views -vii -viii -viking -villa -village -villages -villas -vincent -vintage -vinyl -violation -violations -violence -violent -violin -vip -viral -virgin -virginia -virtual -virtually -virtue -virus -viruses -visa -visibility -visible -vision -visit -visited -visiting -visitor -visitors -visits -vista -visual -vital -vitamin -vitamins -vocabulary -vocal -vocals -vocational -voice -voices -void -voip -vol -volkswagen -volleyball -volt -voltage -volume -volumes -voluntary -volunteer -volunteers -volvo -von -vote -voted -voters -votes -voting -voyeur -voyeurweb -voyuer -vp -vpn -vs -vsnet -vt -vulnerability -vulnerable -w -wa -wage -wages -wagner -wagon -wait -waiting -waiver -wake -wal -wales -walk -walked -walker -walking -walks -wall -wallace -wallet -wallpaper -wallpapers -walls -walnut -walt -walter -wan -wang -wanna -want -wanted -wanting -wants -war -warcraft -ward -ware -warehouse -warm -warming -warned -warner -warning -warnings -warrant -warranties -warranty -warren -warrior -warriors -wars -was -wash -washer -washing -washington -waste -watch -watched -watches -watching -water -waterproof -waters -watershed -watson -watt -watts -wav -wave -waves -wax -way -wayne -ways -wb -wc -we -weak -wealth -weapon -weapons -wear -wearing -weather -web -webcam -webcams -webcast -weblog -weblogs -webmaster -webmasters -webpage -webshots -website -websites -webster -wed -wedding -weddings -wednesday -weed -week -weekend -weekends -weekly -weeks -weight -weighted -weights -weird -welcome -welding -welfare -well -wellington -wellness -wells -welsh -wendy -went -were -wesley -west -western -westminster -wet -whale -what -whatever -whats -wheat -wheel -wheels -when -whenever -where -whereas -wherever -whether -which -while -whilst -white -who -whole -wholesale -whom -whore -whose -why -wi -wichita -wicked -wide -widely -wider -widescreen -widespread -width -wife -wifi -wiki -wikipedia -wild -wilderness -wildlife -wiley -will -william -williams -willing -willow -wilson -win -wind -window -windows -winds -windsor -wine -wines -wing -wings -winner -winners -winning -wins -winston -winter -wire -wired -wireless -wires -wiring -wisconsin -wisdom -wise -wish -wishes -wishlist -wit -witch -with -withdrawal -within -without -witness -witnesses -wives -wizard -wm -wma -wn -wolf -woman -women -womens -won -wonder -wonderful -wondering -wood -wooden -woods -wool -worcester -word -wordpress -words -work -worked -worker -workers -workflow -workforce -working -workout -workplace -works -workshop -workshops -workstation -world -worldcat -worlds -worldsex -worldwide -worm -worn -worried -worry -worse -worship -worst -worth -worthy -would -wound -wow -wp -wr -wrap -wrapped -wrapping -wrestling -wright -wrist -write -writer -writers -writes -writing -writings -written -wrong -wrote -ws -wt -wto -wu -wv -ww -www -wx -wy -wyoming -x -xanax -xbox -xerox -xhtml -xi -xl -xml -xnxx -xp -xx -xxx -y -ya -yacht -yahoo -yale -yamaha -yang -yard -yards -yarn -ye -yea -yeah -year -yearly -years -yeast -yellow -yemen -yen -yes -yesterday -yet -yield -yields -yn -yo -yoga -york -yorkshire -you -young -younger -your -yours -yourself -youth -yr -yrs -yu -yugoslavia -yukon -z -za -zambia -zdnet -zealand -zen -zero -zimbabwe -zinc -zip -zoloft -zone -zones -zoning -zoo -zoom -zoophilia -zope -zshops -zu -zum -zus \ No newline at end of file