diff options
Diffstat (limited to 'phpBB/phpbb/captcha')
| -rw-r--r-- | phpBB/phpbb/captcha/char_cube3d.php | 277 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/colour_manager.php | 527 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/factory.php | 88 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/gd.php | 1847 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/gd_wave.php | 845 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/non_gd.php | 386 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/captcha_abstract.php | 390 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/gd.php | 130 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/gd_wave.php | 42 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/nogd.php | 42 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/qa.php | 1009 | ||||
| -rw-r--r-- | phpBB/phpbb/captcha/plugins/recaptcha.php | 330 | 
12 files changed, 5913 insertions, 0 deletions
| diff --git a/phpBB/phpbb/captcha/char_cube3d.php b/phpBB/phpbb/captcha/char_cube3d.php new file mode 100644 index 0000000000..a712b16dce --- /dev/null +++ b/phpBB/phpbb/captcha/char_cube3d.php @@ -0,0 +1,277 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class char_cube3d +{ +	var $bitmap; +	var $bitmap_width; +	var $bitmap_height; + +	var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)); +	var $abs_x = array(1, 0); +	var $abs_y = array(0, 1); +	var $x = 0; +	var $y = 1; +	var $z = 2; +	var $letter = ''; + +	/** +	*/ +	function __construct(&$bitmaps, $letter) +	{ +		$this->bitmap			= $bitmaps['data'][$letter]; +		$this->bitmap_width		= $bitmaps['width']; +		$this->bitmap_height	= $bitmaps['height']; + +		$this->basis_matrix[0][0] = mt_rand(-600, 600); +		$this->basis_matrix[0][1] = mt_rand(-600, 600); +		$this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000; +		$this->basis_matrix[1][0] = mt_rand(-1000, 1000); +		$this->basis_matrix[1][1] = mt_rand(-1000, 1000); +		$this->basis_matrix[1][2] = mt_rand(-1000, 1000); + +		$this->normalize($this->basis_matrix[0]); +		$this->normalize($this->basis_matrix[1]); +		$this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]); +		$this->normalize($this->basis_matrix[2]); + +		// $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0] +		$this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]); +		$this->normalize($this->basis_matrix[1]); + +		// Make sure our cube is facing into the canvas (assuming +z == in) +		for ($i = 0; $i < 3; ++$i) +		{ +			if ($this->basis_matrix[$i][2] < 0) +			{ +				$this->basis_matrix[$i][0] *= -1; +				$this->basis_matrix[$i][1] *= -1; +				$this->basis_matrix[$i][2] *= -1; +			} +		} + +		// Force our "z" basis vector to be the one with greatest absolute z value +		$this->x = 0; +		$this->y = 1; +		$this->z = 2; + +		// Swap "y" with "z" +		if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2]) +		{ +			$this->z = 1; +			$this->y = 2; +		} + +		// Swap "x" with "z" +		if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2]) +		{ +			$this->x = $this->z; +			$this->z = 0; +		} + +		// Still need to determine which of $x,$y are which. +		// wrong orientation if y's y-component is less than it's x-component +		// likewise if x's x-component is less than it's y-component +		// if they disagree, go with the one with the greater weight difference. +		// rotate if positive +		$weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1])); + +		// Swap "x" with "y" +		if ($weight > 0) +		{ +			list($this->x, $this->y) = array($this->y, $this->x); +		} + +		$this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]); +		$this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]); + +		if ($this->abs_x[0] < 0) +		{ +			$this->abs_x[0] *= -1; +			$this->abs_x[1] *= -1; +		} + +		if ($this->abs_y[1] > 0) +		{ +			$this->abs_y[0] *= -1; +			$this->abs_y[1] *= -1; +		} + +		$this->letter = $letter; +	} + +	/** +	* Draw a character +	*/ +	function drawchar($scale, $xoff, $yoff, $img, $background, $colours) +	{ +		$width	= $this->bitmap_width; +		$height	= $this->bitmap_height; +		$bitmap	= $this->bitmap; + +		$colour1 = $colours[array_rand($colours)]; +		$colour2 = $colours[array_rand($colours)]; + +		$swapx = ($this->basis_matrix[$this->x][0] > 0); +		$swapy = ($this->basis_matrix[$this->y][1] < 0); + +		for ($y = 0; $y < $height; ++$y) +		{ +			for ($x = 0; $x < $width; ++$x) +			{ +				$xp = ($swapx) ? ($width - $x - 1) : $x; +				$yp = ($swapy) ? ($height - $y - 1) : $y; + +				if ($bitmap[$height - $yp - 1][$xp]) +				{ +					$dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale); +					$dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale); +					$xo = $xoff + $dx[0] + $dy[0]; +					$yo = $yoff + $dx[1] + $dy[1]; + +					$origin = array(0, 0, 0); +					$xvec = $this->scale($this->basis_matrix[$this->x], $scale); +					$yvec = $this->scale($this->basis_matrix[$this->y], $scale); +					$face_corner = $this->sum2($xvec, $yvec); + +					$zvec = $this->scale($this->basis_matrix[$this->z], $scale); +					$x_corner = $this->sum2($xvec, $zvec); +					$y_corner = $this->sum2($yvec, $zvec); + +					imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1); +					imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2); + +					$face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec); + +					imagefilledpolygon($img, $face, 4, $background); +					imagepolygon($img, $face, 4, $colour1); +				} +			} +		} +	} + +	/* +	* return a roughly acceptable range of sizes for rendering with this texttype +	*/ +	function range() +	{ +		return array(3, 4); +	} + +	/** +	* Vector length +	*/ +	function vectorlen($vector) +	{ +		return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2)); +	} + +	/** +	* Normalize +	*/ +	function normalize(&$vector, $length = 1) +	{ +		$length = (( $length < 1) ? 1 : $length); +		$length /= $this->vectorlen($vector); +		$vector[0] *= $length; +		$vector[1] *= $length; +		$vector[2] *= $length; +	} + +	/** +	*/ +	function cross_product($vector1, $vector2) +	{ +		$retval = array(0, 0, 0); +		$retval[0] =  (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1])); +		$retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0])); +		$retval[2] =  (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0])); + +		return $retval; +	} + +	/** +	*/ +	function sum($vector1, $vector2) +	{ +		return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]); +	} + +	/** +	*/ +	function sum2($vector1, $vector2) +	{ +		return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]); +	} + +	/** +	*/ +	function scale($vector, $length) +	{ +		if (sizeof($vector) == 2) +		{ +			return array($vector[0] * $length, $vector[1] * $length); +		} + +		return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length); +	} + +	/** +	*/ +	function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4) +	{ +		$poly = array(); +		$poly[0] = $xoff + $vec1[0]; +		$poly[1] = $yoff + $vec1[1]; +		$poly[2] = $xoff + $vec2[0]; +		$poly[3] = $yoff + $vec2[1]; +		$poly[4] = $xoff + $vec3[0]; +		$poly[5] = $yoff + $vec3[1]; +		$poly[6] = $xoff + $vec4[0]; +		$poly[7] = $yoff + $vec4[1]; + +		return $poly; +	} + +	/** +	* dimensions +	*/ +	function dimensions($size) +	{ +		$xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size); +		$xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size); +		$yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size); +		$yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size); + +		$p = array(); +		$p[0] = $this->sum2($xn, $yn); +		$p[1] = $this->sum2($xp, $yn); +		$p[2] = $this->sum2($xp, $yp); +		$p[3] = $this->sum2($xn, $yp); + +		$min_x = $max_x = $p[0][0]; +		$min_y = $max_y = $p[0][1]; + +		for ($i = 1; $i < 4; ++$i) +		{ +			$min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x; +			$min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y; +			$max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x; +			$max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y; +		} + +		return array($min_x, $min_y, $max_x, $max_y); +	} +} diff --git a/phpBB/phpbb/captcha/colour_manager.php b/phpBB/phpbb/captcha/colour_manager.php new file mode 100644 index 0000000000..6ca3c3fd2c --- /dev/null +++ b/phpBB/phpbb/captcha/colour_manager.php @@ -0,0 +1,527 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class colour_manager +{ +	var $img; +	var $mode; +	var $colours; +	var $named_colours; + +	/** +	* Create the colour manager, link it to the image resource +	*/ +	function __construct($img, $background = false, $mode = 'ahsv') +	{ +		$this->img = $img; +		$this->mode = $mode; +		$this->colours = array(); +		$this->named_colours = array(); + +		if ($background !== false) +		{ +			$bg = $this->allocate_named('background', $background); +			imagefill($this->img, 0, 0, $bg); +		} +	} + +	/** +	* Lookup a named colour resource +	*/ +	function get_resource($named_colour) +	{ +		if (isset($this->named_colours[$named_colour])) +		{ +			return $this->named_colours[$named_colour]; +		} + +		if (isset($this->named_rgb[$named_colour])) +		{ +			return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb'); +		} + +		return false; +	} + +	/** +	* Assign a name to a colour resource +	*/ +	function name_colour($name, $resource) +	{ +		$this->named_colours[$name] = $resource; +	} + +	/** +	* names and allocates a colour resource +	*/ +	function allocate_named($name, $colour, $mode = false) +	{ +		$resource = $this->allocate($colour, $mode); + +		if ($resource !== false) +		{ +			$this->name_colour($name, $resource); +		} +		return $resource; +	} + +	/** +	* allocates a specified colour into the image +	*/ +	function allocate($colour, $mode = false) +	{ +		if ($mode === false) +		{ +			$mode = $this->mode; +		} + +		if (!is_array($colour)) +		{ +			if (isset($this->named_rgb[$colour])) +			{ +				return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb'); +			} + +			if (!is_int($colour)) +			{ +				return false; +			} + +			$mode = 'rgb'; +			$colour = array(255 & ($colour >> 16), 255 & ($colour >>  8), 255 & $colour); +		} + +		if (isset($colour['mode'])) +		{ +			$mode = $colour['mode']; +			unset($colour['mode']); +		} + +		if (isset($colour['random'])) +		{ +			unset($colour['random']); +			// everything else is params +			return $this->random_colour($colour, $mode); +		} + +		$rgb		= $this->model_convert($colour, $mode, 'rgb'); +		$store		= ($this->mode == 'rgb') ? $rgb : $this->model_convert($colour, $mode, $this->mode); +		$resource	= imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]); +		$this->colours[$resource] = $store; + +		return $resource; +	} + +	/** +	* randomly generates a colour, with optional params +	*/ +	function random_colour($params = array(), $mode = false) +	{ +		if ($mode === false) +		{ +			$mode = $this->mode; +		} + +		switch ($mode) +		{ +			case 'rgb': +				// @TODO random rgb generation. do we intend to do this, or is it just too tedious? +				break; + +			case 'ahsv': +			case 'hsv': +			default: + +				$default_params = array( +					'hue_bias'			=> false,	// degree / 'r'/'g'/'b'/'c'/'m'/'y'   /'o' +					'hue_range'			=> false,	// if hue bias, then difference range +/- from bias +					'min_saturation'	=> 30,		// 0 - 100 +					'max_saturation'	=> 80,		// 0 - 100 +					'min_value'			=> 30,		// 0 - 100 +					'max_value'			=> 80,		// 0 - 100 +				); + +				$alt = ($mode == 'ahsv') ? true : false; +				$params = array_merge($default_params, $params); + +				$min_hue		= 0; +				$max_hue		= 359; +				$min_saturation	= max(0, $params['min_saturation']); +				$max_saturation	= min(100, $params['max_saturation']); +				$min_value		= max(0, $params['min_value']); +				$max_value		= min(100, $params['max_value']); + +				if ($params['hue_bias'] !== false) +				{ +					if (is_numeric($params['hue_bias'])) +					{ +						$h = intval($params['hue_bias']) % 360; +					} +					else +					{ +						switch ($params['hue_bias']) +						{ +							case 'o': +								$h = $alt ?  60 :  30; +								break; + +							case 'y': +								$h = $alt ? 120 :  60; +								break; + +							case 'g': +								$h = $alt ? 180 : 120; +								break; + +							case 'c': +								$h = $alt ? 210 : 180; +								break; + +							case 'b': +								$h = 240; +								break; + +							case 'm': +								$h = 300; +								break; + +							case 'r': +							default: +								$h = 0; +								break; +						} +					} + +					$min_hue = $h + 360; +					$max_hue = $h + 360; + +					if ($params['hue_range']) +					{ +						$min_hue -= min(180, $params['hue_range']); +						$max_hue += min(180, $params['hue_range']); +					} +				} + +				$h = mt_rand($min_hue, $max_hue); +				$s = mt_rand($min_saturation, $max_saturation); +				$v = mt_rand($min_value, $max_value); + +				return $this->allocate(array($h, $s, $v), $mode); + +				break; +		} +	} + +	/** +	*/ +	function colour_scheme($resource, $include_original = true) +	{ +		$mode = 'hsv'; + +		if (($pre = $this->get_resource($resource)) !== false) +		{ +			$resource = $pre; +		} + +		$colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); +		$results = ($include_original) ? array($resource) : array(); +		$colour2 = $colour3 = $colour4 = $colour; +		$colour2[0] += 150; +		$colour3[0] += 180; +		$colour4[0] += 210; + +		$results[] = $this->allocate($colour2, $mode); +		$results[] = $this->allocate($colour3, $mode); +		$results[] = $this->allocate($colour4, $mode); + +		return $results; +	} + +	/** +	*/ +	function mono_range($resource, $count = 5, $include_original = true) +	{ +		if (is_array($resource)) +		{ +			$results = array(); +			for ($i = 0, $size = sizeof($resource); $i < $size; ++$i) +			{ +				$results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original)); +			} +			return $results; +		} + +		$mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv'); +		if (($pre = $this->get_resource($resource)) !== false) +		{ +			$resource = $pre; +		} + +		$colour = $this->model_convert($this->colours[$resource], $this->mode, $mode); + +		$results = array(); +		if ($include_original) +		{ +			$results[] = $resource; +			$count--; +		} + +		// This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness. + +		while ($count > 0) +		{ +			$colour[1] = ($colour[1] + mt_rand(40,60)) % 99; +			$colour[2] = ($colour[2] + mt_rand(40,60)); +			$results[] = $this->allocate($colour, $mode); +			$count--; +		} +		return $results; +	} + +	/** +	* Convert from one colour model to another +	*/ +	function model_convert($colour, $from_model, $to_model) +	{ +		if ($from_model == $to_model) +		{ +			return $colour; +		} + +		switch ($to_model) +		{ +			case 'hsv': + +				switch ($from_model) +				{ +					case 'ahsv': +						return $this->ah2h($colour); +						break; + +					case 'rgb': +						return $this->rgb2hsv($colour); +						break; +				} +				break; + +			case 'ahsv': + +				switch ($from_model) +				{ +					case 'hsv': +						return $this->h2ah($colour); +						break; + +					case 'rgb': +						return $this->h2ah($this->rgb2hsv($colour)); +						break; +				} +				break; + +			case 'rgb': +				switch ($from_model) +				{ +					case 'hsv': +						return $this->hsv2rgb($colour); +						break; + +					case 'ahsv': +						return $this->hsv2rgb($this->ah2h($colour)); +						break; +				} +				break; +		} +		return false; +	} + +	/** +	* Slightly altered from wikipedia's algorithm +	*/ +	function hsv2rgb($hsv) +	{ +		$this->normalize_hue($hsv[0]); + +		$h = $hsv[0]; +		$s = min(1, max(0, $hsv[1] / 100)); +		$v = min(1, max(0, $hsv[2] / 100)); + +		// calculate hue sector +		$hi = floor($hsv[0] / 60); + +		// calculate opposite colour +		$p = $v * (1 - $s); + +		// calculate distance between hex vertices +		$f = ($h / 60) - $hi; + +		// coming in or going out? +		if (!($hi & 1)) +		{ +			$f = 1 - $f; +		} + +		// calculate adjacent colour +		$q = $v * (1 - ($f * $s)); + +		switch ($hi) +		{ +			case 0: +				$rgb = array($v, $q, $p); +				break; + +			case 1: +				$rgb = array($q, $v, $p); +				break; + +			case 2: +				$rgb = array($p, $v, $q); +				break; + +			case 3: +				$rgb = array($p, $q, $v); +				break; + +			case 4: +				$rgb = array($q, $p, $v); +				break; + +			case 5: +				$rgb = array($v, $p, $q); +				break; + +			default: +				return array(0, 0, 0); +				break; +		} + +		return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]); +	} + +	/** +	* (more than) Slightly altered from wikipedia's algorithm +	*/ +	function rgb2hsv($rgb) +	{ +		$r = min(255, max(0, $rgb[0])); +		$g = min(255, max(0, $rgb[1])); +		$b = min(255, max(0, $rgb[2])); +		$max = max($r, $g, $b); +		$min = min($r, $g, $b); + +		$v = $max / 255; +		$s = (!$max) ? 0 : 1 - ($min / $max); + +		// if max - min is 0, we want hue to be 0 anyway. +		$h = $max - $min; + +		if ($h) +		{ +			switch ($max) +			{ +				case $g: +					$h = 120 + (60 * ($b - $r) / $h); +					break; + +				case $b: +					$h = 240 + (60 * ($r - $g) / $h); +					break; + +				case $r: +					$h = 360 + (60 * ($g - $b) / $h); +					break; +			} +		} +		$this->normalize_hue($h); + +		return array($h, $s * 100, $v * 100); +	} + +	/** +	*/ +	function normalize_hue(&$hue) +	{ +		$hue %= 360; + +		if ($hue < 0) +		{ +			$hue += 360; +		} +	} + +	/** +	* Alternate hue to hue +	*/ +	function ah2h($ahue) +	{ +		if (is_array($ahue)) +		{ +			$ahue[0] = $this->ah2h($ahue[0]); +			return $ahue; +		} +		$this->normalize_hue($ahue); + +		// blue through red is already ok +		if ($ahue >= 240) +		{ +			return $ahue; +		} + +		// ahue green is at 180 +		if ($ahue >= 180) +		{ +			// return (240 - (2 * (240 - $ahue))); +			return (2 * $ahue) - 240; // equivalent +		} + +		// ahue yellow is at 120   (RYB rather than RGB) +		if ($ahue >= 120) +		{ +			return $ahue - 60; +		} + +		return $ahue / 2; +	} + +	/** +	* hue to Alternate hue +	*/ +	function h2ah($hue) +	{ +		if (is_array($hue)) +		{ +			$hue[0] = $this->h2ah($hue[0]); +			return $hue; +		} +		$this->normalize_hue($hue); + +		// blue through red is already ok +		if ($hue >= 240) +		{ +			return $hue; +		} +		else if ($hue <= 60) +		{ +			return $hue * 2; +		} +		else if ($hue <= 120) +		{ +			return $hue + 60; +		} +		else +		{ +			return ($hue + 240) / 2; +		} +	} +} diff --git a/phpBB/phpbb/captcha/factory.php b/phpBB/phpbb/captcha/factory.php new file mode 100644 index 0000000000..dd44aca8bb --- /dev/null +++ b/phpBB/phpbb/captcha/factory.php @@ -0,0 +1,88 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class factory +{ +	/** +	* @var \Symfony\Component\DependencyInjection\ContainerInterface +	*/ +	private $container; + +	/** +	* @var \phpbb\di\service_collection +	*/ +	private $plugins; + +	/** +	* Constructor +	* +	* @param \Symfony\Component\DependencyInjection\ContainerInterface $container +	* @param \phpbb\di\service_collection                              $plugins +	*/ +	public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, \phpbb\di\service_collection $plugins) +	{ +		$this->container = $container; +		$this->plugins = $plugins; +	} + +	/** +	* Return a new instance of a given plugin +	* +	* @param $name +	* @return object +	*/ +	public function get_instance($name) +	{ +		return $this->container->get($name); +	} + +	/** +	* Call the garbage collector +	* +	* @param string $name The name to the captcha service. +	*/ +	function garbage_collect($name) +	{ +		$captcha = $this->get_instance($name); +		$captcha->garbage_collect(0); +	} + +	/** +	* Return a list of all registered CAPTCHA plugins +	* +	* @returns array +	*/ +	function get_captcha_types() +	{ +		$captchas = array( +			'available'		=> array(), +			'unavailable'	=> array(), +		); + +		foreach ($this->plugins as $plugin => $plugin_instance) +		{ +			if ($plugin_instance->is_available()) +			{ +				$captchas['available'][$plugin] = $plugin_instance->get_name(); +			} +			else +			{ +				$captchas['unavailable'][$plugin] = $plugin_instance->get_name(); +			} +		} + +		return $captchas; +	} +} diff --git a/phpBB/phpbb/captcha/gd.php b/phpBB/phpbb/captcha/gd.php new file mode 100644 index 0000000000..652df28f8a --- /dev/null +++ b/phpBB/phpbb/captcha/gd.php @@ -0,0 +1,1847 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +class gd +{ +	var $width = 360; +	var $height = 96; + +	/** +	* Create the image containing $code with a seed of $seed +	*/ +	function execute($code, $seed) +	{ +		global $config; + +		mt_srand($seed); + +		// Create image +		$img = imagecreatetruecolor($this->width, $this->height); + +		// Generate colours +		$colour = new colour_manager($img, array( +			'random'	=> true, +			'min_value'	=> 60, +		), 'hsv'); + +		$scheme = $colour->colour_scheme('background', false); +		$scheme = $colour->mono_range($scheme, 10, false); +		shuffle($scheme); + +		$bg_colours = array_splice($scheme, mt_rand(6, 12)); + +		// Generate code characters +		$characters = $sizes = $bounding_boxes = $noise = array(); +		$width_avail = $this->width - 15; +		$code_len = strlen($code); +		$captcha_bitmaps = $this->captcha_bitmaps(); + +		for ($i = 0; $i < $code_len; ++$i) +		{ +			$characters[$i] = new char_cube3d($captcha_bitmaps, $code[$i]); + +			list($min, $max) = $characters[$i]->range(); +			$sizes[$i] = mt_rand($min, $max); + +			$box = $characters[$i]->dimensions($sizes[$i]); +			$width_avail -= ($box[2] - $box[0]); +			$bounding_boxes[$i] = $box; +		} + +		// Redistribute leftover x-space +		$offset = array(); +		for ($i = 0; $i < $code_len; ++$i) +		{ +			$denom = ($code_len - $i); +			$denom = max(1.3, $denom); +			$offset[$i] = phpbb_mt_rand(0, (int) round((1.5 * $width_avail) / $denom)); +			$width_avail -= $offset[$i]; +		} + +		if ($config['captcha_gd_x_grid']) +		{ +			$grid = (int) $config['captcha_gd_x_grid']; +			for ($y = 0; $y < $this->height; $y += mt_rand($grid - 2, $grid + 2)) +			{ +				$current_colour = $scheme[array_rand($scheme)]; +				imageline($img, mt_rand(0,4), mt_rand($y - 3, $y), mt_rand($this->width - 5, $this->width), mt_rand($y - 3, $y), $current_colour); +			} +		} + +		if ($config['captcha_gd_y_grid']) +		{ +			$grid = (int) $config['captcha_gd_y_grid']; +			for ($x = 0; $x < $this->width; $x += mt_rand($grid - 2, $grid + 2)) +			{ +				$current_colour = $scheme[array_rand($scheme)]; +				imagedashedline($img, mt_rand($x -3, $x + 3), mt_rand(0, 4), mt_rand($x -3, $x + 3), mt_rand($this->height - 5, $this->height), $current_colour); +			} +		} + +		if ($config['captcha_gd_wave'] && ($config['captcha_gd_y_grid'] || $config['captcha_gd_y_grid'])) +		{ +			$this->wave($img); +		} + +		if ($config['captcha_gd_3d_noise']) +		{ +			$xoffset = mt_rand(0,9); +			$noise_bitmaps = $this->captcha_noise_bg_bitmaps(); +			for ($i = 0; $i < $code_len; ++$i) +			{ +				$noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, sizeof($noise_bitmaps['data']))); + +				list($min, $max) = $noise[$i]->range(); +				//$box = $noise[$i]->dimensions($sizes[$i]); +			} +			$xoffset = 0; +			for ($i = 0; $i < $code_len; ++$i) +			{ +				$dimm = $bounding_boxes[$i]; +				$xoffset += ($offset[$i] - $dimm[0]); +				$yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]); + +				$noise[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme); +				$xoffset += $dimm[2]; +			} +		} + +		$xoffset = 5; +		for ($i = 0; $i < $code_len; ++$i) +		{ +			$dimm = $bounding_boxes[$i]; +			$xoffset += ($offset[$i] - $dimm[0]); +			$yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]); + +			$characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme); +			$xoffset += $dimm[2]; +		} + +		if ($config['captcha_gd_wave']) +		{ +			$this->wave($img); +		} + +		if ($config['captcha_gd_foreground_noise']) +		{ +			$this->noise_line($img, 0, 0, $this->width, $this->height, $colour->get_resource('background'), $scheme, $bg_colours); +		} + +		// Send image +		header('Content-Type: image/png'); +		header('Cache-control: no-cache, no-store'); +		imagepng($img); +		imagedestroy($img); +	} + +	/** +	* Sinus +	*/ +	function wave($img) +	{ +		global $config; + +		$period_x = mt_rand(12,18); +		$period_y = mt_rand(7,14); +		$amp_x = mt_rand(5,10); +		$amp_y = mt_rand(2,4); +		$socket = mt_rand(0,100); + +		$dampen_x = mt_rand($this->width/5, $this->width/2); +		$dampen_y = mt_rand($this->height/5, $this->height/2); +		$direction_x = (mt_rand (0, 1)); +		$direction_y = (mt_rand (0, 1)); + +		for ($i = 0; $i < $this->width; $i++) +		{ +			$dir = ($direction_x) ? $i : ($this->width - $i); +			imagecopy($img, $img, $i-1, sin($socket+ $i/($period_x + $dir/$dampen_x)) * $amp_x, $i, 0, 1, $this->height); +		} +		$socket = mt_rand(0,100); +		for ($i = 0; $i < $this->height; $i++) +		{ +			$dir = ($direction_y) ? $i : ($this->height - $i); +			imagecopy($img, $img ,sin($socket + $i/($period_y + ($dir)/$dampen_y)) * $amp_y, $i-1, 0, $i, $this->width, 1); +		} +		return $img; +	} + +	/** +	* Noise line +	*/ +	function noise_line($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font) +	{ +		imagesetthickness($img, 2); + +		$x1 = $min_x; +		$x2 = $max_x; +		$y1 = $min_y; +		$y2 = $min_y; + +		do +		{ +			$line = array_merge( +				array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), +				array_fill(0, mt_rand(30, 60), $bg) +			); + +			imagesetstyle($img, $line); +			imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + +			$y1 += mt_rand(12, 35); +			$y2 += mt_rand(12, 35); +		} +		while ($y1 < $max_y && $y2 < $max_y); + +		$x1 = $min_x; +		$x2 = $min_x; +		$y1 = $min_y; +		$y2 = $max_y; + +		do +		{ +			$line = array_merge( +				array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), +				array_fill(0, mt_rand(30, 60), $bg) +			); + +			imagesetstyle($img, $line); +			imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + +			$x1 += mt_rand(20, 35); +			$x2 += mt_rand(20, 35); +		} +		while ($x1 < $max_x && $x2 < $max_x); +		imagesetthickness($img, 1); +	} + +	function captcha_noise_bg_bitmaps() +	{ +		return array( +			'width'		=> 15, +			'height'	=> 5, +			'data'		=> array( + +			1 => array( +				array(1,0,0,0,1,0,0,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,1,0,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,1,0,0,0,0,0,0,1,0,0), +				array(1,0,0,0,0,0,1,0,0,0,0,1,0,0,0), +			), +			2 => array( +				array(1,1,mt_rand(0,1),1,0,1,1,1,1,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,1,1,0,1,1,1), +			), +			3 => array( +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,1,0,0,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,1), +			), +			4 => array( +				array(1,0,1,0,1,0,0,1,1,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(1,0,1,0,0,0,0,0,0,0,0,0,0,0,0), +			), +			5 => array( +				array(1,1,1,1,0,0,0,1,1,1,0,0,1,0,1), +				array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(1,0,1,0,0,0,0,0,0,0,0,0,0,0,0), +			), +			6 => array( +				array(mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),0,mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),0,mt_rand(0,1),mt_rand(0,1),mt_rand(0,1)), +				array(0,0,0,0,0,0,0,mt_rand(0,1),0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(mt_rand(0,1),0,mt_rand(0,1),0,0,0,0,0,0,0,0,0,0,0,0), +			), +			7 => array( +				array(0,0,0,0,0,0,0,0,0,0,1,1,0,1,1), +				array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +				array(0,0,1,1,0,0,0,1,0,0,0,0,0,0,0), +				array(0,1,0,0,0,1,0,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +			), +		)); +	} + +	/** +	* Return bitmaps +	*/ +	function captcha_bitmaps() +	{ +		global $config; + +		$chars = array( +			'A'	=>	array( +						array( +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,1,1,1,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,1,1,0,1,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,1,1,1,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,1,0,0,0,1,1,0), +							array(1,1,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,1,1), +							array(0,0,0,0,0,1,1,1,1), +							array(0,0,0,1,1,1,0,0,1), +							array(0,1,1,1,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,0,0,0,0,1,1,1), +							array(0,1,1,1,1,1,1,0,1), +						), +					), +		'B'	=>		array( +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +						), +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +						), +						array( +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,1,1,1,1,0,0), +						), +					), +		'C'	=>		array( +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,1,1,1,1,1,0,1), +							array(0,1,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,1), +							array(0,0,1,1,1,1,1,0,1), +						), +					), +		'D'	=>		array( +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +						), +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,1,1,1,1,1,0,1), +							array(0,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,1,0,0,0,1,1,1), +							array(0,0,1,1,1,1,1,0,1), +						), +					), +		'E'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,1,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,1,0,0,0,1,1,0), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,0,0,0,0,0,1,1), +							array(0,1,1,1,1,1,1,1,0), +						), +					), +		'F'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +						), +						array( +							array(0,1,1,1,1,1,1,1,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,0,0,0), +						), +						array( +							array(0,0,0,1,1,0,0,0,0), +							array(0,0,1,1,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(1,1,1,1,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +						), +					), +		'G'	=>		array( +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,1,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,1,1,1,1,1,0,1), +							array(0,1,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,1,1,1,1,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,1), +							array(0,0,1,1,1,1,1,0,1), +						), +						array( +							array(0,0,1,1,1,1,1,0,1), +							array(0,1,1,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,1,0,0,0,0,0,1), +							array(0,0,1,1,1,1,1,1,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,1,1), +							array(1,1,1,1,1,1,1,1,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +						), +					), +		'H'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,1,1,1,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,1,1,1,0,0,0), +							array(1,1,1,1,0,1,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +						), +					), +		'I'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(0,0,0,1,1,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +						), +					), +		'J'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,0,1,1,0,0,0,0,0), +						), +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,1,0,0,1,0,0,0,0), +							array(1,0,1,1,0,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,0,1,1,0,0,0,0,0), +						), +					), +		'K'	=>		array( +						array(    // New 'K', supplied by NeoThermic +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,1,0,0,0,0), +							array(1,0,0,1,0,0,0,0,0), +							array(1,0,1,0,0,0,0,0,0), +							array(1,1,0,0,0,0,0,0,0), +							array(1,0,1,0,0,0,0,0,0), +							array(1,0,0,1,0,0,0,0,0), +							array(1,0,0,0,1,0,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,1,0,0), +							array(0,1,0,0,0,1,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,1,0,1,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,0,1,0,0,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,1,0,0,0,1,0,0,0), +							array(0,1,0,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,1,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,1,0,1,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,0,1,0,0,0,0,0), +							array(0,1,0,0,1,0,0,0,0), +							array(0,1,0,0,0,1,0,0,0), +							array(0,1,0,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +						), +					), +		'L'	=>		array( +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,1), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,0,1,1,1,0,0,0,0), +						), +					), +		'M'	=>		array( +						array( +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,1,0,1,0,1,0,1,0), +							array(0,1,0,1,0,1,0,1,0), +							array(0,1,0,1,0,1,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,1,1,0,1,1,1,0), +							array(1,1,0,1,1,1,0,1,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +						), +					), +		'N'	=>		array( +						array( +							array(1,1,0,0,0,0,0,0,1), +							array(1,1,0,0,0,0,0,0,1), +							array(1,0,1,0,0,0,0,0,1), +							array(1,0,1,0,0,0,0,0,1), +							array(1,0,0,1,0,0,0,0,1), +							array(1,0,0,1,0,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,0,1,0,0,1), +							array(1,0,0,0,0,1,0,0,1), +							array(1,0,0,0,0,0,1,0,1), +							array(1,0,0,0,0,0,1,0,1), +							array(1,0,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,0,0,0,0,1,0), +							array(0,1,1,0,0,0,0,1,0), +							array(0,1,1,0,0,0,0,1,0), +							array(0,1,0,1,0,0,0,1,0), +							array(0,1,0,1,0,0,0,1,0), +							array(0,1,0,1,0,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,0,1,1,0,1,0), +							array(0,1,0,0,0,1,0,1,0), +							array(0,1,0,0,0,1,1,1,0), +							array(0,1,0,0,0,0,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(1,0,1,1,1,1,0,0,0), +							array(1,1,1,0,0,1,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +						), +					), +		'O'	=>		array( +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,1,1,1,1,0,0,0), +							array(1,1,1,0,0,1,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,1,0,0,0,1,1,0,0), +							array(0,1,1,1,1,1,0,0,0), +						), +					), +		'P'	=>		array( +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +						), +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,1,1,0,0,0,0,0), +							array(1,1,0,1,1,0,0,0,0), +							array(1,0,0,0,1,0,0,0,0), +							array(1,0,0,0,1,0,0,0,0), +							array(1,0,0,1,1,0,0,0,0), +							array(1,1,1,1,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +						), +					), +		'Q'	=>		array( +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,1,0,0,1), +							array(1,0,0,0,0,0,1,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,1), +						), +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,1,0,0,1,1,0,1,1), +							array(0,1,1,1,1,1,1,1,0), +							array(0,0,0,0,0,0,1,1,0), +							array(0,0,0,0,0,0,0,1,1), +							array(0,0,0,0,0,0,0,0,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,1,1,1,1), +							array(0,0,0,0,1,1,0,0,1), +							array(0,0,0,0,1,0,0,0,1), +							array(0,0,0,0,1,0,0,0,1), +							array(0,0,0,0,1,1,0,1,1), +							array(0,0,0,0,0,1,1,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +						), +					), +		'R'	=>		array( +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +							array(1,1,1,0,0,0,0,0,0), +							array(1,0,0,1,0,0,0,0,0), +							array(1,0,0,0,1,0,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,0,1,0,0), +							array(1,0,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,1,1,1,1,0,0), +							array(0,1,1,0,0,0,0,0,0), +							array(0,1,1,1,0,0,0,0,0), +							array(0,1,0,1,1,0,0,0,0), +							array(0,1,0,0,1,1,0,0,0), +							array(0,1,0,0,0,1,1,0,0), +							array(0,1,0,0,0,0,1,1,0), +							array(1,1,1,0,0,0,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,0,0,0,0), +							array(1,1,0,0,1,1,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +						), +					), +		'S'	=>		array( +						array( +							array(0,0,1,1,1,1,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,0,1,1,1,1,1,0,0), +							array(0,0,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,1,1,1,1,1,0,1), +							array(0,1,0,0,0,0,0,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(0,0,1,1,1,1,1,0,0), +							array(0,0,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,0,0,0,0,0,1,0), +							array(1,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,1,1,1,0,0,0,0), +							array(1,0,0,0,0,1,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,0,0,0,0,0,0,0), +							array(0,1,1,1,1,0,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(1,0,0,0,1,1,0,0,0), +							array(0,1,1,1,1,0,0,0,0), +						), +					), +		'T'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +						), +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,1,0,0,0,1), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +						), +						array( +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,1,1,1,1,1,1,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,1,0,0,0), +							array(0,0,0,0,0,1,1,1,0), +						), +					), +		'U'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,0,1,1,1,1,1,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,1,0,0,0,0,0,1), +							array(0,0,1,0,0,0,0,0,1), +							array(0,0,1,0,0,0,0,0,1), +							array(0,0,1,0,0,0,0,0,1), +							array(0,0,1,0,0,0,0,0,1), +							array(0,0,1,0,0,0,0,1,1), +							array(0,0,1,1,0,0,1,1,1), +							array(0,0,0,1,1,1,1,0,1), +						), +					), +		'V'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +						), +					), +		'W'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,0,1,0,0,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,0,1,0,1,0,0,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,0,1,0,0,0,1,0,1), +							array(1,1,0,0,0,0,0,1,1), +							array(1,1,0,0,0,0,0,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,1,1,1,0,1,0), +							array(0,1,0,1,0,1,0,1,0), +							array(0,1,1,1,0,1,1,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,0,1,0,0,1,0), +							array(0,1,0,1,1,1,0,1,0), +							array(0,1,0,1,0,1,0,1,0), +							array(0,1,1,1,0,1,1,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,0,0,0), +						), +					), +		'X'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,1,0,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,1,0,0,0,0,1,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,0,0,0,0,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,0,1,1,0,1,1,0,0), +							array(0,0,0,1,1,1,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +							array(0,0,1,1,0,1,1,0,0), +							array(0,1,1,0,0,0,1,1,0), +							array(0,0,0,0,0,0,0,0,0), +						), +					), +		'Y'	=>		array( +						array( +							array(1,0,0,0,0,0,0,0,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(1,1,1,0,0,0,1,1,1), +							array(0,1,0,0,0,0,0,1,0), +							array(0,1,0,0,0,0,0,1,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,1,0,0,0,1,0,0), +							array(0,0,0,1,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,1,1,0,0,0), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,1,0,0,0,0,1), +							array(0,0,0,1,1,0,0,0,1), +							array(0,0,0,0,1,0,0,1,1), +							array(0,0,0,0,1,1,0,1,0), +							array(0,0,0,0,0,1,1,1,0), +							array(0,0,0,0,0,0,1,0,0), +							array(0,0,0,0,0,1,1,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,1,1,0,0,0), +							array(0,0,1,1,1,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +						), +					), +		'Z'	=>		array( +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(1,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,1,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,1,0,0,0,0), +							array(0,0,0,1,0,0,0,0,0), +							array(0,0,0,1,0,0,0,0,0), +							array(0,0,1,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,1), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(1,1,1,1,1,1,1,1,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,0,1), +							array(0,0,0,0,0,0,0,1,0), +							array(0,0,0,0,0,0,1,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,0,0,0,1,0,0,0), +							array(0,0,1,1,1,1,1,0,0), +							array(0,0,0,1,0,0,0,0,0), +							array(0,0,0,1,0,0,0,0,0), +							array(0,0,1,0,0,0,0,0,0), +							array(0,1,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,0,0,0,0,0,0,0,0), +							array(1,1,1,1,1,1,1,1,1), +						), +						array( +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,0,0,0,0,0,0,0,0), +							array(0,1,1,1,1,1,1,1,0), +							array(0,0,0,0,0,1,1,0,0), +							array(0,0,0,0,1,1,0,0,0), +							array(0,0,0,1,1,0,0,0,0), +							array(0,0,1,1,0,0,0,0,0), +							array(0,0,1,0,0,0,0,0,0), +							array(0,1,1,1,1,1,1,1,0), +						), +					), +				); +		return array( +			'width'		=> 9, +			'height'	=> 15, +			'data'		=> array( + +			'A' =>	$chars['A'][mt_rand(0, min(sizeof($chars['A']), $config['captcha_gd_fonts']) -1)], +			'B' =>	$chars['B'][mt_rand(0, min(sizeof($chars['B']), $config['captcha_gd_fonts']) -1)], +			'C' =>	$chars['C'][mt_rand(0, min(sizeof($chars['C']), $config['captcha_gd_fonts']) -1)], +			'D' =>	$chars['D'][mt_rand(0, min(sizeof($chars['D']), $config['captcha_gd_fonts']) -1)], +			'E' =>	$chars['E'][mt_rand(0, min(sizeof($chars['E']), $config['captcha_gd_fonts']) -1)], +			'F' =>	$chars['F'][mt_rand(0, min(sizeof($chars['F']), $config['captcha_gd_fonts']) -1)], +			'G' =>	$chars['G'][mt_rand(0, min(sizeof($chars['G']), $config['captcha_gd_fonts']) -1)], +			'H' =>	$chars['H'][mt_rand(0, min(sizeof($chars['H']), $config['captcha_gd_fonts']) -1)], +			'I' =>	$chars['I'][mt_rand(0, min(sizeof($chars['I']), $config['captcha_gd_fonts']) -1)], +			'J' =>	$chars['J'][mt_rand(0, min(sizeof($chars['J']), $config['captcha_gd_fonts']) -1)], +			'K' =>	$chars['K'][mt_rand(0, min(sizeof($chars['K']), $config['captcha_gd_fonts']) -1)], +			'L' =>	$chars['L'][mt_rand(0, min(sizeof($chars['L']), $config['captcha_gd_fonts']) -1)], +			'M' =>	$chars['M'][mt_rand(0, min(sizeof($chars['M']), $config['captcha_gd_fonts']) -1)], +			'N' =>	$chars['N'][mt_rand(0, min(sizeof($chars['N']), $config['captcha_gd_fonts']) -1)], +			'O' =>	$chars['O'][mt_rand(0, min(sizeof($chars['O']), $config['captcha_gd_fonts']) -1)], +			'P' =>	$chars['P'][mt_rand(0, min(sizeof($chars['P']), $config['captcha_gd_fonts']) -1)], +			'Q' =>	$chars['Q'][mt_rand(0, min(sizeof($chars['Q']), $config['captcha_gd_fonts']) -1)], +			'R' =>	$chars['R'][mt_rand(0, min(sizeof($chars['R']), $config['captcha_gd_fonts']) -1)], +			'S' =>	$chars['S'][mt_rand(0, min(sizeof($chars['S']), $config['captcha_gd_fonts']) -1)], +			'T' =>	$chars['T'][mt_rand(0, min(sizeof($chars['T']), $config['captcha_gd_fonts']) -1)], +			'U' =>	$chars['U'][mt_rand(0, min(sizeof($chars['U']), $config['captcha_gd_fonts']) -1)], +			'V' =>	$chars['V'][mt_rand(0, min(sizeof($chars['V']), $config['captcha_gd_fonts']) -1)], +			'W' =>	$chars['W'][mt_rand(0, min(sizeof($chars['W']), $config['captcha_gd_fonts']) -1)], +			'X' =>	$chars['X'][mt_rand(0, min(sizeof($chars['X']), $config['captcha_gd_fonts']) -1)], +			'Y' =>	$chars['Y'][mt_rand(0, min(sizeof($chars['Y']), $config['captcha_gd_fonts']) -1)], +			'Z' =>	$chars['Z'][mt_rand(0, min(sizeof($chars['Z']), $config['captcha_gd_fonts']) -1)], + +			'1' => array( +				array(0,0,0,1,1,0,0,0,0), +				array(0,0,1,0,1,0,0,0,0), +				array(0,1,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,1,1,1,1,1,1,1,0), +			), +			'2' => array(    // New '2' supplied by Anon +				array(0,0,0,1,1,1,0,0,0), +				array(0,0,1,0,0,0,1,0,0), +				array(0,1,0,0,0,0,1,1,0), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,1,1), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,1,0,0), +				array(0,0,0,0,0,1,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,1,0,0,0,0,0), +				array(0,0,1,0,0,0,0,0,0), +				array(0,1,0,0,0,0,0,0,0), +				array(1,1,1,1,1,1,1,1,1), +				array(0,0,0,0,0,0,0,0,0), +			), +			'3' => array( +				array(0,0,1,1,1,1,1,0,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,1,1,0,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +			), +			'4' => array( +				array(0,0,0,0,0,0,1,1,0), +				array(0,0,0,0,0,1,0,1,0), +				array(0,0,0,0,1,0,0,1,0), +				array(0,0,0,1,0,0,0,1,0), +				array(0,0,1,0,0,0,0,1,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,1,0), +				array(1,1,1,1,1,1,1,1,1), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +			), +			'5' => array( +				array(1,1,1,1,1,1,1,1,1), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +				array(0,1,0,0,0,0,0,0,0), +				array(0,0,1,1,1,1,1,0,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +			), +			'6' => array( +				array(0,0,1,1,1,1,1,0,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,1,1,1,1,0,0), +				array(1,0,1,0,0,0,0,1,0), +				array(1,1,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +			), +			'7' => array( +				array(1,1,1,1,1,1,1,1,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,0,1,0), +				array(0,0,0,0,0,0,1,0,0), +				array(0,0,0,0,0,1,0,0,0), +				array(0,0,0,0,0,1,0,0,0), +				array(0,0,0,0,1,0,0,0,0), +				array(0,0,0,1,0,0,0,0,0), +				array(0,0,0,1,0,0,0,0,0), +				array(0,0,1,0,0,0,0,0,0), +				array(0,1,0,0,0,0,0,0,0), +				array(0,1,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +				array(1,0,0,0,0,0,0,0,0), +			), +			'8' => array( +				array(0,0,1,1,1,1,1,0,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +			), +			'9' => array( +				array(0,0,1,1,1,1,1,0,0), +				array(0,1,0,0,0,0,0,1,0), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,1,1), +				array(0,1,0,0,0,0,1,0,1), +				array(0,0,1,1,1,1,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(0,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(1,0,0,0,0,0,0,0,1), +				array(0,1,0,0,0,0,0,1,0), +				array(0,0,1,1,1,1,1,0,0), +			), +			) +		); +	} +} diff --git a/phpBB/phpbb/captcha/gd_wave.php b/phpBB/phpbb/captcha/gd_wave.php new file mode 100644 index 0000000000..d48fc753a5 --- /dev/null +++ b/phpBB/phpbb/captcha/gd_wave.php @@ -0,0 +1,845 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +/** +* Wave3D CAPTCHA +*/ +class gd_wave +{ +	var $width		= 360; +	var $height		= 96; + +	function execute($code, $seed) +	{ +		global $starttime; + +		// seed the random generator +		mt_srand($seed); + +		// set height and width +		$img_x = $this->width; +		$img_y = $this->height; + +		// Generate image +		$img	= imagecreatetruecolor($img_x, $img_y); +		$x_grid = mt_rand(6, 10); +		$y_grid = mt_rand(6, 10); + +		// Ok, so lets cut to the chase. We could accurately represent this in 3d and +		// do all the appropriate linear transforms. my questions is... why bother? +		// The computational overhead is unnecessary when you consider the simple fact: +		// we're not here to accurately represent a model, but to just show off some random-ish +		// polygons + +		// Conceive of 3 spaces. +		// 1) planar-space (discrete "pixel" grid) +		// 2) 3-space. (planar-space with z/height aspect) +		// 3) image space (pixels on the screen) +		// resolution of the planar-space we're embedding the text code in +		$plane_x	= 100; +		$plane_y	= 30; + +		$subdivision_factor = 3; + +		// $box is the 4 points in img_space that correspond to the corners of the plane in 3-space +		$box = array( +			'upper_left'	=> array( +				'x' => mt_rand(5, 15), +				'y' => mt_rand(10, 15) +			), +			'upper_right'	=> array( +				'x' => mt_rand($img_x - 35, $img_x - 19), +				'y' => mt_rand(10, 17) +			), +			'lower_left'	=> array( +				'x' => mt_rand($img_x - 45, $img_x - 5), +				'y' => mt_rand($img_y - 15, $img_y - 0), +			), +		); + +		$box['lower_right'] = array( +			'x' => $box['lower_left']['x'] + $box['upper_left']['x'] - $box['upper_right']['x'], +			'y' => $box['lower_left']['y'] + $box['upper_left']['y'] - $box['upper_right']['y'], +		); + +		// TODO +		$background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255)); +		imagefill($img, 0, 0, $background); +		$black = imagecolorallocate($img, 0, 0, 0); + +		$random = array(); +		$fontcolors = array(); + +		for ($i = 0; $i < 15; ++$i) +		{ +			$random[$i] = imagecolorallocate($img, mt_rand(120, 255), mt_rand(120, 255), mt_rand(120, 255)); +		} + +		$fontcolors[0] = imagecolorallocate($img, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120)); + +		$colors = array(); + +		$minr = mt_rand(20, 30); +		$ming = mt_rand(20, 30); +		$minb = mt_rand(20, 30); + +		$maxr = mt_rand(150, 230); +		$maxg = mt_rand(150, 230); +		$maxb = mt_rand(150, 230); + +		for ($i = -30; $i <= 30; ++$i) +		{ +			$coeff1 = ($i + 12) / 45; +			$coeff2 = 1 - $coeff1; +			$colors[$i] = imagecolorallocate($img, ($coeff2 * $maxr) + ($coeff1 * $minr), ($coeff2 * $maxg) + ($coeff1 * $ming), ($coeff2 * $maxb) + ($coeff1 * $minb)); +		} + +		// $img_buffer is the last row of 3-space positions (converted to img-space), cached +		// (using this means we don't need to recalculate all 4 positions for each new polygon, +		// merely the newest point that we're adding, which is then cached. +		$img_buffer = array(array(), array()); + +		// In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space +		$dxx = ($box['upper_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_x); +		$dxy = ($box['upper_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_x); + +		// In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space +		$dyx = ($box['lower_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_y); +		$dyy = ($box['lower_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_y); + +		// Initial captcha-letter offset in planar-space +		$plane_offset_x = mt_rand(3, 8); +		$plane_offset_y = mt_rand( 12, 15); + +		// character map +		$map = $this->captcha_bitmaps(); + +		// matrix +		$plane = array(); + +		// for each character, we'll silkscreen it into our boolean pixel plane +		for ($c = 0, $code_num = strlen($code); $c < $code_num; ++$c) +		{ +			$letter = $code[$c]; + +			for ($x = $map['width'] - 1; $x >= 0; --$x) +			{ +				for ($y = $map['height'] - 1; $y >= 0; --$y) +				{ +					if ($map['data'][$letter][$y][$x]) +					{ +						$plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true; +					} +				} +			} +			$plane_offset_x += 11; +		} + +		// calculate our first buffer, we can't actually draw polys with these yet +		// img_pos_prev == screen x,y location to our immediate left. +		// img_pos_cur == current screen x,y location +		// we calculate screen position of our +		// current cell based on the difference from the previous cell +		// rather than recalculating from absolute coordinates +		// What we cache into the $img_buffer contains the raised text coordinates. +		$img_pos_prev	= $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']); +		$cur_height		= $prev_height = $this->wave_height(0, 0, $subdivision_factor); +		$full_x			= $plane_x * $subdivision_factor; +		$full_y			= $plane_y * $subdivision_factor; + +		for ($x = 1; $x <= $full_x; ++$x) +		{ +			$cur_height		= $this->wave_height($x, 0, $subdivision_factor); +			$offset			= $cur_height - $prev_height; +			$img_pos_cur	= array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + +			$img_buffer[0][$x]	= $img_pos_cur; +			$img_pos_prev		= $img_pos_cur; +			$prev_height		= $cur_height; +		} + +		for ($y = 1; $y <= $full_y; ++$y) +		{ +			// swap buffers +			$buffer_cur		= $y & 1; +			$buffer_prev	= 1 - $buffer_cur; + +			$prev_height	= $this->wave_height(0, $y, $subdivision_factor); +			$offset			= $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor); +			$img_pos_cur	= array($img_buffer[$buffer_prev][0][0] + $dyx, min($img_buffer[$buffer_prev][0][1] + $dyy + $offset, $img_y - 1)); + +			// make sure we don't try to write off the page +			$img_pos_prev	= $img_pos_cur; + +			$img_buffer[$buffer_cur][0]	= $img_pos_cur; + +			for ($x = 1; $x <= $full_x; ++$x) +			{ +				$cur_height		= $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, $x_grid, $y_grid, 1); + +				// height is a z-factor, not a y-factor +				$offset			= $cur_height - $prev_height; +				$img_pos_cur	= array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + +				// height is float, index it to an int, get closest color +				$color			= $colors[intval($cur_height)]; +				$img_pos_prev	= $img_pos_cur; +				$prev_height	= $cur_height; + +				$y_index_old = intval(($y - 1) / $subdivision_factor); +				$y_index_new = intval($y / $subdivision_factor); +				$x_index_old = intval(($x - 1) / $subdivision_factor); +				$x_index_new = intval($x / $subdivision_factor); + +				if (!empty($plane[$y_index_new][$x_index_new])) +				{ +					$img_pos_cur[1]	+= $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height; +					$color			= $colors[20]; +				} +				$img_pos_cur[1] = min($img_pos_cur[1], $img_y - 1); +				$img_buffer[$buffer_cur][$x] = $img_pos_cur; + +				// Smooth the edges as much as possible by having not more than one low<->high traingle per square +				// Otherwise, just +				$diag_down	= (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new])); +				$diag_up	= (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old])); + +				// natural switching +				$mode = ($x + $y) & 1; + +				// override if it requires it +				if ($diag_down != $diag_up) +				{ +					$mode = $diag_up; +				} + +				if ($mode) +				{ +					//		+-/			  / +					// 1	|/		2	 /| +					//		/			/-+ +					$poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]); +					$poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]); +				} +				else +				{ +					//		\			\-+ +					// 1	|\		2	 \| +					//		+-\			  \ +					$poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]); +					$poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]); +				} + +				imagefilledpolygon($img, $poly1, 3, $color); +				imagefilledpolygon($img, $poly2, 3, $color); +			} +		} + +		// Output image +		header('Content-Type: image/png'); +		header('Cache-control: no-cache, no-store'); +		//$mtime = explode(' ', microtime()); +		//$totaltime = $mtime[0] + $mtime[1] - $starttime; + +		//echo $totaltime . "<br />\n"; +		//echo memory_get_usage() - $tmp; +		imagepng($img); +		imagedestroy($img); +	} + +	function wave_height($x, $y, $factor = 1, $tweak = 0.7) +	{ +		// stretch the wave. TODO: pretty it up +		$x = $x/5 + 180; +		$y = $y/4; +		return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak); +	} + +	function grid_height($x, $y, $x_grid, $y_grid, $factor = 1) +	{ +		return ((!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0); +	} + +	function captcha_bitmaps() +	{ +		return array( +			'width'		=> 9, +			'height'	=> 13, +			'data'		=> array( +				'A' => array( +					array(0,0,1,1,1,1,0,0,0), +					array(0,1,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,1,1,1,1,1,1,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'B' => array( +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,1,1,1,1,1,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'C' => array( +					array(0,0,1,1,1,1,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'D' => array( +					array(1,1,1,1,1,1,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,1,0), +					array(1,1,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'E' => array( +					array(0,0,1,1,1,1,1,1,1), +					array(0,1,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,1,1,1,1,1,1,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,1,0,0,0,0,0,0,0), +					array(0,0,1,1,1,1,1,1,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'F' => array( +					array(0,0,1,1,1,1,1,1,0), +					array(0,1,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'G' => array( +					array(0,0,1,1,1,1,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,1,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'H' => array( +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,1,1,1,1,1,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'I' => array( +					array(0,1,1,1,1,1,1,1,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,1,1,1,1,1,1,1,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'J' => array( +					array(0,0,0,0,0,0,1,1,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,0,1,0,0,0,0,1,0), +					array(0,0,0,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'K' => array( +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,1,0,0,0), +					array(1,0,0,0,1,0,0,0,0), +					array(1,0,0,1,0,0,0,0,0), +					array(1,0,1,0,0,0,0,0,0), +					array(1,1,0,0,0,0,0,0,0), +					array(1,0,1,0,0,0,0,0,0), +					array(1,0,0,1,0,0,0,0,0), +					array(1,0,0,0,1,0,0,0,0), +					array(1,0,0,0,0,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'L' => array( +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,1,0,0,0,0,0,0,0), +					array(0,0,1,1,1,1,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'M' => array( +					array(0,1,0,0,0,0,0,1,0), +					array(0,1,1,0,0,0,1,1,0), +					array(0,1,0,1,0,1,0,1,0), +					array(0,1,0,0,1,0,0,1,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'N' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,1,0,0,0,0,0,0,1), +					array(1,0,1,0,0,0,0,0,1), +					array(1,0,0,1,0,0,0,0,1), +					array(1,0,0,0,1,0,0,0,1), +					array(1,0,0,0,0,1,0,0,1), +					array(1,0,0,0,0,0,1,0,1), +					array(1,0,0,0,0,0,0,1,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'O' => array( +					array(0,0,0,1,1,1,0,0,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,0,0,1,1,1,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'P' => array( +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'Q' => array( +					array(0,0,1,1,1,1,0,0,0), +					array(0,1,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,1,0,0,1,0), +					array(1,0,0,0,0,1,0,1,0), +					array(0,1,0,0,0,0,1,0,0), +					array(0,0,1,1,1,1,0,1,0), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'R' => array( +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,1,0,0), +					array(1,1,1,1,1,1,0,0,0), +					array(1,0,1,0,0,0,0,0,0), +					array(1,0,0,1,0,0,0,0,0), +					array(1,0,0,0,1,0,0,0,0), +					array(1,0,0,0,0,1,0,0,0), +					array(1,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'S' => array( +					array(0,0,1,1,1,1,1,1,1), +					array(0,1,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,1,0,0,0,0,0,0,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,1,0), +					array(1,1,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'T' => array( +					array(1,1,1,1,1,1,1,1,1), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'U' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'V' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,0,0,1,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'W' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,1,0,0,0,1), +					array(1,0,0,1,0,1,0,0,1), +					array(1,0,1,0,0,0,1,0,1), +					array(1,1,0,0,0,0,0,1,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'X' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,0,0,1,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,1,0,1,0,0,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'Y' => array( +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,0,0,1,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'Z' => array( +					array(1,1,1,1,1,1,1,1,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,1,0,0,0,0,0), +					array(0,0,1,0,0,0,0,0,0), +					array(0,1,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,1,1,1,1,1,1,1,1), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'1' => array( +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,1,1,0,0,0,0), +					array(0,0,1,0,1,0,0,0,0), +					array(0,1,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,1,1,1,1,1,1,1,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'2' => array( +					array(0,0,0,1,1,1,0,0,0), +					array(0,0,1,0,0,0,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,1,0,0,0,0,0), +					array(0,0,1,0,0,0,0,0,0), +					array(0,1,1,1,1,1,1,1,1), +					array(0,0,0,0,0,0,0,0,0), +				), +				'3' => array( +					array(0,0,0,1,1,1,1,0,0), +					array(0,0,1,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,1,1,0,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,0,1,0,0,0,0,1,0), +					array(0,0,0,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'4' => array( +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,1,1,0), +					array(0,0,0,0,0,1,0,1,0), +					array(0,0,0,0,1,0,0,1,0), +					array(0,0,0,1,0,0,0,1,0), +					array(0,0,1,0,0,0,0,1,0), +					array(0,1,1,1,1,1,1,1,1), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'5' => array( +					array(1,1,1,1,1,1,1,1,1), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(0,1,0,0,0,0,0,0,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'6' => array( +					array(0,0,1,1,1,1,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,0,0,0,0,0,0), +					array(1,0,0,1,1,1,1,0,0), +					array(1,0,1,0,0,0,0,1,0), +					array(1,1,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'7' => array( +					array(1,1,1,1,1,1,1,1,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,1,0), +					array(0,0,0,0,0,0,1,0,0), +					array(0,0,0,0,0,1,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,1,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'8' => array( +					array(0,0,1,1,1,1,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,1,0,0,0,0,0,1,0), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(1,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,0), +					array(0,0,1,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +				'9' => array( +					array(0,0,0,1,1,1,1,0,0), +					array(0,0,1,0,0,0,0,1,0), +					array(0,1,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,1,1), +					array(0,0,1,1,1,1,1,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,0,0,0,0,0,0,0,1), +					array(0,1,0,0,0,0,0,0,1), +					array(0,0,1,0,0,0,0,1,0), +					array(0,0,0,1,1,1,1,0,0), +					array(0,0,0,0,0,0,0,0,0), +					array(0,0,0,0,0,0,0,0,0), +				), +			) +		); +	} +} diff --git a/phpBB/phpbb/captcha/non_gd.php b/phpBB/phpbb/captcha/non_gd.php new file mode 100644 index 0000000000..3818672f17 --- /dev/null +++ b/phpBB/phpbb/captcha/non_gd.php @@ -0,0 +1,386 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha; + +/** +* Main non-gd captcha class +* @ignore +*/ +class non_gd +{ +	var $filtered_pngs; +	var $width = 320; +	var $height = 50; + +	/** +	* Define filtered pngs on init +	*/ +	function __construct() +	{ +		// If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff +		$this->define_filtered_pngs(); +	} + +	/** +	* Create the image containing $code with a seed of $seed +	*/ +	function execute($code, $seed) +	{ +		$img_height = $this->height - 10; +		$img_width = 0; + +		mt_srand($seed); + +		$char_widths = $hold_chars = array(); +		$code_len = strlen($code); + +		for ($i = 0; $i < $code_len; $i++) +		{ +			$char = $code[$i]; + +			$width = mt_rand(0, 4); +			$raw_width = $this->filtered_pngs[$char]['width']; +			$char_widths[$i] = $width; +			$img_width += $raw_width - $width; + +			// Split the char into chunks of $raw_width + 1 length +			if (empty($hold_chars[$char])) +			{ +				$hold_chars[$char] = str_split(base64_decode($this->filtered_pngs[$char]['data']), $raw_width + 1); +			} +		} + +		$offset_x = mt_rand(0, $this->width - $img_width); +		$offset_y = mt_rand(0, $this->height - $img_height); + +		$image = ''; +		for ($i = 0; $i < $this->height; $i++) +		{ +			$image .= chr(0); + +			if ($i > $offset_y && $i < $offset_y + $img_height) +			{ +				for ($j = 0; $j < $offset_x; $j++) +				{ +					$image .= chr(mt_rand(140, 255)); +				} + +				for ($j = 0; $j < $code_len; $j++) +				{ +					$image .= $this->randomise(substr($hold_chars[$code{$j}][$i - $offset_y - 1], 1), $char_widths[$j]); +				} + +				for ($j = $offset_x + $img_width; $j < $this->width; $j++) +				{ +					$image .= chr(mt_rand(140, 255)); +				} +			} +			else +			{ +				for ($j = 0; $j < $this->width; $j++) +				{ +					$image .= chr(mt_rand(140, 255)); +				} +			} +		} +		unset($hold_chars); + +		$image = $this->create_png($image, $this->width, $this->height); + +		// Output image +		header('Content-Type: image/png'); +		header('Cache-control: no-cache, no-store'); +		echo $image; +		exit; +	} + +	/** +	* This is designed to randomise the pixels of the image data within +	* certain limits so as to keep it readable. It also varies the image +	* width a little +	*/ +	function randomise($scanline, $width) +	{ +		$new_line = ''; + +		$end = strlen($scanline) - ceil($width/2); +		for ($i = (int) floor($width / 2); $i < $end; $i++) +		{ +			$pixel = ord($scanline{$i}); + +			if ($pixel < 190) +			{ +				$new_line .= chr(mt_rand(0, 205)); +			} +			else if ($pixel > 190) +			{ +				$new_line .= chr(mt_rand(145, 255)); +			} +			else +			{ +				$new_line .= $scanline{$i}; +			} +		} + +		return $new_line; +	} + +	/** +	* This creates a chunk of the given type, with the given data +	* of the given length adding the relevant crc +	*/ +	function png_chunk($length, $type, $data) +	{ +		$raw = $type . $data; + +		return pack('N', $length) . $raw . pack('N', crc32($raw)); +	} + +	/** +	* Creates greyscale 8bit png - The PNG spec can be found at +	* http://www.libpng.org/pub/png/spec/PNG-Contents.html we use +	* png because it's a fully recognised open standard and supported +	* by practically all modern browsers and OSs +	*/ +	function create_png($raw_image, $width, $height) +	{ +		// SIG +		$image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10); + +		// IHDR +		$raw = pack('N2', $width, $height); +		$raw .= pack('C5', 8, 0, 0, 0, 0); +		$image .= $this->png_chunk(13, 'IHDR', $raw); + +		// IDAT +		if (@extension_loaded('zlib')) +		{ +			$raw_image = gzcompress($raw_image); +			$length = strlen($raw_image); +		} +		else +		{ +			// The total length of this image, uncompressed, is just a calculation of pixels +			$length = ($width + 1) * $height; + +			// Adler-32 hash generation +			// Note: The hash is _backwards_ so we must reverse it + +			if (@extension_loaded('hash')) +			{ +				$adler_hash = strrev(hash('adler32', $raw_image, true)); +			} +			else if (@extension_loaded('mhash')) +			{ +				$adler_hash = strrev(mhash(MHASH_ADLER32, $raw_image)); +			} +			else +			{ +				// Optimized Adler-32 loop ported from the GNU Classpath project +				$temp_length = $length; +				$s1 = 1; +				$s2 = $index = 0; + +				while ($temp_length > 0) +				{ +					// We can defer the modulo operation: +					// s1 maximally grows from 65521 to 65521 + 255 * 3800 +					// s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 +					$substract_value = ($temp_length < 3800) ? $temp_length : 3800; +					$temp_length -= $substract_value; + +					while (--$substract_value >= 0) +					{ +						$s1 += ord($raw_image[$index]); +						$s2 += $s1; + +						$index++; +					} + +					$s1 %= 65521; +					$s2 %= 65521; +				} +				$adler_hash = pack('N', ($s2 << 16) | $s1); +			} + +			// This is the same thing as gzcompress($raw_image, 0) but does not need zlib +			$raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash; + +			// The Zlib header + Adler hash make us add on 11 +			$length += 11; +		} + +		// IDAT +		$image .= $this->png_chunk($length, 'IDAT', $raw_image); + +		// IEND +		$image .= $this->png_chunk(0, 'IEND', ''); + +		return $image; +	} + +	/** +	* png image data +	* Each 'data' element is base64_encoded uncompressed IDAT +	*/ +	function define_filtered_pngs() +	{ +		$this->filtered_pngs = array( +			'0' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==', +				'width' => 40 +			), +			'1' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'2' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'3' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'4' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'5' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'6' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'7' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'8' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'9' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'A' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'B' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'C' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'D' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'E' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'F' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'G' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'H' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'I' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'J' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'K' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'L' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'M' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'N' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'O' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'P' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'Q' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'R' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'S' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'T' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'U' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'V' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'W' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'X' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'Y' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +			'Z' => array( +				'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', +				'width' => 40 +			), +		); +	} +} diff --git a/phpBB/phpbb/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php new file mode 100644 index 0000000000..24ed7f939d --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php @@ -0,0 +1,390 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +/** +* This class holds the code shared by the two default 3.0.x CAPTCHAs. +*/ +abstract class captcha_abstract +{ +	var $confirm_id; +	var $confirm_code; +	var $code; +	var $seed; +	var $attempts = 0; +	var $type; +	var $solved = 0; +	var $captcha_vars = false; + +	/** +	* @var string name of the service. +	*/ +	protected $service_name; + +	function init($type) +	{ +		global $config, $db, $user; + +		// read input +		$this->confirm_id = request_var('confirm_id', ''); +		$this->confirm_code = request_var('confirm_code', ''); +		$refresh = request_var('refresh_vc', false) && $config['confirm_refresh']; + +		$this->type = (int) $type; + +		if (!strlen($this->confirm_id) || !$this->load_code()) +		{ +			// we have no confirm ID, better get ready to display something +			$this->generate_code(); +		} +		else if ($refresh) +		{ +			$this->regenerate_code(); +		} +	} + +	function execute_demo() +	{ +		global $user; + +		$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); +		$this->seed = hexdec(substr(unique_id(), 4, 10)); + +		// compute $seed % 0x7fffffff +		$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + +		$generator = $this->get_generator_class(); +		$captcha = new $generator(); +		define('IMAGE_OUTPUT', 1); +		$captcha->execute($this->code, $this->seed); +	} + +	function execute() +	{ +		if (empty($this->code)) +		{ +			if (!$this->load_code()) +			{ +				// invalid request, bail out +				return false; +			} +		} +		$generator = $this->get_generator_class(); +		$captcha = new $generator(); +		define('IMAGE_OUTPUT', 1); +		$captcha->execute($this->code, $this->seed); +	} + +	function get_template() +	{ +		global $config, $user, $template, $phpEx, $phpbb_root_path; + +		if ($this->is_solved()) +		{ +			return false; +		} +		else +		{ +			$link = append_sid($phpbb_root_path . 'ucp.' . $phpEx,  'mode=confirm&confirm_id=' . $this->confirm_id . '&type=' . $this->type); +			$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx); +			$explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="' . $contact_link . '">', '</a>'); + +			$template->assign_vars(array( +				'CONFIRM_IMAGE_LINK'		=> $link, +				'CONFIRM_IMAGE'				=> '<img src="' . $link . '" />', +				'CONFIRM_IMG'				=> '<img src="' . $link . '" />', +				'CONFIRM_ID'				=> $this->confirm_id, +				'S_CONFIRM_CODE'			=> true, +				'S_TYPE'					=> $this->type, +				'S_CONFIRM_REFRESH'			=> ($config['enable_confirm'] && $config['confirm_refresh'] && $this->type == CONFIRM_REG) ? true : false, +				'L_CONFIRM_EXPLAIN'			=> $explain, +			)); + +			return 'captcha_default.html'; +		} +	} + +	function get_demo_template($id) +	{ +		global $config, $user, $template, $phpbb_admin_path, $phpEx; + +		$variables = ''; + +		if (is_array($this->captcha_vars)) +		{ +			foreach ($this->captcha_vars as $captcha_var => $template_var) +			{ +				$variables .= '&' . rawurlencode($captcha_var) . '=' . request_var($captcha_var, (int) $config[$captcha_var]); +			} +		} + +		// acp_captcha has a delivery function; let's use it +		$template->assign_vars(array( +			'CONFIRM_IMAGE'		=> append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_service_name()) . $variables, +			'CONFIRM_ID'		=> $this->confirm_id, +		)); + +		return 'captcha_default_acp_demo.html'; +	} + +	function get_hidden_fields() +	{ +		$hidden_fields = array(); + +		// this is required for posting.php - otherwise we would forget about the captcha being already solved +		if ($this->solved) +		{ +			$hidden_fields['confirm_code'] = $this->confirm_code; +		} +		$hidden_fields['confirm_id'] = $this->confirm_id; +		return $hidden_fields; +	} + +	function garbage_collect($type) +	{ +		global $db, $config; + +		$sql = 'SELECT DISTINCT c.session_id +			FROM ' . CONFIRM_TABLE . ' c +			LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) +			WHERE s.session_id IS NULL' . +				((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); +		$result = $db->sql_query($sql); + +		if ($row = $db->sql_fetchrow($result)) +		{ +			$sql_in = array(); +			do +			{ +				$sql_in[] = (string) $row['session_id']; +			} +			while ($row = $db->sql_fetchrow($result)); + +			if (sizeof($sql_in)) +			{ +				$sql = 'DELETE FROM ' . CONFIRM_TABLE . ' +					WHERE ' . $db->sql_in_set('session_id', $sql_in); +				$db->sql_query($sql); +			} +		} +		$db->sql_freeresult($result); +	} + +	function uninstall() +	{ +		$this->garbage_collect(0); +	} + +	function install() +	{ +		return; +	} + +	function validate() +	{ +		global $config, $db, $user; + +		if (empty($user->lang)) +		{ +			$user->setup(); +		} + +		$error = ''; +		if (!$this->confirm_id) +		{ +			$error = $user->lang['CONFIRM_CODE_WRONG']; +		} +		else +		{ +			if ($this->check_code()) +			{ +				$this->solved = true; +			} +			else +			{ +				$error = $user->lang['CONFIRM_CODE_WRONG']; +			} +		} + +		if (strlen($error)) +		{ +			// okay, incorrect answer. Let's ask a new question. +			$this->new_attempt(); +			return $error; +		} +		else +		{ +			return false; +		} +	} + +	/** +	* The old way to generate code, suitable for GD and non-GD. Resets the internal state. +	*/ +	function generate_code() +	{ +		global $db, $user; + +		$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); +		$this->confirm_id = md5(unique_id($user->ip)); +		$this->seed = hexdec(substr(unique_id(), 4, 10)); +		$this->solved = 0; +		// compute $seed % 0x7fffffff +		$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + +		$sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( +				'confirm_id'	=> (string) $this->confirm_id, +				'session_id'	=> (string) $user->session_id, +				'confirm_type'	=> (int) $this->type, +				'code'			=> (string) $this->code, +				'seed'			=> (int) $this->seed) +		); +		$db->sql_query($sql); +	} + +	/** +	* New Question, if desired. +	*/ +	function regenerate_code() +	{ +		global $db, $user; + +		$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); +		$this->seed = hexdec(substr(unique_id(), 4, 10)); +		$this->solved = 0; +		// compute $seed % 0x7fffffff +		$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + +		$sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( +				'code'			=> (string) $this->code, +				'seed'			=> (int) $this->seed)) . ' +				WHERE +				confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' +					AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; +		$db->sql_query($sql); +	} + +	/** +	* New Question, if desired. +	*/ +	function new_attempt() +	{ +		global $db, $user; + +		$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); +		$this->seed = hexdec(substr(unique_id(), 4, 10)); +		$this->solved = 0; +		// compute $seed % 0x7fffffff +		$this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + +		$sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( +				'code'			=> (string) $this->code, +				'seed'			=> (int) $this->seed)) . ' +				, attempts = attempts + 1 +				WHERE +				confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' +					AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; +		$db->sql_query($sql); +	} + +	/** +	* Look up everything we need for painting&checking. +	*/ +	function load_code() +	{ +		global $db, $user; + +		$sql = 'SELECT code, seed, attempts +			FROM ' . CONFIRM_TABLE . " +			WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' +				AND session_id = '" . $db->sql_escape($user->session_id) . "' +				AND confirm_type = " . $this->type; +		$result = $db->sql_query($sql); +		$row = $db->sql_fetchrow($result); +		$db->sql_freeresult($result); + +		if ($row) +		{ +			$this->code = $row['code']; +			$this->seed = $row['seed']; +			$this->attempts = $row['attempts']; +			return true; +		} + +		return false; +	} + +	function check_code() +	{ +		return (strcasecmp($this->code, $this->confirm_code) === 0); +	} + +	function get_attempt_count() +	{ +		return $this->attempts; +	} + +	function reset() +	{ +		global $db, $user; + +		$sql = 'DELETE FROM ' . CONFIRM_TABLE . " +			WHERE session_id = '" . $db->sql_escape($user->session_id) . "' +				AND confirm_type = " . (int) $this->type; +		$db->sql_query($sql); + +		// we leave the class usable by generating a new question +		$this->generate_code(); +	} + +	function is_solved() +	{ +		if (request_var('confirm_code', false) && $this->solved === 0) +		{ +			$this->validate(); +		} +		return (bool) $this->solved; +	} + +	/** +	*  API function +	*/ +	function has_config() +	{ +		return false; +	} + +	/** +	* @return string the name of the service corresponding to the plugin +	*/ +	function get_service_name() +	{ +		return $this->service_name; +	} + +	/** +	* Set the name of the plugin +	* +	* @param string $name +	*/ +	public function set_name($name) +	{ +		$this->service_name = $name; +	} + +	/** +	* @return string the name of the class used to generate the captcha +	*/ +	abstract function get_generator_class(); +} diff --git a/phpBB/phpbb/captcha/plugins/gd.php b/phpBB/phpbb/captcha/plugins/gd.php new file mode 100644 index 0000000000..f6200b5b2f --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/gd.php @@ -0,0 +1,130 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class gd extends captcha_abstract +{ +	var $captcha_vars = array( +		'captcha_gd_x_grid'				=> 'CAPTCHA_GD_X_GRID', +		'captcha_gd_y_grid'				=> 'CAPTCHA_GD_Y_GRID', +		'captcha_gd_foreground_noise'	=> 'CAPTCHA_GD_FOREGROUND_NOISE', +//		'captcha_gd'					=> 'CAPTCHA_GD_PREVIEWED', +		'captcha_gd_wave'				=> 'CAPTCHA_GD_WAVE', +		'captcha_gd_3d_noise'			=> 'CAPTCHA_GD_3D_NOISE', +		'captcha_gd_fonts'				=> 'CAPTCHA_GD_FONTS', +	); + +	public function is_available() +	{ +		return @extension_loaded('gd'); +	} + +	/** +	* @return string the name of the class used to generate the captcha +	*/ +	function get_generator_class() +	{ +		return '\\phpbb\\captcha\\gd'; +	} + +	/** +	*  API function +	*/ +	function has_config() +	{ +		return true; +	} + +	public function get_name() +	{ +		return 'CAPTCHA_GD'; +	} + +	function acp_page($id, &$module) +	{ +		global $db, $user, $auth, $template; +		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + +		$user->add_lang('acp/board'); + +		$config_vars = array( +			'enable_confirm'		=> 'REG_ENABLE', +			'enable_post_confirm'	=> 'POST_ENABLE', +			'confirm_refresh'		=> 'CONFIRM_REFRESH', +			'captcha_gd'			=> 'CAPTCHA_GD', +		); + +		$module->tpl_name = 'captcha_gd_acp'; +		$module->page_title = 'ACP_VC_SETTINGS'; +		$form_key = 'acp_captcha'; +		add_form_key($form_key); + +		$submit = request_var('submit', ''); + +		if ($submit && check_form_key($form_key)) +		{ +			$captcha_vars = array_keys($this->captcha_vars); +			foreach ($captcha_vars as $captcha_var) +			{ +				$value = request_var($captcha_var, 0); +				if ($value >= 0) +				{ +					set_config($captcha_var, $value); +				} +			} + +			add_log('admin', 'LOG_CONFIG_VISUAL'); +			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); +		} +		else if ($submit) +		{ +			trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); +		} +		else +		{ +			foreach ($this->captcha_vars as $captcha_var => $template_var) +			{ +				$var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; +				$template->assign_var($template_var, $var); +			} + +			$template->assign_vars(array( +				'CAPTCHA_PREVIEW'	=> $this->get_demo_template($id), +				'CAPTCHA_NAME'		=> $this->get_service_name(), +				'U_ACTION'			=> $module->u_action, +			)); +		} +	} + +	function execute_demo() +	{ +		global $config; + +		$config_old = $config; + +		$config = new \phpbb\config\config(array()); +		foreach ($config_old as $key => $value) +		{ +			$config->set($key, $value); +		} + +		foreach ($this->captcha_vars as $captcha_var => $template_var) +		{ +			$config->set($captcha_var, request_var($captcha_var, (int) $config[$captcha_var])); +		} +		parent::execute_demo(); +		$config = $config_old; +	} + +} diff --git a/phpBB/phpbb/captcha/plugins/gd_wave.php b/phpBB/phpbb/captcha/plugins/gd_wave.php new file mode 100644 index 0000000000..e1d44df778 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/gd_wave.php @@ -0,0 +1,42 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class gd_wave extends captcha_abstract +{ +	public function is_available() +	{ +		return @extension_loaded('gd'); +	} + +	public function get_name() +	{ +		return 'CAPTCHA_GD_3D'; +	} + +	/** +	* @return string the name of the class used to generate the captcha +	*/ +	function get_generator_class() +	{ +		return '\\phpbb\\captcha\\gd_wave'; +	} + +	function acp_page($id, &$module) +	{ +		global $config, $db, $template, $user; + +		trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); +	} +} diff --git a/phpBB/phpbb/captcha/plugins/nogd.php b/phpBB/phpbb/captcha/plugins/nogd.php new file mode 100644 index 0000000000..6845e5935c --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/nogd.php @@ -0,0 +1,42 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class nogd extends captcha_abstract +{ +	public function is_available() +	{ +		return true; +	} + +	public function get_name() +	{ +		return 'CAPTCHA_NO_GD'; +	} + +	/** +	* @return string the name of the class used to generate the captcha +	*/ +	function get_generator_class() +	{ +		return '\\phpbb\\captcha\\non_gd'; +	} + +	function acp_page($id, &$module) +	{ +		global $user; + +		trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); +	} +} diff --git a/phpBB/phpbb/captcha/plugins/qa.php b/phpBB/phpbb/captcha/plugins/qa.php new file mode 100644 index 0000000000..a7ba994cc3 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/qa.php @@ -0,0 +1,1009 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +/** +* And now to something completely different. Let's make a captcha without extending the abstract class. +* QA CAPTCHA sample implementation +*/ +class qa +{ +	var $confirm_id; +	var $answer; +	var $question_ids; +	var $question_text; +	var $question_lang; +	var $question_strict; +	var $attempts = 0; +	var $type; +	// dirty trick: 0 is false, but can still encode that the captcha is not yet validated +	var $solved = 0; + +	protected $table_captcha_questions; +	protected $table_captcha_answers; +	protected $table_qa_confirm; + +	/** +	* @var string name of the service. +	*/ +	protected $service_name; + +	/** +	* Constructor +	* +	* @param string $table_captcha_questions +	* @param string $table_captcha_answers +	* @param string $table_qa_confirm +	*/ +	function __construct($table_captcha_questions, $table_captcha_answers, $table_qa_confirm) +	{ +		$this->table_captcha_questions = $table_captcha_questions; +		$this->table_captcha_answers = $table_captcha_answers; +		$this->table_qa_confirm = $table_qa_confirm; +	} + +	/** +	* @param int $type  as per the CAPTCHA API docs, the type +	*/ +	function init($type) +	{ +		global $config, $db, $user; + +		// load our language file +		$user->add_lang('captcha_qa'); + +		// read input +		$this->confirm_id = request_var('qa_confirm_id', ''); +		$this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true)); + +		$this->type = (int) $type; +		$this->question_lang = $user->lang_name; + +		// we need all defined questions - shouldn't be too many, so we can just grab them +		// try the user's lang first +		$sql = 'SELECT question_id +			FROM ' . $this->table_captcha_questions . " +			WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; +		$result = $db->sql_query($sql, 3600); + +		while ($row = $db->sql_fetchrow($result)) +		{ +			$this->question_ids[$row['question_id']] = $row['question_id']; +		} +		$db->sql_freeresult($result); + +		// fallback to the board default lang +		if (!sizeof($this->question_ids)) +		{ +			$this->question_lang = $config['default_lang']; + +			$sql = 'SELECT question_id +				FROM ' . $this->table_captcha_questions . " +				WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; +			$result = $db->sql_query($sql, 7200); + +			while ($row = $db->sql_fetchrow($result)) +			{ +				$this->question_ids[$row['question_id']] = $row['question_id']; +			} +			$db->sql_freeresult($result); +		} + +		// okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one +		if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) +		{ +			// we have no valid confirm ID, better get ready to ask something +			$this->select_question(); +		} +	} + +	/** +	* See if the captcha has created its tables. +	*/ +	public function is_installed() +	{ +		global $db; + +		$db_tool = new \phpbb\db\tools($db); + +		return $db_tool->sql_table_exists($this->table_captcha_questions); +	} + +	/** +	*  API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang +	*/ +	public function is_available() +	{ +		global $config, $db, $phpbb_root_path, $phpEx, $user; + +		// load language file for pretty display in the ACP dropdown +		$user->add_lang('captcha_qa'); + +		if (!$this->is_installed()) +		{ +			return false; +		} + +		$sql = 'SELECT COUNT(question_id) AS question_count +			FROM ' . $this->table_captcha_questions . " +			WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; +		$result = $db->sql_query($sql); +		$row = $db->sql_fetchrow($result); +		$db->sql_freeresult($result); + +		return ((bool) $row['question_count']); +	} + +	/** +	*  API function +	*/ +	function has_config() +	{ +		return true; +	} + +	/** +	*  API function +	*/ +	static public function get_name() +	{ +		return 'CAPTCHA_QA'; +	} + +	/** +	* @return string the name of the service corresponding to the plugin +	*/ +	function get_service_name() +	{ +		return $this->service_name; +	} + +	/** +	* Set the name of the plugin +	* +	* @param string $name +	*/ +	public function set_name($name) +	{ +		$this->service_name = $name; +	} + +	/** +	*  API function - not needed as we don't display an image +	*/ +	function execute_demo() +	{ +	} + +	/** +	*  API function - not needed as we don't display an image +	*/ +	function execute() +	{ +	} + +	/** +	*  API function - send the question to the template +	*/ +	function get_template() +	{ +		global $template; + +		if ($this->is_solved()) +		{ +			return false; +		} +		else +		{ +			$template->assign_vars(array( +				'QA_CONFIRM_QUESTION'		=> $this->question_text, +				'QA_CONFIRM_ID'				=> $this->confirm_id, +				'S_CONFIRM_CODE'			=> true, +				'S_TYPE'					=> $this->type, +			)); + +			return 'captcha_qa.html'; +		} +	} + +	/** +	*  API function - we just display a mockup so that the captcha doesn't need to be installed +	*/ +	function get_demo_template() +	{ +		global $config, $db, $template; + +		if ($this->is_available()) +		{ +			$sql = 'SELECT question_text +				FROM ' . $this->table_captcha_questions . " +				WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; +			$result = $db->sql_query_limit($sql, 1); +			if ($row = $db->sql_fetchrow($result)) +			{ +				$template->assign_vars(array( +					'QA_CONFIRM_QUESTION'		=> $row['question_text'], +				)); +			} +			$db->sql_freeresult($result); +		} +		return 'captcha_qa_acp_demo.html'; +	} + +	/** +	*  API function +	*/ +	function get_hidden_fields() +	{ +		$hidden_fields = array(); + +		// this is required - otherwise we would forget about the captcha being already solved +		if ($this->solved) +		{ +			$hidden_fields['qa_answer'] = $this->answer; +		} +		$hidden_fields['qa_confirm_id'] = $this->confirm_id; + +		return $hidden_fields; +	} + +	/** +	*  API function +	*/ +	function garbage_collect($type = 0) +	{ +		global $db, $config; + +		$sql = 'SELECT c.confirm_id +			FROM ' . $this->table_qa_confirm . ' c +			LEFT JOIN ' . SESSIONS_TABLE . ' s +				ON (c.session_id = s.session_id) +			WHERE s.session_id IS NULL' . +				((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); +		$result = $db->sql_query($sql); + +		if ($row = $db->sql_fetchrow($result)) +		{ +			$sql_in = array(); + +			do +			{ +				$sql_in[] = (string) $row['confirm_id']; +			} +			while ($row = $db->sql_fetchrow($result)); + +			if (sizeof($sql_in)) +			{ +				$sql = 'DELETE FROM ' . $this->table_qa_confirm . ' +					WHERE ' . $db->sql_in_set('confirm_id', $sql_in); +				$db->sql_query($sql); +			} +		} +		$db->sql_freeresult($result); +	} + +	/** +	*  API function - we don't drop the tables here, as that would cause the loss of all entered questions. +	*/ +	function uninstall() +	{ +		$this->garbage_collect(0); +	} + +	/** +	*  API function - set up shop +	*/ +	function install() +	{ +		global $db; + +		$db_tool = new \phpbb\db\tools($db); + +		$tables = array($this->table_captcha_questions, $this->table_captcha_answers, $this->table_qa_confirm); + +		$schemas = array( +				$this->table_captcha_questions		=> array ( +					'COLUMNS' => array( +						'question_id'	=> array('UINT', null, 'auto_increment'), +						'strict'		=> array('BOOL', 0), +						'lang_id'		=> array('UINT', 0), +						'lang_iso'		=> array('VCHAR:30', ''), +						'question_text'	=> array('TEXT_UNI', ''), +					), +					'PRIMARY_KEY'		=> 'question_id', +					'KEYS'				=> array( +						'lang'			=> array('INDEX', 'lang_iso'), +					), +				), +				$this->table_captcha_answers		=> array ( +					'COLUMNS' => array( +						'question_id'	=> array('UINT', 0), +						'answer_text'	=> array('STEXT_UNI', ''), +					), +					'KEYS'				=> array( +						'qid'			=> array('INDEX', 'question_id'), +					), +				), +				$this->table_qa_confirm		=> array ( +					'COLUMNS' => array( +						'session_id'	=> array('CHAR:32', ''), +						'confirm_id'	=> array('CHAR:32', ''), +						'lang_iso'		=> array('VCHAR:30', ''), +						'question_id'	=> array('UINT', 0), +						'attempts'		=> array('UINT', 0), +						'confirm_type'	=> array('USINT', 0), +					), +					'KEYS'				=> array( +						'session_id'			=> array('INDEX', 'session_id'), +						'lookup'				=> array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), +					), +					'PRIMARY_KEY'		=> 'confirm_id', +				), +		); + +		foreach($schemas as $table => $schema) +		{ +			if (!$db_tool->sql_table_exists($table)) +			{ +				$db_tool->sql_create_table($table, $schema); +			} +		} +	} + +	/** +	*  API function - see what has to be done to validate +	*/ +	function validate() +	{ +		global $config, $db, $user; + +		$error = ''; + +		if (!sizeof($this->question_ids)) +		{ +			return false; +		} + +		if (!$this->confirm_id) +		{ +			$error = $user->lang['CONFIRM_QUESTION_WRONG']; +		} +		else +		{ +			if ($this->check_answer()) +			{ +				$this->solved = true; +			} +			else +			{ +				$error = $user->lang['CONFIRM_QUESTION_WRONG']; +			} +		} + +		if (strlen($error)) +		{ +			// okay, incorrect answer. Let's ask a new question. +			$this->new_attempt(); +			$this->solved = false; + +			return $error; +		} +		else +		{ +			return false; +		} +	} + +	/** +	*  Select a question +	*/ +	function select_question() +	{ +		global $db, $user; + +		if (!sizeof($this->question_ids)) +		{ +			return false; +		} +		$this->confirm_id = md5(unique_id($user->ip)); +		$this->question = (int) array_rand($this->question_ids); + +		$sql = 'INSERT INTO ' . $this->table_qa_confirm . ' ' . $db->sql_build_array('INSERT', array( +			'confirm_id'	=> (string) $this->confirm_id, +			'session_id'	=> (string) $user->session_id, +			'lang_iso'		=> (string) $this->question_lang, +			'confirm_type'	=> (int) $this->type, +			'question_id'	=> (int) $this->question, +		)); +		$db->sql_query($sql); + +		$this->load_answer(); +	} + +	/** +	* New Question, if desired. +	*/ +	function reselect_question() +	{ +		global $db, $user; + +		if (!sizeof($this->question_ids)) +		{ +			return false; +		} + +		$this->question = (int) array_rand($this->question_ids); +		$this->solved = 0; + +		$sql = 'UPDATE ' . $this->table_qa_confirm . ' +			SET question_id = ' . (int) $this->question . " +			WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' +				AND session_id = '" . $db->sql_escape($user->session_id) . "'"; +		$db->sql_query($sql); + +		$this->load_answer(); +	} + +	/** +	* Wrong answer, so we increase the attempts and use a different question. +	*/ +	function new_attempt() +	{ +		global $db, $user; + +		// yah, I would prefer a stronger rand, but this should work +		$this->question = (int) array_rand($this->question_ids); +		$this->solved = 0; + +		$sql = 'UPDATE ' . $this->table_qa_confirm . ' +			SET question_id = ' . (int) $this->question . ", +				attempts = attempts + 1 +			WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' +				AND session_id = '" . $db->sql_escape($user->session_id) . "'"; +		$db->sql_query($sql); + +		$this->load_answer(); +	} + + +	/** +	* See if there is already an entry for the current session. +	*/ +	function load_confirm_id() +	{ +		global $db, $user; + +		$sql = 'SELECT confirm_id +			FROM ' . $this->table_qa_confirm . " +			WHERE +				session_id = '" . $db->sql_escape($user->session_id) . "' +				AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' +				AND confirm_type = " . $this->type; +		$result = $db->sql_query_limit($sql, 1); +		$row = $db->sql_fetchrow($result); +		$db->sql_freeresult($result); + +		if ($row) +		{ +			$this->confirm_id = $row['confirm_id']; +			return true; +		} +		return false; +	} + +	/** +	* Look up everything we need and populate the instance variables. +	*/ +	function load_answer() +	{ +		global $db, $user; + +		if (!strlen($this->confirm_id) || !sizeof($this->question_ids)) +		{ +			return false; +		} + +		$sql = 'SELECT con.question_id, attempts, question_text, strict +			FROM ' . $this->table_qa_confirm . ' con, ' . $this->table_captcha_questions . " qes +			WHERE con.question_id = qes.question_id +				AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' +				AND session_id = '" . $db->sql_escape($user->session_id) . "' +				AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' +				AND confirm_type = " . $this->type; +		$result = $db->sql_query($sql); +		$row = $db->sql_fetchrow($result); +		$db->sql_freeresult($result); + +		if ($row) +		{ +			$this->question = $row['question_id']; + +			$this->attempts = $row['attempts']; +			$this->question_strict = $row['strict']; +			$this->question_text = $row['question_text']; + +			return true; +		} + +		return false; +	} + +	/** +	*  The actual validation +	*/ +	function check_answer() +	{ +		global $db; + +		$answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); + +		$sql = 'SELECT answer_text +			FROM ' . $this->table_captcha_answers . ' +			WHERE question_id = ' . (int) $this->question; +		$result = $db->sql_query($sql); + +		while ($row = $db->sql_fetchrow($result)) +		{ +			$solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); + +			if ($solution === $answer) +			{ +				$this->solved = true; + +				break; +			} +		} +		$db->sql_freeresult($result); + +		return $this->solved; +	} + +	/** +	*  API function +	*/ +	function get_attempt_count() +	{ +		return $this->attempts; +	} + +	/** +	*  API function +	*/ +	function reset() +	{ +		global $db, $user; + +		$sql = 'DELETE FROM ' . $this->table_qa_confirm . " +			WHERE session_id = '" . $db->sql_escape($user->session_id) . "' +				AND confirm_type = " . (int) $this->type; +		$db->sql_query($sql); + +		// we leave the class usable by generating a new question +		$this->select_question(); +	} + +	/** +	*  API function +	*/ +	function is_solved() +	{ +		if (request_var('qa_answer', false) && $this->solved === 0) +		{ +			$this->validate(); +		} + +		return (bool) $this->solved; +	} + +	/** +	*  API function - The ACP backend, this marks the end of the easy methods +	*/ +	function acp_page($id, &$module) +	{ +		global $db, $user, $auth, $template; +		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + +		$user->add_lang('acp/board'); +		$user->add_lang('captcha_qa'); + +		if (!self::is_installed()) +		{ +			$this->install(); +		} + +		$module->tpl_name = 'captcha_qa_acp'; +		$module->page_title = 'ACP_VC_SETTINGS'; +		$form_key = 'acp_captcha'; +		add_form_key($form_key); + +		$submit = request_var('submit', false); +		$question_id = request_var('question_id', 0); +		$action = request_var('action', ''); + +		// we have two pages, so users might want to navigate from one to the other +		$list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_service_name(); + +		$template->assign_vars(array( +			'U_ACTION'		=> $module->u_action, +			'QUESTION_ID'	=> $question_id , +			'CLASS'			=> $this->get_service_name(), +		)); + +		// show the list? +		if (!$question_id && $action != 'add') +		{ +			$this->acp_question_list($module); +		} +		else if ($question_id && $action == 'delete') +		{ +			if ($this->get_service_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) +			{ +				if (confirm_box(true)) +				{ +					$this->acp_delete_question($question_id); + +					trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); +				} +				else +				{ +					confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( +						'question_id'		=> $question_id, +						'action'			=> $action, +						'configure'			=> 1, +						'select_captcha'	=> $this->get_service_name(), +						)) +					); +				} +			} +			else +			{ +				trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); +			} +		} +		else +		{ +			// okay, show the editor +			$error = false; +			$input_question = request_var('question_text', '', true); +			$input_answers = request_var('answers', '', true); +			$input_lang = request_var('lang_iso', '', true); +			$input_strict = request_var('strict', false); +			$langs = $this->get_languages(); + +			foreach ($langs as $lang => $entry) +			{ +				$template->assign_block_vars('langs', array( +					'ISO' => $lang, +					'NAME' => $entry['name'], +				)); +			} + +			$template->assign_vars(array( +				'U_LIST' => $list_url, +			)); + +			if ($question_id) +			{ +				if ($question = $this->acp_get_question_data($question_id)) +				{ +					$answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); + +					$template->assign_vars(array( +						'QUESTION_TEXT'		=> ($input_question) ? $input_question : $question['question_text'], +						'LANG_ISO'			=> ($input_lang) ? $input_lang : $question['lang_iso'], +						'STRICT'			=> (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], +						'ANSWERS'			=> $answers, +					)); +				} +				else +				{ +					trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); +				} +			} +			else +			{ +				$template->assign_vars(array( +					'QUESTION_TEXT'		=> $input_question, +					'LANG_ISO'			=> $input_lang, +					'STRICT'			=> $input_strict, +					'ANSWERS'			=> $input_answers, +				)); +			} + +			if ($submit && check_form_key($form_key)) +			{ +				$data = $this->acp_get_question_input(); + +				if (!$this->validate_input($data)) +				{ +					$template->assign_vars(array( +						'S_ERROR'			=> true, +					)); +				} +				else +				{ +					if ($question_id) +					{ +						$this->acp_update_question($data, $question_id); +					} +					else +					{ +						$this->acp_add_question($data); +					} + +					add_log('admin', 'LOG_CONFIG_VISUAL'); +					trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); +				} +			} +			else if ($submit) +			{ +				trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); +			} +		} +	} + +	/** +	*  This handles the list overview +	*/ +	function acp_question_list(&$module) +	{ +		global $db, $template; + +		$sql = 'SELECT * +			FROM ' . $this->table_captcha_questions; +		$result = $db->sql_query($sql); + +		$template->assign_vars(array( +			'S_LIST'			=> true, +		)); + +		while ($row = $db->sql_fetchrow($result)) +		{ +			$url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_service_name() . '&'; + +			$template->assign_block_vars('questions', array( +				'QUESTION_TEXT'		=> $row['question_text'], +				'QUESTION_ID'		=> $row['question_id'], +				'QUESTION_LANG'		=> $row['lang_iso'], +				'U_DELETE'			=> "{$url}action=delete", +				'U_EDIT'			=> "{$url}action=edit", +			)); +		} +		$db->sql_freeresult($result); +	} + +	/** +	*  Grab a question and bring it into a format the editor understands +	*/ +	function acp_get_question_data($question_id) +	{ +		global $db; + +		if ($question_id) +		{ +			$sql = 'SELECT * +				FROM ' . $this->table_captcha_questions . ' +				WHERE question_id = ' . $question_id; +			$result = $db->sql_query($sql); +			$question = $db->sql_fetchrow($result); +			$db->sql_freeresult($result); + +			if (!$question) +			{ +				return false; +			} + +			$question['answers'] = array(); + +			$sql = 'SELECT * +				FROM ' . $this->table_captcha_answers . ' +				WHERE question_id = ' . $question_id; +			$result = $db->sql_query($sql); + +			while ($row = $db->sql_fetchrow($result)) +			{ +				$question['answers'][] = $row['answer_text']; +			} +			$db->sql_freeresult($result); + +			return $question; +		} +	} + +	/** +	*  Grab a question from input and bring it into a format the editor understands +	*/ +	function acp_get_question_input() +	{ +		$answers = utf8_normalize_nfc(request_var('answers', '', true)); +		$question = array( +			'question_text'	=> request_var('question_text', '', true), +			'strict'		=> request_var('strict', false), +			'lang_iso'		=> request_var('lang_iso', ''), +			'answers'		=> (strlen($answers)) ? explode("\n", $answers) : '', +		); + +		return $question; +	} + +	/** +	*  Update a question. +	* param mixed $data : an array as created from acp_get_question_input or acp_get_question_data +	*/ +	function acp_update_question($data, $question_id) +	{ +		global $db, $cache; + +		// easier to delete all answers than to figure out which to update +		$sql = 'DELETE FROM ' . $this->table_captcha_answers . " WHERE question_id = $question_id"; +		$db->sql_query($sql); + +		$langs = $this->get_languages(); +		$question_ary = $data; +		$question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; +		unset($question_ary['answers']); + +		$sql = 'UPDATE ' . $this->table_captcha_questions . ' +			SET ' . $db->sql_build_array('UPDATE', $question_ary) . " +			WHERE question_id = $question_id"; +		$db->sql_query($sql); + +		$this->acp_insert_answers($data, $question_id); + +		$cache->destroy('sql', $this->table_captcha_questions); +	} + +	/** +	*  Insert a question. +	* param mixed $data : an array as created from acp_get_question_input or acp_get_question_data +	*/ +	function acp_add_question($data) +	{ +		global $db, $cache; + +		$langs = $this->get_languages(); +		$question_ary = $data; + +		$question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; +		unset($question_ary['answers']); + +		$sql = 'INSERT INTO ' . $this->table_captcha_questions . ' ' . $db->sql_build_array('INSERT', $question_ary); +		$db->sql_query($sql); + +		$question_id = $db->sql_nextid(); + +		$this->acp_insert_answers($data, $question_id); + +		$cache->destroy('sql', $this->table_captcha_questions); +	} + +	/** +	*  Insert the answers. +	* param mixed $data : an array as created from acp_get_question_input or acp_get_question_data +	*/ +	function acp_insert_answers($data, $question_id) +	{ +		global $db, $cache; + +		foreach ($data['answers'] as $answer) +		{ +			$answer_ary = array( +				'question_id'	=> $question_id, +				'answer_text'	=> $answer, +			); + +			$sql = 'INSERT INTO ' . $this->table_captcha_answers . ' ' . $db->sql_build_array('INSERT', $answer_ary); +			$db->sql_query($sql); +		} + +		$cache->destroy('sql', $this->table_captcha_answers); +	} + +	/** +	*  Delete a question. +	*/ +	function acp_delete_question($question_id) +	{ +		global $db, $cache; + +		$tables = array($this->table_captcha_questions, $this->table_captcha_answers); + +		foreach ($tables as $table) +		{ +			$sql = "DELETE FROM $table +				WHERE question_id = $question_id"; +			$db->sql_query($sql); +		} + +		$cache->destroy('sql', $tables); +	} + +	/** +	*  Check if the entered data can be inserted/used +	* param mixed $data : an array as created from acp_get_question_input or acp_get_question_data +	*/ +	function validate_input($question_data) +	{ +		$langs = $this->get_languages(); + +		if (!isset($question_data['lang_iso']) || +			!isset($question_data['question_text']) || +			!isset($question_data['strict']) || +			!isset($question_data['answers'])) +		{ +			return false; +		} + +		if (!isset($langs[$question_data['lang_iso']]) || +			!strlen($question_data['question_text']) || +			!sizeof($question_data['answers']) || +			!is_array($question_data['answers'])) +		{ +			return false; +		} + +		return true; +	} + +	/** +	* List the installed language packs +	*/ +	function get_languages() +	{ +		global $db; + +		$sql = 'SELECT * +			FROM ' . LANG_TABLE; +		$result = $db->sql_query($sql); + +		$langs = array(); +		while ($row = $db->sql_fetchrow($result)) +		{ +			$langs[$row['lang_iso']] = array( +				'name'	=> $row['lang_local_name'], +				'id'	=> (int) $row['lang_id'], +			); +		} +		$db->sql_freeresult($result); + +		return $langs; +	} + + + +	/** +	*  See if there is a question other than the one we have +	*/ +	function acp_is_last($question_id) +	{ +		global $config, $db; + +		if ($question_id) +		{ +			$sql = 'SELECT question_id +				FROM ' . $this->table_captcha_questions . " +				WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' +					AND  question_id <> " .  (int) $question_id; +			$result = $db->sql_query_limit($sql, 1); +			$question = $db->sql_fetchrow($result); +			$db->sql_freeresult($result); + +			if (!$question) +			{ +				return true; +			} +			return false; +		} +	} +} diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php new file mode 100644 index 0000000000..ea446d7bc3 --- /dev/null +++ b/phpBB/phpbb/captcha/plugins/recaptcha.php @@ -0,0 +1,330 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\captcha\plugins; + +class recaptcha extends captcha_abstract +{ +	var $recaptcha_server = 'http://www.google.com/recaptcha/api'; +	var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( + +	// We are opening a socket to port 80 of this host and send +	// the POST request asking for verification to the path specified here. +	var $recaptcha_verify_server = 'www.google.com'; +	var $recaptcha_verify_path = '/recaptcha/api/verify'; + +	var $challenge; +	var $response; + +	// PHP4 Constructor +	function phpbb_recaptcha() +	{ +		global $request; +		$this->recaptcha_server = $request->is_secure() ? $this->recaptcha_server_secure : $this->recaptcha_server; +	} + +	function init($type) +	{ +		global $config, $db, $user; + +		$user->add_lang('captcha_recaptcha'); +		parent::init($type); +		$this->challenge = request_var('recaptcha_challenge_field', ''); +		$this->response = request_var('recaptcha_response_field', ''); +	} + +	public function is_available() +	{ +		global $config, $user; +		$user->add_lang('captcha_recaptcha'); +		return (isset($config['recaptcha_pubkey']) && !empty($config['recaptcha_pubkey'])); +	} + +	/** +	*  API function +	*/ +	function has_config() +	{ +		return true; +	} + +	static public function get_name() +	{ +		return 'CAPTCHA_RECAPTCHA'; +	} + +	/** +	* This function is implemented because required by the upper class, but is never used for reCaptcha. +	*/ +	function get_generator_class() +	{ +		throw new \Exception('No generator class given.'); +	} + +	function acp_page($id, &$module) +	{ +		global $config, $db, $template, $user; + +		$captcha_vars = array( +			'recaptcha_pubkey'				=> 'RECAPTCHA_PUBKEY', +			'recaptcha_privkey'				=> 'RECAPTCHA_PRIVKEY', +		); + +		$module->tpl_name = 'captcha_recaptcha_acp'; +		$module->page_title = 'ACP_VC_SETTINGS'; +		$form_key = 'acp_captcha'; +		add_form_key($form_key); + +		$submit = request_var('submit', ''); + +		if ($submit && check_form_key($form_key)) +		{ +			$captcha_vars = array_keys($captcha_vars); +			foreach ($captcha_vars as $captcha_var) +			{ +				$value = request_var($captcha_var, ''); +				if ($value) +				{ +					set_config($captcha_var, $value); +				} +			} + +			add_log('admin', 'LOG_CONFIG_VISUAL'); +			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); +		} +		else if ($submit) +		{ +			trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); +		} +		else +		{ +			foreach ($captcha_vars as $captcha_var => $template_var) +			{ +				$var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : ''); +				$template->assign_var($template_var, $var); +			} + +			$template->assign_vars(array( +				'CAPTCHA_PREVIEW'	=> $this->get_demo_template($id), +				'CAPTCHA_NAME'		=> $this->get_service_name(), +				'U_ACTION'			=> $module->u_action, +			)); + +		} +	} + +	// not needed +	function execute_demo() +	{ +	} + +	// not needed +	function execute() +	{ +	} + +	function get_template() +	{ +		global $config, $user, $template, $phpbb_root_path, $phpEx; + +		if ($this->is_solved()) +		{ +			return false; +		} +		else +		{ +			$contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx); +			$explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="' . $contact_link . '">', '</a>'); + +			$template->assign_vars(array( +				'RECAPTCHA_SERVER'			=> $this->recaptcha_server, +				'RECAPTCHA_PUBKEY'			=> isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '', +				'RECAPTCHA_ERRORGET'		=> '', +				'S_RECAPTCHA_AVAILABLE'		=> self::is_available(), +				'S_CONFIRM_CODE'			=> true, +				'S_TYPE'					=> $this->type, +				'L_CONFIRM_EXPLAIN'			=> $explain, +			)); + +			return 'captcha_recaptcha.html'; +		} +	} + +	function get_demo_template($id) +	{ +		return $this->get_template(); +	} + +	function get_hidden_fields() +	{ +		$hidden_fields = array(); + +		// this is required for posting.php - otherwise we would forget about the captcha being already solved +		if ($this->solved) +		{ +			$hidden_fields['confirm_code'] = $this->code; +		} +		$hidden_fields['confirm_id'] = $this->confirm_id; +		return $hidden_fields; +	} + +	function uninstall() +	{ +		$this->garbage_collect(0); +	} + +	function install() +	{ +		return; +	} + +	function validate() +	{ +		if (!parent::validate()) +		{ +			return false; +		} +		else +		{ +			return $this->recaptcha_check_answer(); +		} +	} + +// Code from here on is based on recaptchalib.php +/* + * This is a PHP library that handles calling reCAPTCHA. + *	- Documentation and latest version + *		  http://recaptcha.net/plugins/php/ + *	- Get a reCAPTCHA API Key + *		  http://recaptcha.net/api/getkey + *	- Discussion group + *		  http://groups.google.com/group/recaptcha + * + * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net + * AUTHORS: + *   Mike Crawford + *   Ben Maurer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +	/** +	* Submits an HTTP POST to a reCAPTCHA server +	* @param string $host +	* @param string $path +	* @param array $data +	* @param int port +	* @return array response +	*/ +	function _recaptcha_http_post($host, $path, $data, $port = 80) +	{ +		$req = $this->_recaptcha_qsencode ($data); + +		$http_request  = "POST $path HTTP/1.0\r\n"; +		$http_request .= "Host: $host\r\n"; +		$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; +		$http_request .= "Content-Length: " . strlen($req) . "\r\n"; +		$http_request .= "User-Agent: reCAPTCHA/PHP/phpBB\r\n"; +		$http_request .= "\r\n"; +		$http_request .= $req; + +		$response = ''; +		if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10))) +		{ +			trigger_error('RECAPTCHA_SOCKET_ERROR', E_USER_ERROR); +		} + +		fwrite($fs, $http_request); + +		while (!feof($fs)) +		{ +			// One TCP-IP packet +			$response .= fgets($fs, 1160); +		} +		fclose($fs); +		$response = explode("\r\n\r\n", $response, 2); + +		return $response; +	} + +	/** +	* Calls an HTTP POST function to verify if the user's guess was correct +	* @param array $extra_params an array of extra variables to post to the server +	* @return ReCaptchaResponse +	*/ +	function recaptcha_check_answer($extra_params = array()) +	{ +		global $config, $user; + +		//discard spam submissions +		if ($this->challenge == null || strlen($this->challenge) == 0 || $this->response == null || strlen($this->response) == 0) +		{ +			return $user->lang['RECAPTCHA_INCORRECT']; +		} + +		$response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path, +			array( +				'privatekey'	=> $config['recaptcha_privkey'], +				'remoteip'		=> $user->ip, +				'challenge'		=> $this->challenge, +				'response'		=> $this->response +			) + $extra_params +		); + +		$answers = explode("\n", $response[1]); + +		if (trim($answers[0]) === 'true') +		{ +			$this->solved = true; +			return false; +		} +		else +		{ +			return $user->lang['RECAPTCHA_INCORRECT']; +		} +	} + +	/** +	* Encodes the given data into a query string format +	* @param $data - array of string elements to be encoded +	* @return string - encoded request +	*/ +	function _recaptcha_qsencode($data) +	{ +		$req = ''; +		foreach ($data as $key => $value) +		{ +			$req .= $key . '=' . urlencode(stripslashes($value)) . '&'; +		} + +		// Cut the last '&' +		$req = substr($req, 0, strlen($req) - 1); +		return $req; +	} +} | 
