On Friday, January 31, 2014 1:54:30 PM UTC-6, Daniel "paradigm" Thau wrote:
> On Thursday, January 30, 2014 9:07:19 PM UTC-5, Daniel "paradigm" Thau wrote:
> > On Thursday, January 30, 2014 8:07:04 PM UTC-5, Marcin Szamotulski wrote:
> > > On 16:45 Wed 29 Jan , Daniel "paradigm" Thau wrote:
> > >
> > > > Apologies for the delay.
> > >
> > > >
> > >
> > > > Review for those who have forgotten and/or don't care to backread:
> > >
> > > >
> > >
> > > > This patch adds a new text object, "m", which will take one more
> > > > character as input. That character will be used as bounds to the left
> > > > and right for the object. For example, "cim$" will change between
> > > > dollar signs. This supports multi-line objects, so one could do "cim'"
> > > > which, unlike "ci'", will search across lines; this way users have both.
> > >
> > > >
> > > Thanks I'm really happy to see this patch. I compiled it now and there
> > >
> > > is one thing that does not work: the "." command. For example di< or ci<
> > >
> > > can be repeated with . but dim, or cim, cannot.
> > >
> > >
> > >
> > > Best regards,
> > >
> > > Marcin Szamotulski
> >
> > Good catch. I can replicate that on my end. Will fix.
>
> Should be fixed in the attachment. As a bonus, it now supports things such
> as digraphs.
I tried updating this patch for 7-4-220 and mostly succeeded, just by applying
a couple hundred lines of fuzz, but visual mode is not selecting the full text
inside the matched pairs. I don't have time to try to fix it further. I'm
attaching the updated patch in case I just did something wrong. I know there
have been some visual mode changes outside of this patch between now and the
time the patch was created.
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff -ur vim-7-4-220/runtime/doc/motion.txt vim-7-4-220_patched/runtime/doc/motion.txt
--- vim-7-4-220/runtime/doc/motion.txt Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/runtime/doc/motion.txt Thu Mar 27 11:27:22 2014
@@ -662,6 +662,14 @@
Special case: With a count of 2 the quotes are
included, but no extra white space as with a"/a'/a`.
+am{char} *v_am* *am*
+ "a matched {char}". Selects the text from the
+ previous {char} until the next {char}. A count is
+ currently not used.
+
+im{char} *v_im* *im*
+ Like am{char} but exclude the {char}.
+
When used after an operator:
For non-block objects:
For the "a" commands: The operator applies to the object and the white
diff -ur vim-7-4-220/runtime/doc/tags vim-7-4-220_patched/runtime/doc/tags
--- vim-7-4-220/runtime/doc/tags Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/runtime/doc/tags Thu Mar 27 11:27:22 2014
@@ -4763,6 +4763,7 @@
alt intro.txt /*alt*
alt-input debugger.txt /*alt-input*
alternate-file editing.txt /*alternate-file*
+am motion.txt /*am*
amiga-window starting.txt /*amiga-window*
and() eval.txt /*and()*
anonymous-function eval.txt /*anonymous-function*
@@ -6538,6 +6539,7 @@
if_sniff.txt if_sniff.txt /*if_sniff.txt*
if_tcl.txt if_tcl.txt /*if_tcl.txt*
ignore-errors eval.txt /*ignore-errors*
+im motion.txt /*im*
improved-autocmds-5.4 version5.txt /*improved-autocmds-5.4*
improved-quickfix version5.txt /*improved-quickfix*
improved-sessions version5.txt /*improved-sessions*
@@ -8473,6 +8475,7 @@
v_a] motion.txt /*v_a]*
v_a` motion.txt /*v_a`*
v_ab motion.txt /*v_ab*
+v_am motion.txt /*v_am*
v_ap motion.txt /*v_ap*
v_aquote motion.txt /*v_aquote*
v_as motion.txt /*v_as*
@@ -8520,6 +8523,7 @@
v_i] motion.txt /*v_i]*
v_i` motion.txt /*v_i`*
v_ib motion.txt /*v_ib*
+v_im motion.txt /*v_im*
v_ip motion.txt /*v_ip*
v_iquote motion.txt /*v_iquote*
v_is motion.txt /*v_is*
diff -ur vim-7-4-220/src/normal.c vim-7-4-220_patched/src/normal.c
--- vim-7-4-220/src/normal.c Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/src/normal.c Thu Mar 27 11:27:22 2014
@@ -942,7 +942,7 @@
cp = &ca.nchar;
}
lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG));
-
+getchar:
/*
* Get a second or third character.
*/
@@ -1093,6 +1093,18 @@
}
#endif
}
+#ifdef FEAT_TEXTOBJ
+ /*
+ * The im/am text object needs one more character to use as left/right
+ * bounds.
+ */
+ if ((ca.cmdchar == 'a' || ca.cmdchar == 'i') && ca.nchar == 'm'
+ && ca.extra_char == NUL)
+ {
+ cp = &ca.extra_char;
+ goto getchar;
+ }
+#endif
--no_mapping;
--allow_keys;
}
@@ -1455,6 +1467,16 @@
prep_redo(oap->regname, cap->count0,
get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
oap->motion_force, cap->cmdchar, cap->nchar);
+#ifdef FEAT_TEXTOBJ
+ /*
+ * If using the am/im text object, there is one additional
+ * character used as left/right bounds which needs to be added to
+ * the redo buffer.
+ */
+ if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
+ && cap->nchar == 'm' && cap->extra_char != NUL)
+ AppendCharToRedobuff(cap->extra_char);
+#endif
if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */
{
/*
@@ -9123,6 +9145,10 @@
case '`': /* "a`" = a backtick quoted string */
flag = current_quote(cap->oap, cap->count1, include,
cap->nchar);
+ break;
+ case 'm': /* "am{char}" = a matched pair of characters */
+ flag = current_match(cap->oap, cap->count1, include,
+ cap->extra_char);
break;
#if 0 /* TODO */
case 'S': /* "aS" = a section */
diff -ur vim-7-4-220/src/proto/search.pro vim-7-4-220_patched/src/proto/search.pro
--- vim-7-4-220/src/proto/search.pro Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/src/proto/search.pro Thu Mar 27 11:27:23 2014
@@ -32,6 +32,7 @@
int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include));
int current_par __ARGS((oparg_T *oap, long count, int include, int type));
int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar));
+int current_match __ARGS((oparg_T *oap, long count, int include, int matchchar));
int current_search __ARGS((long count, int forward));
int linewhite __ARGS((linenr_T lnum));
void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum));
diff -ur vim-7-4-220/src/search.c vim-7-4-220_patched/src/search.c
--- vim-7-4-220/src/search.c Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/src/search.c Thu Mar 27 11:27:23 2014
@@ -4437,6 +4437,147 @@
return OK;
}
+ /*
+ * Find matching {char} on each side of cursor/visually selected range.
+ * Returns TRUE if found, else FALSE.
+ */
+ int
+current_match(oap, count, include, matchchar)
+ oparg_T *oap; /* used to set operator range, mode, etc */
+ long count; /* not currently used */
+ int include; /* TRUE == include bounding char */
+ int matchchar; /* char to match on both sides */
+{
+ pos_T old_pos; /* initial cursor position (to restore) */
+ pos_T start_pos; /* left bound */
+ pos_T end_pos; /* right bound */
+ int ret; /* temp holder for return values */
+#ifdef FEAT_VISUAL
+ int vis_bef_curs; /* store visual mode direction */
+
+ /*
+ * Store visual mode direction so we can be sure it is set the same
+ * direction when we're done.
+ */
+ vis_bef_curs = ltoreq(VIsual, curwin->w_cursor);
+#endif
+
+ /*
+ * Remember starting position so we can restore if we cannot find the
+ * requested object.
+ */
+ old_pos = curwin->w_cursor;
+
+ /*
+ * If there is a visually selected range, use its bounds as the starting
+ * bounds. Otherwise, have both bounds start under the cursor.
+ */
+#ifdef FEAT_VISUAL
+ if (VIsual_active && lt(VIsual, curwin->w_cursor))
+ {
+ start_pos = VIsual;
+ end_pos = curwin->w_cursor;
+ }
+ else if (VIsual_active && lt(curwin->w_cursor, VIsual))
+ {
+ start_pos = curwin->w_cursor;
+ end_pos = VIsual;
+ }
+ else
+#endif
+ {
+ start_pos = curwin->w_cursor;
+ end_pos = curwin->w_cursor;
+ }
+
+ /*
+ * Search for the left bound. It can be under or behind the starting
+ * position of the cursor position/visually selected range.
+ */
+ curwin->w_cursor = start_pos;
+ while (gchar_cursor() != matchchar && dec_cursor() != -1)
+ ;
+ if (gchar_cursor() != matchchar)
+ {
+ /* Failed to find left bound, abort. */
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ start_pos = curwin->w_cursor;
+
+ /*
+ * Search for the right bound. It has to be to the right of the starting
+ * cursor position/visually selected range.
+ */
+ curwin->w_cursor = end_pos;
+ while (inc_cursor() != -1 && gchar_cursor() != matchchar)
+ ;
+ if (gchar_cursor() != matchchar)
+ {
+ /* Failed to find right bound, abort. */
+ curwin->w_cursor = old_pos;
+ return FAIL;
+ }
+ end_pos = curwin->w_cursor;
+
+ /*
+ * If not include (i.e.: o_i was used), try to move the bounds inward, but
+ * be sure they don't overlap or switch sides.
+ */
+ if (!include)
+ {
+ /* try moving in right bound */
+ curwin->w_cursor = end_pos;
+ ret = dec_cursor();
+ if (ret == 2)
+ ret = dec_cursor();
+ if (ret != -1 && !ltoreq(curwin->w_cursor, start_pos))
+ {
+ end_pos = curwin->w_cursor;
+ }
+
+ /* try moving in left bound */
+ curwin->w_cursor = start_pos;
+ ret = inc_cursor();
+ if (ret == 2)
+ ret = inc_cursor();
+ if (ret != -1 && !ltoreq(end_pos, curwin->w_cursor))
+ {
+ start_pos = curwin->w_cursor;
+ }
+ }
+
+ /*
+ * We've found the new bounds. Set it in the appropriate places before
+ * returning.
+ */
+#ifdef FEAT_VISUAL
+ if (VIsual_active)
+ {
+ /* Retain direction we had when starting. */
+ if (vis_bef_curs)
+ {
+ VIsual = start_pos;
+ curwin->w_cursor = end_pos;
+ }
+ else
+ {
+ curwin->w_cursor = start_pos;
+ VIsual = end_pos;
+ }
+ redraw_curbuf_later(INVERTED); /* update the inversion */
+ }
+ else
+#endif
+ {
+ oap->start = start_pos;
+ curwin->w_cursor = end_pos;
+ oap->motion_type = MCHAR;
+ oap->inclusive = TRUE;
+ }
+ return OK;
+}
+
#endif /* FEAT_TEXTOBJ */
static int is_one_char __ARGS((char_u *pattern));
diff -ur vim-7-4-220/src/testdir/Makefile vim-7-4-220_patched/src/testdir/Makefile
--- vim-7-4-220/src/testdir/Makefile Thu Mar 27 06:40:30 2014
+++ vim-7-4-220_patched/src/testdir/Makefile Thu Mar 27 11:27:23 2014
@@ -31,7 +31,7 @@
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
test99.out test100.out test101.out test102.out test103.out \
- test104.out test105.out test106.out
+ test104.out test105.out test106.out test107.out
SCRIPTS_GUI = test16.out
diff --git a/src/testdir/test107.in b/src/testdir/test107.in
new file mode 100644
--- /dev/null
+++ b/src/testdir/test107.in
@@ -0,0 +1,62 @@
+Test for im/am text object
+
+Tests every combination of the following:
+- every non-whitespace printable ASCII character (bang/33 to tilde/126)
+- im (i) or am (a)
+- in-line (l) or entire-line (L)
+- single line (s) or multiple line (S)
+- that . will properly repeat
+
+STARTTEST
+:so small.vim
+:enew
+:
+:" add all of the non-whitespace printable ASCII characters
+:let objs = []
+::for nr in range(33,126)
+:: let objs += [nr2char(nr)]
+::endfor
+:" spaces are characters that we aren't using as bounds
+:let diffchars = " "
+
+:" Generate lines with im/am objects in them
+:for char in objs
+: for ia in ["i", "a"]
+: for lL in ["l", "L"]
+: for sS in ["s", "S"]
+: if sS == "s"
+: let lines = diffchars
+: else
+: let lines = diffchars . "\<cr>" . diffchars
+: endif
+: execute "normal o" . char . ia . lL . sS . "X" . char . lines . char . "X\<esc>"
+: execute "normal oX" . char . lines . char . "X\<esc>"
+: endfor
+: endfor
+: endfor
+:endfor
+:
+:" Apply im/am to every created object, both directly and with .
+:
+:for char in objs
+: for ia in ["i", "a"]
+: for lL in ["l", "L"]
+: for sS in ["s", "S"]
+: execute "normal /^\\V" . escape(char,"\\") . ia . lL . sS . "\<cr>4x"
+: if lL == "L"
+: if sS == "s"
+: execute "normal $x0x"
+: else
+: execute "normal j$xk0x"
+: endif
+: endif
+: execute "normal lc" . ia . "m" . char . "OK\<esc>j03l."
+: endfor
+: endfor
+: endfor
+:endfor
+:
+:w! test.out
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test107.ok b/src/testdir/test107.ok
new file mode 100644
--- /dev/null
+++ b/src/testdir/test107.ok
@@ -0,0 +1,1505 @@
+
+X!OK!X
+X!OK!X
+X!OK!X
+X!OK!X
+!OK!
+X!OK!X
+!OK!
+X!OK!X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X"OK"X
+X"OK"X
+X"OK"X
+X"OK"X
+"OK"
+X"OK"X
+"OK"
+X"OK"X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X#OK#X
+X#OK#X
+X#OK#X
+X#OK#X
+#OK#
+X#OK#X
+#OK#
+X#OK#X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X$OK$X
+X$OK$X
+X$OK$X
+X$OK$X
+$OK$
+X$OK$X
+$OK$
+X$OK$X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X%OK%X
+X%OK%X
+X%OK%X
+X%OK%X
+%OK%
+X%OK%X
+%OK%
+X%OK%X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X&OK&X
+X&OK&X
+X&OK&X
+X&OK&X
+&OK&
+X&OK&X
+&OK&
+X&OK&X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X'OK'X
+X'OK'X
+X'OK'X
+X'OK'X
+'OK'
+X'OK'X
+'OK'
+X'OK'X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X(OK(X
+X(OK(X
+X(OK(X
+X(OK(X
+(OK(
+X(OK(X
+(OK(
+X(OK(X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X)OK)X
+X)OK)X
+X)OK)X
+X)OK)X
+)OK)
+X)OK)X
+)OK)
+X)OK)X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X*OK*X
+X*OK*X
+X*OK*X
+X*OK*X
+*OK*
+X*OK*X
+*OK*
+X*OK*X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X+OK+X
+X+OK+X
+X+OK+X
+X+OK+X
++OK+
+X+OK+X
++OK+
+X+OK+X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X,OK,X
+X,OK,X
+X,OK,X
+X,OK,X
+,OK,
+X,OK,X
+,OK,
+X,OK,X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X-OK-X
+X-OK-X
+X-OK-X
+X-OK-X
+-OK-
+X-OK-X
+-OK-
+X-OK-X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X.OK.X
+X.OK.X
+X.OK.X
+X.OK.X
+.OK.
+X.OK.X
+.OK.
+X.OK.X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X/OK/X
+X/OK/X
+X/OK/X
+X/OK/X
+/OK/
+X/OK/X
+/OK/
+X/OK/X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X0OK0X
+X0OK0X
+X0OK0X
+X0OK0X
+0OK0
+X0OK0X
+0OK0
+X0OK0X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X1OK1X
+X1OK1X
+X1OK1X
+X1OK1X
+1OK1
+X1OK1X
+1OK1
+X1OK1X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X2OK2X
+X2OK2X
+X2OK2X
+X2OK2X
+2OK2
+X2OK2X
+2OK2
+X2OK2X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X3OK3X
+X3OK3X
+X3OK3X
+X3OK3X
+3OK3
+X3OK3X
+3OK3
+X3OK3X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X4OK4X
+X4OK4X
+X4OK4X
+X4OK4X
+4OK4
+X4OK4X
+4OK4
+X4OK4X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X5OK5X
+X5OK5X
+X5OK5X
+X5OK5X
+5OK5
+X5OK5X
+5OK5
+X5OK5X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X6OK6X
+X6OK6X
+X6OK6X
+X6OK6X
+6OK6
+X6OK6X
+6OK6
+X6OK6X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X7OK7X
+X7OK7X
+X7OK7X
+X7OK7X
+7OK7
+X7OK7X
+7OK7
+X7OK7X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X8OK8X
+X8OK8X
+X8OK8X
+X8OK8X
+8OK8
+X8OK8X
+8OK8
+X8OK8X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X9OK9X
+X9OK9X
+X9OK9X
+X9OK9X
+9OK9
+X9OK9X
+9OK9
+X9OK9X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X:OK:X
+X:OK:X
+X:OK:X
+X:OK:X
+:OK:
+X:OK:X
+:OK:
+X:OK:X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X;OK;X
+X;OK;X
+X;OK;X
+X;OK;X
+;OK;
+X;OK;X
+;OK;
+X;OK;X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X<OK<X
+X<OK<X
+X<OK<X
+X<OK<X
+<OK<
+X<OK<X
+<OK<
+X<OK<X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X=OK=X
+X=OK=X
+X=OK=X
+X=OK=X
+=OK=
+X=OK=X
+=OK=
+X=OK=X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X>OK>X
+X>OK>X
+X>OK>X
+X>OK>X
+>OK>
+X>OK>X
+>OK>
+X>OK>X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X?OK?X
+X?OK?X
+X?OK?X
+X?OK?X
+?OK?
+X?OK?X
+?OK?
+X?OK?X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X@OK@X
+X@OK@X
+X@OK@X
+X@OK@X
+@OK@
+X@OK@X
+@OK@
+X@OK@X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XAOKAX
+XAOKAX
+XAOKAX
+XAOKAX
+AOKA
+XAOKAX
+AOKA
+XAOKAX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XBOKBX
+XBOKBX
+XBOKBX
+XBOKBX
+BOKB
+XBOKBX
+BOKB
+XBOKBX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XCOKCX
+XCOKCX
+XCOKCX
+XCOKCX
+COKC
+XCOKCX
+COKC
+XCOKCX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XDOKDX
+XDOKDX
+XDOKDX
+XDOKDX
+DOKD
+XDOKDX
+DOKD
+XDOKDX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XEOKEX
+XEOKEX
+XEOKEX
+XEOKEX
+EOKE
+XEOKEX
+EOKE
+XEOKEX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XFOKFX
+XFOKFX
+XFOKFX
+XFOKFX
+FOKF
+XFOKFX
+FOKF
+XFOKFX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XGOKGX
+XGOKGX
+XGOKGX
+XGOKGX
+GOKG
+XGOKGX
+GOKG
+XGOKGX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XHOKHX
+XHOKHX
+XHOKHX
+XHOKHX
+HOKH
+XHOKHX
+HOKH
+XHOKHX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XIOKIX
+XIOKIX
+XIOKIX
+XIOKIX
+IOKI
+XIOKIX
+IOKI
+XIOKIX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XJOKJX
+XJOKJX
+XJOKJX
+XJOKJX
+JOKJ
+XJOKJX
+JOKJ
+XJOKJX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XKOKKX
+XKOKKX
+XKOKKX
+XKOKKX
+KOKK
+XKOKKX
+KOKK
+XKOKKX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XLOKLX
+XLOKLX
+XLOKLX
+XLOKLX
+LOKL
+XLOKLX
+LOKL
+XLOKLX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XMOKMX
+XMOKMX
+XMOKMX
+XMOKMX
+MOKM
+XMOKMX
+MOKM
+XMOKMX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XNOKNX
+XNOKNX
+XNOKNX
+XNOKNX
+NOKN
+XNOKNX
+NOKN
+XNOKNX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XOOKOX
+XOOKOX
+XOOKOX
+XOOKOX
+OOKO
+XOOKOX
+OOKO
+XOOKOX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XPOKPX
+XPOKPX
+XPOKPX
+XPOKPX
+POKP
+XPOKPX
+POKP
+XPOKPX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XQOKQX
+XQOKQX
+XQOKQX
+XQOKQX
+QOKQ
+XQOKQX
+QOKQ
+XQOKQX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XROKRX
+XROKRX
+XROKRX
+XROKRX
+ROKR
+XROKRX
+ROKR
+XROKRX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XSOKSX
+XSOKSX
+XSOKSX
+XSOKSX
+SOKS
+XSOKSX
+SOKS
+XSOKSX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XTOKTX
+XTOKTX
+XTOKTX
+XTOKTX
+TOKT
+XTOKTX
+TOKT
+XTOKTX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XUOKUX
+XUOKUX
+XUOKUX
+XUOKUX
+UOKU
+XUOKUX
+UOKU
+XUOKUX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XVOKVX
+XVOKVX
+XVOKVX
+XVOKVX
+VOKV
+XVOKVX
+VOKV
+XVOKVX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XWOKWX
+XWOKWX
+XWOKWX
+XWOKWX
+WOKW
+XWOKWX
+WOKW
+XWOKWX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XXOKXX
+XXOKXX
+XXOKXX
+XXOKXX
+XOKX
+XXOKXX
+XOKX
+XXOKXX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XYOKYX
+XYOKYX
+XYOKYX
+XYOKYX
+YOKY
+XYOKYX
+YOKY
+XYOKYX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XZOKZX
+XZOKZX
+XZOKZX
+XZOKZX
+ZOKZ
+XZOKZX
+ZOKZ
+XZOKZX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X[OK[X
+X[OK[X
+X[OK[X
+X[OK[X
+[OK[
+X[OK[X
+[OK[
+X[OK[X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X\OK\X
+X\OK\X
+X\OK\X
+X\OK\X
+\OK\
+X\OK\X
+\OK\
+X\OK\X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X]OK]X
+X]OK]X
+X]OK]X
+X]OK]X
+]OK]
+X]OK]X
+]OK]
+X]OK]X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X^OK^X
+X^OK^X
+X^OK^X
+X^OK^X
+^OK^
+X^OK^X
+^OK^
+X^OK^X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X_OK_X
+X_OK_X
+X_OK_X
+X_OK_X
+_OK_
+X_OK_X
+_OK_
+X_OK_X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X`OK`X
+X`OK`X
+X`OK`X
+X`OK`X
+`OK`
+X`OK`X
+`OK`
+X`OK`X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XaOKaX
+XaOKaX
+XaOKaX
+XaOKaX
+aOKa
+XaOKaX
+aOKa
+XaOKaX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XbOKbX
+XbOKbX
+XbOKbX
+XbOKbX
+bOKb
+XbOKbX
+bOKb
+XbOKbX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XcOKcX
+XcOKcX
+XcOKcX
+XcOKcX
+cOKc
+XcOKcX
+cOKc
+XcOKcX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XdOKdX
+XdOKdX
+XdOKdX
+XdOKdX
+dOKd
+XdOKdX
+dOKd
+XdOKdX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XeOKeX
+XeOKeX
+XeOKeX
+XeOKeX
+eOKe
+XeOKeX
+eOKe
+XeOKeX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XfOKfX
+XfOKfX
+XfOKfX
+XfOKfX
+fOKf
+XfOKfX
+fOKf
+XfOKfX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XgOKgX
+XgOKgX
+XgOKgX
+XgOKgX
+gOKg
+XgOKgX
+gOKg
+XgOKgX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XhOKhX
+XhOKhX
+XhOKhX
+XhOKhX
+hOKh
+XhOKhX
+hOKh
+XhOKhX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XiOKiX
+XiOKiX
+XiOKiX
+XiOKiX
+iOKi
+XiOKiX
+iOKi
+XiOKiX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XjOKjX
+XjOKjX
+XjOKjX
+XjOKjX
+jOKj
+XjOKjX
+jOKj
+XjOKjX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XkOKkX
+XkOKkX
+XkOKkX
+XkOKkX
+kOKk
+XkOKkX
+kOKk
+XkOKkX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XlOKlX
+XlOKlX
+XlOKlX
+XlOKlX
+lOKl
+XlOKlX
+lOKl
+XlOKlX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XmOKmX
+XmOKmX
+XmOKmX
+XmOKmX
+mOKm
+XmOKmX
+mOKm
+XmOKmX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XnOKnX
+XnOKnX
+XnOKnX
+XnOKnX
+nOKn
+XnOKnX
+nOKn
+XnOKnX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XoOKoX
+XoOKoX
+XoOKoX
+XoOKoX
+oOKo
+XoOKoX
+oOKo
+XoOKoX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XpOKpX
+XpOKpX
+XpOKpX
+XpOKpX
+pOKp
+XpOKpX
+pOKp
+XpOKpX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XqOKqX
+XqOKqX
+XqOKqX
+XqOKqX
+qOKq
+XqOKqX
+qOKq
+XqOKqX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XrOKrX
+XrOKrX
+XrOKrX
+XrOKrX
+rOKr
+XrOKrX
+rOKr
+XrOKrX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XsOKsX
+XsOKsX
+XsOKsX
+XsOKsX
+sOKs
+XsOKsX
+sOKs
+XsOKsX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XtOKtX
+XtOKtX
+XtOKtX
+XtOKtX
+tOKt
+XtOKtX
+tOKt
+XtOKtX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XuOKuX
+XuOKuX
+XuOKuX
+XuOKuX
+uOKu
+XuOKuX
+uOKu
+XuOKuX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XvOKvX
+XvOKvX
+XvOKvX
+XvOKvX
+vOKv
+XvOKvX
+vOKv
+XvOKvX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XwOKwX
+XwOKwX
+XwOKwX
+XwOKwX
+wOKw
+XwOKwX
+wOKw
+XwOKwX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XxOKxX
+XxOKxX
+XxOKxX
+XxOKxX
+xOKx
+XxOKxX
+xOKx
+XxOKxX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XyOKyX
+XyOKyX
+XyOKyX
+XyOKyX
+yOKy
+XyOKyX
+yOKy
+XyOKyX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+XzOKzX
+XzOKzX
+XzOKzX
+XzOKzX
+zOKz
+XzOKzX
+zOKz
+XzOKzX
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X{OK{X
+X{OK{X
+X{OK{X
+X{OK{X
+{OK{
+X{OK{X
+{OK{
+X{OK{X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X|OK|X
+X|OK|X
+X|OK|X
+X|OK|X
+|OK|
+X|OK|X
+|OK|
+X|OK|X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X}OK}X
+X}OK}X
+X}OK}X
+X}OK}X
+}OK}
+X}OK}X
+}OK}
+X}OK}X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX
+X~OK~X
+X~OK~X
+X~OK~X
+X~OK~X
+~OK~
+X~OK~X
+~OK~
+X~OK~X
+XOKX
+XOKX
+XOKX
+XOKX
+OK
+XOKX
+OK
+XOKX