1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h>
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h>
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test case supplied by Sergei Trofimovich */
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Real life example (MSDOS file INFO.EXE) has code like this
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * I don't know why author/compiler done code like this. Only guess:
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *    guess 1 (strong :]):
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *      This archaic code was used by dynamic memory regeneration
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *      handler (according to code around it's called from
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *      interrupt handler).
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *    guess 2: cache flush (whether processors had caches at that time?)
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * a disasmed snippet:
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   mov     byte ptr [bx], 0FFh
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   sti
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   mov     cx, 0FFFFh         ; 65535
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   rep lods byte ptr es:[si]
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   jcxz    short somewhere_1  ; it seems code could be
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *                              ; interrupted here
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   call    something_2
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   cmp     dx, 4
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   mov     byte ptr [bx], 0
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *   jmp     somewhere_3
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define GET_BIT(var, bit_no) ((var >> bit_no) & 1)
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic char sz_eflags[] = "        "; // 8 spaces
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_eflags (unsigned int _8bits_eflags)
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  assert (_8bits_eflags >= 0);
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  assert (_8bits_eflags <= 0xFF);
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sz_eflags[0] = GET_BIT(_8bits_eflags, 7) ? 'S' : ' ';
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sz_eflags[1] = GET_BIT(_8bits_eflags, 6) ? 'Z' : ' ';
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sz_eflags[3] = GET_BIT(_8bits_eflags, 4) ? 'A' : ' ';
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sz_eflags[5] = GET_BIT(_8bits_eflags, 2) ? 'P' : ' ';
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sz_eflags[7] = GET_BIT(_8bits_eflags, 0) ? 'C' : ' ';
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define EMIT_CALL(dir_insn, insn, in_eax, in_esi, in_eflags, out_eax, out_esi, out_eflags, count) \
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  asm volatile(                             \
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %3, %%eax \t\n"                       \
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "sahf       \t\n" /* loading our eflags */          \
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %4, %%eax \t\n"                       \
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %5, %%esi \t\n"                       \
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %6, %%ecx \t\n"                       \
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    \
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    dir_insn "\t\n"                         \
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    insn "\t\n"                           \
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    \
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    /* return result */                       \
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %%eax, %0 \t\n"                       \
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "lahf       \t\n"                       \
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %%eax, %1 \t\n"                       \
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "movl %%esi, %2 \t\n"                       \
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    "cld \t\n" \
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : "=d"(out_eax),                        \
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "=b"(out_eflags),                       \
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "=r"(out_esi)                         \
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    \
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : "m"(in_eflags),                         \
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "m"(in_eax),                          \
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "m"(in_esi),                          \
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "q"(count)                          \
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    \
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    : "%eax", "%esi", "%ecx", "cc" /* we mess up EFLAGS */);
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed char  b_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4};
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed long  l_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4};
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed short w_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4};
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst int lens[] = { 4, 3, 2, 1, 0, 0, 1, 2, 3, 4};
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main ()
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  const signed char * b_center = (signed char *) memchr(b_mem_buff, 0xaa, sizeof (b_mem_buff));
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  const signed char * w_center = (signed char *) memchr(w_mem_buff, 0xaa, sizeof (w_mem_buff));
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  const signed char * l_center = (signed char *) memchr(l_mem_buff, 0xaa, sizeof (l_mem_buff));
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int insn;
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (insn = 0; insn < 4; ++insn) //b,w[rep/addr],d,w[addr/rep]
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    int idx;
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    for (idx = 0; idx < sizeof (lens)/sizeof(lens[0]); ++idx)
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    {
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int eflags;
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int eax = 0x12348765;
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int esi;
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      const char * i_name = NULL;
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int resulting_eflags;
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int resulting_eax;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unsigned int resulting_esi;
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int len;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int df;
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn)
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0: //b
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          esi = (unsigned int) b_center;
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          i_name = "lodsb";
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1: //w
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          esi = (unsigned int) w_center;
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          i_name = "lodsw[rep/addr]";
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2: //d
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          esi = (unsigned int) l_center;
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          i_name = "lodsl";
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3: //w
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          esi = (unsigned int) w_center;
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          i_name = "lodsw[addr/rep]";
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      eflags = 0;
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_eflags ((eflags >> 8) & 0xFF); // scratching off AH
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      printf ("REP %s (EAX = %08X, EFLAGS = %s) => ", i_name, eax, sz_eflags);
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      resulting_eflags = 0;
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      resulting_eax = 0;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      len = lens[idx];
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      df  = (idx >= (sizeof(lens)/sizeof(lens[0]))/2);
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn)
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0: //b
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (df)
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("cld",
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "rep lodsb",
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          else
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("std",
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "rep lodsb",
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1: //w[rep/addr]
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (df)
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("cld",
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // "rep lodsw",
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // explicit: rep-pref addr-pref op
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ".byte 0x66,0xf3,0xad",
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          else
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("std",
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // "rep lodsw",
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // explicit: rep-pref addr-pref op
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ".byte 0x66,0xf3,0xad",
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2: //d
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (df)
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("cld",
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "rep lodsl",
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          else
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("std",
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "rep lodsl",
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3: //w[addr/rep]
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (df)
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("cld",
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // "rep lodsw",
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // explicit: rep-pref addr-pref op
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ".byte 0xf3,0x66,0xad",
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          else
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          {
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            EMIT_CALL("std",
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // "rep lodsw",
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // explicit: rep-pref addr-pref op
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  ".byte 0xf3,0x66,0xad",
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags,
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  len);
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          break;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      printf ("DF = %d, count = %2d ", df, len);
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pp_eflags ((resulting_eflags >> 8) & 0xFF); // scratching off AH
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      printf ("(EAX = %08X, EFLAGS = %s)\n", resulting_eax, sz_eflags);
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
215