import java. io. * ;
import java. util. StringTokenizer ;
class RGB {
private final int RADIX = 16 ;
private int r, g, b;
public RGB ( String pixel) {
if ( pixel. length ( ) == 2 ) {
r = g = b = Integer . parseInt ( pixel. substring ( 1 , 2 ) + pixel. substring ( 1 , 2 ) , RADIX) ;
}
else if ( pixel. length ( ) == 4 ) {
r = Integer . parseInt ( pixel. substring ( 1 , 2 ) + pixel. substring ( 1 , 2 ) , RADIX) ;
g = Integer . parseInt ( pixel. substring ( 2 , 3 ) + pixel. substring ( 2 , 3 ) , RADIX) ;
b = Integer . parseInt ( pixel. substring ( 3 , 4 ) + pixel. substring ( 3 , 4 ) , RADIX) ;
}
else {
r = Integer . parseInt ( pixel. substring ( 1 , 3 ) , RADIX) ;
g = Integer . parseInt ( pixel. substring ( 3 , 5 ) , RADIX) ;
b = Integer . parseInt ( pixel. substring ( 5 , 7 ) , RADIX) ;
}
}
public void add ( RGB that) {
this . r += that. r;
this . g += that. g;
this . b += that. b;
}
public RGB average ( int count) {
this . r /= count;
this . g /= count;
this . b /= count;
return this ;
}
public String toString ( ) {
StringBuilder ans = new StringBuilder ( ) ;
ans. append ( "\\x3B" ) ;
for ( char ch : String . valueOf ( r) . toCharArray ( ) ) {
ans. append ( "\\x" ) . append ( String . format ( "%X" , ( int ) ch) ) ;
}
ans. append ( "\\x3B" ) ;
for ( char ch : String . valueOf ( g) . toCharArray ( ) ) {
ans. append ( "\\x" ) . append ( String . format ( "%X" , ( int ) ch) ) ;
}
ans. append ( "\\x3B" ) ;
for ( char ch : String . valueOf ( b) . toCharArray ( ) ) {
ans. append ( "\\x" ) . append ( String . format ( "%X" , ( int ) ch) ) ;
}
ans. append ( "\\x6D" ) ;
return ans. toString ( ) ;
}
public boolean equals ( RGB that) {
return this . r == that. r && this . g == that. g && this . b == that. b;
}
}
public class Main {
private String space = "\\x20" ;
private String newLine = "\\x0A" ;
private String reset = "\\x1B\\x5B\\x30\\x6D" ;
private String changBackground = "\\x1B\\x5B\\x34\\x38\\x3B\\x32" ;
public Main ( ) {
Scanner sc = new Scanner ( System . in) ;
PrintWriter out = new PrintWriter ( System . out) ;
int m = sc. nextInt ( ) , n = sc. nextInt ( ) ;
int p = sc. nextInt ( ) , q = sc. nextInt ( ) ;
RGB[ ] [ ] image = new RGB[ n] [ m] ;
for ( int i = 0 ; i < n; i++ ) {
for ( int j = 0 ; j < m; j++ ) {
String pixel = sc. next ( ) ;
image[ i] [ j] = new RGB ( pixel) ;
}
}
RGB defau = new RGB ( "#0" ) ;
int _n = n / q, _m = m / p;
for ( int i = 0 ; i < _n; i++ ) {
RGB prev = defau;
for ( int j = 0 ; j < _m; j++ ) {
RGB cur = new RGB ( "#0" ) ;
for ( int ki = q * i; ki < q * ( i+ 1 ) ; ki++ ) {
for ( int kj = p * j; kj < p * ( j+ 1 ) ; kj++ ) {
cur. add ( image[ ki] [ kj] ) ;
}
}
cur. average ( p * q) ;
if ( cur. equals ( prev) ) {
}
else if ( cur. equals ( defau) ) {
out. print ( reset) ;
}
else {
out. print ( changBackground + cur) ;
}
prev = cur;
out. print ( space) ;
}
if ( ! prev. equals ( defau) ) {
out. print ( reset) ;
}
out. print ( newLine) ;
}
out. flush ( ) ;
}
public static void main ( String [ ] args) {
new Main ( ) ;
}
}
class Scanner {
private BufferedReader reader;
private StringTokenizer st;
public Scanner ( InputStream stream) {
reader = new BufferedReader ( new InputStreamReader ( stream) ) ;
st = null ;
}
public String next ( ) {
while ( st == null || ! st. hasMoreTokens ( ) ) {
try {
String line = reader. readLine ( ) ;
if ( line == null ) return null ;
st = new StringTokenizer ( line) ;
} catch ( Exception e) {
throw ( new RuntimeException ( ) ) ;
}
}
return st. nextToken ( ) ;
}
public int nextInt ( ) {
return Integer . parseInt ( next ( ) ) ;
}
}