A project to implement a console using the Mbed using VGA for video output and a PS/2 keyboard for the input. The eventual goal is to also include tools for managing SD cards, and a semi-self-hosting programming environment.
Dependencies: PS2_MbedConsole fastlib SDFileSystem vga640x480g_mbedconsole lightvm mbed
MbedConsole is a cool little project to have a self-contained computer all on an Mbed. So far it has VGA and PS/2 support and can stand alone without a computer powering it. Next planned features are SD card support and a lightweight programmable VM complete with a file editor and self-hosted assembler.
You can view additional details about it at http://earlz.net/tags/mbedconsole
keyboard.cpp@10:bda85442b674, 2012-09-26 (annotated)
- Committer:
- earlz
- Date:
- Wed Sep 26 05:22:44 2012 +0000
- Revision:
- 10:bda85442b674
- Child:
- 11:fede136943a9
AlloyOS' keyboard driver port is mostly a success. Problem now is that apparently our translation set is for scancode set 1 and not scancode set 2
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
earlz | 10:bda85442b674 | 1 | #include "mbedconsole.h" |
earlz | 10:bda85442b674 | 2 | /**This is basically a straight rip off of my x86 OS project AlloyOS. I just ported the keyboard driver from it cause it always treated me well**/ |
earlz | 10:bda85442b674 | 3 | |
earlz | 10:bda85442b674 | 4 | |
earlz | 10:bda85442b674 | 5 | #define KEYBOARD_DATAPIN p11 |
earlz | 10:bda85442b674 | 6 | #define KEYBOARD_CLOCKPIN p12 |
earlz | 10:bda85442b674 | 7 | |
earlz | 10:bda85442b674 | 8 | //how many keys the buffer can hold |
earlz | 10:bda85442b674 | 9 | #define KBD_BUFFER_SIZE 128 |
earlz | 10:bda85442b674 | 10 | |
earlz | 10:bda85442b674 | 11 | //key defines |
earlz | 10:bda85442b674 | 12 | #define LSHIFT_KEY 42 |
earlz | 10:bda85442b674 | 13 | #define RSHIFT_KEY 54 |
earlz | 10:bda85442b674 | 14 | #define CTRL_KEY 29 |
earlz | 10:bda85442b674 | 15 | #define ALT_KEY 56 |
earlz | 10:bda85442b674 | 16 | #define CAPS_KEY 58 |
earlz | 10:bda85442b674 | 17 | #define NUM_KEY 69 |
earlz | 10:bda85442b674 | 18 | #define SCROLL_KEY 70 |
earlz | 10:bda85442b674 | 19 | #define F_BASE_KEY 59 //59 is F1, 60 is F2, and so on until F10 |
earlz | 10:bda85442b674 | 20 | #define HOME_KEY 71 |
earlz | 10:bda85442b674 | 21 | #define UP_KEY 72 |
earlz | 10:bda85442b674 | 22 | #define PAGE_UP_KEY 73 |
earlz | 10:bda85442b674 | 23 | #define LEFT_KEY 75 |
earlz | 10:bda85442b674 | 24 | #define RIGHT_KEY 77 |
earlz | 10:bda85442b674 | 25 | #define END_KEY 79 |
earlz | 10:bda85442b674 | 26 | #define DOWN_KEY 80 |
earlz | 10:bda85442b674 | 27 | #define PAGE_DOWN_KEY 81 |
earlz | 10:bda85442b674 | 28 | #define INSERT_KEY 82 |
earlz | 10:bda85442b674 | 29 | #define DEL_KEY 83 |
earlz | 10:bda85442b674 | 30 | #define F11_KEY 87 |
earlz | 10:bda85442b674 | 31 | #define F12_KEY 89 |
earlz | 10:bda85442b674 | 32 | |
earlz | 10:bda85442b674 | 33 | #define SCROLL_LED 1 |
earlz | 10:bda85442b674 | 34 | #define NUM_LED 2 |
earlz | 10:bda85442b674 | 35 | #define CAPS_LED 4 |
earlz | 10:bda85442b674 | 36 | |
earlz | 10:bda85442b674 | 37 | |
earlz | 10:bda85442b674 | 38 | const char kbdus[128] = |
earlz | 10:bda85442b674 | 39 | { |
earlz | 10:bda85442b674 | 40 | 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ |
earlz | 10:bda85442b674 | 41 | '9', '0', '-', '=', '\b', /* Backspace */ |
earlz | 10:bda85442b674 | 42 | '\t', /* Tab */ |
earlz | 10:bda85442b674 | 43 | 'q', 'w', 'e', 'r', /* 19 */ |
earlz | 10:bda85442b674 | 44 | 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ |
earlz | 10:bda85442b674 | 45 | 0, /* 29 - Control */ |
earlz | 10:bda85442b674 | 46 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ |
earlz | 10:bda85442b674 | 47 | '\'', '`', 0, /* Left shift */ |
earlz | 10:bda85442b674 | 48 | '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ |
earlz | 10:bda85442b674 | 49 | 'm', ',', '.', '/', 0, /* Right shift */ |
earlz | 10:bda85442b674 | 50 | '*', |
earlz | 10:bda85442b674 | 51 | 0, /* Alt */ |
earlz | 10:bda85442b674 | 52 | ' ', /* Space bar */ |
earlz | 10:bda85442b674 | 53 | 0, /* Caps lock */ |
earlz | 10:bda85442b674 | 54 | 0, /* 59 - F1 key ... > */ |
earlz | 10:bda85442b674 | 55 | 0, 0, 0, 0, 0, 0, 0, 0, |
earlz | 10:bda85442b674 | 56 | 0, /* < ... F10 */ |
earlz | 10:bda85442b674 | 57 | 0, /* 69 - Num lock*/ |
earlz | 10:bda85442b674 | 58 | 0, /* Scroll Lock */ |
earlz | 10:bda85442b674 | 59 | 0, /* Home key */ |
earlz | 10:bda85442b674 | 60 | 0, /* Up Arrow */ |
earlz | 10:bda85442b674 | 61 | 0, /* Page Up */ |
earlz | 10:bda85442b674 | 62 | '-', |
earlz | 10:bda85442b674 | 63 | 0, /* Left Arrow */ |
earlz | 10:bda85442b674 | 64 | 0, |
earlz | 10:bda85442b674 | 65 | 0, /* Right Arrow */ |
earlz | 10:bda85442b674 | 66 | '+', |
earlz | 10:bda85442b674 | 67 | 0, /* 79 - End key*/ |
earlz | 10:bda85442b674 | 68 | 0, /* Down Arrow */ |
earlz | 10:bda85442b674 | 69 | 0, /* Page Down */ |
earlz | 10:bda85442b674 | 70 | 0, /* Insert Key */ |
earlz | 10:bda85442b674 | 71 | 0, /* Delete Key */ |
earlz | 10:bda85442b674 | 72 | 0, 0, 0, |
earlz | 10:bda85442b674 | 73 | 0, /* F11 Key */ |
earlz | 10:bda85442b674 | 74 | 0, /* F12 Key */ |
earlz | 10:bda85442b674 | 75 | 0, /* All other keys are undefined */ |
earlz | 10:bda85442b674 | 76 | }; |
earlz | 10:bda85442b674 | 77 | |
earlz | 10:bda85442b674 | 78 | const char kbdus_caps[128] = |
earlz | 10:bda85442b674 | 79 | { |
earlz | 10:bda85442b674 | 80 | 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ |
earlz | 10:bda85442b674 | 81 | '(', ')', '_', '+', '\b', /* Backspace */ |
earlz | 10:bda85442b674 | 82 | '\t', /* Tab */ |
earlz | 10:bda85442b674 | 83 | 'Q', 'W', 'E', 'R', /* 19 */ |
earlz | 10:bda85442b674 | 84 | 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */ |
earlz | 10:bda85442b674 | 85 | 0, /* 29 - Control */ |
earlz | 10:bda85442b674 | 86 | 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ |
earlz | 10:bda85442b674 | 87 | '"', '~', 0, /* Left shift */ |
earlz | 10:bda85442b674 | 88 | '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ |
earlz | 10:bda85442b674 | 89 | 'M', '<', '>', '?', 0, /* Right shift */ |
earlz | 10:bda85442b674 | 90 | '*', |
earlz | 10:bda85442b674 | 91 | 0, /* Alt */ |
earlz | 10:bda85442b674 | 92 | ' ', /* Space bar */ |
earlz | 10:bda85442b674 | 93 | 0, /* Caps lock */ |
earlz | 10:bda85442b674 | 94 | 0, /* 59 - F1 key ... > */ |
earlz | 10:bda85442b674 | 95 | 0, 0, 0, 0, 0, 0, 0, 0, |
earlz | 10:bda85442b674 | 96 | 0, /* < ... F10 */ |
earlz | 10:bda85442b674 | 97 | 0, /* 69 - Num lock*/ |
earlz | 10:bda85442b674 | 98 | 0, /* Scroll Lock */ |
earlz | 10:bda85442b674 | 99 | 0, /* Home key */ |
earlz | 10:bda85442b674 | 100 | 0, /* Up Arrow */ |
earlz | 10:bda85442b674 | 101 | 0, /* Page Up */ |
earlz | 10:bda85442b674 | 102 | '-', |
earlz | 10:bda85442b674 | 103 | 0, /* Left Arrow */ |
earlz | 10:bda85442b674 | 104 | 0, |
earlz | 10:bda85442b674 | 105 | 0, /* Right Arrow */ |
earlz | 10:bda85442b674 | 106 | '+', |
earlz | 10:bda85442b674 | 107 | 0, /* 79 - End key*/ |
earlz | 10:bda85442b674 | 108 | 0, /* Down Arrow */ |
earlz | 10:bda85442b674 | 109 | 0, /* Page Down */ |
earlz | 10:bda85442b674 | 110 | 0, /* Insert Key */ |
earlz | 10:bda85442b674 | 111 | 0, /* Delete Key */ |
earlz | 10:bda85442b674 | 112 | 0, 0, 0, |
earlz | 10:bda85442b674 | 113 | 0, /* F11 Key */ |
earlz | 10:bda85442b674 | 114 | 0, /* F12 Key */ |
earlz | 10:bda85442b674 | 115 | 0, /* All other keys are undefined */ |
earlz | 10:bda85442b674 | 116 | }; |
earlz | 10:bda85442b674 | 117 | |
earlz | 10:bda85442b674 | 118 | |
earlz | 10:bda85442b674 | 119 | typedef struct { |
earlz | 10:bda85442b674 | 120 | unsigned char caps; |
earlz | 10:bda85442b674 | 121 | unsigned char shift; |
earlz | 10:bda85442b674 | 122 | unsigned char scroll; |
earlz | 10:bda85442b674 | 123 | unsigned char num; |
earlz | 10:bda85442b674 | 124 | unsigned char ctrl; |
earlz | 10:bda85442b674 | 125 | unsigned char alt; |
earlz | 10:bda85442b674 | 126 | } |
earlz | 10:bda85442b674 | 127 | shift_locks; /*for simplicity and speed*/ |
earlz | 10:bda85442b674 | 128 | |
earlz | 10:bda85442b674 | 129 | extern volatile shift_locks kbd_shifts; |
earlz | 10:bda85442b674 | 130 | |
earlz | 10:bda85442b674 | 131 | |
earlz | 10:bda85442b674 | 132 | typedef struct { |
earlz | 10:bda85442b674 | 133 | uint16_t scancode; |
earlz | 10:bda85442b674 | 134 | uint8_t asci; |
earlz | 10:bda85442b674 | 135 | }kbd_key; |
earlz | 10:bda85442b674 | 136 | |
earlz | 10:bda85442b674 | 137 | |
earlz | 10:bda85442b674 | 138 | PS2KB_INIT *ps2_kb_init; |
earlz | 10:bda85442b674 | 139 | PS2KB *ps2_kb; |
earlz | 10:bda85442b674 | 140 | |
earlz | 10:bda85442b674 | 141 | volatile kbd_key *keys; |
earlz | 10:bda85442b674 | 142 | volatile uint8_t current_key=0; |
earlz | 10:bda85442b674 | 143 | volatile uint8_t key_got=0; |
earlz | 10:bda85442b674 | 144 | volatile char pending_key=0; |
earlz | 10:bda85442b674 | 145 | volatile uint8_t led_status=0; |
earlz | 10:bda85442b674 | 146 | |
earlz | 10:bda85442b674 | 147 | void keyboard_callback(PS2KB kb, uint8_t val); |
earlz | 10:bda85442b674 | 148 | |
earlz | 10:bda85442b674 | 149 | void keyboard_init() |
earlz | 10:bda85442b674 | 150 | { |
earlz | 10:bda85442b674 | 151 | keys=(kbd_key*)malloc(256*sizeof(kbd_key)); |
earlz | 10:bda85442b674 | 152 | kbd_shifts.shift=0; |
earlz | 10:bda85442b674 | 153 | kbd_shifts.caps=0; |
earlz | 10:bda85442b674 | 154 | kbd_shifts.num=0; |
earlz | 10:bda85442b674 | 155 | kbd_shifts.scroll=0; |
earlz | 10:bda85442b674 | 156 | kbd_shifts.ctrl=0; |
earlz | 10:bda85442b674 | 157 | kbd_shifts.alt=0; |
earlz | 10:bda85442b674 | 158 | ps2_kb_init=new PS2KB_INIT(KEYBOARD_CLOCKPIN, KEYBOARD_DATAPIN); |
earlz | 10:bda85442b674 | 159 | ps2_kb=new PS2KB(KEYBOARD_CLOCKPIN, KEYBOARD_DATAPIN, (KeyboardCallback) &keyboard_callback); |
earlz | 10:bda85442b674 | 160 | } |
earlz | 10:bda85442b674 | 161 | |
earlz | 10:bda85442b674 | 162 | |
earlz | 10:bda85442b674 | 163 | |
earlz | 10:bda85442b674 | 164 | volatile shift_locks kbd_shifts; |
earlz | 10:bda85442b674 | 165 | |
earlz | 10:bda85442b674 | 166 | |
earlz | 10:bda85442b674 | 167 | |
earlz | 10:bda85442b674 | 168 | /**The way the keyboard driver works is this: |
earlz | 10:bda85442b674 | 169 | the buffer is 256 elements big. key_got and current_key are both |
earlz | 10:bda85442b674 | 170 | bytes. Rather than setting current_key to 0, the entire buffer is constantly |
earlz | 10:bda85442b674 | 171 | in use. when a key is pushed, current key is incremented. when a key is got(with safety checks) |
earlz | 10:bda85442b674 | 172 | key_got is incremented. Also, when it reaches the end of the buffer, it simply wraps around |
earlz | 10:bda85442b674 | 173 | to the beginning due to byte overflow. The worst that can happen is if 256 bytes get |
earlz | 10:bda85442b674 | 174 | built up, in which case everything will be screwed up.. I should eventually controlt he capture |
earlz | 10:bda85442b674 | 175 | of these keys to where not all of them are stored, and they are only stored when needed**/ |
earlz | 10:bda85442b674 | 176 | |
earlz | 10:bda85442b674 | 177 | int kbd_PutBuffer(uint16_t scan,uint8_t asci){ |
earlz | 10:bda85442b674 | 178 | keys[current_key].scancode=scan; |
earlz | 10:bda85442b674 | 179 | keys[current_key].asci=asci; |
earlz | 10:bda85442b674 | 180 | current_key++; |
earlz | 10:bda85442b674 | 181 | pending_key++;; |
earlz | 10:bda85442b674 | 182 | return 0; |
earlz | 10:bda85442b674 | 183 | } |
earlz | 10:bda85442b674 | 184 | |
earlz | 10:bda85442b674 | 185 | kbd_key kbd_PopBuffer(){ |
earlz | 10:bda85442b674 | 186 | kbd_key k; |
earlz | 10:bda85442b674 | 187 | while(pending_key==0){ |
earlz | 10:bda85442b674 | 188 | //hlt(); |
earlz | 10:bda85442b674 | 189 | //fill in busy code here |
earlz | 10:bda85442b674 | 190 | } |
earlz | 10:bda85442b674 | 191 | |
earlz | 10:bda85442b674 | 192 | k.scancode=keys[key_got].scancode; |
earlz | 10:bda85442b674 | 193 | k.asci=keys[key_got].asci; |
earlz | 10:bda85442b674 | 194 | pending_key--; |
earlz | 10:bda85442b674 | 195 | key_got++; |
earlz | 10:bda85442b674 | 196 | return k; |
earlz | 10:bda85442b674 | 197 | } |
earlz | 10:bda85442b674 | 198 | |
earlz | 10:bda85442b674 | 199 | uint8_t kbd_GetKey(){ //this will just return the asci code |
earlz | 10:bda85442b674 | 200 | kbd_key k; |
earlz | 10:bda85442b674 | 201 | k.asci=0; |
earlz | 10:bda85442b674 | 202 | while(k.asci==0){ |
earlz | 10:bda85442b674 | 203 | k=kbd_PopBuffer(); |
earlz | 10:bda85442b674 | 204 | } |
earlz | 10:bda85442b674 | 205 | return k.asci; |
earlz | 10:bda85442b674 | 206 | } |
earlz | 10:bda85442b674 | 207 | |
earlz | 10:bda85442b674 | 208 | |
earlz | 10:bda85442b674 | 209 | void kbd_update_leds(uint8_t status){ |
earlz | 10:bda85442b674 | 210 | uint8_t tmp; |
earlz | 10:bda85442b674 | 211 | //TODO |
earlz | 10:bda85442b674 | 212 | /*while((inportb(0x64)&2)!=0){} |
earlz | 10:bda85442b674 | 213 | outportb(0x60,0xED); |
earlz | 10:bda85442b674 | 214 | |
earlz | 10:bda85442b674 | 215 | while((inportb(0x64)&2)!=0){} |
earlz | 10:bda85442b674 | 216 | outportb(0x60,status); |
earlz | 10:bda85442b674 | 217 | */ |
earlz | 10:bda85442b674 | 218 | } |
earlz | 10:bda85442b674 | 219 | |
earlz | 10:bda85442b674 | 220 | |
earlz | 10:bda85442b674 | 221 | |
earlz | 10:bda85442b674 | 222 | int kbd_DoShifts(uint8_t scan){ |
earlz | 10:bda85442b674 | 223 | switch(scan){ |
earlz | 10:bda85442b674 | 224 | case RSHIFT_KEY: |
earlz | 10:bda85442b674 | 225 | kbd_shifts.shift++; |
earlz | 10:bda85442b674 | 226 | break; |
earlz | 10:bda85442b674 | 227 | case LSHIFT_KEY: |
earlz | 10:bda85442b674 | 228 | kbd_shifts.shift++; |
earlz | 10:bda85442b674 | 229 | break; |
earlz | 10:bda85442b674 | 230 | case CTRL_KEY: |
earlz | 10:bda85442b674 | 231 | kbd_shifts.ctrl++; |
earlz | 10:bda85442b674 | 232 | break; |
earlz | 10:bda85442b674 | 233 | case ALT_KEY: |
earlz | 10:bda85442b674 | 234 | kbd_shifts.alt++; |
earlz | 10:bda85442b674 | 235 | break; |
earlz | 10:bda85442b674 | 236 | case CAPS_KEY: |
earlz | 10:bda85442b674 | 237 | led_status^=CAPS_LED; |
earlz | 10:bda85442b674 | 238 | kbd_update_leds(led_status); |
earlz | 10:bda85442b674 | 239 | kbd_shifts.caps^=1; |
earlz | 10:bda85442b674 | 240 | break; |
earlz | 10:bda85442b674 | 241 | case NUM_KEY: |
earlz | 10:bda85442b674 | 242 | led_status^=NUM_LED; |
earlz | 10:bda85442b674 | 243 | kbd_update_leds(led_status); |
earlz | 10:bda85442b674 | 244 | kbd_shifts.num^=1; |
earlz | 10:bda85442b674 | 245 | break; |
earlz | 10:bda85442b674 | 246 | case SCROLL_KEY: |
earlz | 10:bda85442b674 | 247 | led_status^=SCROLL_LED; |
earlz | 10:bda85442b674 | 248 | kbd_update_leds(led_status); |
earlz | 10:bda85442b674 | 249 | kbd_shifts.scroll^=1; |
earlz | 10:bda85442b674 | 250 | break; |
earlz | 10:bda85442b674 | 251 | default: |
earlz | 10:bda85442b674 | 252 | return 0; |
earlz | 10:bda85442b674 | 253 | break; |
earlz | 10:bda85442b674 | 254 | } |
earlz | 10:bda85442b674 | 255 | return 1; |
earlz | 10:bda85442b674 | 256 | } |
earlz | 10:bda85442b674 | 257 | |
earlz | 10:bda85442b674 | 258 | int kbd_DoUnshifts(uint8_t scan){ |
earlz | 10:bda85442b674 | 259 | switch(scan){ |
earlz | 10:bda85442b674 | 260 | case RSHIFT_KEY: |
earlz | 10:bda85442b674 | 261 | kbd_shifts.shift--; |
earlz | 10:bda85442b674 | 262 | break; |
earlz | 10:bda85442b674 | 263 | case LSHIFT_KEY: |
earlz | 10:bda85442b674 | 264 | kbd_shifts.shift--; |
earlz | 10:bda85442b674 | 265 | break; |
earlz | 10:bda85442b674 | 266 | case CTRL_KEY: |
earlz | 10:bda85442b674 | 267 | kbd_shifts.ctrl--; |
earlz | 10:bda85442b674 | 268 | break; |
earlz | 10:bda85442b674 | 269 | case ALT_KEY: |
earlz | 10:bda85442b674 | 270 | kbd_shifts.alt--; |
earlz | 10:bda85442b674 | 271 | break; |
earlz | 10:bda85442b674 | 272 | case CAPS_KEY: |
earlz | 10:bda85442b674 | 273 | //kbd_shifts.caps=0; |
earlz | 10:bda85442b674 | 274 | break; |
earlz | 10:bda85442b674 | 275 | case NUM_KEY: |
earlz | 10:bda85442b674 | 276 | //kbd_shifts.num=0; |
earlz | 10:bda85442b674 | 277 | break; |
earlz | 10:bda85442b674 | 278 | case SCROLL_KEY: |
earlz | 10:bda85442b674 | 279 | //kbd_shifts.scroll=0; |
earlz | 10:bda85442b674 | 280 | break; |
earlz | 10:bda85442b674 | 281 | default: |
earlz | 10:bda85442b674 | 282 | return 0; |
earlz | 10:bda85442b674 | 283 | break; |
earlz | 10:bda85442b674 | 284 | } |
earlz | 10:bda85442b674 | 285 | return 1; |
earlz | 10:bda85442b674 | 286 | } |
earlz | 10:bda85442b674 | 287 | volatile bool expecting_break=false; |
earlz | 10:bda85442b674 | 288 | void keyboard_callback(PS2KB kb, uint8_t val) //this is called from interrupt! Must be fast |
earlz | 10:bda85442b674 | 289 | { |
earlz | 10:bda85442b674 | 290 | //stopints(); |
earlz | 10:bda85442b674 | 291 | if(expecting_break){ |
earlz | 10:bda85442b674 | 292 | val^=0x80; |
earlz | 10:bda85442b674 | 293 | kbd_DoUnshifts(val); |
earlz | 10:bda85442b674 | 294 | expecting_break=false; |
earlz | 10:bda85442b674 | 295 | }else{ |
earlz | 10:bda85442b674 | 296 | if(val>=0x80){ |
earlz | 10:bda85442b674 | 297 | expecting_break=true; |
earlz | 10:bda85442b674 | 298 | }else{ |
earlz | 10:bda85442b674 | 299 | if(kbd_DoShifts(val)==0){ //if not a shift-type key |
earlz | 10:bda85442b674 | 300 | |
earlz | 10:bda85442b674 | 301 | if ((kbd_shifts.caps^kbd_shifts.shift)==1) { |
earlz | 10:bda85442b674 | 302 | kbd_PutBuffer(val,kbdus_caps[val]); |
earlz | 10:bda85442b674 | 303 | }else{ |
earlz | 10:bda85442b674 | 304 | kbd_PutBuffer(val,kbdus[val]); |
earlz | 10:bda85442b674 | 305 | } |
earlz | 10:bda85442b674 | 306 | } |
earlz | 10:bda85442b674 | 307 | } |
earlz | 10:bda85442b674 | 308 | } |
earlz | 10:bda85442b674 | 309 | } |
earlz | 10:bda85442b674 | 310 | |
earlz | 10:bda85442b674 | 311 |