]> git.openstreetmap.org Git - nominatim.git/commitdiff
nominatim refactoring
authorBrian Quinion <openstreetmap@brian.quinion.co.uk>
Sat, 23 Oct 2010 23:12:37 +0000 (23:12 +0000)
committerBrian Quinion <openstreetmap@brian.quinion.co.uk>
Sat, 23 Oct 2010 23:12:37 +0000 (23:12 +0000)
40 files changed:
lib/cmd.php [new file with mode: 0644]
lib/db.php [new file with mode: 0644]
lib/init-cmd.php [new file with mode: 0644]
lib/init-website.php [new file with mode: 0644]
lib/init.php [new file with mode: 0644]
lib/lib.php [new file with mode: 0644]
lib/log.php [new file with mode: 0644]
module/Makefile [new file with mode: 0644]
module/nominatim.c [new file with mode: 0644]
module/tokenstringreplacements.inc [new file with mode: 0644]
module/utfasciitable.h [new file with mode: 0644]
nominatim/Makefile.in [new file with mode: 0644]
nominatim/README.txt [new file with mode: 0644]
nominatim/autogen.sh [new file with mode: 0755]
nominatim/config.h.in [new file with mode: 0644]
nominatim/configure.ac [new file with mode: 0644]
nominatim/export.c [new file with mode: 0644]
nominatim/export.h [new file with mode: 0644]
nominatim/geometry.cpp [new file with mode: 0644]
nominatim/import.c [new file with mode: 0644]
nominatim/import.h [new file with mode: 0644]
nominatim/index.c [new file with mode: 0644]
nominatim/index.h [new file with mode: 0644]
nominatim/input.c [new file with mode: 0644]
nominatim/input.h [new file with mode: 0644]
nominatim/nominatim-svn.sh [new file with mode: 0755]
nominatim/nominatim.c [new file with mode: 0644]
nominatim/nominatim.h [new file with mode: 0644]
nominatim/nominatim.spec.in [new file with mode: 0644]
nominatim/partitionedtags.def [new file with mode: 0644]
nominatim/postgresql.c [new file with mode: 0644]
nominatim/postgresql.h [new file with mode: 0644]
nominatim/sprompt.c [new file with mode: 0644]
nominatim/sprompt.h [new file with mode: 0644]
settings/settings.php [new file with mode: 0644]
sql/functions.sql [new file with mode: 0644]
sql/loaddata.sql [new file with mode: 0644]
sql/partitions.src.sql [new file with mode: 0644]
sql/tables.sql [new file with mode: 0644]
utils/setup.php [new file with mode: 0755]

diff --git a/lib/cmd.php b/lib/cmd.php
new file mode 100644 (file)
index 0000000..0c9201a
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+
+       function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false)
+       {
+               $aQuick = array();
+               $aCounts = array();
+
+               foreach($aSpec as $aLine)
+               {
+                       if (is_array($aLine))
+                       {
+                               if ($aLine[0]) $aQuick['--'.$aLine[0]] = $aLine;
+                               if ($aLine[1]) $aQuick['-'.$aLine[1]] = $aLine;
+                               $aCounts[$aLine[0]] = 0;
+                       }
+               }
+
+               $aResult = array();
+               $bUnknown = false;
+               $iSize = sizeof($aArg);
+               for ($i = 1; $i < $iSize; $i++)
+               {
+                       if (isset($aQuick[$aArg[$i]]))
+                       {
+                               $aLine = $aQuick[$aArg[$i]];
+                               $aCounts[$aLine[0]]++;
+                               $xVal = null;
+                               if ($aLine[4] == $aLine[5])
+                               {
+                                       if ($aLine[4])
+                                       {
+                                               $xVal = array();
+                                               for($n = $aLine[4]; $i < $iSize && $n; $n--)
+                                               {
+                                                       $i++;
+                                                       if ($i >= $iSize || $aArg[$i][0] == '-') showUsage($aSpec, $bExitOnError, 'Parameter of  \''.$aLine[0].'\' is missing');
+
+                                                       switch ($aLine[6])
+                                                       {
+                                                       case 'realpath':
+                                                               $xVal[] = realpath($aArg[$i]);
+                                                               break;
+                                                       case 'realdir':
+                                                               $sPath = realpath(dirname($aArg[$i]));
+                                                               if ($sPath)
+                                                                       $xVal[] = $sPath . '/' . basename($aArg[$i]);
+                                                               else
+                                                                       $xVal[] = $sPath;
+                                                               break;
+                                                       case 'bool':
+                                                               $xVal[] = (bool)$aArg[$i];
+                                                               break;
+                                                       case 'int':
+                                                               $xVal[] = (int)$aArg[$i];
+                                                               break;
+                                                       case 'float':
+                                                               $xVal[] = (float)$aArg[$i];
+                                                               break;
+                                                       default:
+                                                               $xVal[] = $aArg[$i];
+                                                               break;
+                                                       }
+                                               }
+                                               if ($aLine[4] == 1) $xVal = $xVal[0];
+                                       }
+                                       else
+                                       {
+                                               $xVal = true;
+                                       }
+                               }
+                               else
+                               {
+                                       fail('Variable numbers of params not yet supported');
+                               }
+
+                               if ($aLine[3] > 1)
+                               {
+                                       if (!array_key_exists($aLine[0], $aResult)) $aResult[$aLine[0]] = array();
+                                       $aResult[$aLine[0]][] = $xVal;
+                               }
+                               else
+                               {
+                                       $aResult[$aLine[0]] = $xVal;
+                               }
+                       }
+                       else
+                       {
+                               $bUnknown = $aArg[$i];
+                       }
+               }
+
+               if (array_key_exists('help', $aResult)) showUsage($aSpec);
+               if ($bUnknown && $bExitOnUnknown) showUsage($aSpec, $bExitOnError, 'Unknown option \''.$bUnknown.'\'');
+
+               foreach($aSpec as $aLine)
+               {
+                       if (is_array($aLine))
+                       {
+                               if ($aCounts[$aLine[0]] < $aLine[2]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing');
+                               if ($aCounts[$aLine[0]] > $aLine[3]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times');
+                               switch ($aLine[6])
+                               {
+                               case 'bool':
+                                       if (!array_key_exists($aLine[0], $aResult))
+                                               $aResult[$aLine[0]] = false;
+                                       break;
+                               }
+                       }
+               }
+               return $bUnknown;
+       }
+
+       function showUsage($aSpec, $bExit = false, $sError = false)
+       {
+               if ($sError)
+               {
+                       echo basename($_SERVER['argv'][0]).': '.$sError."\n";
+                       echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n";
+                       exit;
+               }
+               echo "Usage: ".basename($_SERVER['argv'][0])."\n";
+               $bFirst = true;
+               foreach($aSpec as $aLine)
+               {
+                       if (is_array($aLine))
+                       {
+                               if ($bFirst)
+                               {
+                                       $bFirst = false;
+                                       echo "\n";
+                               }
+                               $aNames = array();
+                               if ($aLine[1]) $aNames[] = '-'.$aLine[1];
+                               if ($aLine[0]) $aNames[] = '--'.$aLine[0];
+                               $sName = join(', ',$aNames);
+                               echo '  '.$sName.str_repeat(' ',30-strlen($sName)).$aLine[7]."\n";
+                       }
+                       else
+                       {
+                               echo $aLine."\n";
+                       }
+               }
+               echo "\n";
+               exit;
+       }
diff --git a/lib/db.php b/lib/db.php
new file mode 100644 (file)
index 0000000..4f7336c
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+       require_once('DB.php');
+
+       // Get the database object
+       $oDB =& DB::connect(CONST_Database_DSN, false);
+       if (PEAR::IsError($oDB))
+       {
+               fail($oDB->getMessage(), 'Unable to connect to the database');
+       }
+       $oDB->setFetchMode(DB_FETCHMODE_ASSOC);
+       $oDB->query("SET DateStyle TO 'sql,european'");
+       $oDB->query("SET client_encoding TO 'utf-8'");
+
+       function getDBQuoted($s)
+       {
+               return "'".pg_escape_string($s)."'";
+       }
+
diff --git a/lib/init-cmd.php b/lib/init-cmd.php
new file mode 100644 (file)
index 0000000..7558efd
--- /dev/null
@@ -0,0 +1,4 @@
+<?php
+
+       require_once('init.php');
+       require_once('cmd.php');
diff --git a/lib/init-website.php b/lib/init-website.php
new file mode 100644 (file)
index 0000000..d21ca7a
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+       require_once('init.php');
+
+       if (CONST_ClosedForIndexing && strpos(CONST_ClosedForIndexingExceptionIPs, ','.$_SERVER["REMOTE_ADDR"].',') === false)
+       {
+               echo "Closed for re-indexing...";
+               exit;
+       }
+
+       if (strpos(CONST_BlockedIPs, ','.$_SERVER["REMOTE_ADDR"].',') !== false)
+       {
+               echo "Your IP has been blocked. \n";
+               echo "Please create a nominatim trac ticket (http://trac.openstreetmap.org/newticket?component=nominatim) to request this to be removed. \n";
+               echo "Information on the Nominatim usage policy can be found here: http://wiki.openstreetmap.org/wiki/Nominatim#Usage_Policy \n";
+               exit;
+       }
+
+       header('Content-type: text/html; charset=utf-8');
diff --git a/lib/init.php b/lib/init.php
new file mode 100644 (file)
index 0000000..17f262c
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+       @define('CONST_BasePath', dirname(dirname(__FILE__)));
+
+       require_once(CONST_BasePath.'/settings/settings.php');
+       require_once(CONST_BasePath.'/lib/lib.php');
+       require_once(CONST_BasePath.'/lib/db.php');
+
+       if (get_magic_quotes_gpc())
+       {
+               echo "Please disable magic quotes in your php.ini configuration";
+               exit;
+       }
diff --git a/lib/lib.php b/lib/lib.php
new file mode 100644 (file)
index 0000000..e384949
--- /dev/null
@@ -0,0 +1,760 @@
+<?php
+
+       function fail($sError, $sUserError = false)
+       {
+               if (!$sUserError) $sUserError = $sError;
+               log('ERROR:'.$sError);
+               echo $sUserError;
+               exit;
+       }
+
+       function getBlockingProcesses()
+       {
+                $sStats = file_get_contents('/proc/stat');
+                if (preg_match('/procs_blocked ([0-9]+)/i', $sStats, $aMatches))
+                {
+                       return (int)$aMatches[1];
+                }
+               return 0;
+       }
+
+       function getLoadAverage()
+       {
+               $sLoadAverage = file_get_contents('/proc/loadavg');
+                $aLoadAverage = explode(' ',$sLoadAverage);
+               return (int)$aLoadAverage[0];
+       }
+       
+       function bySearchRank($a, $b)
+       {
+               if ($a['iSearchRank'] == $b['iSearchRank']) return 0;
+               return ($a['iSearchRank'] < $b['iSearchRank']?-1:1);
+       }
+
+       function byImportance($a, $b)
+       {
+               if ($a['aPointPolygon']['numfeatures'] != $b['aPointPolygon']['numfeatures'])
+                       return ($a['aPointPolygon']['numfeatures'] > $b['aPointPolygon']['numfeatures']?-1:1);
+               if ($a['aPointPolygon']['area'] != $b['aPointPolygon']['area'])
+                       return ($a['aPointPolygon']['area'] > $b['aPointPolygon']['area']?-1:1);
+               if ($a['importance'] != $b['importance'])
+                       return ($a['importance'] < $b['importance']?-1:1);
+               return ($a['foundorder'] < $b['foundorder']?-1:1);
+       }
+
+       function getPrefferedLangauges()
+       {
+               // If we have been provided the value in $_GET it overrides browser value
+               if (isset($_GET['accept-language']) && $_GET['accept-language'])
+               {
+                       $_SERVER["HTTP_ACCEPT_LANGUAGE"] = $_GET['accept-language'];
+               }
+               
+               $aLanguages = array();
+               if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $aLanguagesParse, PREG_SET_ORDER))
+               {
+                       foreach($aLanguagesParse as $iLang => $aLanguage)
+                       {
+                               $aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
+                               if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
+                       }
+                       arsort($aLanguages);
+               }
+               if (!sizeof($aLanguages)) $aLanguages = array(CONST_Default_Language=>1);
+               foreach($aLanguages as $sLangauge => $fLangauagePref)
+               {
+                       $aLangPrefOrder['short_name:'.$sLangauge] = 'short_name:'.$sLangauge;
+               }
+               foreach($aLanguages as $sLangauge => $fLangauagePref)
+               {
+                       $aLangPrefOrder['name:'.$sLangauge] = 'name:'.$sLangauge;
+               }
+               foreach($aLanguages as $sLangauge => $fLangauagePref)
+               {
+                       $aLangPrefOrder['place_name:'.$sLangauge] = 'place_name:'.$sLangauge;
+               }
+               foreach($aLanguages as $sLangauge => $fLangauagePref)
+               {
+                       $aLangPrefOrder['official_name:'.$sLangauge] = 'official_name:'.$sLangauge;
+               }
+               $aLangPrefOrder['short_name'] = 'short_name';
+               $aLangPrefOrder['name'] = 'name';
+               $aLangPrefOrder['place_name'] = 'place_name';
+               $aLangPrefOrder['official_name'] = 'official_name';
+               $aLangPrefOrder['ref'] = 'ref';
+               $aLangPrefOrder['type'] = 'type';
+               return $aLangPrefOrder;
+       }
+
+       function getWordSets($aWords)
+       {
+               $aResult = array(array(join(' ',$aWords)));
+               $sFirstToken = '';
+               while(sizeof($aWords) > 1)
+               {
+                       $sWord = array_shift($aWords);
+                       $sFirstToken .= ($sFirstToken?' ':'').$sWord;
+                       $aRest = getWordSets($aWords);
+                       foreach($aRest as $aSet)
+                       {
+                               $aResult[] = array_merge(array($sFirstToken),$aSet);
+                       }
+               }
+               return $aResult;
+       }
+
+       function getTokensFromSets($aSets)
+       {
+               $aTokens = array();
+               foreach($aSets as $aSet)
+               {
+                       foreach($aSet as $sWord)
+                       {
+                               $aTokens[' '.$sWord] = ' '.$sWord;
+                               $aTokens[$sWord] = $sWord;
+                               //if (!strpos($sWord,' ')) $aTokens[$sWord] = $sWord;
+                       }
+               }
+               return $aTokens;
+       }
+
+       /*
+               GB Postcode functions
+       */
+
+       function gbPostcodeAlphaDifference($s1, $s2)
+       {
+               $aValues = array(
+                       'A'=>0,
+                       'B'=>1,
+                       'D'=>2,
+                       'E'=>3,
+                       'F'=>4,
+                       'G'=>5,
+                       'H'=>6,
+                       'J'=>7,
+                       'L'=>8,
+                       'N'=>9,
+                       'O'=>10,
+                       'P'=>11,
+                       'Q'=>12,
+                       'R'=>13,
+                       'S'=>14,
+                       'T'=>15,
+                       'U'=>16,
+                       'W'=>17,
+                       'X'=>18,
+                       'Y'=>19,
+                       'Z'=>20);
+               return abs(($aValues[$s1[0]]*21+$aValues[$s1[1]]) - ($aValues[$s2[0]]*21+$aValues[$s2[1]]));
+       }
+       
+       function gbPostcodeCalculate($sPostcode, $sPostcodeSector, $sPostcodeEnd, &$oDB)
+       {
+               // Try an exact match on the gb_postcode table
+               $sSQL = 'select \'AA\', ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where upper(postcode) = \''.$sPostcode.'\'';
+               $aNearPostcodes = $oDB->getAll($sSQL);
+               if (PEAR::IsError($aNearPostcodes))
+               {
+                       var_dump($sSQL, $aNearPostcodes);
+                       exit;
+               }
+
+               if (!sizeof($aNearPostcodes))
+               {
+                       $sSQL = 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from placex where country_code::text = \'gb\'::text AND substring(upper(postcode) from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\' and class=\'place\' and type=\'postcode\' ';
+                       $sSQL .= ' union ';
+                       $sSQL .= 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where substring(upper(postcode) from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\'';
+                       $aNearPostcodes = $oDB->getAll($sSQL);
+                       if (PEAR::IsError($aNearPostcodes))
+                       {
+                               var_dump($sSQL, $aNearPostcodes);
+                               exit;
+                       }
+               }
+
+               if (!sizeof($aNearPostcodes))
+               {
+                       return false;
+               }
+
+               $fTotalLat = 0;
+               $fTotalLon = 0;
+               $fTotalFac = 0;
+               foreach($aNearPostcodes as $aPostcode)
+               {
+                       $iDiff = gbPostcodeAlphaDifference($sPostcodeEnd, $aPostcode['substring'])*2 + 1;
+                       if ($iDiff == 0)
+                               $fFac = 1;
+                       else
+                               $fFac = 1/($iDiff*$iDiff);
+                       
+                       $fTotalFac += $fFac;
+                       $fTotalLat += $aPostcode['lat'] * $fFac;
+                       $fTotalLon += $aPostcode['lon'] * $fFac;
+               }
+               if ($fTotalFac)
+               {
+                       $fLat = $fTotalLat / $fTotalFac;
+                       $fLon = $fTotalLon / $fTotalFac;
+                       $fRadius = min(0.1 / $fTotalFac, 0.02);
+                       return array(array('lat' => $fLat, 'lon' => $fLon, 'radius' => $fRadius));
+               }
+               return false;
+
+               /*
+                       $fTotalFac is a suprisingly good indicator of accuracy
+                       $iZoom = 18 + round(log($fTotalFac,32));
+                       $iZoom = max(13,min(18,$iZoom));
+               */
+       }
+
+       function usPostcodeCalculate($sPostcode, &$oDB)
+       {
+               $iZipcode = (int)$sPostcode;
+
+               // Try an exact match on the us_zippostcode table
+               $sSQL = 'select zipcode, ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from us_zipcode where zipcode = '.$iZipcode;
+               $aNearPostcodes = $oDB->getAll($sSQL);
+               if (PEAR::IsError($aNearPostcodes))
+               {
+                       var_dump($sSQL, $aNearPostcodes);
+                       exit;
+               }
+
+               if (!sizeof($aNearPostcodes))
+               {
+                       $sSQL = 'select zipcode,ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from us_zipcode where zipcode between '.($iZipcode-100).' and '.($iZipcode+100).' order by abs(zipcode - '.$iZipcode.') asc limit 5';
+                       $aNearPostcodes = $oDB->getAll($sSQL);
+                       if (PEAR::IsError($aNearPostcodes))
+                       {
+                               var_dump($sSQL, $aNearPostcodes);
+                               exit;
+                       }
+               }
+
+               if (!sizeof($aNearPostcodes))
+               {
+                       return false;
+               }
+
+               $fTotalLat = 0;
+               $fTotalLon = 0;
+               $fTotalFac = 0;
+               foreach($aNearPostcodes as $aPostcode)
+               {
+                       $iDiff = abs($aPostcode['zipcode'] - $iZipcode) + 1;
+                       if ($iDiff == 0)
+                               $fFac = 1;
+                       else
+                               $fFac = 1/($iDiff*$iDiff);
+                       
+                       $fTotalFac += $fFac;
+                       $fTotalLat += $aPostcode['lat'] * $fFac;
+                       $fTotalLon += $aPostcode['lon'] * $fFac;
+               }
+               if ($fTotalFac)
+               {
+                       $fLat = $fTotalLat / $fTotalFac;
+                       $fLon = $fTotalLon / $fTotalFac;
+                       return array(array('lat' => $fLat, 'lon' => $fLon, 'radius' => 0.2));
+               }
+               return false;
+
+               /*
+                       $fTotalFac is a suprisingly good indicator of accuracy
+                       $iZoom = 18 + round(log($fTotalFac,32));
+                       $iZoom = max(13,min(18,$iZoom));
+               */
+       }
+
+       function getClassTypes()
+       {
+               return array(
+ 'boundary:adminitrative:2' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:4' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:5' => array('label'=>'State District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:6' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:8' => array('label'=>'City','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:9' => array('label'=>'City District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:10' => array('label'=>'Suburb','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:adminitrative:11' => array('label'=>'Neighbourhood','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'place:city' => array('label'=>'City','frequency'=>66,'icon'=>'poi_place_city','defzoom'=>12, 'defdiameter' => 0.32,),
+ 'place:country' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>6, 'defdiameter' => 15,),
+ 'place:state' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
+ 'place:region' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
+ 'place:island' => array('label'=>'Island','frequency'=>288,'icon'=>'','defzoom'=>11, 'defdiameter' => 0.64,),
+ 'place:county' => array('label'=>'County','frequency'=>108,'icon'=>'poi_boundary_administrative','defzoom'=>10, 'defdiameter' => 1.28,),
+ 'boundary:adminitrative' => array('label'=>'Administrative','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'place:town' => array('label'=>'Town','frequency'=>1497,'icon'=>'poi_place_town','defzoom'=>14, 'defdiameter' => 0.08,),
+ 'place:village' => array('label'=>'Village','frequency'=>11230,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
+ 'place:hamlet' => array('label'=>'Hamlet','frequency'=>7075,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
+ 'place:suburb' => array('label'=>'Suburb','frequency'=>2528,'icon'=>'poi_place_village', 'defdiameter' => 0.04,),
+ 'place:locality' => array('label'=>'Locality','frequency'=>4113,'icon'=>'poi_place_village', 'defdiameter' => 0.02,),
+ 'landuse:farm' => array('label'=>'Farm','frequency'=>1201,'icon'=>'', 'defdiameter' => 0.02,),
+ 'place:farm' => array('label'=>'Farm','frequency'=>1162,'icon'=>'', 'defdiameter' => 0.02,),
+
+ 'highway:motorway_junction' => array('label'=>'Motorway Junction','frequency'=>1126,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:motorway' => array('label'=>'Motorway','frequency'=>4627,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:trunk' => array('label'=>'Trunk','frequency'=>23084,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:primary' => array('label'=>'Primary','frequency'=>32138,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:secondary' => array('label'=>'Secondary','frequency'=>25807,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:tertiary' => array('label'=>'Tertiary','frequency'=>29829,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:residential' => array('label'=>'Residential','frequency'=>361498,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:unclassified' => array('label'=>'Unclassified','frequency'=>66441,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:living_street' => array('label'=>'Living Street','frequency'=>710,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:service' => array('label'=>'Service','frequency'=>9963,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:track' => array('label'=>'Track','frequency'=>2565,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:road' => array('label'=>'Road','frequency'=>591,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:byway' => array('label'=>'Byway','frequency'=>346,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:bridleway' => array('label'=>'Bridleway','frequency'=>1556,'icon'=>'',),
+ 'highway:cycleway' => array('label'=>'Cycleway','frequency'=>2419,'icon'=>'',),
+ 'highway:pedestrian' => array('label'=>'Pedestrian','frequency'=>2757,'icon'=>'',),
+ 'highway:footway' => array('label'=>'Footway','frequency'=>15008,'icon'=>'',),
+ 'highway:steps' => array('label'=>'Steps','frequency'=>444,'icon'=>'','simplelabel'=>'Footway',),
+ 'highway:motorway_link' => array('label'=>'Motorway Link','frequency'=>795,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:trunk_link' => array('label'=>'Trunk Link','frequency'=>1258,'icon'=>'','simplelabel'=>'Road',),
+ 'highway:primary_link' => array('label'=>'Primary Link','frequency'=>313,'icon'=>'','simplelabel'=>'Road',),
+
+ 'landuse:industrial' => array('label'=>'Industrial','frequency'=>1062,'icon'=>'',),
+ 'landuse:residential' => array('label'=>'Residential','frequency'=>886,'icon'=>'',),
+ 'landuse:retail' => array('label'=>'Retail','frequency'=>754,'icon'=>'',),
+ 'landuse:commercial' => array('label'=>'Commercial','frequency'=>657,'icon'=>'',),
+
+ 'place:airport' => array('label'=>'Airport','frequency'=>36,'icon'=>'transport_airport2', 'defdiameter' => 0.03,),
+ 'railway:station' => array('label'=>'Station','frequency'=>3431,'icon'=>'transport_train_station2', 'defdiameter' => 0.01,),
+ 'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship3',),
+ 'amenity:pub' => array('label'=>'Pub','frequency'=>18969,'icon'=>'food_pub',),
+ 'amenity:bar' => array('label'=>'Bar','frequency'=>164,'icon'=>'food_bar',),
+ 'amenity:university' => array('label'=>'University','frequency'=>607,'icon'=>'education_university',),
+ 'tourism:museum' => array('label'=>'Museum','frequency'=>543,'icon'=>'tourist_museum',),
+ 'amenity:arts_centre' => array('label'=>'Arts Centre','frequency'=>136,'icon'=>'tourist_art_gallery2',),
+ 'tourism:zoo' => array('label'=>'Zoo','frequency'=>47,'icon'=>'tourist_zoo',),
+ 'tourism:theme_park' => array('label'=>'Theme Park','frequency'=>24,'icon'=>'poi_point_of_interest',),
+ 'tourism:attraction' => array('label'=>'Attraction','frequency'=>1463,'icon'=>'poi_point_of_interest',),
+ 'leisure:golf_course' => array('label'=>'Golf Course','frequency'=>712,'icon'=>'sport_golf',),
+ 'historic:castle' => array('label'=>'Castle','frequency'=>316,'icon'=>'tourist_castle',),
+ 'amenity:hospital' => array('label'=>'Hospital','frequency'=>879,'icon'=>'health_hospital',),
+ 'amenity:school' => array('label'=>'School','frequency'=>8192,'icon'=>'education_school',),
+ 'amenity:theatre' => array('label'=>'Theatre','frequency'=>371,'icon'=>'tourist_theatre',),
+ 'amenity:public_building' => array('label'=>'Public Building','frequency'=>985,'icon'=>'',),
+ 'amenity:library' => array('label'=>'Library','frequency'=>794,'icon'=>'amenity_library',),
+ 'amenity:townhall' => array('label'=>'Townhall','frequency'=>242,'icon'=>'',),
+ 'amenity:community_centre' => array('label'=>'Community Centre','frequency'=>157,'icon'=>'',),
+ 'amenity:fire_station' => array('label'=>'Fire Station','frequency'=>221,'icon'=>'amenity_firestation3',),
+ 'amenity:police' => array('label'=>'Police','frequency'=>334,'icon'=>'amenity_police2',),
+ 'amenity:bank' => array('label'=>'Bank','frequency'=>1248,'icon'=>'money_bank2',),
+ 'amenity:post_office' => array('label'=>'Post Office','frequency'=>859,'icon'=>'amenity_post_office',),
+ 'leisure:park' => array('label'=>'Park','frequency'=>2378,'icon'=>'',),
+ 'amenity:park' => array('label'=>'Park','frequency'=>53,'icon'=>'',),
+ 'landuse:park' => array('label'=>'Park','frequency'=>50,'icon'=>'',),
+ 'landuse:recreation_ground' => array('label'=>'Recreation Ground','frequency'=>517,'icon'=>'',),
+ 'tourism:hotel' => array('label'=>'Hotel','frequency'=>2150,'icon'=>'accommodation_hotel2',),
+ 'tourism:motel' => array('label'=>'Motel','frequency'=>43,'icon'=>'',),
+ 'amenity:cinema' => array('label'=>'Cinema','frequency'=>277,'icon'=>'tourist_cinema',),
+ 'tourism:information' => array('label'=>'Information','frequency'=>224,'icon'=>'amenity_information',),
+ 'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'art_gallery2',),
+ 'historic:archaeological_site' => array('label'=>'Archaeological Site','frequency'=>407,'icon'=>'tourist_archaeological2',),
+ 'amenity:doctors' => array('label'=>'Doctors','frequency'=>581,'icon'=>'health_doctors',),
+ 'leisure:sports_centre' => array('label'=>'Sports Centre','frequency'=>767,'icon'=>'sport_leisure_centre',),
+ 'leisure:swimming_pool' => array('label'=>'Swimming Pool','frequency'=>24,'icon'=>'sport_swimming_outdoor',),
+ 'shop:supermarket' => array('label'=>'Supermarket','frequency'=>2673,'icon'=>'shopping_supermarket',),
+ 'shop:convenience' => array('label'=>'Convenience','frequency'=>1469,'icon'=>'shopping_convenience',),
+ 'amenity:restaurant' => array('label'=>'Restaurant','frequency'=>3179,'icon'=>'food_restaurant',),
+ 'amenity:fast_food' => array('label'=>'Fast Food','frequency'=>2289,'icon'=>'food_fastfood',),
+ 'amenity:cafe' => array('label'=>'Cafe','frequency'=>1780,'icon'=>'food_cafe',),
+ 'tourism:guest_house' => array('label'=>'Guest House','frequency'=>223,'icon'=>'accommodation_bed_and_breakfast',),
+ 'amenity:pharmacy' => array('label'=>'Pharmacy','frequency'=>733,'icon'=>'health_pharmacy_dispensing',),
+ 'amenity:fuel' => array('label'=>'Fuel','frequency'=>1308,'icon'=>'transport_fuel',),
+ 'natural:peak' => array('label'=>'Peak','frequency'=>3212,'icon'=>'poi_peak',),
+ 'waterway:waterfall' => array('label'=>'Waterfall','frequency'=>24,'icon'=>'',),
+ 'natural:wood' => array('label'=>'Wood','frequency'=>1845,'icon'=>'landuse_coniferous_and_deciduous',),
+ 'natural:water' => array('label'=>'Water','frequency'=>1790,'icon'=>'',),
+ 'landuse:forest' => array('label'=>'Forest','frequency'=>467,'icon'=>'',),
+ 'landuse:cemetery' => array('label'=>'Cemetery','frequency'=>463,'icon'=>'',),
+ 'landuse:allotments' => array('label'=>'Allotments','frequency'=>408,'icon'=>'',),
+ 'landuse:farmyard' => array('label'=>'Farmyard','frequency'=>397,'icon'=>'',),
+ 'railway:rail' => array('label'=>'Rail','frequency'=>4894,'icon'=>'',),
+ 'waterway:canal' => array('label'=>'Canal','frequency'=>1723,'icon'=>'',),
+ 'waterway:river' => array('label'=>'River','frequency'=>4089,'icon'=>'',),
+ 'waterway:stream' => array('label'=>'Stream','frequency'=>2684,'icon'=>'',),
+ 'shop:bicycle' => array('label'=>'Bicycle','frequency'=>349,'icon'=>'shopping_bicycle',),
+ 'shop:clothes' => array('label'=>'Clothes','frequency'=>315,'icon'=>'shopping_clothes',),
+ 'shop:hairdresser' => array('label'=>'Hairdresser','frequency'=>312,'icon'=>'shopping_hairdresser',),
+ 'shop:doityourself' => array('label'=>'Doityourself','frequency'=>247,'icon'=>'shopping_diy',),
+ 'shop:estate_agent' => array('label'=>'Estate Agent','frequency'=>162,'icon'=>'shopping_estateagent2',),
+ 'shop:car' => array('label'=>'Car','frequency'=>159,'icon'=>'shopping_car',),
+ 'shop:garden_centre' => array('label'=>'Garden Centre','frequency'=>143,'icon'=>'shopping_garden_centre',),
+ 'shop:car_repair' => array('label'=>'Car Repair','frequency'=>141,'icon'=>'shopping_car_repair',),
+ 'shop:newsagent' => array('label'=>'Newsagent','frequency'=>132,'icon'=>'',),
+ 'shop:bakery' => array('label'=>'Bakery','frequency'=>129,'icon'=>'shopping_bakery',),
+ 'shop:furniture' => array('label'=>'Furniture','frequency'=>124,'icon'=>'',),
+ 'shop:butcher' => array('label'=>'Butcher','frequency'=>105,'icon'=>'shopping_butcher',),
+ 'shop:apparel' => array('label'=>'Apparel','frequency'=>98,'icon'=>'shopping_clothes',),
+ 'shop:electronics' => array('label'=>'Electronics','frequency'=>96,'icon'=>'',),
+ 'shop:department_store' => array('label'=>'Department Store','frequency'=>86,'icon'=>'',),
+ 'shop:books' => array('label'=>'Books','frequency'=>85,'icon'=>'',),
+ 'shop:yes' => array('label'=>'Yes','frequency'=>68,'icon'=>'',),
+ 'shop:outdoor' => array('label'=>'Outdoor','frequency'=>67,'icon'=>'',),
+ 'shop:mall' => array('label'=>'Mall','frequency'=>63,'icon'=>'',),
+ 'shop:florist' => array('label'=>'Florist','frequency'=>61,'icon'=>'',),
+ 'shop:charity' => array('label'=>'Charity','frequency'=>60,'icon'=>'',),
+ 'shop:hardware' => array('label'=>'Hardware','frequency'=>59,'icon'=>'',),
+ 'shop:laundry' => array('label'=>'Laundry','frequency'=>51,'icon'=>'shopping_laundrette',),
+ 'shop:shoes' => array('label'=>'Shoes','frequency'=>49,'icon'=>'',),
+ 'shop:beverages' => array('label'=>'Beverages','frequency'=>48,'icon'=>'shopping_alcohol',),
+ 'shop:dry_cleaning' => array('label'=>'Dry Cleaning','frequency'=>46,'icon'=>'',),
+ 'shop:carpet' => array('label'=>'Carpet','frequency'=>45,'icon'=>'',),
+ 'shop:computer' => array('label'=>'Computer','frequency'=>44,'icon'=>'',),
+ 'shop:alcohol' => array('label'=>'Alcohol','frequency'=>44,'icon'=>'shopping_alcohol',),
+ 'shop:optician' => array('label'=>'Optician','frequency'=>55,'icon'=>'health_opticians',),
+ 'shop:chemist' => array('label'=>'Chemist','frequency'=>42,'icon'=>'health_pharmacy',),
+ 'shop:gallery' => array('label'=>'Gallery','frequency'=>38,'icon'=>'tourist_art_gallery2',),
+ 'shop:mobile_phone' => array('label'=>'Mobile Phone','frequency'=>37,'icon'=>'',),
+ 'shop:sports' => array('label'=>'Sports','frequency'=>37,'icon'=>'',),
+ 'shop:jewelry' => array('label'=>'Jewelry','frequency'=>32,'icon'=>'shopping_jewelry',),
+ 'shop:pet' => array('label'=>'Pet','frequency'=>29,'icon'=>'',),
+ 'shop:beauty' => array('label'=>'Beauty','frequency'=>28,'icon'=>'',),
+ 'shop:stationery' => array('label'=>'Stationery','frequency'=>25,'icon'=>'',),
+ 'shop:shopping_centre' => array('label'=>'Shopping Centre','frequency'=>25,'icon'=>'',),
+ 'shop:general' => array('label'=>'General','frequency'=>25,'icon'=>'',),
+ 'shop:electrical' => array('label'=>'Electrical','frequency'=>25,'icon'=>'',),
+ 'shop:toys' => array('label'=>'Toys','frequency'=>23,'icon'=>'',),
+ 'shop:jeweller' => array('label'=>'Jeweller','frequency'=>23,'icon'=>'',),
+ 'shop:betting' => array('label'=>'Betting','frequency'=>23,'icon'=>'',),
+ 'shop:household' => array('label'=>'Household','frequency'=>21,'icon'=>'',),
+ 'shop:travel_agency' => array('label'=>'Travel Agency','frequency'=>21,'icon'=>'',),
+ 'shop:hifi' => array('label'=>'Hifi','frequency'=>21,'icon'=>'',),
+ 'amenity:shop' => array('label'=>'Shop','frequency'=>61,'icon'=>'',),
+
+ 'place:house' => array('label'=>'House','frequency'=>2086,'icon'=>'','defzoom'=>18,),
+
+//
+
+ 'leisure:pitch' => array('label'=>'Pitch','frequency'=>762,'icon'=>'',),
+ 'highway:unsurfaced' => array('label'=>'Unsurfaced','frequency'=>492,'icon'=>'',),
+ 'historic:ruins' => array('label'=>'Ruins','frequency'=>483,'icon'=>'shopping_jewelry',),
+ 'amenity:college' => array('label'=>'College','frequency'=>473,'icon'=>'education_school',),
+ 'historic:monument' => array('label'=>'Monument','frequency'=>470,'icon'=>'tourist_monument',),
+ 'railway:subway' => array('label'=>'Subway','frequency'=>385,'icon'=>'',),
+ 'historic:memorial' => array('label'=>'Memorial','frequency'=>382,'icon'=>'tourist_monument',),
+ 'leisure:nature_reserve' => array('label'=>'Nature Reserve','frequency'=>342,'icon'=>'',),
+ 'leisure:common' => array('label'=>'Common','frequency'=>322,'icon'=>'',),
+ 'waterway:lock_gate' => array('label'=>'Lock Gate','frequency'=>321,'icon'=>'',),
+ 'natural:fell' => array('label'=>'Fell','frequency'=>308,'icon'=>'',),
+ 'amenity:nightclub' => array('label'=>'Nightclub','frequency'=>292,'icon'=>'',),
+ 'highway:path' => array('label'=>'Path','frequency'=>287,'icon'=>'',),
+ 'leisure:garden' => array('label'=>'Garden','frequency'=>285,'icon'=>'',),
+ 'landuse:reservoir' => array('label'=>'Reservoir','frequency'=>276,'icon'=>'',),
+ 'leisure:playground' => array('label'=>'Playground','frequency'=>264,'icon'=>'',),
+ 'leisure:stadium' => array('label'=>'Stadium','frequency'=>212,'icon'=>'',),
+ 'historic:mine' => array('label'=>'Mine','frequency'=>193,'icon'=>'poi_mine',),
+ 'natural:cliff' => array('label'=>'Cliff','frequency'=>193,'icon'=>'',),
+ 'tourism:caravan_site' => array('label'=>'Caravan Site','frequency'=>183,'icon'=>'accommodation_caravan_park',),
+ 'amenity:bus_station' => array('label'=>'Bus Station','frequency'=>181,'icon'=>'transport_bus_station',),
+ 'amenity:kindergarten' => array('label'=>'Kindergarten','frequency'=>179,'icon'=>'',),
+ 'highway:construction' => array('label'=>'Construction','frequency'=>176,'icon'=>'',),
+ 'amenity:atm' => array('label'=>'Atm','frequency'=>172,'icon'=>'money_atm2',),
+ 'amenity:emergency_phone' => array('label'=>'Emergency Phone','frequency'=>164,'icon'=>'',),
+ 'waterway:lock' => array('label'=>'Lock','frequency'=>146,'icon'=>'',),
+ 'waterway:riverbank' => array('label'=>'Riverbank','frequency'=>143,'icon'=>'',),
+ 'natural:coastline' => array('label'=>'Coastline','frequency'=>142,'icon'=>'',),
+ 'tourism:viewpoint' => array('label'=>'Viewpoint','frequency'=>140,'icon'=>'tourist_view_point',),
+ 'tourism:hostel' => array('label'=>'Hostel','frequency'=>140,'icon'=>'',),
+ 'tourism:bed_and_breakfast' => array('label'=>'Bed And Breakfast','frequency'=>140,'icon'=>'accommodation_bed_and_breakfast',),
+ 'railway:halt' => array('label'=>'Halt','frequency'=>135,'icon'=>'',),
+ 'railway:platform' => array('label'=>'Platform','frequency'=>134,'icon'=>'',),
+ 'railway:tram' => array('label'=>'Tram','frequency'=>130,'icon'=>'transport_tram_stop',),
+ 'amenity:courthouse' => array('label'=>'Courthouse','frequency'=>129,'icon'=>'amenity_court',),
+ 'amenity:recycling' => array('label'=>'Recycling','frequency'=>126,'icon'=>'amenity_recycling',),
+ 'amenity:dentist' => array('label'=>'Dentist','frequency'=>124,'icon'=>'health_dentist',),
+ 'natural:beach' => array('label'=>'Beach','frequency'=>121,'icon'=>'tourist_beach',),
+ 'place:moor' => array('label'=>'Moor','frequency'=>118,'icon'=>'',),
+ 'amenity:grave_yard' => array('label'=>'Grave Yard','frequency'=>110,'icon'=>'',),
+ 'waterway:derelict_canal' => array('label'=>'Derelict Canal','frequency'=>109,'icon'=>'',),
+ 'waterway:drain' => array('label'=>'Drain','frequency'=>108,'icon'=>'',),
+ 'landuse:grass' => array('label'=>'Grass','frequency'=>106,'icon'=>'',),
+ 'landuse:village_green' => array('label'=>'Village Green','frequency'=>106,'icon'=>'',),
+ 'natural:bay' => array('label'=>'Bay','frequency'=>102,'icon'=>'',),
+ 'railway:tram_stop' => array('label'=>'Tram Stop','frequency'=>101,'icon'=>'transport_tram_stop',),
+ 'leisure:marina' => array('label'=>'Marina','frequency'=>98,'icon'=>'',),
+ 'highway:stile' => array('label'=>'Stile','frequency'=>97,'icon'=>'',),
+ 'natural:moor' => array('label'=>'Moor','frequency'=>95,'icon'=>'',),
+ 'railway:light_rail' => array('label'=>'Light Rail','frequency'=>91,'icon'=>'',),
+ 'railway:narrow_gauge' => array('label'=>'Narrow Gauge','frequency'=>90,'icon'=>'',),
+ 'natural:land' => array('label'=>'Land','frequency'=>86,'icon'=>'',),
+ 'amenity:village_hall' => array('label'=>'Village Hall','frequency'=>82,'icon'=>'',),
+ 'waterway:dock' => array('label'=>'Dock','frequency'=>80,'icon'=>'',),
+ 'amenity:veterinary' => array('label'=>'Veterinary','frequency'=>79,'icon'=>'',),
+ 'landuse:brownfield' => array('label'=>'Brownfield','frequency'=>77,'icon'=>'',),
+ 'leisure:track' => array('label'=>'Track','frequency'=>76,'icon'=>'',),
+ 'railway:historic_station' => array('label'=>'Historic Station','frequency'=>74,'icon'=>'',),
+ 'landuse:construction' => array('label'=>'Construction','frequency'=>72,'icon'=>'',),
+ 'amenity:prison' => array('label'=>'Prison','frequency'=>71,'icon'=>'amenity_prison',),
+ 'landuse:quarry' => array('label'=>'Quarry','frequency'=>71,'icon'=>'',),
+ 'amenity:telephone' => array('label'=>'Telephone','frequency'=>70,'icon'=>'',),
+ 'highway:traffic_signals' => array('label'=>'Traffic Signals','frequency'=>66,'icon'=>'',),
+ 'natural:heath' => array('label'=>'Heath','frequency'=>62,'icon'=>'',),
+ 'historic:house' => array('label'=>'House','frequency'=>61,'icon'=>'',),
+ 'amenity:social_club' => array('label'=>'Social Club','frequency'=>61,'icon'=>'',),
+ 'landuse:military' => array('label'=>'Military','frequency'=>61,'icon'=>'',),
+ 'amenity:health_centre' => array('label'=>'Health Centre','frequency'=>59,'icon'=>'',),
+ 'historic:building' => array('label'=>'Building','frequency'=>58,'icon'=>'',),
+ 'amenity:clinic' => array('label'=>'Clinic','frequency'=>57,'icon'=>'',),
+ 'highway:services' => array('label'=>'Services','frequency'=>56,'icon'=>'',),
+ 'amenity:ferry_terminal' => array('label'=>'Ferry Terminal','frequency'=>55,'icon'=>'',),
+ 'natural:marsh' => array('label'=>'Marsh','frequency'=>55,'icon'=>'',),
+ 'natural:hill' => array('label'=>'Hill','frequency'=>54,'icon'=>'',),
+ 'highway:raceway' => array('label'=>'Raceway','frequency'=>53,'icon'=>'',),
+ 'amenity:taxi' => array('label'=>'Taxi','frequency'=>47,'icon'=>'',),
+ 'amenity:take_away' => array('label'=>'Take Away','frequency'=>45,'icon'=>'',),
+ 'amenity:car_rental' => array('label'=>'Car Rental','frequency'=>44,'icon'=>'',),
+ 'place:islet' => array('label'=>'Islet','frequency'=>44,'icon'=>'',),
+ 'amenity:nursery' => array('label'=>'Nursery','frequency'=>44,'icon'=>'',),
+ 'amenity:nursing_home' => array('label'=>'Nursing Home','frequency'=>43,'icon'=>'',),
+ 'amenity:toilets' => array('label'=>'Toilets','frequency'=>38,'icon'=>'',),
+ 'amenity:hall' => array('label'=>'Hall','frequency'=>38,'icon'=>'',),
+ 'waterway:boatyard' => array('label'=>'Boatyard','frequency'=>36,'icon'=>'',),
+ 'highway:mini_roundabout' => array('label'=>'Mini Roundabout','frequency'=>35,'icon'=>'',),
+ 'historic:manor' => array('label'=>'Manor','frequency'=>35,'icon'=>'',),
+ 'tourism:chalet' => array('label'=>'Chalet','frequency'=>34,'icon'=>'',),
+ 'amenity:bicycle_parking' => array('label'=>'Bicycle Parking','frequency'=>34,'icon'=>'',),
+ 'amenity:hotel' => array('label'=>'Hotel','frequency'=>34,'icon'=>'',),
+ 'waterway:weir' => array('label'=>'Weir','frequency'=>33,'icon'=>'',),
+ 'natural:wetland' => array('label'=>'Wetland','frequency'=>33,'icon'=>'',),
+ 'natural:cave_entrance' => array('label'=>'Cave Entrance','frequency'=>32,'icon'=>'',),
+ 'amenity:crematorium' => array('label'=>'Crematorium','frequency'=>31,'icon'=>'',),
+ 'tourism:picnic_site' => array('label'=>'Picnic Site','frequency'=>31,'icon'=>'',),
+ 'landuse:wood' => array('label'=>'Wood','frequency'=>30,'icon'=>'',),
+ 'landuse:basin' => array('label'=>'Basin','frequency'=>30,'icon'=>'',),
+ 'natural:tree' => array('label'=>'Tree','frequency'=>30,'icon'=>'',),
+ 'leisure:slipway' => array('label'=>'Slipway','frequency'=>29,'icon'=>'',),
+ 'landuse:meadow' => array('label'=>'Meadow','frequency'=>29,'icon'=>'',),
+ 'landuse:piste' => array('label'=>'Piste','frequency'=>28,'icon'=>'',),
+ 'amenity:care_home' => array('label'=>'Care Home','frequency'=>28,'icon'=>'',),
+ 'amenity:club' => array('label'=>'Club','frequency'=>28,'icon'=>'',),
+ 'amenity:medical_centre' => array('label'=>'Medical Centre','frequency'=>27,'icon'=>'',),
+ 'historic:roman_road' => array('label'=>'Roman Road','frequency'=>27,'icon'=>'',),
+ 'historic:fort' => array('label'=>'Fort','frequency'=>26,'icon'=>'',),
+ 'railway:subway_entrance' => array('label'=>'Subway Entrance','frequency'=>26,'icon'=>'',),
+ 'historic:yes' => array('label'=>'Yes','frequency'=>25,'icon'=>'',),
+ 'highway:gate' => array('label'=>'Gate','frequency'=>25,'icon'=>'',),
+ 'leisure:fishing' => array('label'=>'Fishing','frequency'=>24,'icon'=>'',),
+ 'historic:museum' => array('label'=>'Museum','frequency'=>24,'icon'=>'',),
+ 'amenity:car_wash' => array('label'=>'Car Wash','frequency'=>24,'icon'=>'',),
+ 'railway:level_crossing' => array('label'=>'Level Crossing','frequency'=>23,'icon'=>'',),
+ 'leisure:bird_hide' => array('label'=>'Bird Hide','frequency'=>23,'icon'=>'',),
+ 'natural:headland' => array('label'=>'Headland','frequency'=>21,'icon'=>'',),
+ 'tourism:apartments' => array('label'=>'Apartments','frequency'=>21,'icon'=>'',),
+ 'amenity:shopping' => array('label'=>'Shopping','frequency'=>21,'icon'=>'',),
+ 'natural:scrub' => array('label'=>'Scrub','frequency'=>20,'icon'=>'',),
+ 'natural:fen' => array('label'=>'Fen','frequency'=>20,'icon'=>'',),
+
+ 'amenity:parking' => array('label'=>'Parking','frequency'=>3157,'icon'=>'',),
+ 'highway:bus_stop' => array('label'=>'Bus Stop','frequency'=>35777,'icon'=>'transport_bus_stop2',),
+ 'place:postcode' => array('label'=>'Postcode','frequency'=>27267,'icon'=>'',),
+ 'amenity:post_box' => array('label'=>'Post Box','frequency'=>9613,'icon'=>'',),
+
+ 'place:houses' => array('label'=>'Houses','frequency'=>85,'icon'=>'',),
+ 'railway:preserved' => array('label'=>'Preserved','frequency'=>227,'icon'=>'',),
+ 'waterway:derelict canal' => array('label'=>'Derelict Canal','frequency'=>21,'icon'=>'',),
+ 'amenity:dead_pub' => array('label'=>'Dead Pub','frequency'=>20,'icon'=>'',),
+ 'railway:disused_station' => array('label'=>'Disused Station','frequency'=>114,'icon'=>'',),
+ 'railway:abandoned' => array('label'=>'Abandoned','frequency'=>641,'icon'=>'',),
+ 'railway:disused' => array('label'=>'Disused','frequency'=>72,'icon'=>'',),
+                       );              
+       }
+       
+       function getClassTypesWithImportance()
+       {
+               $aOrders = getClassTypes();
+               $i = 1;
+               foreach($aOrders as $sID => $a)
+               {
+                       $aOrders[$sID]['importance'] = $i++;
+               }
+               return $aOrders;
+       }
+       
+       
+        function javascript_isarray($xVal)
+        {
+                if (!is_array($xVal)) return false;
+                for($i = 0; $i < sizeof($xVal); $i++)
+                {
+                        if (!array_key_exists($i, $xVal)) return false;
+                }
+                return true;
+        }
+
+        function javascript_renderData($xVal, $bForceHash = false)
+        {
+                if (is_array($xVal))
+                {
+                        $aVals = array();
+                        if (javascript_isarray($xVal) && !$bForceHash)
+                        {
+                                foreach($xVal as $sKey => $xData)
+                                {
+                                        $aVals[] = javascript_renderData($xData);
+                                }
+                                return '['.join(',',$aVals).']';
+                        }
+                        else
+                        {
+                                foreach($xVal as $sKey => $xData)
+                                {
+                                        $aVals[] = '"'.addslashes($sKey).'"'.':'.javascript_renderData($xData);
+                                }
+                                return '{'.join(',',$aVals).'}';
+                        }
+                }
+                else
+                {
+                        if (is_bool($xVal)) return $xVal?'true':'false';
+                       if (is_numeric($xVal)) return $xVal;
+                        return '"'.str_replace('>','\\>',str_replace(array("\n","\r"),'\\n',str_replace(array("\n\r","\r\n"),'\\n',str_replace('"','\\"',$xVal)))).'"';
+                }
+        }
+
+       function _debugDumpGroupedSearches($aData, $aTokens)
+       {
+               $aWordsIDs = array();
+               foreach($aTokens as $sToken => $aWords)
+               {
+                       foreach($aWords as $aToken)
+                       {
+                               $aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
+                       }
+               }
+               echo "<table border=\"1\">";
+               echo "<tr><th>rank</th><th>Name Tokens</th><th>Address Tokens</th><th>country</th><th>operator</th><th>class</th><th>type</th><th>house#</th><th>Lat</th><th>Lon</th><th>Radius</th></tr>";
+               foreach($aData as $iRank => $aRankedSet)
+               {
+                       foreach($aRankedSet as $aRow)
+                       {               
+                               echo "<tr>";
+                               echo "<td>$iRank</td>";
+
+                               echo "<td>";
+                               $sSep = '';
+                               foreach($aRow['aName'] as $iWordID)
+                               {
+                                       echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
+                                       $sSep = ', ';
+                               }
+                               echo "</td>";
+
+                               echo "<td>";
+                               $sSep = '';
+                               foreach($aRow['aAddress'] as $iWordID)
+                               {
+//                                     if (!isset($aRow['aName'][$iWordID]))
+                                       {
+                                               echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
+                                               $sSep = ', ';
+                                       }
+                               }
+                               echo "</td>";
+
+                               echo "<td>".$aRow['sCountryCode']."</td>";
+
+                               echo "<td>".$aRow['sOperator']."</td>";
+                               echo "<td>".$aRow['sClass']."</td>";
+                               echo "<td>".$aRow['sType']."</td>";
+
+                               echo "<td>".$aRow['sHouseNumber']."</td>";
+
+                               echo "<td>".$aRow['fLat']."</td>";
+                               echo "<td>".$aRow['fLon']."</td>";
+                               echo "<td>".$aRow['fRadius']."</td>";
+       
+                               echo "</tr>";
+                       }
+               }
+               echo "</table>";
+       }
+
+
+       function getAddressDetails(&$oDB, $sLanguagePrefArraySQL, $iPlaceID, $sCountryCode = false, $bRaw = false)
+       {
+               $aHouseNumber = $oDB->getRow('select housenumber, get_name_by_language(name,ARRAY[\'addr:housename\']) as housename,rank_search from placex where place_id = '.$iPlaceID);
+               $sHouseNumber = $aHouseNumber['housenumber'];
+               $sHouseName = $aHouseNumber['housename'];
+               $iRank = $aHouseNumber['rank_search'];
+
+               // Address
+               $sSQL = "select country_code, placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, ";
+               $sSQL .= "get_searchrank_label(rank_search) as rank_search_label, fromarea, isaddress, distance, ";
+               $sSQL .= " CASE WHEN type = 'postcode' THEN postcode ELSE get_name_by_language(name,$sLanguagePrefArraySQL) END as localname, ";
+               $sSQL .= " length(name::text) as namelength ";
+               $sSQL .= " from place_addressline join placex on (address_place_id = placex.place_id)";
+               $sSQL .= " where place_addressline.place_id = $iPlaceID and (rank_address > 0 OR address_place_id = $iPlaceID)";
+// and isaddress";
+               if ($sCountryCode)
+               {
+                       $sSQL .= " and (placex.country_code IS NULL OR placex.country_code = '".$sCountryCode."' OR rank_address < 4)";
+               }
+               $sSQL .= " order by cached_rank_address desc,fromarea desc,distance asc,rank_search desc,namelength desc";
+//var_dump($sSQL);
+               $aAddressLines = $oDB->getAll($sSQL);
+               if (PEAR::IsError($aAddressLines))
+               {
+                       var_dump($aAddressLines);
+                       exit;
+               }
+               if ($bRaw) return $aAddressLines;
+       
+               $aClassType = getClassTypes();
+
+               $iMinRank = 100;
+               $aAddress = array();
+               if ($iRank >= 28 && $sHouseNumber) $aAddress['house_number'] = $sHouseNumber;
+               if ($iRank >= 28 && $sHouseName) $aAddress['house_name'] = $sHouseName;
+               foreach($aAddressLines as $aLine)
+               {
+                       if (!$sCountryCode) $sCountryCode = $aLine['country_code'];
+                       if ($aLine['rank_address'] < $iMinRank)
+                       {
+                               $aTypeLabel = false;
+                               if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
+                               elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
+                               else $aTypeLabel = array('simplelabel'=>$aLine['class']);
+                               if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
+                               {
+                                       $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
+                                       if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
+                               }
+                               $iMinRank = $aLine['rank_address'];
+                       }
+               }
+               if ($iMinRank > 4 && $sCountryCode)
+               {
+                       $sSQL = "select get_name_by_language(country_name.name,$sLanguagePrefArraySQL) as name";
+                       $sSQL .= " from country_name where country_code = '$sCountryCode'";
+                       $sCountryName = $oDB->getOne($sSQL);
+                       if ($sCountryName)
+                       {
+                               $aAddress['country'] = $sCountryName;
+                       }
+               }
+               if ($sCountryCode)
+               {
+                       $aAddress['country_code'] = $sCountryCode;
+               }
+
+               return $aAddress;
+       }
+
+       function getWordSuggestions(&$oDB, $sWord)
+       {
+               $sWordQuoted = getDBQuoted(trim($sWord));
+               $sSQL = "select *,levenshtein($sWordQuoted,word) from test_token ";
+               $sSQL .= "where (metaphone = dmetaphone($sWordQuoted) or metaphonealt = dmetaphone($sWordQuoted) or ";
+               $sSQL .= "metaphone = dmetaphone_alt($sWordQuoted) or metaphonealt = dmetaphone_alt($sWordQuoted)) ";
+               $sSQL .= "and len between length($sWordQuoted)-2 and length($sWordQuoted)+2 ";
+               $sSQL .= "and levenshtein($sWordQuoted,word) < 3 ";
+               $sSQL .= "order by levenshtein($sWordQuoted,word) asc, abs(len - length($sWordQuoted)) asc limit 20";
+               $aSimilar = $oDB->getAll($sSQL);
+               return $aSimilar;
+       }
diff --git a/lib/log.php b/lib/log.php
new file mode 100644 (file)
index 0000000..12e2953
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+       function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
+       {
+               $aStartTime = explode('.',microtime(true));
+               if (!$aStartTime[1]) $aStartTime[1] = '0';
+
+               $hLog = array(
+                               date('Y-m-d H:i:s',$aStartTime[0]).'.'.$aStartTime[1],
+                               $_SERVER["REMOTE_ADDR"],
+                               $_SERVER['QUERY_STRING'],
+                               $sQuery
+                       );
+
+                // Log
+               if ($sType == 'search')
+               {
+                       $oDB->query('insert into query_log values ('.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[3]).','.getDBQuoted($hLog[1]).')');
+               }
+
+               $sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format)';
+               $sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
+               $sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($_SERVER['HTTP_USER_AGENT']).','.getDBQuoted(join(',',$aLanguageList)).','.getDBQuoted($_GET['format']).')';
+               $oDB->query($sSQL);
+
+
+               return $hLog;
+       }
+
+       function logEnd(&$oDB, $hLog, $iNumResults)
+       {
+                $aEndTime = explode('.',microtime(true));
+                if (!$aEndTime[1]) $aEndTime[1] = '0';
+                $sEndTime = date('Y-m-d H:i:s',$aEndTime[0]).'.'.$aEndTime[1];
+
+               $sSQL = 'update query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
+               $sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
+               $sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
+               $sSQL .= ' and query = '.getDBQuoted($hLog[3]);
+                $oDB->query($sSQL);
+
+               $sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
+               $sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
+               $sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
+               $sSQL .= ' and query = '.getDBQuoted($hLog[2]);
+               $oDB->query($sSQL);
+       }
diff --git a/module/Makefile b/module/Makefile
new file mode 100644 (file)
index 0000000..0fdb2da
--- /dev/null
@@ -0,0 +1,4 @@
+MODULES = nominatim
+PGXS := $(shell pg_config --pgxs)
+include $(PGXS)
+
diff --git a/module/nominatim.c b/module/nominatim.c
new file mode 100644 (file)
index 0000000..1555315
--- /dev/null
@@ -0,0 +1,287 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "mb/pg_wchar.h"
+#include <utfasciitable.h>
+
+#ifdef PG_MODULE_MAGIC
+PG_MODULE_MAGIC;
+#endif
+
+Datum transliteration( PG_FUNCTION_ARGS );
+Datum gettokenstring( PG_FUNCTION_ARGS );
+void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int);
+void str_dupspaces(char* buffer);
+
+PG_FUNCTION_INFO_V1( transliteration );
+Datum
+transliteration( PG_FUNCTION_ARGS )
+{
+       static char * ascii = UTFASCII;
+       static uint16 asciilookup[65536] = UTFASCIILOOKUP;
+       char * asciipos;
+
+       text *source;
+       unsigned char *sourcedata;
+       int sourcedatalength;
+
+        unsigned int c1,c2,c3,c4;
+       unsigned int * wchardata;
+       unsigned int * wchardatastart;
+
+       text *result;
+       unsigned char *resultdata;
+       int resultdatalength;
+       int iLen;
+
+       if (GetDatabaseEncoding() != PG_UTF8) 
+       {
+               ereport(ERROR,
+                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                         errmsg("requires UTF8 database encoding")));
+       }
+
+       if (PG_ARGISNULL(0))
+       {
+               PG_RETURN_NULL();
+       }
+
+       // The original string
+       source = PG_GETARG_TEXT_P(0);
+       sourcedata = (unsigned char *)VARDATA(source);
+       sourcedatalength = VARSIZE(source) - VARHDRSZ;
+
+       // Intermediate wchar version of string
+       wchardatastart = wchardata = (unsigned int *)palloc((sourcedatalength+1)*sizeof(int));
+
+       // Based on pg_utf2wchar_with_len from wchar.c
+        while (sourcedatalength > 0 && *sourcedata)
+        {
+                if ((*sourcedata & 0x80) == 0)
+                {
+                        *wchardata = *sourcedata++;
+                       wchardata++;
+                        sourcedatalength--;
+                }
+                else if ((*sourcedata & 0xe0) == 0xc0)
+                {
+                        if (sourcedatalength < 2) break;
+                        c1 = *sourcedata++ & 0x1f;
+                        c2 = *sourcedata++ & 0x3f;
+                        *wchardata = (c1 << 6) | c2;
+                       wchardata++;
+                        sourcedatalength -= 2;
+                }
+                else if ((*sourcedata & 0xf0) == 0xe0)
+                {
+                        if (sourcedatalength < 3) break;
+                        c1 = *sourcedata++ & 0x0f;
+                        c2 = *sourcedata++ & 0x3f;
+                        c3 = *sourcedata++ & 0x3f;
+                        *wchardata = (c1 << 12) | (c2 << 6) | c3;
+                       wchardata++;
+                        sourcedatalength -= 3;
+                }
+                else if ((*sourcedata & 0xf8) == 0xf0)
+                {
+                        if (sourcedatalength < 4) break;
+                        c1 = *sourcedata++ & 0x07;
+                        c2 = *sourcedata++ & 0x3f;
+                        c3 = *sourcedata++ & 0x3f;
+                        c4 = *sourcedata++ & 0x3f;
+                        *wchardata = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
+                       wchardata++;
+                        sourcedatalength -= 4;
+                }
+                else if ((*sourcedata & 0xfc) == 0xf8)
+                {
+                       // table does not extend beyond 4 char long, just skip
+                       if (sourcedatalength < 5) break;
+                       sourcedatalength -= 5;
+               }
+                else if ((*sourcedata & 0xfe) == 0xfc)
+                {
+                       // table does not extend beyond 4 char long, just skip
+                       if (sourcedatalength < 6) break;
+                       sourcedatalength -= 6;
+               }
+                else
+                {
+                       // assume lenngth 1, silently drop bogus characters
+                        sourcedatalength--;
+                }
+        }
+        *wchardata = 0;
+
+       // calc the length of transliteration string
+       resultdatalength = 0;
+       wchardata = wchardatastart;
+       while(*wchardata)
+       {
+               if (*(asciilookup + *wchardata) > 0) resultdatalength += *(ascii + *(asciilookup + *wchardata));
+               wchardata++;
+       }
+
+       // allocate & create the result
+       result = (text *)palloc(resultdatalength + VARHDRSZ);
+       SET_VARSIZE(result, resultdatalength + VARHDRSZ);
+       resultdata = (unsigned char *)VARDATA(result);
+
+       wchardata = wchardatastart;
+       while(*wchardata)
+       {
+               if (*(asciilookup + *wchardata) > 0)
+               {
+                       asciipos = ascii + *(asciilookup + *wchardata);
+                       for(iLen = *asciipos; iLen > 0; iLen--)
+                       {
+                               asciipos++;
+                               *resultdata = *asciipos;
+                               resultdata++;
+                       }
+               }
+               else
+               {
+                       ereport( WARNING, ( errcode( ERRCODE_SUCCESSFUL_COMPLETION ),
+                             errmsg( "missing char: %i\n", *wchardata )));
+                       
+               }
+               wchardata++;
+       }
+
+       pfree(wchardatastart);
+
+       PG_RETURN_TEXT_P(result);
+}
+
+void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int isspace)
+{
+        char *p;
+
+        // Search string is too long to be pressent
+        if (fromlen > *len) return;
+
+        p = strstr(buffer, from);
+        while(p)
+        {
+                if (!isspace || *(p-1) != ' ')
+                {
+                        (*changes)++;
+                        if (tolen != fromlen) memmove(p+tolen, p+fromlen, *len-(p-buffer)+1);
+                        memcpy(p, to, tolen);
+                        *len += tolen - fromlen;
+                }
+                p = strstr(p+1, from);
+        }
+}
+
+void str_dupspaces(char* buffer)
+{
+        char *out;
+        int wasspace;
+
+        out = buffer;
+        wasspace = 0;
+        while(*buffer)
+        {
+                if (wasspace && *buffer != ' ') wasspace = 0;
+                if (!wasspace)
+                {
+                        *out = *buffer;
+                        out++;
+                        wasspace = (*buffer == ' ');
+                }
+                buffer++;
+        }
+        *out = 0;
+}
+
+PG_FUNCTION_INFO_V1( gettokenstring );
+Datum
+gettokenstring( PG_FUNCTION_ARGS )
+{
+       text *source;
+       unsigned char *sourcedata;
+       int sourcedatalength;
+
+       char * buffer;
+       int len;
+       int changes;
+
+       text *result;
+
+       if (GetDatabaseEncoding() != PG_UTF8) 
+       {
+               ereport(ERROR,
+                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                         errmsg("requires UTF8 database encoding")));
+       }
+
+       if (PG_ARGISNULL(0))
+       {
+               PG_RETURN_NULL();
+       }
+
+       // The original string
+       source = PG_GETARG_TEXT_P(0);
+       sourcedata = (unsigned char *)VARDATA(source);
+       sourcedatalength = VARSIZE(source) - VARHDRSZ;
+
+       // Buffer for doing the replace in - string could get slightly longer (double is mastive overkill)
+       buffer = (char *)palloc((sourcedatalength*2)*sizeof(char));
+       memcpy(buffer+1, sourcedata, sourcedatalength);
+       buffer[0] = 32;
+       buffer[sourcedatalength+1] = 32;
+       buffer[sourcedatalength+2] = 0;
+       len = sourcedatalength+3;
+
+       changes = 1;
+       str_dupspaces(buffer);
+       while(changes)
+       {
+               changes = 0;
+               #include <tokenstringreplacements.inc>
+               str_dupspaces(buffer);
+       }
+
+       // 'and' in various languages
+       str_replace(buffer, &len, &changes, " and ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " und ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " en ", 4, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " et ", 4, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " e ", 3, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " y ", 3, " ", 1, 0);
+
+       // 'the' (and similar)
+       str_replace(buffer, &len, &changes, " the ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " der ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " den ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " die ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " das ", 5, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " la ", 4, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " le ", 4, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " el ", 4, " ", 1, 0);
+       str_replace(buffer, &len, &changes, " il ", 4, " ", 1, 0);
+
+       // german
+       str_replace(buffer, &len, &changes, "ae", 2, "a", 1, 0);
+       str_replace(buffer, &len, &changes, "oe", 2, "o", 1, 0);
+       str_replace(buffer, &len, &changes, "ue", 2, "u", 1, 0);
+       str_replace(buffer, &len, &changes, "sss", 3, "ss", 2, 0);
+       str_replace(buffer, &len, &changes, "ih", 2, "i", 1, 0);
+       str_replace(buffer, &len, &changes, "eh", 2, "e", 1, 0);
+
+       // russian
+       str_replace(buffer, &len, &changes, "ie", 2, "i", 1, 0);
+       str_replace(buffer, &len, &changes, "yi", 2, "i", 1, 0);
+
+       // allocate & create the result
+       len--;// Drop the terminating zero
+       result = (text *)palloc(len + VARHDRSZ);
+       SET_VARSIZE(result, len + VARHDRSZ);
+       memcpy(VARDATA(result), buffer, len);
+
+       pfree(buffer);
+
+       PG_RETURN_TEXT_P(result);
+}
+
diff --git a/module/tokenstringreplacements.inc b/module/tokenstringreplacements.inc
new file mode 100644 (file)
index 0000000..77519c0
--- /dev/null
@@ -0,0 +1,876 @@
+       str_replace(buffer, &len, &changes, " national wildlife refuge area ", 31, " nwra ", 6, 0);
+       str_replace(buffer, &len, &changes, " national recreation area ", 26, " nra ", 5, 0);
+       str_replace(buffer, &len, &changes, " air national guard base ", 25, " angb ", 6, 0);
+       str_replace(buffer, &len, &changes, " zhilishchien komplieks ", 24, " zh k ", 6, 0);
+       str_replace(buffer, &len, &changes, " trung tam thuong mdhi ", 23, " tttm ", 6, 0);
+       str_replace(buffer, &len, &changes, " poligono industrial ", 21, " pgind ", 7, 0);
+       str_replace(buffer, &len, &changes, " trung hoc pho thong ", 21, " thpt ", 6, 0);
+       str_replace(buffer, &len, &changes, " onze lieve vrouw e ", 20, " olv ", 5, 0);
+       str_replace(buffer, &len, &changes, " strada provinciale ", 20, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, "onze lieve vrouw e ", 19, " olv ", 5, 0);
+       str_replace(buffer, &len, &changes, " punto kilometrico ", 19, " pk ", 4, 0);
+       str_replace(buffer, &len, &changes, " cong vien van hoa ", 19, " cvvh ", 6, 0);
+       str_replace(buffer, &len, &changes, " can cu khong quan ", 19, " cckq ", 6, 0);
+       str_replace(buffer, &len, &changes, "strada provinciale ", 19, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " strada regionale ", 18, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " strada comunale ", 17, " sc ", 4, 0);
+       str_replace(buffer, &len, &changes, "strada regionale ", 17, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " trung hoc co so ", 17, " thcs ", 6, 0);
+       str_replace(buffer, &len, &changes, " san bay quoc te ", 17, " sbqt ", 6, 0);
+       str_replace(buffer, &len, &changes, " cong ty co phyn ", 17, " ctcp ", 6, 0);
+       str_replace(buffer, &len, &changes, " khu cong nghiep ", 17, " kcn ", 5, 0);
+       str_replace(buffer, &len, &changes, " air force base ", 16, " afb ", 5, 0);
+       str_replace(buffer, &len, &changes, " strada statale ", 16, " ss ", 4, 0);
+       str_replace(buffer, &len, &changes, " vien bcyo tang ", 16, " vbt ", 5, 0);
+       str_replace(buffer, &len, &changes, "strada comunale ", 16, " sc ", 4, 0);
+       str_replace(buffer, &len, &changes, " circunvalacion ", 16, " ccvcn ", 7, 0);
+       str_replace(buffer, &len, &changes, " paseo maritimo ", 16, " psmar ", 7, 0);
+       str_replace(buffer, &len, &changes, " wielkopolskie ", 15, " wlkp ", 6, 0);
+       str_replace(buffer, &len, &changes, " national park ", 15, " np ", 4, 0);
+       str_replace(buffer, &len, &changes, " middle school ", 15, " ms ", 4, 0);
+       str_replace(buffer, &len, &changes, " international ", 15, " intl ", 6, 0);
+       str_replace(buffer, &len, &changes, " burgermeister ", 15, " bgm ", 5, 0);
+       str_replace(buffer, &len, &changes, " vuon quoc gia ", 15, " vqg ", 5, 0);
+       str_replace(buffer, &len, &changes, " qucyng truong ", 15, " qt ", 4, 0);
+       str_replace(buffer, &len, &changes, "strada statale ", 15, " ss ", 4, 0);
+       str_replace(buffer, &len, &changes, " state highway ", 15, " sh ", 4, 0);
+       str_replace(buffer, &len, &changes, "burgermeister ", 14, " bgm ", 5, 0);
+       str_replace(buffer, &len, &changes, " right of way ", 14, " rowy ", 6, 0);
+       str_replace(buffer, &len, &changes, " hauptbahnhof ", 14, " hbf ", 5, 0);
+       str_replace(buffer, &len, &changes, " apartamentos ", 14, " aptos ", 7, 0);
+       str_replace(buffer, &len, &changes, " wielkopolski ", 14, " wlkp ", 6, 0);
+       str_replace(buffer, &len, &changes, " burgemeester ", 14, " bg ", 4, 0);
+       str_replace(buffer, &len, &changes, " camino nuevo ", 14, " c n ", 5, 0);
+       str_replace(buffer, &len, &changes, " camino hondo ", 14, " c h ", 5, 0);
+       str_replace(buffer, &len, &changes, " urbanizacion ", 14, " urb ", 5, 0);
+       str_replace(buffer, &len, &changes, " camino viejo ", 14, " c v ", 5, 0);
+       str_replace(buffer, &len, &changes, " wielkopolska ", 14, " wlkp ", 6, 0);
+       str_replace(buffer, &len, &changes, " wojewodztwie ", 14, " woj ", 5, 0);
+       str_replace(buffer, &len, &changes, " county route ", 14, " cr ", 4, 0);
+       str_replace(buffer, &len, &changes, " prolongacion ", 14, " prol ", 6, 0);
+       str_replace(buffer, &len, &changes, " thoroughfare ", 14, " thor ", 6, 0);
+       str_replace(buffer, &len, &changes, " san van dong ", 14, " svd ", 5, 0);
+       str_replace(buffer, &len, &changes, " tong cong ty ", 14, " tct ", 5, 0);
+       str_replace(buffer, &len, &changes, " khu nghi mat ", 14, " knm ", 5, 0);
+       str_replace(buffer, &len, &changes, " nha thi dzu ", 13, " ntd ", 5, 0);
+       str_replace(buffer, &len, &changes, " khu du lich ", 13, " kdl ", 5, 0);
+       str_replace(buffer, &len, &changes, " demarcacion ", 13, " demar ", 7, 0);
+       str_replace(buffer, &len, &changes, " cau ldhc bo ", 13, " clb ", 5, 0);
+       str_replace(buffer, &len, &changes, " interchange ", 13, " intg ", 6, 0);
+       str_replace(buffer, &len, &changes, " distributor ", 13, " dstr ", 6, 0);
+       str_replace(buffer, &len, &changes, " state route ", 13, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " wojewodztwo ", 13, " woj ", 5, 0);
+       str_replace(buffer, &len, &changes, " reservation ", 13, " res ", 5, 0);
+       str_replace(buffer, &len, &changes, " monseigneur ", 13, " mgr ", 5, 0);
+       str_replace(buffer, &len, &changes, " transversal ", 13, " trval ", 7, 0);
+       str_replace(buffer, &len, &changes, " extrarradio ", 13, " extrr ", 7, 0);
+       str_replace(buffer, &len, &changes, " high school ", 13, " hs ", 4, 0);
+       str_replace(buffer, &len, &changes, " mazowieckie ", 13, " maz ", 5, 0);
+       str_replace(buffer, &len, &changes, " residencial ", 13, " resid ", 7, 0);
+       str_replace(buffer, &len, &changes, " cong truong ", 13, " ct ", 4, 0);
+       str_replace(buffer, &len, &changes, " cooperativa ", 13, " coop ", 6, 0);
+       str_replace(buffer, &len, &changes, " diseminado ", 12, " disem ", 7, 0);
+       str_replace(buffer, &len, &changes, " barranquil ", 12, " bqllo ", 7, 0);
+       str_replace(buffer, &len, &changes, " fire track ", 12, " ftrk ", 6, 0);
+       str_replace(buffer, &len, &changes, " south east ", 12, " se ", 4, 0);
+       str_replace(buffer, &len, &changes, " north east ", 12, " ne ", 4, 0);
+       str_replace(buffer, &len, &changes, " university ", 12, " univ ", 6, 0);
+       str_replace(buffer, &len, &changes, " south west ", 12, " sw ", 4, 0);
+       str_replace(buffer, &len, &changes, " monasterio ", 12, " mtrio ", 7, 0);
+       str_replace(buffer, &len, &changes, " vecindario ", 12, " vecin ", 7, 0);
+       str_replace(buffer, &len, &changes, " carreterin ", 12, " ctrin ", 7, 0);
+       str_replace(buffer, &len, &changes, " callejuela ", 12, " cjla ", 6, 0);
+       str_replace(buffer, &len, &changes, " north-east ", 12, " ne ", 4, 0);
+       str_replace(buffer, &len, &changes, " south-west ", 12, " sw ", 4, 0);
+       str_replace(buffer, &len, &changes, " gebroeders ", 12, " gebr ", 6, 0);
+       str_replace(buffer, &len, &changes, " serviceway ", 12, " swy ", 5, 0);
+       str_replace(buffer, &len, &changes, " quadrangle ", 12, " qdgl ", 6, 0);
+       str_replace(buffer, &len, &changes, " commandant ", 12, " cmdt ", 6, 0);
+       str_replace(buffer, &len, &changes, " extramuros ", 12, " extrm ", 7, 0);
+       str_replace(buffer, &len, &changes, " escalinata ", 12, " escal ", 7, 0);
+       str_replace(buffer, &len, &changes, " north-west ", 12, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " bulevardul ", 12, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " particular ", 12, " parti ", 7, 0);
+       str_replace(buffer, &len, &changes, " mazowiecka ", 12, " maz ", 5, 0);
+       str_replace(buffer, &len, &changes, " mazowiecki ", 12, " maz ", 5, 0);
+       str_replace(buffer, &len, &changes, " north west ", 12, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " industrial ", 12, " ind ", 5, 0);
+       str_replace(buffer, &len, &changes, " costanilla ", 12, " cstan ", 7, 0);
+       str_replace(buffer, &len, &changes, " khach sdhn ", 12, " ks ", 4, 0);
+       str_replace(buffer, &len, &changes, " south-east ", 12, " se ", 4, 0);
+       str_replace(buffer, &len, &changes, " phi truong ", 12, " pt ", 4, 0);
+       str_replace(buffer, &len, &changes, " expressway ", 12, " exp ", 5, 0);
+       str_replace(buffer, &len, &changes, " fondamenta ", 12, " f ta ", 6, 0);
+       str_replace(buffer, &len, &changes, " apartments ", 12, " apts ", 6, 0);
+       str_replace(buffer, &len, &changes, " cul de sac ", 12, " cds ", 5, 0);
+       str_replace(buffer, &len, &changes, " corralillo ", 12, " crrlo ", 7, 0);
+       str_replace(buffer, &len, &changes, " mitropolit ", 12, " mit ", 5, 0);
+       str_replace(buffer, &len, &changes, " etorbidea ", 11, " etorb ", 7, 0);
+       str_replace(buffer, &len, &changes, " ploshchad ", 11, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " cobertizo ", 11, " cbtiz ", 7, 0);
+       str_replace(buffer, &len, &changes, " underpass ", 11, " upas ", 6, 0);
+       str_replace(buffer, &len, &changes, " crossroad ", 11, " crd ", 5, 0);
+       str_replace(buffer, &len, &changes, " fundatura ", 11, " fnd ", 5, 0);
+       str_replace(buffer, &len, &changes, " foreshore ", 11, " fshr ", 6, 0);
+       str_replace(buffer, &len, &changes, " parklands ", 11, " pkld ", 6, 0);
+       str_replace(buffer, &len, &changes, " esplanade ", 11, " esp ", 5, 0);
+       str_replace(buffer, &len, &changes, " centreway ", 11, " cnwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " formation ", 11, " form ", 6, 0);
+       str_replace(buffer, &len, &changes, " explanada ", 11, " expla ", 7, 0);
+       str_replace(buffer, &len, &changes, " viviendas ", 11, " vvdas ", 7, 0);
+       str_replace(buffer, &len, &changes, " northeast ", 11, " ne ", 4, 0);
+       str_replace(buffer, &len, &changes, " cong vien ", 11, " cv ", 4, 0);
+       str_replace(buffer, &len, &changes, " northwest ", 11, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " buildings ", 11, " bldgs ", 7, 0);
+       str_replace(buffer, &len, &changes, " errepidea ", 11, " err ", 5, 0);
+       str_replace(buffer, &len, &changes, " extension ", 11, " ex ", 4, 0);
+       str_replace(buffer, &len, &changes, " municipal ", 11, " mun ", 5, 0);
+       str_replace(buffer, &len, &changes, " southeast ", 11, " se ", 4, 0);
+       str_replace(buffer, &len, &changes, " sanatorio ", 11, " sanat ", 7, 0);
+       str_replace(buffer, &len, &changes, " thanh pho ", 11, " tp ", 4, 0);
+       str_replace(buffer, &len, &changes, " firetrail ", 11, " fit ", 5, 0);
+       str_replace(buffer, &len, &changes, " santuario ", 11, " santu ", 7, 0);
+       str_replace(buffer, &len, &changes, " southwest ", 11, " sw ", 4, 0);
+       str_replace(buffer, &len, &changes, " autopista ", 11, " auto ", 6, 0);
+       str_replace(buffer, &len, &changes, " president ", 11, " pres ", 6, 0);
+       str_replace(buffer, &len, &changes, " rinconada ", 11, " rcda ", 6, 0);
+       str_replace(buffer, &len, &changes, " kardinaal ", 11, " kard ", 6, 0);
+       str_replace(buffer, &len, &changes, " plazoleta ", 11, " pzta ", 6, 0);
+       str_replace(buffer, &len, &changes, " duong sat ", 11, " ds ", 4, 0);
+       str_replace(buffer, &len, &changes, " trung tam ", 11, " tt ", 4, 0);
+       str_replace(buffer, &len, &changes, " piazzetta ", 11, " pta ", 5, 0);
+       str_replace(buffer, &len, &changes, " boardwalk ", 11, " bwlk ", 6, 0);
+       str_replace(buffer, &len, &changes, " bulievard ", 11, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " luitenant ", 11, " luit ", 6, 0);
+       str_replace(buffer, &len, &changes, " courtyard ", 11, " ctyd ", 6, 0);
+       str_replace(buffer, &len, &changes, " reservoir ", 11, " res ", 5, 0);
+       str_replace(buffer, &len, &changes, " bulevardu ", 11, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " community ", 11, " comm ", 6, 0);
+       str_replace(buffer, &len, &changes, " concourse ", 11, " con ", 5, 0);
+       str_replace(buffer, &len, &changes, " profiesor ", 11, " prof ", 6, 0);
+       str_replace(buffer, &len, &changes, " promenade ", 11, " prom ", 6, 0);
+       str_replace(buffer, &len, &changes, " gienieral ", 11, " ghien ", 7, 0);
+       str_replace(buffer, &len, &changes, " puistikko ", 11, " pko ", 5, 0);
+       str_replace(buffer, &len, &changes, " balneario ", 11, " balnr ", 7, 0);
+       str_replace(buffer, &len, &changes, " carretera ", 11, " ctra ", 6, 0);
+       str_replace(buffer, &len, &changes, " ingenieur ", 11, " ir ", 4, 0);
+       str_replace(buffer, &len, &changes, " boulevard ", 11, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " deviation ", 11, " devn ", 6, 0);
+       str_replace(buffer, &len, &changes, " hipodromo ", 11, " hipod ", 7, 0);
+       str_replace(buffer, &len, &changes, " professor ", 11, " prof ", 6, 0);
+       str_replace(buffer, &len, &changes, " triangle ", 10, " tri ", 5, 0);
+       str_replace(buffer, &len, &changes, " dotsient ", 10, " dots ", 6, 0);
+       str_replace(buffer, &len, &changes, " boundary ", 10, " bdy ", 5, 0);
+       str_replace(buffer, &len, &changes, " salizada ", 10, " s da ", 6, 0);
+       str_replace(buffer, &len, &changes, " trunkway ", 10, " tkwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " cinturon ", 10, " cint ", 6, 0);
+       str_replace(buffer, &len, &changes, "president ", 10, " pres ", 6, 0);
+       str_replace(buffer, &len, &changes, " military ", 10, " mil ", 5, 0);
+       str_replace(buffer, &len, &changes, " jonkheer ", 10, " jhr ", 5, 0);
+       str_replace(buffer, &len, &changes, " motorway ", 10, " mwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " steenweg ", 10, " stwg ", 6, 0);
+       str_replace(buffer, &len, &changes, " crescent ", 10, " cr ", 4, 0);
+       str_replace(buffer, &len, &changes, " kanunnik ", 10, " kan ", 5, 0);
+       str_replace(buffer, &len, &changes, " koningin ", 10, " kon ", 5, 0);
+       str_replace(buffer, &len, &changes, " crossing ", 10, " xing ", 6, 0);
+       str_replace(buffer, &len, &changes, " callejon ", 10, " cjon ", 6, 0);
+       str_replace(buffer, &len, &changes, " pasadizo ", 10, " pzo ", 5, 0);
+       str_replace(buffer, &len, &changes, " crossway ", 10, " cowy ", 6, 0);
+       str_replace(buffer, &len, &changes, " cottages ", 10, " cotts ", 7, 0);
+       str_replace(buffer, &len, &changes, " mountain ", 10, " mtn ", 5, 0);
+       str_replace(buffer, &len, &changes, " business ", 10, " bus ", 5, 0);
+       str_replace(buffer, &len, &changes, " pierwszy ", 10, " 1 ", 3, 0);
+       str_replace(buffer, &len, &changes, " pierwsza ", 10, " 1 ", 3, 0);
+       str_replace(buffer, &len, &changes, " pierwsze ", 10, " 1 ", 3, 0);
+       str_replace(buffer, &len, &changes, " barriada ", 10, " barda ", 7, 0);
+       str_replace(buffer, &len, &changes, " entrance ", 10, " ent ", 5, 0);
+       str_replace(buffer, &len, &changes, " causeway ", 10, " cway ", 6, 0);
+       str_replace(buffer, &len, &changes, " generaal ", 10, " gen ", 5, 0);
+       str_replace(buffer, &len, &changes, " driveway ", 10, " dvwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " township ", 10, " twp ", 5, 0);
+       str_replace(buffer, &len, &changes, " stazione ", 10, " staz ", 6, 0);
+       str_replace(buffer, &len, &changes, " broadway ", 10, " bway ", 6, 0);
+       str_replace(buffer, &len, &changes, " alleyway ", 10, " alwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " quadrant ", 10, " qdrt ", 6, 0);
+       str_replace(buffer, &len, &changes, " apeadero ", 10, " apdro ", 7, 0);
+       str_replace(buffer, &len, &changes, " arboleda ", 10, " arb ", 5, 0);
+       str_replace(buffer, &len, &changes, " escalera ", 10, " esca ", 6, 0);
+       str_replace(buffer, &len, &changes, " rdhp hat ", 10, " rh ", 4, 0);
+       str_replace(buffer, &len, &changes, " transito ", 10, " trans ", 7, 0);
+       str_replace(buffer, &len, &changes, " ddhi hoc ", 10, " dh ", 4, 0);
+       str_replace(buffer, &len, &changes, " travesia ", 10, " trva ", 6, 0);
+       str_replace(buffer, &len, &changes, " barranco ", 10, " branc ", 7, 0);
+       str_replace(buffer, &len, &changes, " namestie ", 10, " nam ", 5, 0);
+       str_replace(buffer, &len, &changes, " viaducto ", 10, " vcto ", 6, 0);
+       str_replace(buffer, &len, &changes, " convento ", 10, " cnvto ", 7, 0);
+       str_replace(buffer, &len, &changes, " estacion ", 10, " estcn ", 7, 0);
+       str_replace(buffer, &len, &changes, "puistikko ", 10, " pko ", 5, 0);
+       str_replace(buffer, &len, &changes, " precinct ", 10, " pct ", 5, 0);
+       str_replace(buffer, &len, &changes, " heiligen ", 10, " hl ", 4, 0);
+       str_replace(buffer, &len, &changes, " edificio ", 10, " edifc ", 7, 0);
+       str_replace(buffer, &len, &changes, " prazuela ", 10, " przla ", 7, 0);
+       str_replace(buffer, &len, &changes, " thi trzn ", 10, " tt ", 4, 0);
+       str_replace(buffer, &len, &changes, " ridgeway ", 10, " rgwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " riverway ", 10, " rvwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " corredor ", 10, " crrdo ", 7, 0);
+       str_replace(buffer, &len, &changes, " passatge ", 10, " ptge ", 6, 0);
+       str_replace(buffer, &len, &changes, " junction ", 10, " jnc ", 5, 0);
+       str_replace(buffer, &len, &changes, " hospital ", 10, " hosp ", 6, 0);
+       str_replace(buffer, &len, &changes, " highroad ", 10, " hrd ", 5, 0);
+       str_replace(buffer, &len, &changes, " torrente ", 10, " trrnt ", 7, 0);
+       str_replace(buffer, &len, &changes, " avinguda ", 10, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, " portillo ", 10, " ptilo ", 7, 0);
+       str_replace(buffer, &len, &changes, " diagonal ", 10, " diag ", 6, 0);
+       str_replace(buffer, &len, &changes, " buu dien ", 10, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " alqueria ", 10, " alque ", 7, 0);
+       str_replace(buffer, &len, &changes, " poligono ", 10, " polig ", 7, 0);
+       str_replace(buffer, &len, &changes, " roadside ", 10, " rdsd ", 6, 0);
+       str_replace(buffer, &len, &changes, " glorieta ", 10, " gta ", 5, 0);
+       str_replace(buffer, &len, &changes, " fundacul ", 10, " fdc ", 5, 0);
+       str_replace(buffer, &len, &changes, " cao dang ", 10, " cd ", 4, 0);
+       str_replace(buffer, &len, &changes, " rosebowl ", 10, " rsbl ", 6, 0);
+       str_replace(buffer, &len, &changes, " complejo ", 10, " compj ", 7, 0);
+       str_replace(buffer, &len, &changes, " carretil ", 10, " crtil ", 7, 0);
+       str_replace(buffer, &len, &changes, " intrarea ", 10, " int ", 5, 0);
+       str_replace(buffer, &len, &changes, " gran via ", 10, " g v ", 5, 0);
+       str_replace(buffer, &len, &changes, " approach ", 10, " app ", 5, 0);
+       str_replace(buffer, &len, &changes, " stradela ", 10, " sdla ", 6, 0);
+       str_replace(buffer, &len, &changes, " conjunto ", 10, " cjto ", 6, 0);
+       str_replace(buffer, &len, &changes, " arterial ", 10, " artl ", 6, 0);
+       str_replace(buffer, &len, &changes, " plazuela ", 10, " plzla ", 7, 0);
+       str_replace(buffer, &len, &changes, " frontage ", 10, " frtg ", 6, 0);
+       str_replace(buffer, &len, &changes, " faubourg ", 10, " fg ", 4, 0);
+       str_replace(buffer, &len, &changes, " mansions ", 10, " mans ", 6, 0);
+       str_replace(buffer, &len, &changes, " turnpike ", 10, " tpk ", 5, 0);
+       str_replace(buffer, &len, &changes, " piazzale ", 10, " p le ", 6, 0);
+       str_replace(buffer, &len, &changes, " tieu hoc ", 10, " th ", 4, 0);
+       str_replace(buffer, &len, &changes, " bulevard ", 10, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " sendera ", 9, " sedra ", 7, 0);
+       str_replace(buffer, &len, &changes, " cutting ", 9, " cutt ", 6, 0);
+       str_replace(buffer, &len, &changes, " cantina ", 9, " canti ", 7, 0);
+       str_replace(buffer, &len, &changes, " cantera ", 9, " cantr ", 7, 0);
+       str_replace(buffer, &len, &changes, " rotonda ", 9, " rtda ", 6, 0);
+       str_replace(buffer, &len, &changes, " pasillo ", 9, " psllo ", 7, 0);
+       str_replace(buffer, &len, &changes, " landing ", 9, " ldg ", 5, 0);
+       str_replace(buffer, &len, &changes, " kolonel ", 9, " kol ", 5, 0);
+       str_replace(buffer, &len, &changes, " cong ty ", 9, " cty ", 5, 0);
+       str_replace(buffer, &len, &changes, " fairway ", 9, " fawy ", 6, 0);
+       str_replace(buffer, &len, &changes, " highway ", 9, " hwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " lookout ", 9, " lkt ", 5, 0);
+       str_replace(buffer, &len, &changes, " meander ", 9, " mr ", 4, 0);
+       str_replace(buffer, &len, &changes, " carrera ", 9, " cra ", 5, 0);
+       str_replace(buffer, &len, &changes, " station ", 9, " stn ", 5, 0);
+       str_replace(buffer, &len, &changes, " kapitan ", 9, " kap ", 5, 0);
+       str_replace(buffer, &len, &changes, " medical ", 9, " med ", 5, 0);
+       str_replace(buffer, &len, &changes, " broeder ", 9, " br ", 4, 0);
+       str_replace(buffer, &len, &changes, " poblado ", 9, " pbdo ", 6, 0);
+       str_replace(buffer, &len, &changes, " impasse ", 9, " imp ", 5, 0);
+       str_replace(buffer, &len, &changes, " gardens ", 9, " gdn ", 5, 0);
+       str_replace(buffer, &len, &changes, " nha tho ", 9, " nt ", 4, 0);
+       str_replace(buffer, &len, &changes, " nha hat ", 9, " nh ", 4, 0);
+       str_replace(buffer, &len, &changes, " freeway ", 9, " fwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " trasera ", 9, " tras ", 6, 0);
+       str_replace(buffer, &len, &changes, " portico ", 9, " prtco ", 7, 0);
+       str_replace(buffer, &len, &changes, " terrace ", 9, " ter ", 5, 0);
+       str_replace(buffer, &len, &changes, " heights ", 9, " hts ", 5, 0);
+       str_replace(buffer, &len, &changes, " camping ", 9, " campg ", 7, 0);
+       str_replace(buffer, &len, &changes, " callizo ", 9, " cllzo ", 7, 0);
+       str_replace(buffer, &len, &changes, " footway ", 9, " ftwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " calzada ", 9, " czada ", 7, 0);
+       str_replace(buffer, &len, &changes, " dominee ", 9, " ds ", 4, 0);
+       str_replace(buffer, &len, &changes, " meadows ", 9, " mdws ", 6, 0);
+       str_replace(buffer, &len, &changes, " sendero ", 9, " send ", 6, 0);
+       str_replace(buffer, &len, &changes, " osiedle ", 9, " os ", 4, 0);
+       str_replace(buffer, &len, &changes, " estrada ", 9, " estda ", 7, 0);
+       str_replace(buffer, &len, &changes, " avenida ", 9, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, " zgornji ", 9, " zg ", 4, 0);
+       str_replace(buffer, &len, &changes, " zgornje ", 9, " zg ", 4, 0);
+       str_replace(buffer, &len, &changes, " zgornja ", 9, " zg ", 4, 0);
+       str_replace(buffer, &len, &changes, " arrabal ", 9, " arral ", 7, 0);
+       str_replace(buffer, &len, &changes, " espalda ", 9, " eslda ", 7, 0);
+       str_replace(buffer, &len, &changes, " entrada ", 9, " entd ", 6, 0);
+       str_replace(buffer, &len, &changes, " kleiner ", 9, " kl ", 4, 0);
+       str_replace(buffer, &len, &changes, " kleines ", 9, " kl ", 4, 0);
+       str_replace(buffer, &len, &changes, " viaduct ", 9, " via ", 5, 0);
+       str_replace(buffer, &len, &changes, " roadway ", 9, " rdwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " strasse ", 9, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " spodnje ", 9, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " spodnji ", 9, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " spodnja ", 9, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " fabrica ", 9, " fca ", 5, 0);
+       str_replace(buffer, &len, &changes, " muntele ", 9, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " maantee ", 9, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " srednje ", 9, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " unterer ", 9, " u ", 3, 0);
+       str_replace(buffer, &len, &changes, " unteres ", 9, " u ", 3, 0);
+       str_replace(buffer, &len, &changes, " plateau ", 9, " plat ", 6, 0);
+       str_replace(buffer, &len, &changes, " srednji ", 9, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " empresa ", 9, " empr ", 6, 0);
+       str_replace(buffer, &len, &changes, " angosta ", 9, " angta ", 7, 0);
+       str_replace(buffer, &len, &changes, " costera ", 9, " coste ", 7, 0);
+       str_replace(buffer, &len, &changes, " tinh lo ", 9, " tl ", 4, 0);
+       str_replace(buffer, &len, &changes, " quoc lo ", 9, " ql ", 4, 0);
+       str_replace(buffer, &len, &changes, " auf der ", 9, " a d ", 5, 0);
+       str_replace(buffer, &len, &changes, " bulvari ", 9, " bl ", 4, 0);
+       str_replace(buffer, &len, &changes, " ddhi lo ", 9, " dl ", 4, 0);
+       str_replace(buffer, &len, &changes, " namesti ", 9, " nam ", 5, 0);
+       str_replace(buffer, &len, &changes, " passeig ", 9, " pg ", 4, 0);
+       str_replace(buffer, &len, &changes, " carrero ", 9, " cro ", 5, 0);
+       str_replace(buffer, &len, &changes, " cortijo ", 9, " crtjo ", 7, 0);
+       str_replace(buffer, &len, &changes, " san bay ", 9, " sb ", 4, 0);
+       str_replace(buffer, &len, &changes, " riviera ", 9, " rvra ", 6, 0);
+       str_replace(buffer, &len, &changes, " caddesi ", 9, " cd ", 4, 0);
+       str_replace(buffer, &len, &changes, " andador ", 9, " andad ", 7, 0);
+       str_replace(buffer, &len, &changes, " walkway ", 9, " wkwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " granden ", 9, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " grosser ", 9, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " grosses ", 9, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " reserve ", 9, " res ", 5, 0);
+       str_replace(buffer, &len, &changes, " alameda ", 9, " alam ", 6, 0);
+       str_replace(buffer, &len, &changes, " retreat ", 9, " rtt ", 5, 0);
+       str_replace(buffer, &len, &changes, " acequia ", 9, " aceq ", 6, 0);
+       str_replace(buffer, &len, &changes, " platsen ", 9, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " bahnhof ", 9, " bf ", 4, 0);
+       str_replace(buffer, &len, &changes, " autovia ", 9, " autov ", 7, 0);
+       str_replace(buffer, &len, &changes, " srednja ", 9, " sr ", 4, 0);
+       str_replace(buffer, &len, &changes, " galeria ", 9, " gale ", 6, 0);
+       str_replace(buffer, &len, &changes, " circuit ", 9, " cct ", 5, 0);
+       str_replace(buffer, &len, &changes, " svingen ", 9, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " plassen ", 9, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " mirador ", 9, " mrdor ", 7, 0);
+       str_replace(buffer, &len, &changes, " laneway ", 9, " lnwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " kolonia ", 9, " kol ", 5, 0);
+       str_replace(buffer, &len, &changes, " outlook ", 9, " otlk ", 6, 0);
+       str_replace(buffer, &len, &changes, " caravan ", 9, " cvn ", 5, 0);
+       str_replace(buffer, &len, &changes, " osiedlu ", 9, " os ", 4, 0);
+       str_replace(buffer, &len, &changes, " palacio ", 9, " palac ", 7, 0);
+       str_replace(buffer, &len, &changes, " pantano ", 9, " pant ", 6, 0);
+       str_replace(buffer, &len, &changes, " partida ", 9, " ptda ", 6, 0);
+       str_replace(buffer, &len, &changes, " calleja ", 9, " cllja ", 7, 0);
+       str_replace(buffer, &len, &changes, " mevrouw ", 9, " mevr ", 6, 0);
+       str_replace(buffer, &len, &changes, " meester ", 9, " mr ", 4, 0);
+       str_replace(buffer, &len, &changes, " pastoor ", 9, " past ", 6, 0);
+       str_replace(buffer, &len, &changes, " prinses ", 9, " pr ", 4, 0);
+       str_replace(buffer, &len, &changes, " bulevar ", 9, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " tollway ", 9, " tlwy ", 6, 0);
+       str_replace(buffer, &len, &changes, "steenweg ", 9, " stwg ", 6, 0);
+       str_replace(buffer, &len, &changes, " caserio ", 9, " csrio ", 7, 0);
+       str_replace(buffer, &len, &changes, " mercado ", 9, " merc ", 6, 0);
+       str_replace(buffer, &len, &changes, " alejach ", 9, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " kvartal ", 9, " kv ", 4, 0);
+       str_replace(buffer, &len, &changes, " parkway ", 9, " pwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " passage ", 9, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " pathway ", 9, " pway ", 6, 0);
+       str_replace(buffer, &len, &changes, " splaiul ", 9, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " soseaua ", 9, " sos ", 5, 0);
+       str_replace(buffer, &len, &changes, " colonia ", 9, " col ", 5, 0);
+       str_replace(buffer, &len, &changes, " wielkie ", 9, " wlk ", 5, 0);
+       str_replace(buffer, &len, &changes, " trzecie ", 9, " 3 ", 3, 0);
+       str_replace(buffer, &len, &changes, " llanura ", 9, " llnra ", 7, 0);
+       str_replace(buffer, &len, &changes, " malecon ", 9, " malec ", 7, 0);
+       str_replace(buffer, &len, &changes, " trzecia ", 9, " 3 ", 3, 0);
+       str_replace(buffer, &len, &changes, " trailer ", 9, " trlr ", 6, 0);
+       str_replace(buffer, &len, &changes, " cuadra ", 8, " cuadr ", 7, 0);
+       str_replace(buffer, &len, &changes, " cty cp ", 8, " ctcp ", 6, 0);
+       str_replace(buffer, &len, &changes, " paraje ", 8, " praje ", 7, 0);
+       str_replace(buffer, &len, &changes, " parque ", 8, " pque ", 6, 0);
+       str_replace(buffer, &len, &changes, " piazza ", 8, " p za ", 6, 0);
+       str_replace(buffer, &len, &changes, " puerta ", 8, " pta ", 5, 0);
+       str_replace(buffer, &len, &changes, " little ", 8, " lt ", 4, 0);
+       str_replace(buffer, &len, &changes, " pueblo ", 8, " pblo ", 6, 0);
+       str_replace(buffer, &len, &changes, " puente ", 8, " pnte ", 6, 0);
+       str_replace(buffer, &len, &changes, " jardin ", 8, " jdin ", 6, 0);
+       str_replace(buffer, &len, &changes, " granja ", 8, " granj ", 7, 0);
+       str_replace(buffer, &len, &changes, " market ", 8, " mkt ", 5, 0);
+       str_replace(buffer, &len, &changes, " pasaje ", 8, " psaje ", 7, 0);
+       str_replace(buffer, &len, &changes, " rotary ", 8, " rty ", 5, 0);
+       str_replace(buffer, &len, &changes, " corral ", 8, " crral ", 7, 0);
+       str_replace(buffer, &len, &changes, " siding ", 8, " sdng ", 6, 0);
+       str_replace(buffer, &len, &changes, " nucleo ", 8, " ncleo ", 7, 0);
+       str_replace(buffer, &len, &changes, " muelle ", 8, " muell ", 7, 0);
+       str_replace(buffer, &len, &changes, " carril ", 8, " crril ", 7, 0);
+       str_replace(buffer, &len, &changes, " portal ", 8, " prtal ", 7, 0);
+       str_replace(buffer, &len, &changes, " ramble ", 8, " rmbl ", 6, 0);
+       str_replace(buffer, &len, &changes, " pocket ", 8, " pkt ", 5, 0);
+       str_replace(buffer, &len, &changes, " chalet ", 8, " chlet ", 7, 0);
+       str_replace(buffer, &len, &changes, " canton ", 8, " cant ", 6, 0);
+       str_replace(buffer, &len, &changes, " ladera ", 8, " ldera ", 7, 0);
+       str_replace(buffer, &len, &changes, " parade ", 8, " pde ", 5, 0);
+       str_replace(buffer, &len, &changes, " dehesa ", 8, " dhsa ", 6, 0);
+       str_replace(buffer, &len, &changes, " museum ", 8, " mus ", 5, 0);
+       str_replace(buffer, &len, &changes, " middle ", 8, " mid ", 5, 0);
+       str_replace(buffer, &len, &changes, " cuesta ", 8, " custa ", 7, 0);
+       str_replace(buffer, &len, &changes, " gracht ", 8, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " virful ", 8, " vf ", 4, 0);
+       str_replace(buffer, &len, &changes, " m tele ", 8, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " varful ", 8, " vf ", 4, 0);
+       str_replace(buffer, &len, &changes, " str la ", 8, " sdla ", 6, 0);
+       str_replace(buffer, &len, &changes, " arcade ", 8, " arc ", 5, 0);
+       str_replace(buffer, &len, &changes, " strada ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " access ", 8, " accs ", 6, 0);
+       str_replace(buffer, &len, &changes, " bajada ", 8, " bjada ", 7, 0);
+       str_replace(buffer, &len, &changes, " veliki ", 8, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, "strasse ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " velike ", 8, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " untere ", 8, " u ", 3, 0);
+       str_replace(buffer, &len, &changes, " velika ", 8, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " artery ", 8, " arty ", 6, 0);
+       str_replace(buffer, &len, &changes, " avenue ", 8, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, " miasto ", 8, " m ", 3, 0);
+       str_replace(buffer, &len, &changes, " bypass ", 8, " byp ", 5, 0);
+       str_replace(buffer, &len, &changes, " placem ", 8, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " barrio ", 8, " bo ", 4, 0);
+       str_replace(buffer, &len, &changes, " center ", 8, " ctr ", 5, 0);
+       str_replace(buffer, &len, &changes, " bldngs ", 8, " bldgs ", 7, 0);
+       str_replace(buffer, &len, &changes, " puerto ", 8, " pto ", 5, 0);
+       str_replace(buffer, &len, &changes, " wielka ", 8, " wlk ", 5, 0);
+       str_replace(buffer, &len, &changes, " tunnel ", 8, " tun ", 5, 0);
+       str_replace(buffer, &len, &changes, " wielki ", 8, " wlk ", 5, 0);
+       str_replace(buffer, &len, &changes, " bridge ", 8, " bri ", 5, 0);
+       str_replace(buffer, &len, &changes, " trzeci ", 8, " 3 ", 3, 0);
+       str_replace(buffer, &len, &changes, " veliko ", 8, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " quelle ", 8, " qu ", 4, 0);
+       str_replace(buffer, &len, &changes, " acceso ", 8, " acces ", 7, 0);
+       str_replace(buffer, &len, &changes, " bulvar ", 8, " bl ", 4, 0);
+       str_replace(buffer, &len, &changes, " sokagi ", 8, " sk ", 4, 0);
+       str_replace(buffer, &len, &changes, "platsen ", 8, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " stigen ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " brucke ", 8, " br ", 4, 0);
+       str_replace(buffer, &len, &changes, " an der ", 8, " a d ", 5, 0);
+       str_replace(buffer, &len, &changes, " thi xa ", 8, " tx ", 4, 0);
+       str_replace(buffer, &len, &changes, " nordre ", 8, " ndr ", 5, 0);
+       str_replace(buffer, &len, &changes, " rambla ", 8, " rbla ", 6, 0);
+       str_replace(buffer, &len, &changes, " sondre ", 8, " sdr ", 5, 0);
+       str_replace(buffer, &len, &changes, "quoc lo ", 8, " ql ", 4, 0);
+       str_replace(buffer, &len, &changes, " phuong ", 8, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, " vastra ", 8, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " carrer ", 8, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, " oberes ", 8, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, " raitti ", 8, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " puisto ", 8, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " arroyo ", 8, " arry ", 6, 0);
+       str_replace(buffer, &len, &changes, " penger ", 8, " pgr ", 5, 0);
+       str_replace(buffer, &len, &changes, " oberer ", 8, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, " kleine ", 8, " kl ", 4, 0);
+       str_replace(buffer, &len, &changes, " grosse ", 8, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, "granden ", 8, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " villas ", 8, " vlls ", 6, 0);
+       str_replace(buffer, &len, &changes, " taival ", 8, " tvl ", 5, 0);
+       str_replace(buffer, &len, &changes, " in der ", 8, " i d ", 5, 0);
+       str_replace(buffer, &len, &changes, " centre ", 8, " ctr ", 5, 0);
+       str_replace(buffer, &len, &changes, " drugie ", 8, " 2 ", 3, 0);
+       str_replace(buffer, &len, &changes, " dokter ", 8, " dr ", 4, 0);
+       str_replace(buffer, &len, &changes, " grange ", 8, " gra ", 5, 0);
+       str_replace(buffer, &len, &changes, " doctor ", 8, " dr ", 4, 0);
+       str_replace(buffer, &len, &changes, " vicolo ", 8, " v lo ", 6, 0);
+       str_replace(buffer, &len, &changes, " kort e ", 8, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, " koning ", 8, " kon ", 5, 0);
+       str_replace(buffer, &len, &changes, " straat ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " svieti ", 8, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " callej ", 8, " cjon ", 6, 0);
+       str_replace(buffer, &len, &changes, " ground ", 8, " grnd ", 6, 0);
+       str_replace(buffer, &len, &changes, " vereda ", 8, " vreda ", 7, 0);
+       str_replace(buffer, &len, &changes, " chemin ", 8, " ch ", 4, 0);
+       str_replace(buffer, &len, &changes, " street ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " strand ", 8, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " sainte ", 8, " ste ", 5, 0);
+       str_replace(buffer, &len, &changes, " camino ", 8, " cno ", 5, 0);
+       str_replace(buffer, &len, &changes, " garden ", 8, " gdn ", 5, 0);
+       str_replace(buffer, &len, &changes, " follow ", 8, " folw ", 6, 0);
+       str_replace(buffer, &len, &changes, " estate ", 8, " est ", 5, 0);
+       str_replace(buffer, &len, &changes, " doktor ", 8, " d r ", 5, 0);
+       str_replace(buffer, &len, &changes, " subway ", 8, " sbwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " ulitsa ", 8, " ul ", 4, 0);
+       str_replace(buffer, &len, &changes, " square ", 8, " sq ", 4, 0);
+       str_replace(buffer, &len, &changes, " towers ", 8, " twrs ", 6, 0);
+       str_replace(buffer, &len, &changes, "plassen ", 8, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " county ", 8, " co ", 4, 0);
+       str_replace(buffer, &len, &changes, " brazal ", 8, " brzal ", 7, 0);
+       str_replace(buffer, &len, &changes, " circus ", 8, " crcs ", 6, 0);
+       str_replace(buffer, &len, &changes, "svingen ", 8, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " rampla ", 8, " rampa ", 7, 0);
+       str_replace(buffer, &len, &changes, " bloque ", 8, " blque ", 7, 0);
+       str_replace(buffer, &len, &changes, " circle ", 8, " cir ", 5, 0);
+       str_replace(buffer, &len, &changes, " island ", 8, " is ", 4, 0);
+       str_replace(buffer, &len, &changes, " common ", 8, " comm ", 6, 0);
+       str_replace(buffer, &len, &changes, " ribera ", 8, " rbra ", 6, 0);
+       str_replace(buffer, &len, &changes, " sector ", 8, " sect ", 6, 0);
+       str_replace(buffer, &len, &changes, " rincon ", 8, " rcon ", 6, 0);
+       str_replace(buffer, &len, &changes, " van de ", 8, " vd ", 4, 0);
+       str_replace(buffer, &len, &changes, " corner ", 8, " cnr ", 5, 0);
+       str_replace(buffer, &len, &changes, " subida ", 8, " sbida ", 7, 0);
+       str_replace(buffer, &len, &changes, " banda ", 7, " b ", 3, 0);
+       str_replace(buffer, &len, &changes, " bulev ", 7, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " barro ", 7, " bo ", 4, 0);
+       str_replace(buffer, &len, &changes, " cllon ", 7, " cjon ", 6, 0);
+       str_replace(buffer, &len, &changes, " p zza ", 7, " p za ", 6, 0);
+       str_replace(buffer, &len, &changes, " drugi ", 7, " 2 ", 3, 0);
+       str_replace(buffer, &len, &changes, " druga ", 7, " 2 ", 3, 0);
+       str_replace(buffer, &len, &changes, " placu ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " aleji ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " aleja ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " aleje ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " stary ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " stara ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " dolny ", 7, " dln ", 5, 0);
+       str_replace(buffer, &len, &changes, " dolna ", 7, " dln ", 5, 0);
+       str_replace(buffer, &len, &changes, " gorne ", 7, " gn ", 4, 0);
+       str_replace(buffer, &len, &changes, " gorna ", 7, " gn ", 4, 0);
+       str_replace(buffer, &len, &changes, " stare ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " gorny ", 7, " gn ", 4, 0);
+       str_replace(buffer, &len, &changes, " ulicy ", 7, " ul ", 4, 0);
+       str_replace(buffer, &len, &changes, " ulica ", 7, " ul ", 4, 0);
+       str_replace(buffer, &len, &changes, " o l v ", 7, " olv ", 5, 0);
+       str_replace(buffer, &len, &changes, " plein ", 7, " pln ", 5, 0);
+       str_replace(buffer, &len, &changes, " markt ", 7, " mkt ", 5, 0);
+       str_replace(buffer, &len, &changes, " lange ", 7, " l ", 3, 0);
+       str_replace(buffer, &len, &changes, " viale ", 7, " v le ", 6, 0);
+       str_replace(buffer, &len, &changes, "gracht ", 7, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " prins ", 7, " pr ", 4, 0);
+       str_replace(buffer, &len, &changes, "straat ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " plass ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " sving ", 7, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " gaten ", 7, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " veien ", 7, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " vliet ", 7, " vlt ", 5, 0);
+       str_replace(buffer, &len, &changes, " dolne ", 7, " dln ", 5, 0);
+       str_replace(buffer, &len, &changes, " b dul ", 7, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " sodra ", 7, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " norra ", 7, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " gamla ", 7, " gla ", 5, 0);
+       str_replace(buffer, &len, &changes, " grand ", 7, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " vagen ", 7, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " gatan ", 7, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " ostra ", 7, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, "vastra ", 7, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " cadde ", 7, " cd ", 4, 0);
+       str_replace(buffer, &len, &changes, " duong ", 7, " d ", 3, 0);
+       str_replace(buffer, &len, &changes, " sokak ", 7, " sk ", 4, 0);
+       str_replace(buffer, &len, &changes, " plats ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, "stigen ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " vayla ", 7, " vla ", 5, 0);
+       str_replace(buffer, &len, &changes, "taival ", 7, " tvl ", 5, 0);
+       str_replace(buffer, &len, &changes, " sveti ", 7, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " aukio ", 7, " auk ", 5, 0);
+       str_replace(buffer, &len, &changes, " sveta ", 7, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, " cesta ", 7, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, " piata ", 7, " pta ", 5, 0);
+       str_replace(buffer, &len, &changes, " aleea ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " kaari ", 7, " kri ", 5, 0);
+       str_replace(buffer, &len, &changes, "penger ", 7, " pgr ", 5, 0);
+       str_replace(buffer, &len, &changes, " ranta ", 7, " rt ", 4, 0);
+       str_replace(buffer, &len, &changes, " rinne ", 7, " rn ", 4, 0);
+       str_replace(buffer, &len, &changes, "raitti ", 7, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, "puisto ", 7, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " polku ", 7, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, " porta ", 7, " pta ", 5, 0);
+       str_replace(buffer, &len, &changes, " ponte ", 7, " p te ", 6, 0);
+       str_replace(buffer, &len, &changes, " paseo ", 7, " po ", 4, 0);
+       str_replace(buffer, &len, &changes, " fbrca ", 7, " fca ", 5, 0);
+       str_replace(buffer, &len, &changes, " allee ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " cours ", 7, " crs ", 5, 0);
+       str_replace(buffer, &len, &changes, "sainte ", 7, " ste ", 5, 0);
+       str_replace(buffer, &len, &changes, "square ", 7, " sq ", 4, 0);
+       str_replace(buffer, &len, &changes, " largo ", 7, " l go ", 6, 0);
+       str_replace(buffer, &len, &changes, " wharf ", 7, " whrf ", 6, 0);
+       str_replace(buffer, &len, &changes, " corte ", 7, " c te ", 6, 0);
+       str_replace(buffer, &len, &changes, " corso ", 7, " c so ", 6, 0);
+       str_replace(buffer, &len, &changes, " campo ", 7, " c po ", 6, 0);
+       str_replace(buffer, &len, &changes, " santa ", 7, " sta ", 5, 0);
+       str_replace(buffer, &len, &changes, " calle ", 7, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, " strip ", 7, " strp ", 6, 0);
+       str_replace(buffer, &len, &changes, " alley ", 7, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " north ", 7, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " block ", 7, " blk ", 5, 0);
+       str_replace(buffer, &len, &changes, " gully ", 7, " gly ", 5, 0);
+       str_replace(buffer, &len, &changes, " sielo ", 7, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " brace ", 7, " br ", 4, 0);
+       str_replace(buffer, &len, &changes, " ronde ", 7, " rnde ", 6, 0);
+       str_replace(buffer, &len, &changes, " grove ", 7, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " break ", 7, " brk ", 5, 0);
+       str_replace(buffer, &len, &changes, " roads ", 7, " rds ", 5, 0);
+       str_replace(buffer, &len, &changes, " track ", 7, " trk ", 5, 0);
+       str_replace(buffer, &len, &changes, " house ", 7, " ho ", 4, 0);
+       str_replace(buffer, &len, &changes, " trail ", 7, " trl ", 5, 0);
+       str_replace(buffer, &len, &changes, " mount ", 7, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " cross ", 7, " crss ", 6, 0);
+       str_replace(buffer, &len, &changes, " beach ", 7, " bch ", 5, 0);
+       str_replace(buffer, &len, &changes, " point ", 7, " pt ", 4, 0);
+       str_replace(buffer, &len, &changes, " basin ", 7, " basn ", 6, 0);
+       str_replace(buffer, &len, &changes, " green ", 7, " gn ", 4, 0);
+       str_replace(buffer, &len, &changes, " plaza ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " lille ", 7, " ll ", 4, 0);
+       str_replace(buffer, &len, &changes, " slope ", 7, " slpe ", 6, 0);
+       str_replace(buffer, &len, &changes, " placa ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " place ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " shunt ", 7, " shun ", 6, 0);
+       str_replace(buffer, &len, &changes, " saint ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " ulice ", 7, " ul ", 4, 0);
+       str_replace(buffer, &len, &changes, " amble ", 7, " ambl ", 6, 0);
+       str_replace(buffer, &len, &changes, " route ", 7, " rt ", 4, 0);
+       str_replace(buffer, &len, &changes, " sound ", 7, " snd ", 5, 0);
+       str_replace(buffer, &len, &changes, " store ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " front ", 7, " frnt ", 6, 0);
+       str_replace(buffer, &len, &changes, " elbow ", 7, " elb ", 5, 0);
+       str_replace(buffer, &len, &changes, " glade ", 7, " gl ", 4, 0);
+       str_replace(buffer, &len, &changes, " south ", 7, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " round ", 7, " rnd ", 5, 0);
+       str_replace(buffer, &len, &changes, " drive ", 7, " dr ", 4, 0);
+       str_replace(buffer, &len, &changes, " croft ", 7, " cft ", 5, 0);
+       str_replace(buffer, &len, &changes, " platz ", 7, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " ferry ", 7, " fy ", 4, 0);
+       str_replace(buffer, &len, &changes, " ridge ", 7, " rdge ", 6, 0);
+       str_replace(buffer, &len, &changes, " tanav ", 7, " tn ", 4, 0);
+       str_replace(buffer, &len, &changes, " banan ", 7, " ba ", 4, 0);
+       str_replace(buffer, &len, &changes, " quays ", 7, " qys ", 5, 0);
+       str_replace(buffer, &len, &changes, " sankt ", 7, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " vkhod ", 7, " vkh ", 5, 0);
+       str_replace(buffer, &len, &changes, " chase ", 7, " ch ", 4, 0);
+       str_replace(buffer, &len, &changes, " vista ", 7, " vsta ", 6, 0);
+       str_replace(buffer, &len, &changes, " rhein ", 7, " rh ", 4, 0);
+       str_replace(buffer, &len, &changes, " court ", 7, " ct ", 4, 0);
+       str_replace(buffer, &len, &changes, "brucke ", 7, " br ", 4, 0);
+       str_replace(buffer, &len, &changes, " upper ", 7, " up ", 4, 0);
+       str_replace(buffer, &len, &changes, " river ", 7, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " range ", 7, " rnge ", 6, 0);
+       str_replace(buffer, &len, &changes, " lower ", 7, " lr ", 4, 0);
+       str_replace(buffer, &len, &changes, " kalea ", 7, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, " crest ", 7, " crst ", 6, 0);
+       str_replace(buffer, &len, &changes, " obere ", 7, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, " manor ", 7, " mnr ", 5, 0);
+       str_replace(buffer, &len, &changes, " byway ", 7, " bywy ", 6, 0);
+       str_replace(buffer, &len, &changes, " reach ", 7, " rch ", 5, 0);
+       str_replace(buffer, &len, &changes, " copse ", 7, " cps ", 5, 0);
+       str_replace(buffer, &len, &changes, "quelle ", 7, " qu ", 4, 0);
+       str_replace(buffer, &len, &changes, " creek ", 7, " cr ", 4, 0);
+       str_replace(buffer, &len, &changes, " close ", 7, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, " fort ", 6, " ft ", 4, 0);
+       str_replace(buffer, &len, &changes, " apch ", 6, " app ", 5, 0);
+       str_replace(buffer, &len, &changes, " mont ", 6, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " bdul ", 6, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, "saint ", 6, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " back ", 6, " bk ", 4, 0);
+       str_replace(buffer, &len, &changes, " c le ", 6, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, "place ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " frwy ", 6, " fwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " quai ", 6, " qu ", 4, 0);
+       str_replace(buffer, &len, &changes, " ally ", 6, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " m te ", 6, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, " lane ", 6, " ln ", 4, 0);
+       str_replace(buffer, &len, &changes, "aukio ", 6, " auk ", 5, 0);
+       str_replace(buffer, &len, &changes, " loop ", 6, " lp ", 4, 0);
+       str_replace(buffer, &len, &changes, " line ", 6, " ln ", 4, 0);
+       str_replace(buffer, &len, &changes, " alue ", 6, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " link ", 6, " lk ", 4, 0);
+       str_replace(buffer, &len, &changes, " glde ", 6, " gl ", 4, 0);
+       str_replace(buffer, &len, &changes, " alea ", 6, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " gate ", 6, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " intr ", 6, " int ", 5, 0);
+       str_replace(buffer, &len, &changes, " gdns ", 6, " gdn ", 5, 0);
+       str_replace(buffer, &len, &changes, " hird ", 6, " hrd ", 5, 0);
+       str_replace(buffer, &len, &changes, " varf ", 6, " vf ", 4, 0);
+       str_replace(buffer, &len, &changes, " virf ", 6, " vf ", 4, 0);
+       str_replace(buffer, &len, &changes, " hgts ", 6, " hts ", 5, 0);
+       str_replace(buffer, &len, &changes, " expy ", 6, " exp ", 5, 0);
+       str_replace(buffer, &len, &changes, "markt ", 6, " mkt ", 5, 0);
+       str_replace(buffer, &len, &changes, " bypa ", 6, " byp ", 5, 0);
+       str_replace(buffer, &len, &changes, "o l v ", 6, " olv ", 5, 0);
+       str_replace(buffer, &len, &changes, " cres ", 6, " cr ", 4, 0);
+       str_replace(buffer, &len, &changes, " bdwy ", 6, " bway ", 6, 0);
+       str_replace(buffer, &len, &changes, " csac ", 6, " cds ", 5, 0);
+       str_replace(buffer, &len, &changes, " nowy ", 6, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " laan ", 6, " ln ", 4, 0);
+       str_replace(buffer, &len, &changes, " crsg ", 6, " xing ", 6, 0);
+       str_replace(buffer, &len, &changes, "vliet ", 6, " vlt ", 5, 0);
+       str_replace(buffer, &len, &changes, " city ", 6, " cty ", 5, 0);
+       str_replace(buffer, &len, &changes, "sving ", 6, " sv ", 4, 0);
+       str_replace(buffer, &len, &changes, "plass ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, "gaten ", 6, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, "veien ", 6, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " gata ", 6, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " sint ", 6, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " caus ", 6, " cway ", 6, 0);
+       str_replace(buffer, &len, &changes, " cove ", 6, " cv ", 4, 0);
+       str_replace(buffer, &len, &changes, "plein ", 6, " pln ", 5, 0);
+       str_replace(buffer, &len, &changes, " cswy ", 6, " cway ", 6, 0);
+       str_replace(buffer, &len, &changes, " plac ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " nowa ", 6, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " kolo ", 6, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, " katu ", 6, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, " duze ", 6, " dz ", 4, 0);
+       str_replace(buffer, &len, &changes, " blvd ", 6, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " p ta ", 6, " pta ", 5, 0);
+       str_replace(buffer, &len, &changes, " maly ", 6, " ml ", 4, 0);
+       str_replace(buffer, &len, &changes, " mala ", 6, " ml ", 4, 0);
+       str_replace(buffer, &len, &changes, " bdge ", 6, " bri ", 5, 0);
+       str_replace(buffer, &len, &changes, " nowe ", 6, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, " brdg ", 6, " bri ", 5, 0);
+       str_replace(buffer, &len, &changes, " male ", 6, " ml ", 4, 0);
+       str_replace(buffer, &len, &changes, " drwy ", 6, " dvwy ", 6, 0);
+       str_replace(buffer, &len, &changes, " duza ", 6, " dz ", 4, 0);
+       str_replace(buffer, &len, &changes, " utca ", 6, " u ", 3, 0);
+       str_replace(buffer, &len, &changes, " east ", 6, " e ", 3, 0);
+       str_replace(buffer, &len, &changes, " duzy ", 6, " dz ", 4, 0);
+       str_replace(buffer, &len, &changes, "kaari ", 6, " kri ", 5, 0);
+       str_replace(buffer, &len, &changes, " quan ", 6, " q ", 3, 0);
+       str_replace(buffer, &len, &changes, " svwy ", 6, " swy ", 5, 0);
+       str_replace(buffer, &len, &changes, " shwy ", 6, " sh ", 4, 0);
+       str_replace(buffer, &len, &changes, " road ", 6, " rd ", 4, 0);
+       str_replace(buffer, &len, &changes, "sankt ", 6, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " quay ", 6, " qy ", 4, 0);
+       str_replace(buffer, &len, &changes, "plats ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " rise ", 6, " ri ", 4, 0);
+       str_replace(buffer, &len, &changes, " berg ", 6, " bg ", 4, 0);
+       str_replace(buffer, &len, &changes, " tcty ", 6, " tct ", 5, 0);
+       str_replace(buffer, &len, &changes, " viad ", 6, " via ", 5, 0);
+       str_replace(buffer, &len, &changes, " view ", 6, " vw ", 4, 0);
+       str_replace(buffer, &len, &changes, " vdct ", 6, " via ", 5, 0);
+       str_replace(buffer, &len, &changes, " vale ", 6, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " avda ", 6, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, " grad ", 6, " ghr ", 5, 0);
+       str_replace(buffer, &len, &changes, " walk ", 6, " wlk ", 5, 0);
+       str_replace(buffer, &len, &changes, " west ", 6, " w ", 3, 0);
+       str_replace(buffer, &len, &changes, " yard ", 6, " yd ", 4, 0);
+       str_replace(buffer, &len, &changes, " blok ", 6, " bl ", 4, 0);
+       str_replace(buffer, &len, &changes, " terr ", 6, " ter ", 5, 0);
+       str_replace(buffer, &len, &changes, " cmno ", 6, " cno ", 5, 0);
+       str_replace(buffer, &len, &changes, " stra ", 6, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " thfr ", 6, " thor ", 6, 0);
+       str_replace(buffer, &len, &changes, " turn ", 6, " tn ", 4, 0);
+       str_replace(buffer, &len, &changes, " tpke ", 6, " tpk ", 5, 0);
+       str_replace(buffer, &len, &changes, " burg ", 6, " bg ", 4, 0);
+       str_replace(buffer, &len, &changes, "vayla ", 6, " vla ", 5, 0);
+       str_replace(buffer, &len, &changes, "vagen ", 6, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " tori ", 6, " tr ", 4, 0);
+       str_replace(buffer, &len, &changes, "gatan ", 6, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, "grand ", 6, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " pass ", 6, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " pkwy ", 6, " pwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " park ", 6, " pk ", 4, 0);
+       str_replace(buffer, &len, &changes, "rinne ", 6, " rn ", 4, 0);
+       str_replace(buffer, &len, &changes, " mtwy ", 6, " mwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " mndr ", 6, " mr ", 4, 0);
+       str_replace(buffer, &len, &changes, " kyla ", 6, " kl ", 4, 0);
+       str_replace(buffer, &len, &changes, " kuja ", 6, " kj ", 4, 0);
+       str_replace(buffer, &len, &changes, "platz ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, "ranta ", 6, " rt ", 4, 0);
+       str_replace(buffer, &len, &changes, " mile ", 6, " mi ", 4, 0);
+       str_replace(buffer, &len, &changes, " pfad ", 6, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, " mews ", 6, " m ", 3, 0);
+       str_replace(buffer, &len, &changes, "polku ", 6, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, " psge ", 6, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " plza ", 6, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, "ostra ", 6, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, "gamla ", 6, " gla ", 5, 0);
+       str_replace(buffer, &len, &changes, " stig ", 6, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, "norra ", 6, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, "sodra ", 6, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " pike ", 6, " pk ", 4, 0);
+       str_replace(buffer, &len, &changes, " dorf ", 6, " df ", 4, 0);
+       str_replace(buffer, &len, &changes, " piaz ", 6, " p za ", 6, 0);
+       str_replace(buffer, &len, &changes, " phwy ", 6, " pway ", 6, 0);
+       str_replace(buffer, &len, &changes, "pfad ", 5, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, " mnt ", 5, " mt ", 4, 0);
+       str_replace(buffer, &len, &changes, "gata ", 5, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " bhf ", 5, " bf ", 4, 0);
+       str_replace(buffer, &len, &changes, " bad ", 5, " b ", 3, 0);
+       str_replace(buffer, &len, &changes, "gate ", 5, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " zum ", 5, " z ", 3, 0);
+       str_replace(buffer, &len, &changes, "stig ", 5, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " blv ", 5, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, "kuja ", 5, " kj ", 4, 0);
+       str_replace(buffer, &len, &changes, " bul ", 5, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " str ", 5, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, "alue ", 5, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " cen ", 5, " ctr ", 5, 0);
+       str_replace(buffer, &len, &changes, " ave ", 5, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, "kyla ", 5, " kl ", 4, 0);
+       str_replace(buffer, &len, &changes, " ale ", 5, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " spl ", 5, " sp ", 4, 0);
+       str_replace(buffer, &len, &changes, " all ", 5, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, " k s ", 5, " ks ", 4, 0);
+       str_replace(buffer, &len, &changes, " aly ", 5, " al ", 4, 0);
+       str_replace(buffer, &len, &changes, "dorf ", 5, " df ", 4, 0);
+       str_replace(buffer, &len, &changes, " bvd ", 5, " bd ", 4, 0);
+       str_replace(buffer, &len, &changes, " vag ", 5, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " iii ", 5, " 3 ", 3, 0);
+       str_replace(buffer, &len, &changes, " tie ", 5, " t ", 3, 0);
+       str_replace(buffer, &len, &changes, " sok ", 5, " sk ", 4, 0);
+       str_replace(buffer, &len, &changes, "burg ", 5, " bg ", 4, 0);
+       str_replace(buffer, &len, &changes, "katu ", 5, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, "berg ", 5, " bg ", 4, 0);
+       str_replace(buffer, &len, &changes, "tori ", 5, " tr ", 4, 0);
+       str_replace(buffer, &len, &changes, " kte ", 5, " k ", 3, 0);
+       str_replace(buffer, &len, &changes, " gro ", 5, " gr ", 4, 0);
+       str_replace(buffer, &len, &changes, " grn ", 5, " gn ", 4, 0);
+       str_replace(buffer, &len, &changes, " gld ", 5, " gl ", 4, 0);
+       str_replace(buffer, &len, &changes, " san ", 5, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " hse ", 5, " ho ", 4, 0);
+       str_replace(buffer, &len, &changes, " gte ", 5, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, " rte ", 5, " rt ", 4, 0);
+       str_replace(buffer, &len, &changes, " rue ", 5, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " che ", 5, " ch ", 4, 0);
+       str_replace(buffer, &len, &changes, " pas ", 5, " ps ", 4, 0);
+       str_replace(buffer, &len, &changes, " plz ", 5, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " pnt ", 5, " pt ", 4, 0);
+       str_replace(buffer, &len, &changes, " pky ", 5, " pwy ", 5, 0);
+       str_replace(buffer, &len, &changes, " pza ", 5, " pl ", 4, 0);
+       str_replace(buffer, &len, &changes, " rvr ", 5, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " riv ", 5, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " lit ", 5, " lt ", 4, 0);
+       str_replace(buffer, &len, &changes, " p k ", 5, " pk ", 4, 0);
+       str_replace(buffer, &len, &changes, " lwr ", 5, " lr ", 4, 0);
+       str_replace(buffer, &len, &changes, " low ", 5, " lr ", 4, 0);
+       str_replace(buffer, &len, &changes, " sth ", 5, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " crk ", 5, " cr ", 4, 0);
+       str_replace(buffer, &len, &changes, "pres ", 5, " pres ", 6, 1);
+       str_replace(buffer, &len, &changes, "laan ", 5, " ln ", 4, 0);
+       str_replace(buffer, &len, &changes, " bda ", 5, " b ", 3, 0);
+       str_replace(buffer, &len, &changes, " vei ", 5, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " via ", 5, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " way ", 5, " wy ", 4, 0);
+       str_replace(buffer, &len, &changes, " upr ", 5, " up ", 4, 0);
+       str_replace(buffer, &len, &changes, " avd ", 5, " av ", 4, 0);
+       str_replace(buffer, &len, &changes, " crt ", 5, " ct ", 4, 0);
+       str_replace(buffer, &len, &changes, "stwg ", 5, " stwg ", 6, 1);
+       str_replace(buffer, &len, &changes, "sint ", 5, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " v d ", 5, " vd ", 4, 0);
+       str_replace(buffer, &len, &changes, " van ", 5, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " drv ", 5, " dr ", 4, 0);
+       str_replace(buffer, &len, &changes, " tce ", 5, " ter ", 5, 0);
+       str_replace(buffer, &len, &changes, " va ", 4, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " oa ", 4, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, " sa ", 4, " s ", 3, 0);
+       str_replace(buffer, &len, &changes, " na ", 4, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, "bgm ", 4, " bgm ", 5, 1);
+       str_replace(buffer, &len, &changes, " nw ", 4, " n ", 3, 0);
+       str_replace(buffer, &len, &changes, "vag ", 4, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " im ", 4, " 1 ", 3, 0);
+       str_replace(buffer, &len, &changes, "vla ", 4, " vla ", 5, 1);
+       str_replace(buffer, &len, &changes, "gla ", 4, " gla ", 5, 1);
+       str_replace(buffer, &len, &changes, " am ", 4, " a ", 3, 0);
+       str_replace(buffer, &len, &changes, " ph ", 4, " p ", 3, 0);
+       str_replace(buffer, &len, &changes, "rue ", 4, " r ", 3, 0);
+       str_replace(buffer, &len, &changes, " ga ", 4, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, "ste ", 4, " ste ", 5, 1);
+       str_replace(buffer, &len, &changes, "str ", 4, " st ", 4, 0);
+       str_replace(buffer, &len, &changes, " cl ", 4, " c ", 3, 0);
+       str_replace(buffer, &len, &changes, " vn ", 4, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, " gt ", 4, " g ", 3, 0);
+       str_replace(buffer, &len, &changes, "vei ", 4, " v ", 3, 0);
+       str_replace(buffer, &len, &changes, "vlt ", 4, " vlt ", 5, 1);
+       str_replace(buffer, &len, &changes, " ce ", 4, " cv ", 4, 0);
+       str_replace(buffer, &len, &changes, " ii ", 4, " 2 ", 3, 0);
+       str_replace(buffer, &len, &changes, "pln ", 4, " pln ", 5, 1);
+       str_replace(buffer, &len, &changes, "olv ", 4, " olv ", 5, 1);
+       str_replace(buffer, &len, &changes, "mkt ", 4, " mkt ", 5, 1);
+       str_replace(buffer, &len, &changes, "tvl ", 4, " tvl ", 5, 1);
+       str_replace(buffer, &len, &changes, " ob ", 4, " o ", 3, 0);
+       str_replace(buffer, &len, &changes, "pgr ", 4, " pgr ", 5, 1);
+       str_replace(buffer, &len, &changes, " in ", 4, " 1 ", 3, 0);
+       str_replace(buffer, &len, &changes, " mw ", 4, " m ", 3, 0);
+       str_replace(buffer, &len, &changes, "kri ", 4, " kri ", 5, 1);
+       str_replace(buffer, &len, &changes, "pko ", 4, " pko ", 5, 1);
+       str_replace(buffer, &len, &changes, "auk ", 4, " auk ", 5, 1);
+       str_replace(buffer, &len, &changes, "tie ", 4, " t ", 3, 0);
+       str_replace(buffer, &len, &changes, " i ", 3, " 1 ", 3, 0);
diff --git a/module/utfasciitable.h b/module/utfasciitable.h
new file mode 100644 (file)
index 0000000..60a2e85
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTFASCII " \x00""\x01"" \x01""0\x01""1\x01""2\x01""3\x01""4\x01""5\x01""6\x01""7\x01""8\x01""9\x01""a\x01""b\x01""c\x01""d\x01""e\x01""f\x01""g\x01""h\x01""i\x01""j\x01""k\x01""l\x01""m\x01""n\x01""o\x01""p\x01""q\x01""r\x01""s\x01""t\x01""u\x01""v\x01""w\x01""x\x01""y\x01""z\x02""ps\x02""ss\x03""deg\x01""-\x02""14\x02""12\x02""34\x02""ae\x02""th\x02""ij\x02""ng\x02""oe\x02""hv\x02""oi\x02""yr\x02""sh\x02""zh\x02""ts\x02""dz\x02""lj\x02""nj\x02""ou\x02""db\x02""qp\x04""stop\x02""lz\x02""tc\x02""fn\x02""ls\x02""ww\x0a""extra-high\x04""high\x03""mid\x04""tone\x09""extra-low\x03""yin\x04""yang\x04""down\x02""up\x04""left\x05""right\x04""ring\x06""middle\x05""tilde\x06""raised\x05""begin\x03""end\x05""shelf\x05""below\x04""heta\x05""sampi\x0a""pamphylian\x02""ks\x02""ph\x02""kh\x05""koppa\x02""st\x02""sp\x02""ch\x02""ti\x03""sho\x03""san\x02""ie\x02""io\x02""dj\x02""gj\x02""yi\x03""tsh\x02""kj\x03""dzh\x04""shch\x04""hard\x02""iu\x02""ia\x02""gh\x02""ot\x04""1000\x06""100000\x07""1000000\x03""tts\x02""el\x02""en\x02""em\x08""palochka\x03""ghe\x02""ha\x02""de\x03""dje\x03""zje\x04""dzje\x03""lje\x03""nje\x03""sje\x03""tje\x02""ze\x03""lha\x03""rha\x03""yae\x02""qa\x02""we\x05""aleut\x02""rh\x02""ew\x04""alef\x02""oy\x05""sanah\x05""safha\x05""misra\x0b""sallallahou\x06""alayhe\x0b""rahmatullah\x04""radi\x09""takhallus\x05""hamza\x02""dh\x05""keheh\x05""farsi\x02""an\x02""un\x02""in\x05""small\x03""dot\x03""beh\x03""qaf\x02""tt\x03""tth\x02""bh\x02""ny\x02""dy\x03""cch\x02""dd\x02""dt\x03""ddh\x02""rr\x02""hy\x02""yu\x03""yeh\x03""sad\x03""dal\x03""reh\x03""heh\x05""alaph\x02""yh\x07""persian\x07""sogdian\x03""hah\x04""seen\x03""ain\x03""feh\x04""meem\x04""noon\x03""lam\x03""waw\x03""kaf\x02""hh\x02""aa\x02""ee\x02""oo\x02""ey\x02""oa\x03""naa\x0a""dagbasinna\x02""ba\x02""pa\x02""ta\x02""ja\x03""cha\x02""da\x02""ra\x03""rra\x02""sa\x03""gba\x02""fa\x02""ka\x02""la\x02""na\x02""ma\x03""nya\x02""wa\x02""ya\x04""jona\x0b""candrabindu\x08""anusvara\x07""visarga\x02""ii\x02""uu\x06""candra\x02""ai\x02""au\x03""kha\x02""ga\x03""gha\x03""nga\x02""ca\x03""jha\x03""tta\x04""ttha\x03""dda\x04""ddha\x03""nna\x03""tha\x03""dha\x04""nnna\x03""pha\x03""bha\x03""lla\x04""llla\x02""va\x03""sha\x03""ssa\x05""nukta\x08""avagraha\x06""virama\x06""udatta\x08""anudatta\x04""khha\x04""ghha\x02""za\x05""dddha\x03""yya\x02""ll\x03""gga\x03""jja\x04""ddda\x03""bba\x06""khanda\x02""on\x02""jh\x02""nn\x03""nnn\x03""lll\x03""aum\x03""khh\x03""ghh\x04""dddh\x02""yy\x06""yakash\x02""rs\x03""1-1\x02""16\x02""bb\x03""geo\x03""tsa\x03""dza\x05""tuumu\x02""10\x03""100\x06""chillu\x08""iruyanna\x06""eyanna\x0a""alpapraana\x07""yayanna\x07""rayanna\x07""dantaja\x09""muurdhaja\x0a""aela-pilla\x05""ketti\x04""diga\x0c""gaetta-pilla\x07""kombuva\x05""kombu\x0b""gayanukitta\x02""ko\x03""kho\x02""yo\x03""tho\x02""so\x07""phinthu\x0b""lakkhangyao\x03""mai\x08""nikhahit\x08""yamakkan\x07""fongman\x0a""angkhankhu\x06""khomut\x03""aae\x02""no\x03""nng\x03""jny\x03""nyj\x04""nndd\x02""nd\x02""mb\x02""lo\x02""om\x02""am\x02""ue\x03""uue\x03""yar\x02""ao\x04""dzha\x03""zha\x02""-a\x04""kssa\x0a""fixed-form\x03""kka\x04""rjes\x04""rnam\x03""sna\x03""lci\x04""mchu\x03""gru\x02""ei\x02""ay\x04""rdel\x02""hn\x02""hm\x04""nnya\x02"" -\x02"" x\x03"" xx\x02""15\x02""25\x02""35\x02""45\x02""55\x02""65\x02""75\x02""85\x02""-5\x04""asat\x06""medial\x05""great\x03""ssh\x03""kss\x07""western\x07""eastern\x04""shan\x05""rumai\x04""char\x02"" o\x03""har\x03""hoe\x03""ban\x03""gan\x03""don\x03""vin\x03""zen\x03""tan\x03""kan\x03""las\x03""man\x03""nar\x03""par\x04""zhar\x03""rae\x03""tar\x04""phar\x04""khar\x04""ghan\x03""qar\x04""shin\x04""chin\x03""can\x03""jil\x03""cil\x03""xan\x04""jhan\x03""hae\x02""he\x03""hie\x02""fi\x02""yn\x05""elifi\x08""georgian\x03""nny\x06""filler\x02""eo\x03""yeo\x02""ye\x03""wae\x03""weo\x02""wi\x02""eu\x03""a-o\x03""a-u\x04""ya-o\x05""ya-yo\x04""eo-o\x04""eo-u\x05""eo-eu\x05""yeo-o\x05""yeo-u\x04""o-eo\x03""o-e\x04""o-ye\x03""o-o\x03""o-u\x05""yo-ya\x06""yo-yae\x06""yo-yeo\x04""yo-o\x04""yo-i\x03""u-a\x04""u-ae\x07""u-eo-eu\x04""u-ye\x03""u-u\x04""yu-a\x05""yu-eo\x04""yu-e\x06""yu-yeo\x05""yu-ye\x04""yu-u\x04""yu-i\x04""eu-u\x05""eu-eu\x04""yi-u\x03""i-a\x04""i-ya\x03""i-o\x03""i-u\x04""i-eu\x07""i-araea\x05""araea\x08""araea-eo\x02""xh\x0c""nieun-tikeut\x0a""nieun-sios\x0d""nieun-pansios\x0d""nieun-thieuth\x0d""tikeut-kiyeok\x0c""tikeut-rieul\x11""rieul-kiyeok-sios\x0b""rieul-nieun\x0c""rieul-tikeut\x12""rieul-tikeut-hieuh\x0b""hieuh-mieum\x0b""hieuh-pieup\x0b""yeorinhieuh\x02""gg\x03""laa\x02""jj\x02""nb\x02""dg\x02""rn\x02""mn\x02""bg\x02""bn\x03""sza\x02""bs\x03""bsg\x03""bst\x03""bsb\x03""bss\x03""bsj\x02""bj\x02""bc\x02""bt\x02""bp\x03""bbn\x02""sg\x02""sn\x02""sd\x02""sr\x02""sm\x02""sb\x03""sbg\x03""sss\x02""sj\x02""sc\x02""sk\x04""shee\x03""she\x04""shwa\x03""qoa\x03""qha\x03""qhu\x02""ck\x04""qhee\x03""qhe\x02""pb\x02""pn\x04""qhwi\x05""qhwaa\x05""qhwee\x04""qhwe\x04""u-eo\x03""u-i\x02""gs\x02""nh\x02""lg\x02""lm\x02""lb\x02""lt\x02""lp\x02""lh\x02""gl\x03""gsg\x02""ns\x02""nz\x02""nt\x02""tl\x03""lgs\x02""ln\x02""ld\x03""lth\x03""lmg\x03""lms\x03""lbs\x03""lbh\x03""rnp\x03""lss\x02""lk\x02""lq\x02""mg\x02""ml\x02""ms\x03""mss\x02""mz\x02""mc\x02""mh\x02""bl\x02""sl\x02""hl\x02""hb\x03""ddi\x04""ddaa\x04""ddee\x03""dde\x03""ddo\x04""ddwa\x02""hu\x02""hi\x03""haa\x03""hee\x02""ho\x03""jwa\x02""lu\x02""li\x03""lee\x02""le\x03""lwa\x03""hha\x03""hhu\x03""hhi\x04""hhaa\x04""hhee\x03""hhe\x03""hho\x04""hhwa\x02""mu\x02""mi\x03""maa\x03""mee\x02""me\x02""mo\x03""mwa\x03""szu\x03""szi\x04""szaa\x04""szee\x03""sze\x03""szo\x04""szwa\x02""ru\x02""ri\x03""raa\x03""ree\x02""re\x02""ro\x03""rwa\x02""su\x02""si\x03""saa\x03""see\x02""se\x03""swa\x03""shu\x03""shi\x04""shaa\x02""qu\x02""qi\x03""qaa\x03""qee\x02""qe\x02""qo\x04""tzoa\x03""qwa\x02""fu\x03""qwi\x04""qwaa\x04""qwee\x03""qwe\x02""fo\x03""fwa\x03""qhi\x04""qhaa\x03""qho\x03""pwa\x04""qhwa\x03""mya\x02""bu\x02""bi\x03""baa\x03""bee\x02""be\x02""bo\x03""bwa\x02""vu\x02""vi\x03""vaa\x03""vee\x02""ve\x02""vo\x03""vwa\x02""tu\x03""taa\x03""tee\x02""te\x02""to\x03""twa\x02""cu\x02""ci\x03""caa\x03""cee\x02""ce\x02""co\x03""cwa\x02""xa\x02""xu\x02""xi\x03""xaa\x03""xee\x02""xe\x02""xo\x03""bwe\x03""xwa\x03""fwi\x03""xwi\x04""xwaa\x04""xwee\x03""xwe\x04""pwee\x03""pwe\x02""nu\x02""ni\x03""nee\x02""ne\x03""nwa\x03""nyu\x03""nyi\x04""nyaa\x04""nyee\x03""nye\x03""nyo\x04""nywa\x02""ku\x02""ki\x03""kaa\x03""kee\x02""ke\x03""kwa\x03""kwi\x04""kwaa\x04""kwee\x03""kwe\x03""kxa\x03""kxu\x03""kxi\x04""kxaa\x04""kxee\x03""kxe\x03""kxo\x03""hna\x04""kxwa\x04""kxwi\x05""kxwaa\x05""kxwee\x04""kxwe\x03""qua\x03""que\x02""wu\x03""waa\x03""wee\x02""wo\x02""di\x02""zu\x02""zi\x03""zaa\x03""zee\x02""zo\x03""zwa\x03""zhu\x03""zhi\x04""zhaa\x04""zhee\x03""zhe\x03""zho\x04""zhwa\x03""yaa\x03""yee\x02""du\x03""daa\x03""dee\x02""do\x03""dwa\x03""ddu\x02""ju\x02""ji\x03""jaa\x03""jee\x02""je\x02""jo\x02""gu\x02""gi\x03""gaa\x03""gee\x02""ge\x02""go\x03""gwa\x03""gwi\x04""gwaa\x04""gwee\x03""gwe\x03""ggu\x03""ggi\x04""ggaa\x04""ggee\x03""gge\x03""ggo\x03""thu\x03""thi\x04""thaa\x04""thee\x03""the\x04""thwa\x03""chu\x03""chi\x04""chaa\x04""chee\x03""che\x03""cho\x04""chwa\x03""phu\x03""phi\x04""phaa\x04""phee\x03""phe\x03""pho\x04""phwa\x03""tsu\x03""tsi\x04""tsaa\x04""tsee\x03""tse\x03""tso\x04""tswa\x03""tza\x03""tzu\x03""tzi\x04""tzaa\x04""tzee\x03""tze\x03""tzo\x03""faa\x03""fee\x02""fe\x02""pu\x02""pi\x03""paa\x03""pee\x02""pe\x02""po\x03""rya\x03""fya\x02""20\x02""30\x02""40\x02""50\x02""60\x02""70\x02""80\x02""90\x05""10000\x02""gv\x02""lv\x03""nah\x02""nv\x03""qui\x03""quo\x03""quu\x03""quv\x02""sv\x02""dv\x03""dla\x03""tla\x03""tle\x03""tli\x03""tlo\x03""tlu\x03""tlv\x03""tsv\x02""wv\x02""yv\x03""aai\x03""wii\x03""woo\x04""paai\x03""pii\x03""poo\x03""pwi\x04""pwii\x03""pwo\x04""pwoo\x04""pwaa\x04""taai\x03""tii\x03""too\x03""twe\x03""twi\x04""twii\x03""two\x04""twoo\x04""twaa\x03""tte\x03""tti\x03""tto\x04""kaai\x03""kii\x03""koo\x04""kwii\x03""kwo\x04""kwoo\x02""kw\x03""keh\x03""kih\x03""koh\x03""kah\x04""caai\x03""cii\x03""coo\x03""cwe\x03""cwi\x04""cwii\x03""cwo\x04""cwoo\x04""cwaa\x04""maai\x03""mii\x03""moo\x03""mwe\x03""mwi\x04""mwii\x03""mwo\x04""mwoo\x04""mwaa\x04""naai\x03""nii\x03""noo\x03""nwe\x04""nwaa\x04""laai\x03""lii\x03""loo\x03""lwe\x03""lwi\x04""lwii\x03""lwo\x04""lwoo\x04""lwaa\x04""saai\x03""sii\x03""soo\x03""swe\x03""swi\x04""swii\x03""swo\x04""swoo\x04""swaa\x02""sw\x03""skw\x04""spwa\x04""stwa\x04""skwa\x04""scwa\x04""shii\x04""shoo\x04""shwe\x04""shwi\x05""shwii\x04""shwo\x05""shwoo\x05""shwaa\x04""yaai\x03""yii\x03""yoo\x03""ywe\x03""ywi\x04""ywii\x03""ywo\x04""ywoo\x03""ywa\x04""ywaa\x04""raai\x03""rii\x03""roo\x04""rwaa\x04""faai\x03""fii\x03""foo\x04""fwaa\x04""thii\x04""thoo\x05""thwaa\x04""tthe\x04""tthi\x04""ttho\x03""tye\x03""tyi\x03""tyo\x03""tya\x03""hii\x03""hoo\x02""hk\x04""qaai\x03""qii\x03""qoo\x04""tlhe\x04""tlhi\x04""tlho\x04""tlha\x05""ngaai\x03""ngi\x04""ngii\x03""ngo\x04""ngoo\x04""ngaa\x03""lhi\x04""lhii\x03""lho\x04""lhoo\x04""lhaa\x03""ghu\x03""gho\x04""ghee\x03""ghi\x03""hwu\x03""hwo\x03""hwe\x04""hwee\x03""hwi\x03""hwa\x03""ttu\x04""ttee\x03""khu\x03""khe\x04""khee\x03""khi\x03""kku\x03""kko\x03""kke\x04""kkee\x03""kki\x02""kk\x03""jju\x03""jjo\x03""jje\x04""jjee\x03""jji\x03""dlu\x03""dlo\x03""dle\x04""dlee\x03""dli\x03""lhu\x03""lhe\x04""lhee\x04""tlhu\x05""tlhee\x04""tlee\x03""dzu\x03""dzo\x03""dze\x04""dzee\x03""dzi\x04""ttsu\x04""ttso\x04""ttse\x05""ttsee\x04""ttsi\x04""ttsa\x03""qai\x04""ngai\x04""nngi\x05""nngii\x04""nngo\x05""nngoo\x04""nnga\x05""nngaa\x03""sso\x02""ac\x03""ear\x03""ior\x02""17\x02""18\x02""19\x08""boundary\x03""ang\x03""zra\x04""todo\x04""sibe\x06""manchu\x02""uk\x03""uuv\x02""ry\x03""ryy\x02""ly\x03""lyy\x02""ua\x02""kr\x03""yan\x09""mukphreng\x09""kemphreng\x04""sa-i\x04""tsha\x02""eh\x03""aue\x05""tone-\x03""kva\x03""xva\x05""vowel\x03""aay\x02""uy\x03""oay\x03""uey\x02""iy\x05""final\x03""lae\x04""laev\x04""ngka\x03""mpa\x03""nra\x04""nyca\x03""ulu\x05""cecek\x06""surang\x05""bisah\x05""akara\x05""ikara\x05""ukara\x05""ekara\x06""aikara\x05""okara\x07""rerekan\x06""tedung\x04""suku\x06""taling\x05""pepet\x04""khot\x04""tzir\x02""ef\x03""zal\x06""asyura\x08""panyecek\x09""panglayar\x09""pangwisad\x09""pamingkal\x08""panyakra\x07""panyiku\x08""panghulu\x07""panyuku\x0a""panaelaeng\x08""panolong\x07""pamepet\x0a""paneuleung\x07""pamaaeh\x03""sya\x03""kla\x03""gla\x03""pla\x03""fla\x03""bla\x03""mla\x03""hla\x07""nyin-do\x04""kang\x03""ran\x02""at\x02""ag\x02""al\x03""aak\x03""aaj\x03""aam\x03""aaw\x02""is\x02""ih\x03""iny\x02""ir\x02""uc\x02""ud\x03""unn\x02""ep\x03""edd\x03""err\x03""ott\x02""ob\x02""ov\x02""oh\x07""capital\x04""open\x08""sideways\x03""top\x06""bottom\x06""voiced\x06""turned\x05""alpha\x05""schwa\x03""eng\x04""beta\x05""greek\x05""delta\x05""gamma\x03""rho\x08""cyrillic\x07""insular\x04""iota\x07""upsilon\x03""esh\x03""ezh\x03""eth\x08""reversed\x07""dotless\x06""script\x06""barred\x05""theta\x09""flattened\x02""av\x02""zr\x02""jy\x02"" 3\x04"" 333\x02""cy\x0c""middle-welsh\x07""epsilon\x03""eta\x07""omicron\x05""omega\x03"" ha\x03"" ga\x03"" zi\x04"" pai\x05"" yong\x05"" bing\x03""tie\x02""et\x03"" xi\x06"" zheng\x06"" chong\x05"" ping\x05"" shan\x06""shapes\x05"" xian\x04"" qia\x05"" jiao\x04"" jue\x04"" hui\x03"" li\x03"" mo\x04"" jin\x05"" zhuo\x04"" shu\x03"" ji\x03"" lu\x03"" le\x04"" you\x04"" sui\x04"" lan\x05"" peng\x03"" bi\x04"" nen\x04"" xia\x04"" zao\x03"" ti\x04"" jie\x04"" nao\x04"" shi\x04"" hua\x05"" lian\x05"" jian\x05"" beng\x06"" jiang\x05"" xing\x04"" bie\x04"" zai\x05"" chou\x04"" sou\x05"" niao\x04"" die\x06"" huang\x04"" dun\x03"" yi\x04""0x22\x02""--\x02""00\x02""pp\x03""ecu\x02""cl\x02""cr\x02""ff\x03""mil\x03""pts\x02""dr\x03"" 13\x03"" 23\x03"" 15\x03"" 25\x03"" 35\x03"" 45\x03"" 16\x03"" 56\x03"" 18\x03"" 38\x03"" 58\x03"" 78\x03""iii\x02""iv\x03""vii\x04""viii\x02""ix\x03""xii\x04"" xie\x04"" lei\x04"" gai\x05"" juan\x05""above\x04"" qiu\x05"" ding\x04"" que\x03""and\x03"" ao\x04"" mei\x03"" ge\x04""with\x03"" qu\x04"" hou\x03""azu\x04""buky\x04""vede\x07""glagoli\x05""dobro\x05""yestu\x07""zhivete\x05""dzelo\x06""zemlja\x04""izhe\x07""initial\x06""djervi\x04""kako\x07""ljudije\x07""myslite\x05""nashi\x03""onu\x06""pokoji\x05""ritsi\x05""slovo\x06""tvrido\x03""uku\x05""fritu\x04""heru\x03""otu\x04""shta\x06""chrivi\x04""yeru\x04""yeri\x04""yati\x07""spidery\x03""yus\x07""iotated\x03""big\x04""fita\x07""izhitsa\x07""shtapic\x0a""trokutasti\x08""latinate\x04""half\x08""tailless\x04""alfa\x04""vida\x05""dalda\x03""eie\x03""sou\x04""zata\x04""hate\x06""thethe\x05""iauda\x04""kapa\x05""laula\x03""ksi\x04""sima\x03""tau\x03""psi\x03""oou\x09""dialect-p\x03""old\x0d""cryptogrammic\x07""crossed\x08""akhmimic\x08""l-shaped\x03""yab\x04""yabh\x03""yag\x05""yaghh\x06""berber\x03""yaj\x03""yad\x04""yadh\x04""yadd\x05""yaddh\x03""yey\x03""yaf\x03""yak\x06""tuareg\x05""yakhh\x03""yah\x04""yahh\x04""yakh\x03""yaq\x04""yazh\x07""ahaggar\x03""yal\x03""yam\x03""yap\x04""yarr\x04""yagh\x04""ayer\x03""yas\x04""yass\x04""yash\x03""yat\x04""yath\x04""yach\x04""yatt\x03""yav\x03""yaw\x03""yay\x03""yaz\x0a""tawellemet\x04""yazz\x0d""labialization\x03""loa\x03""moa\x03""roa\x03""soa\x04""shoa\x03""boa\x03""toa\x03""coa\x03""noa\x04""nyoa\x03""zoa\x03""doa\x04""ddoa\x03""joa\x04""thoa\x04""choa\x04""phoa\x03""poa\x04""ggwa\x04""ggwi\x05""ggwee\x04""ggwe\x03""ssu\x03""ssi\x04""ssaa\x04""ssee\x03""sse\x03""cca\x03""ccu\x03""cci\x04""ccaa\x04""ccee\x03""cce\x03""cco\x03""zza\x03""zzu\x03""zzi\x04""zzaa\x04""zzee\x03""zze\x03""zzo\x04""ccha\x04""cchu\x04""cchi\x05""cchaa\x05""cchee\x04""cche\x04""ccho\x03""qya\x03""qyu\x03""qyi\x04""qyaa\x04""qyee\x03""qye\x03""qyo\x03""kya\x03""kyu\x03""kyi\x04""kyaa\x04""kyee\x03""kye\x03""kyo\x03""xya\x03""xyu\x03""xyi\x04""xyaa\x04""xyee\x03""xye\x03""xyo\x03""gya\x03""gyu\x03""gyi\x04""gyaa\x04""gyee\x03""gye\x03""gyo\x02""er\x02""es\x05""shcha\x05""es-te\x05""djerv\x09""monograph\x08""iotified\x06""little\x04""full\x08""surround\x08""overlaid\x02""gn\x06""kiyeok\x0b""ssangkiyeok\x0b""kiyeok-sios\x05""nieun\x0b""nieun-cieuc\x0b""nieun-hieuh\x06""tikeut\x0b""ssangtikeut\x05""rieul\x0c""rieul-kiyeok\x0b""rieul-mieum\x0b""rieul-pieup\x0a""rieul-sios\x0d""rieul-thieuth\x0d""rieul-phieuph\x0b""rieul-hieuh\x05""mieum\x05""pieup\x0a""ssangpieup\x0a""pieup-sios\x04""sios\x09""ssangsios\x05""ieung\x05""cieuc\x0a""ssangcieuc\x07""chieuch\x07""khieukh\x07""thieuth\x07""phieuph\x05""hieuh\x0a""ssangnieun\x10""rieul-pieup-sios\x0d""rieul-pansios\x11""rieul-yeorinhieuh\x0b""mieum-pieup\x0a""mieum-sios\x0d""mieum-pansios\x0d""kapyeounmieum\x0c""pieup-kiyeok\x0c""pieup-tikeut\x11""pieup-sios-kiyeok\x11""pieup-sios-tikeut\x0b""pieup-cieuc\x0d""pieup-thieuth\x0d""kapyeounpieup\x12""kapyeounssangpieup\x0b""sios-kiyeok\x0a""sios-nieun\x0b""sios-tikeut\x0a""sios-pieup\x0a""sios-cieuc\x07""pansios\x0a""ssangieung\x08""yesieung\x0d""yesieung-sios\x10""yesieung-pansios\x0f""kapyeounphieuph\x0a""ssanghieuh\x06""araeae\x03""enn\x03""onn\x03""ann\x03""inn\x02""im\x03""ngg\x04""ainn\x04""aunn\x03""ong\x04""innn\x05""ojeon\x06""chamko\x05""jueui\x02""d7\x03""d17\x03""d27\x04""d127\x03""d37\x04""d137\x04""d237\x05""d1237\x03""d47\x04""d147\x04""d247\x05""d1247\x04""d347\x05""d1347\x05""d2347\x06""d12347\x03""d57\x04""d157\x04""d257\x05""d1257\x04""d357\x05""d1357\x05""d2357\x06""d12357\x04""d457\x05""d1457\x05""d2457\x06""d12457\x05""d3457\x06""d13457\x06""d23457\x07""d123457\x03""d67\x04""d167\x04""d267\x05""d1267\x04""d367\x05""d1367\x05""d2367\x06""d12367\x04""d467\x05""d1467\x05""d2467\x06""d12467\x05""d3467\x06""d13467\x06""d23467\x07""d123467\x04""d567\x05""d1567\x05""d2567\x06""d12567\x05""d3567\x06""d13567\x06""d23567\x07""d123567\x05""d4567\x06""d14567\x06""d24567\x07""d124567\x06""d34567\x07""d134567\x07""d234567\x08""d1234567\x02""d8\x03""d18\x03""d28\x04""d128\x03""d38\x04""d138\x04""d238\x05""d1238\x03""d48\x04""d148\x04""d248\x05""d1248\x04""d348\x05""d1348\x05""d2348\x06""d12348\x03""d58\x04""d158\x04""d258\x05""d1258\x04""d358\x05""d1358\x05""d2358\x06""d12358\x04""d458\x05""d1458\x05""d2458\x06""d12458\x05""d3458\x06""d13458\x06""d23458\x07""d123458\x03""d68\x04""d168\x04""d268\x05""d1268\x04""d368\x05""d1368\x05""d2368\x06""d12368\x04""d468\x05""d1468\x05""d2468\x06""d12468\x05""d3468\x06""d13468\x06""d23468\x07""d123468\x04""d568\x05""d1568\x05""d2568\x06""d12568\x05""d3568\x06""d13568\x06""d23568\x07""d123568\x05""d4568\x06""d14568\x06""d24568\x07""d124568\x06""d34568\x07""d134568\x07""d234568\x08""d1234568\x03""d78\x04""d178\x04""d278\x05""d1278\x04""d378\x05""d1378\x05""d2378\x06""d12378\x04""d478\x05""d1478\x05""d2478\x06""d12478\x05""d3478\x06""d13478\x06""d23478\x07""d123478\x04""d578\x05""d1578\x05""d2578\x06""d12578\x05""d3578\x06""d13578\x06""d23578\x07""d123578\x05""d4578\x06""d14578\x06""d24578\x07""d124578\x06""d34578\x07""d134578\x07""d234578\x08""d1234578\x04""d678\x05""d1678\x05""d2678\x06""d12678\x05""d3678\x06""d13678\x06""d23678\x07""d123678\x05""d4678\x06""d14678\x06""d24678\x07""d124678\x06""d34678\x07""d134678\x07""d234678\x08""d1234678\x05""d5678\x06""d15678\x06""d25678\x07""d125678\x06""d35678\x07""d135678\x07""d235678\x08""d1235678\x06""d45678\x07""d145678\x07""d245678\x08""d1245678\x07""d345678\x08""d1345678\x08""d2345678\x09""d12345678\x05"" tian\x04"" kua\x03"" wu\x04"" yin\x03"" si\x03"" ye\x04"" nuo\x03"" xu\x06"" xiong\x04"" liu\x04"" lin\x06"" xiang\x04"" xin\x05"" zhen\x04"" dai\x04"" pan\x03"" ma\x05"" qian\x06"" zhong\x02"" n\x06"" cheng\x05"" fang\x04"" zuo\x05"" zhou\x05"" dong\x03"" su\x06"" jiong\x05"" wang\x04"" zhu\x05"" long\x05"" ying\x05"" miao\x03"" yu\x04"" luo\x05"" chai\x04"" hun\x04"" rao\x04"" han\x04"" tai\x03"" ai\x04"" jun\x02"" l\x05"" tang\x05"" xiao\x05"" tiao\x04"" zha\x03"" ku\x03"" er\x05"" nang\x03"" qi\x04"" chi\x03"" mu\x03"" se\x06"" qiong\x03"" sa\x03"" pu\x03"" ta\x03"" ou\x05"" mian\x04"" wen\x05"" diao\x04"" mie\x04"" she\x05"" quan\x04"" cai\x06"" liang\x03"" gu\x04"" mao\x04"" gua\x04"" man\x04"" kou\x05"" chui\x05"" huan\x05"" gong\x04"" nan\x05"" dian\x03"" fu\x04"" yan\x03"" ci\x05"" lang\x03"" he\x04"" tou\x05"" pian\x02"" e\x04"" qie\x04"" rui\x05"" chan\x04"" dan\x04"" duo\x04"" fei\x04"" chu\x05"" bang\x03"" ba\x05"" kuai\x05"" shen\x03"" pi\x05"" yang\x04"" bei\x04"" che\x05"" suan\x05"" heng\x04"" gui\x04"" lou\x04"" sun\x04"" yao\x04"" zou\x04"" zhi\x04"" jia\x03"" hu\x03"" la\x03"" ke\x05"" jing\x04"" wei\x05"" zhao\x04"" kui\x04"" fan\x06"" zhang\x05"" song\x04"" nei\x05"" chen\x04"" guo\x03"" ng\x03"" fa\x04"" hao\x04"" pou\x05"" hong\x04"" tun\x03"" bo\x04"" nie\x04"" wai\x05"" shou\x05"" ling\x04"" lun\x04"" xue\x04"" fen\x05"" chun\x04"" rou\x03"" ze\x06"" sheng\x04"" bai\x04"" gou\x03"" na\x04"" xiu\x03"" cu\x04"" kuo\x04"" lao\x04"" huo\x04"" sai\x05"" rong\x03"" ju\x04"" pao\x04"" can\x05"" nian\x05"" weng\x05"" xuan\x04"" qin\x03"" bu\x05"" zang\x05"" mang\x04"" dui\x04"" bao\x06"" chang\x04"" gun\x05"" liao\x03"" da\x05"" meng\x05"" qiao\x05"" rang\x04"" yun\x04"" gao\x04"" tao\x04"" lai\x04"" ban\x05"" chuo\x03"" nu\x04"" ran\x04"" sha\x04"" dou\x03"" po\x05"" tong\x06"" qiang\x04"" sao\x04"" cha\x04"" xun\x03"" mi\x05"" pang\x04"" cao\x03"" an\x04"" mai\x04"" yue\x05"" huai\x04"" wan\x04"" zan\x04"" hai\x05"" luan\x05"" ning\x03"" ya\x05"" ming\x04"" zui\x04"" cui\x03"" de\x05"" bian\x04"" nou\x04"" tui\x04"" zhe\x05"" zhan\x04"" cen\x04"" min\x03"" zu\x03"" ni\x04"" cuo\x04"" tuo\x04"" pei\x05"" gang\x05"" yuan\x05"" biao\x04"" dao\x04"" jiu\x04"" run\x03"" wo\x05"" cuan\x04"" ren\x04"" kai\x04"" men\x07"" chuang\x05"" feng\x05"" zhai\x03"" di\x04"" ben\x05"" zong\x05"" ceng\x05"" hang\x04"" nin\x05"" kong\x04"" lie\x06"" kuang\x04"" san\x03"" te\x05"" shun\x03"" ce\x04"" ang\x03"" ru\x07"" shuang\x05"" guai\x03"" wa\x05"" shai\x05"" tuan\x05"" piao\x04"" kun\x04"" qun\x06"" chuai\x05"" shao\x04"" suo\x05"" duan\x04"" gen\x06"" guang\x04"" cou\x05"" nuan\x05"" reng\x04"" mou\x03"" tu\x04"" nai\x05"" guan\x04"" hen\x06"" chuan\x05"" kuan\x05"" qing\x04"" pin\x05"" kang\x03"" du\x05"" neng\x04"" tan\x05"" cang\x05"" chao\x05"" nong\x04"" kan\x04"" ken\x05"" ting\x04"" gan\x04"" niu\x05"" ruan\x05"" cong\x05"" zeng\x05"" shui\x05"" geng\x05"" shuo\x05"" zuan\x05"" zhui\x03"" en\x05"" leng\x06"" zhuan\x04"" cun\x03"" ne\x04"" bin\x04"" ruo\x04"" kao\x05"" dang\x05"" teng\x03"" ri\x05"" deng\x03"" za\x06"" niang\x03"" ca\x05"" sang\x05"" keng\x06"" shuai\x04"" pie\x04"" tie\x06"" shuan\x05"" chua\x04"" zen\x06"" shang\x03"" pa\x04"" fou\x04"" diu\x03"" fo\x04"" lon\x03"" ka\x04"" lia\x04"" zun\x05"" seng\x05"" zhun\x06"" zhuen\x03""jis\x02"" 1\x02"" 2\x02"" 4\x02"" 5\x02"" 6\x02"" 7\x02"" 8\x02"" 9\x03"" 10\x04"" kis\x02""1m\x02""2m\x02""3m\x02""4m\x02""5m\x02""6m\x02""7m\x02""8m\x02""9m\x03""10m\x03""11m\x03""12m\x09""apartment\x06""ampere\x03""are\x06""inning\x04""inch\x03""won\x06""escudo\x04""acre\x05""ounce\x03""ohm\x06""kai-ri\x05""carat\x07""calorie\x06""gallon\x04""giga\x06""guinea\x05""curie\x07""guilder\x04""kilo\x08""kilogram\x09""kilometer\x08""kilowatt\x04""gram\x07""gramton\x08""cruzeiro\x05""krone\x04""case\x06""koruna\x05""co-op\x05""cycle\x07""centime\x08""shilling\x05""centi\x04""cent\x05""dozen\x04""desi\x06""dollar\x03""ton\x04""nano\x04""knot\x07""heights\x07""percent\x05""parts\x06""barrel\x07""piaster\x05""picul\x04""pico\x08""building\x05""farad\x04""feet\x06""bushel\x05""franc\x07""hectare\x04""peso\x07""pfennig\x05""hertz\x05""pence\x04""page\x05""point\x04""volt\x03""hon\x05""pound\x04""hall\x04""horn\x05""micro\x04""mile\x04""mach\x04""mark\x07""mansion\x06""micron\x05""milli\x08""millibar\x04""mega\x07""megaton\x05""meter\x04""yard\x04""yuan\x05""liter\x04""lira\x05""rupee\x05""ruble\x03""rem\x08""roentgen\x04""watt\x02""0h\x02""1h\x02""2h\x02""3h\x02""4h\x02""5h\x02""6h\x02""7h\x02""8h\x02""9h\x03""10h\x03""11h\x03""12h\x03""13h\x03""14h\x03""15h\x03""16h\x03""17h\x03""18h\x03""19h\x03""20h\x03""21h\x03""22h\x03""23h\x03""24h\x03""hpa\x03""bar\x02""pc\x06""heisei\x06""syouwa\x07""taisyou\x05""meiji\x03""inc\x08""microamp\x02""kb\x02""gb\x03""cal\x04""kcal\x02""pf\x02""nf\x0a""microfarad\x09""microgram\x02""kg\x02""hz\x03""khz\x03""mhz\x03""ghz\x03""thz\x0a""microliter\x02""dl\x02""kl\x02""fm\x02""nm\x0a""micrometer\x02""mm\x02""cm\x02""km\x03""mm2\x03""cm2\x02""m2\x03""km2\x03""mm4\x03""cm3\x02""m3\x03""km3\x03""ms2\x03""kpa\x03""gpa\x03""rad\x04""rads\x05""rads2\x0b""microsecond\x02""pv\x09""microvolt\x02""mv\x02""kv\x02""pw\x02""nw\x09""microwatt\x02""mw\x04""kohm\x04""mohm\x02""bq\x02""cc\x02""cd\x03""ckg\x02""gy\x02""hp\x02""kt\x03""log\x02""lx\x03""mol\x02""pm\x03""ppm\x02""pr\x02""wb\x02""1d\x02""2d\x02""3d\x02""4d\x02""5d\x02""6d\x02""7d\x02""8d\x02""9d\x03""10d\x03""11d\x03""12d\x03""13d\x03""14d\x03""15d\x03""16d\x03""17d\x03""18d\x03""19d\x03""20d\x03""21d\x03""22d\x03""23d\x03""24d\x03""25d\x03""26d\x03""27d\x03""28d\x03""29d\x03""30d\x03""31d\x07"" zhuang\x03"" re\x04"" zei\x02"" t\x05"" zhua\x06"" zhuai\x04"" sen\x04"" pen\x04"" hei\x06"" shime\x04"" hal\x05"" twul\x04"" kel\x03"" ol\x04"" cal\x04"" sol\x03"" el\x05"" cwul\x04"" sya\x03"" ko\x06"" ppwun\x04"" lam\x05"" tako\x04"" mok\x05"" shua\x05"" mwun\x04"" nay\x03"" uk\x02"" a\x02"" m\x04"" gem\x04"" tha\x06"" sasou\x03"" yo\x04"" mal\x04"" kes\x05"" phos\x04"" cis\x04"" dia\x05"" saai\x04"" sin\x05"" haai\x03"" so\x04"" lue\x04"" iri\x07"" akutsu\x05"" yama\x04"" tay\x05"" gake\x05"" gomi\x06"" pyeng\x07"" toride\x04"" ama\x04"" sho\x05"" mama\x04"" ten\x04"" cay\x04"" uys\x04"" kwu\x04"" hwa\x04"" bou\x05"" kaka\x05"" nata\x05"" yuri\x04"" cem\x05"" kura\x0a"" yamashina\x09"" kewashii\x04"" kek\x04"" pwu\x05"" phas\x07"" tazuna\x04"" koc\x04"" sei\x05"" nagi\x08"" koraeru\x03"" ki\x02"" s\x05"" kyuu\x07"" hameru\x08"" mushiru\x05"" haba\x04"" mye\x03"" es\x03"" hi\x05"" yian\x07"" noboru\x06"" eburi\x05"" moku\x05"" soma\x06"" tochi\x05"" sugi\x05"" waku\x05"" haze\x06"" matsu\x04"" hoy\x06"" sayng\x06"" kasei\x05"" masu\x07"" fumoto\x08"" shikimi\x07"" kunugi\x07"" momiji\x05"" soko\x06"" shide\x06"" myeng\x05"" tafu\x06"" hazou\x08"" katsura\x05"" muro\x07"" sakaki\x06"" hashi\x06"" kashi\x04"" ori\x07"" hokuso\x05"" tara\x05"" zusa\x05"" nude\x05"" toan\x05"" tamo\x04"" kwi\x03"" em\x06"" tsuki\x08"" tsukusu\x0a"" shitamizu\x07"" tsuchi\x05"" niou\x04"" pal\x07"" shibui\x05"" tani\x05"" suei\x05"" qiou\x06"" ratsu\x04"" yie\x04"" oki\x05"" hama\x05"" boku\x06"" hyeng\x08"" oozutsu\x06"" tatsu\x05"" nung\x0d"" tsumekanmuri\x08"" ushihen\x07"" ikenie\x05"" kari\x04"" swu\x04"" ton\x03"" ei\x08"" chiisai\x05"" xiou\x0b"" dekaguramu\x0c"" deshiguramu\x0b"" miriguramu\x05"" thon\x0b"" hekutogura\x07"" sarake\x0b"" senchigura\x04"" tap\x05"" kesa\x07"" tatamu\x04"" nue\x06"" zhung\x06"" shaku\x04"" yai\x08"" aragane\x05"" iong\x05"" kaki\x05"" seki\x07"" utsubo\x04"" sey\x06"" souke\x05"" kago\x04"" sik\x07"" sasara\x05"" yana\x05"" hata\x05"" kuji\x08"" shinshi\x05"" kume\x09"" nukamiso\x03"" ro\x07"" sukumo\x06"" kouji\x05"" kinu\x05"" wata\x04"" gei\x04"" sok\x05"" kase\x06"" yingl\x07"" kasuri\x05"" nawa\x07"" odoshi\x05"" horo\x04"" sem\x05"" jung\x03"" un\x08"" kaakeru\x09"" yashinau\x08"" shikato\x0a"" tsuraneru\x03""een\x04""ween\x04""bhee\x04""mbee\x04""kpee\x05""mgbee\x04""gbee\x04""dhee\x05""dhhee\x04""ndee\x04""njee\x05""nggee\x03""hin\x03""win\x03""bhi\x03""mbi\x03""kpi\x04""mgbi\x03""gbi\x03""dhi\x04""dhhi\x03""ndi\x03""nji\x04""nggi\x04""ngan\x03""han\x03""wan\x03""mba\x04""kpan\x04""mgba\x04""dhha\x03""nda\x03""nja\x04""ngga\x03""oon\x04""woon\x04""bhoo\x03""boo\x04""mboo\x04""kpoo\x05""mgboo\x04""gboo\x03""voo\x04""dhoo\x05""dhhoo\x03""doo\x04""ndoo\x03""zoo\x04""zhoo\x03""joo\x04""njoo\x05""nggoo\x03""goo\x04""nyoo\x03""hun\x03""wun\x03""bhu\x03""mbu\x03""kpu\x04""mgbu\x03""gbu\x03""dhu\x04""dhhu\x03""ndu\x03""nju\x04""nggu\x04""ngon\x03""bho\x03""mbo\x03""kpo\x04""mgbo\x03""gbo\x04""gbon\x03""dho\x04""dhho\x03""ndo\x03""njo\x04""nggo\x04""ngen\x03""hen\x03""wen\x03""bhe\x03""mbe\x03""kpe\x04""kpen\x04""mgbe\x03""gbe\x04""gben\x03""dhe\x04""dhhe\x03""nde\x04""ngge\x05""nggen\x03""gen\x0a""lengthener\x05""ndole\x06""zemlya\x05""broad\x07""neutral\x06""closed\x07""blended\x04""soft\x09""monocular\x09""binocular\x06""double\x0b""multiocular\x03""dwe\x04""dzwe\x04""zhwe\x04""dzze\x04""tswe\x04""tsse\x04""tche\x07""chinese\x06""dotted\x09""left-stem\x05""lower\x08""inverted\x06""stress\x0d""egyptological\x04""heng\x02""tz\x08""tresillo\x09""cuatrillo\x06""broken\x03""rum\x02""vy\x0a""visigothic\x05""thorn\x04""vend\x03""con\x02""us\x03""dum\x03""lum\x03""mum\x03""num\x03""tum\x02""um\x0a""circumflex\x05""colon\x06""equals\x08""saltillo\x08""dvisvara\x07""hasanta\x03""jho\x04""ddho\x03""rro\x09""alternate\x09""voiceless\x09""aspirated\x05""haaru\x03""hta\x04""shya\x04""nyja\x02""ea\x04""ngue\x04""chha\x04""nhue\x03""nha\x04""nhja\x03""nue\x03""ppa\x03""mue\x0b"" obiyaakasu\x04"" noy\x07"" yadoru\x07"" hesaki\x05"" sori\x07"" yofune\x05"" susa\x06"" usagi\x04"" nuc\x0b"" kutabireru\x05"" yaji\x07"" sonoko\x04"" hie\x05"" hagi\x04"" ebi\x09"" kamakiri\x0a"" kamishimo\x05"" yuki\x04"" ena\x06"" hitoe\x08"" chihaya\x07"" tasuki\x08"" yasashi\x04"" miu\x07"" segare\x06"" nerau\x07"" utsuke\x09"" shitsuke\x07"" yagate\x07"" suberu\x04"" sip\x03"" ip\x07"" totemo\x04"" kep\x05"" sako\x07"" appare\x06"" otoko\x0b"" sakenomoto\x09"" ishiyumi\x07"" habaki\x06"" irori\x06"" ngaak\x05"" diou\x08"" kasugai\x07"" kazari\x05"" yari\x05"" yuru\x07"" phwung\x05"" tomo\x07"" kohaze\x03"" on\x07"" oroshi\x05"" shuu\x04"" eri\x07"" namazu\x05"" todo\x07"" kajika\x05"" bora\x05"" mate\x05"" gori\x05"" ugui\x06"" asari\x0a"" subashiri\x09"" kazunoko\x07"" shachi\x06"" dojou\x08"" sukesou\x08"" muroaji\x07"" haraka\x02"" z\x09"" hatahata\x04"" eso\x05"" kyou\x07"" shiira\x06"" mutsu\x04"" nio\x05"" yiao\x06"" shigi\x08"" chidori\x05"" toki\x08"" ikaruga\x07"" kakesu\x06"" isuka\x0c"" kikuitadaki\x08"" tsugumi\x04""jjog\x04""jjon\x04""jjol\x04""jjom\x04""jjob\x04""jjos\x05""jjong\x04""jjoc\x04""jjwa\x05""jjwag\x05""jjwal\x06""jjwass\x05""jjwae\x02""it\x02""ip\x03""iet\x03""iex\x03""iep\x02""ax\x02""ap\x03""uox\x02""uo\x03""uop\x02""ox\x02""op\x02""ex\x03""bit\x03""bix\x03""bip\x04""biet\x04""biex\x03""bie\x04""biep\x03""bat\x03""bax\x03""bap\x04""buox\x03""buo\x04""buop\x03""bot\x03""box\x03""bop\x03""bex\x03""bep\x03""but\x03""bux\x03""bup\x04""burx\x03""bur\x03""byt\x03""byx\x02""by\x03""byp\x04""byrx\x03""byr\x03""pit\x03""pix\x03""pip\x04""piex\x03""pie\x04""piep\x03""pat\x03""pax\x03""pap\x04""puox\x03""puo\x04""puop\x03""pot\x03""pox\x03""pop\x03""put\x03""pux\x03""pup\x04""purx\x03""pur\x03""pyt\x03""pyx\x02""py\x03""pyp\x04""pyrx\x03""pyr\x04""bbit\x04""bbix\x03""bbi\x04""bbip\x05""bbiet\x05""bbiex\x04""bbie\x05""bbiep\x04""bbat\x04""bbax\x04""bbap\x05""bbuox\x04""bbuo\x05""bbuop\x04""bbot\x04""bbox\x03""bbo\x04""bbop\x04""bbex\x03""bbe\x04""bbep\x04""bbut\x04""bbux\x03""bbu\x04""bbup\x05""bburx\x04""bbur\x04""bbyt\x04""bbyx\x03""bby\x04""bbyp\x04""nbit\x04""nbix\x03""nbi\x04""nbip\x05""nbiex\x04""nbie\x05""nbiep\x04""nbat\x04""nbax\x03""nba\x04""nbap\x04""nbot\x04""nbox\x03""nbo\x04""nbop\x04""nbut\x04""nbux\x03""nbu\x04""nbup\x05""nburx\x04""nbur\x04""nbyt\x04""nbyx\x03""nby\x04""nbyp\x05""nbyrx\x04""nbyr\x04""hmit\x04""hmix\x03""hmi\x04""hmip\x05""hmiex\x04""hmie\x05""hmiep\x04""hmat\x04""hmax\x03""hma\x04""hmap\x05""hmuox\x04""hmuo\x05""hmuop\x04""hmot\x04""hmox\x03""hmo\x04""hmop\x04""hmut\x04""hmux\x03""hmu\x04""hmup\x05""hmurx\x04""hmur\x04""hmyx\x03""hmy\x04""hmyp\x05""hmyrx\x04""hmyr\x03""mit\x03""mix\x03""mip\x04""miex\x03""mie\x04""miep\x03""mat\x03""max\x03""map\x04""muot\x04""muox\x03""muo\x04""muop\x03""mot\x03""mox\x03""mop\x03""mex\x03""mut\x03""mux\x03""mup\x04""murx\x03""mur\x03""myt\x03""myx\x02""my\x03""myp\x03""fit\x03""fix\x03""fip\x03""fat\x03""fax\x03""fap\x03""fox\x03""fop\x03""fut\x03""fux\x03""fup\x04""furx\x03""fur\x03""fyt\x03""fyx\x02""fy\x03""fyp\x03""vit\x03""vix\x03""vip\x04""viet\x04""viex\x03""vie\x04""viep\x03""vat\x03""vax\x03""vap\x03""vot\x03""vox\x03""vop\x03""vex\x03""vep\x03""vut\x03""vux\x03""vup\x04""vurx\x03""vur\x03""vyt\x03""vyx\x03""vyp\x04""vyrx\x03""vyr\x03""dit\x03""dix\x03""dip\x04""diex\x03""die\x04""diep\x03""dat\x03""dax\x03""dap\x04""duox\x03""duo\x03""dox\x03""dop\x03""dex\x03""dep\x03""dut\x03""dux\x03""dup\x04""durx\x03""dur\x03""tit\x03""tix\x03""tip\x04""tiex\x04""tiep\x03""tat\x03""tax\x03""tap\x04""tuot\x04""tuox\x03""tuo\x04""tuop\x03""tot\x03""tox\x03""tex\x03""tep\x03""tut\x03""tux\x03""tup\x04""turx\x03""tur\x04""ddit\x04""ddix\x04""ddip\x05""ddiex\x04""ddie\x05""ddiep\x04""ddat\x04""ddax\x04""ddap\x05""dduox\x04""dduo\x05""dduop\x04""ddot\x04""ddox\x04""ddop\x04""ddex\x04""ddep\x04""ddut\x04""ddux\x04""ddup\x05""ddurx\x04""ddur\x04""ndit\x04""ndix\x04""ndip\x05""ndiex\x04""ndie\x04""ndat\x04""ndax\x04""ndap\x04""ndot\x04""ndox\x04""ndop\x04""ndex\x04""ndep\x04""ndut\x04""ndux\x04""ndup\x05""ndurx\x04""ndur\x04""hnit\x04""hnix\x03""hni\x04""hnip\x05""hniet\x05""hniex\x04""hnie\x05""hniep\x04""hnat\x04""hnax\x04""hnap\x05""hnuox\x04""hnuo\x04""hnot\x04""hnox\x04""hnop\x04""hnex\x03""hne\x04""hnep\x04""hnut\x03""nit\x03""nix\x03""nip\x04""niex\x03""nie\x04""niep\x03""nax\x03""nap\x04""nuox\x03""nuo\x04""nuop\x03""not\x03""nox\x03""nop\x03""nex\x03""nep\x03""nut\x03""nux\x03""nup\x04""nurx\x03""nur\x04""hlit\x04""hlix\x03""hli\x04""hlip\x05""hliex\x04""hlie\x05""hliep\x04""hlat\x04""hlax\x04""hlap\x05""hluox\x04""hluo\x05""hluop\x04""hlox\x03""hlo\x04""hlop\x04""hlex\x03""hle\x04""hlep\x04""hlut\x04""hlux\x03""hlu\x04""hlup\x05""hlurx\x04""hlur\x04""hlyt\x04""hlyx\x03""hly\x04""hlyp\x05""hlyrx\x04""hlyr\x03""lit\x03""lix\x03""lip\x04""liet\x04""liex\x03""lie\x04""liep\x03""lat\x03""lax\x03""lap\x04""luot\x04""luox\x03""luo\x04""luop\x03""lot\x03""lox\x03""lop\x03""lex\x03""lep\x03""lut\x03""lux\x03""lup\x04""lurx\x03""lur\x03""lyt\x03""lyx\x03""lyp\x04""lyrx\x03""lyr\x03""git\x03""gix\x03""gip\x04""giet\x04""giex\x03""gie\x04""giep\x03""gat\x03""gax\x03""gap\x04""guot\x04""guox\x03""guo\x04""guop\x03""got\x03""gox\x03""gop\x03""get\x03""gex\x03""gep\x03""gut\x03""gux\x03""gup\x04""gurx\x03""gur\x03""kit\x03""kix\x03""kip\x04""kiex\x03""kie\x04""kiep\x03""kat\x03""kax\x03""kap\x04""kuox\x03""kuo\x04""kuop\x03""kot\x03""kox\x03""kop\x03""ket\x03""kex\x03""kep\x03""kut\x03""kux\x03""kup\x04""kurx\x03""kur\x04""ggit\x04""ggix\x05""ggiex\x04""ggie\x05""ggiep\x04""ggat\x04""ggax\x04""ggap\x05""gguot\x05""gguox\x04""gguo\x05""gguop\x04""ggot\x04""ggox\x04""ggop\x04""gget\x04""ggex\x04""ggep\x04""ggut\x04""ggux\x04""ggup\x05""ggurx\x04""ggur\x05""mgiex\x04""mgie\x04""mgat\x04""mgax\x03""mga\x04""mgap\x05""mguox\x04""mguo\x05""mguop\x04""mgot\x04""mgox\x03""mgo\x04""mgop\x04""mgex\x03""mge\x04""mgep\x04""mgut\x04""mgux\x03""mgu\x04""mgup\x05""mgurx\x04""mgur\x04""hxit\x04""hxix\x03""hxi\x04""hxip\x05""hxiet\x05""hxiex\x04""hxie\x05""hxiep\x04""hxat\x04""hxax\x03""hxa\x04""hxap\x05""hxuot\x05""hxuox\x04""hxuo\x05""hxuop\x04""hxot\x04""hxox\x03""hxo\x04""hxop\x04""hxex\x03""hxe\x04""hxep\x05""ngiex\x04""ngie\x05""ngiep\x04""ngat\x04""ngax\x04""ngap\x05""nguot\x05""nguox\x04""nguo\x04""ngot\x04""ngox\x04""ngop\x04""ngex\x03""nge\x04""ngep\x03""hit\x04""hiex\x03""hat\x03""hax\x03""hap\x04""huot\x04""huox\x03""huo\x04""huop\x03""hot\x03""hox\x03""hop\x03""hex\x03""hep\x03""wat\x03""wax\x03""wap\x04""wuox\x03""wuo\x04""wuop\x03""wox\x03""wop\x03""wex\x03""wep\x03""zit\x03""zix\x03""zip\x04""ziex\x03""zie\x04""ziep\x03""zat\x03""zax\x03""zap\x04""zuox\x03""zuo\x04""zuop\x03""zot\x03""zox\x03""zop\x03""zex\x03""zep\x03""zut\x03""zux\x03""zup\x04""zurx\x03""zur\x03""zyt\x03""zyx\x02""zy\x03""zyp\x04""zyrx\x03""zyr\x03""cit\x03""cix\x03""cip\x04""ciet\x04""ciex\x03""cie\x04""ciep\x03""cat\x03""cax\x03""cap\x04""cuox\x03""cuo\x04""cuop\x03""cot\x03""cox\x03""cop\x03""cex\x03""cep\x03""cut\x03""cux\x03""cup\x04""curx\x03""cur\x03""cyt\x03""cyx\x03""cyp\x04""cyrx\x03""cyr\x04""zzit\x04""zzix\x04""zzip\x05""zziet\x05""zziex\x04""zzie\x05""zziep\x04""zzat\x04""zzax\x04""zzap\x04""zzox\x04""zzop\x04""zzex\x04""zzep\x04""zzux\x04""zzup\x05""zzurx\x04""zzur\x04""zzyt\x04""zzyx\x03""zzy\x04""zzyp\x05""zzyrx\x04""zzyr\x04""nzit\x04""nzix\x03""nzi\x04""nzip\x05""nziex\x04""nzie\x05""nziep\x04""nzat\x04""nzax\x03""nza\x04""nzap\x05""nzuox\x04""nzuo\x04""nzox\x04""nzop\x04""nzex\x03""nze\x04""nzux\x03""nzu\x04""nzup\x05""nzurx\x04""nzur\x04""nzyt\x04""nzyx\x03""nzy\x04""nzyp\x05""nzyrx\x04""nzyr\x03""sit\x03""six\x03""sip\x04""siex\x03""sie\x04""siep\x03""sat\x03""sax\x03""sap\x04""suox\x03""suo\x04""suop\x03""sot\x03""sox\x03""sop\x03""sex\x03""sep\x03""sut\x03""sux\x03""sup\x04""surx\x03""sur\x03""syt\x03""syx\x02""sy\x03""syp\x04""syrx\x03""syr\x04""ssit\x04""ssix\x04""ssip\x05""ssiex\x04""ssie\x05""ssiep\x04""ssat\x04""ssax\x04""ssap\x04""ssot\x04""ssox\x04""ssop\x04""ssex\x04""ssep\x04""ssut\x04""ssux\x04""ssup\x04""ssyt\x04""ssyx\x03""ssy\x04""ssyp\x05""ssyrx\x04""ssyr\x04""zhat\x04""zhax\x04""zhap\x05""zhuox\x04""zhuo\x05""zhuop\x04""zhot\x04""zhox\x04""zhop\x04""zhet\x04""zhex\x04""zhep\x04""zhut\x04""zhux\x04""zhup\x05""zhurx\x04""zhur\x04""zhyt\x04""zhyx\x03""zhy\x04""zhyp\x05""zhyrx\x04""zhyr\x04""chat\x04""chax\x04""chap\x05""chuot\x05""chuox\x04""chuo\x05""chuop\x04""chot\x04""chox\x04""chop\x04""chet\x04""chex\x04""chep\x04""chux\x04""chup\x05""churx\x04""chur\x04""chyt\x04""chyx\x03""chy\x04""chyp\x05""chyrx\x04""chyr\x04""rrax\x05""rruox\x04""rruo\x04""rrot\x04""rrox\x04""rrop\x04""rret\x04""rrex\x03""rre\x04""rrep\x04""rrut\x04""rrux\x03""rru\x04""rrup\x05""rrurx\x04""rrur\x04""rryt\x04""rryx\x03""rry\x04""rryp\x05""rryrx\x04""rryr\x04""nrat\x04""nrax\x04""nrap\x04""nrox\x03""nro\x04""nrop\x04""nret\x04""nrex\x03""nre\x04""nrep\x04""nrut\x04""nrux\x03""nru\x04""nrup\x05""nrurx\x04""nrur\x04""nryt\x04""nryx\x03""nry\x04""nryp\x05""nryrx\x04""nryr\x04""shat\x04""shax\x04""shap\x05""shuox\x04""shuo\x05""shuop\x04""shot\x04""shox\x04""shop\x04""shet\x04""shex\x04""shep\x04""shut\x04""shux\x04""shup\x05""shurx\x04""shur\x04""shyt\x04""shyx\x03""shy\x04""shyp\x05""shyrx\x04""shyr\x03""rat\x03""rax\x03""rap\x04""ruox\x03""ruo\x04""ruop\x03""rot\x03""rox\x03""rop\x03""rex\x03""rep\x03""rut\x03""rux\x03""rup\x04""rurx\x03""rur\x03""ryt\x03""ryx\x03""ryp\x04""ryrx\x03""ryr\x03""jit\x03""jix\x03""jip\x04""jiet\x04""jiex\x03""jie\x04""jiep\x04""juot\x04""juox\x03""juo\x04""juop\x03""jot\x03""jox\x03""jop\x03""jut\x03""jux\x03""jup\x04""jurx\x03""jur\x03""jyt\x03""jyx\x03""jyp\x04""jyrx\x03""jyr\x03""qit\x03""qix\x03""qip\x04""qiet\x04""qiex\x03""qie\x04""qiep\x04""quot\x04""quox\x04""quop\x03""qot\x03""qox\x03""qop\x03""qut\x03""qux\x03""qup\x04""qurx\x03""qur\x03""qyt\x03""qyx\x02""qy\x03""qyp\x04""qyrx\x03""qyr\x04""jjit\x04""jjix\x04""jjip\x05""jjiet\x05""jjiex\x04""jjie\x05""jjiep\x05""jjuox\x04""jjuo\x05""jjuop\x04""jjot\x04""jjox\x04""jjop\x04""jjut\x04""jjux\x04""jjup\x05""jjurx\x04""jjur\x04""jjyt\x04""jjyx\x03""jjy\x04""jjyp\x04""njit\x04""njix\x04""njip\x05""njiet\x05""njiex\x04""njie\x05""njiep\x05""njuox\x04""njuo\x04""njot\x04""njox\x04""njop\x04""njux\x04""njup\x05""njurx\x04""njur\x04""njyt\x04""njyx\x03""njy\x04""njyp\x05""njyrx\x04""njyr\x04""nyit\x04""nyix\x04""nyip\x05""nyiet\x05""nyiex\x04""nyie\x05""nyiep\x05""nyuox\x04""nyuo\x05""nyuop\x04""nyot\x04""nyox\x04""nyop\x04""nyut\x04""nyux\x04""nyup\x03""xit\x03""xix\x03""xip\x04""xiet\x04""xiex\x03""xie\x04""xiep\x04""xuox\x03""xuo\x03""xot\x03""xox\x03""xop\x03""xyt\x03""xyx\x02""xy\x03""xyp\x04""xyrx\x03""xyr\x03""yit\x03""yix\x03""yip\x04""yiet\x04""yiex\x03""yie\x04""yiep\x04""yuot\x04""yuox\x03""yuo\x04""yuop\x03""yot\x03""yox\x03""yop\x03""yut\x03""yux\x03""yup\x04""yurx\x03""yur\x03""yyt\x03""yyx\x03""yyp\x04""yyrx\x03""yyr\x03""kug\x03""kun\x03""kul\x03""kum\x03""kub\x03""kus\x04""kung\x04""kweo\x05""kweon\x05""kweol\x06""kweong\x05""kweng\x04""kwig\x04""kwin\x04""kwil\x04""kwim\x04""kwib\x04""kwis\x05""kwing\x04""kyun\x04""kyul\x04""kyum\x03""keu\x04""keug\x04""keun\x04""keul\x04""keum\x04""keub\x05""keung\x03""kig\x03""kin\x03""kil\x03""kim\x03""kib\x03""kis\x04""king\x03""tag\x03""tal\x04""talg\x03""tam\x03""tab\x03""tas\x04""tass\x04""tang\x03""tae\x04""taeg\x04""taen\x04""tael\x04""taem\x04""taeb\x04""taes\x05""taess\x05""taeng\x05""tyang\x03""teo\x04""teog\x04""teon\x04""teol\x05""teolm\x04""teom\x04""teob\x04""teos\x05""teoss\x05""teong\x03""teg\x03""ten\x03""tel\x03""tem\x03""teb\x03""tes\x04""teng\x04""tyeo\x05""tyeon\x06""tyeoss\x04""tyen\x03""tog\x03""tol\x03""tom\x03""tob\x03""tos\x04""tong\x04""twan\x04""twae\x03""toe\x04""toen\x04""toes\x05""toeng\x03""tug\x03""tun\x03""tul\x03""tub\x03""tus\x04""tung\x04""tweo\x06""tweoss\x04""twig\x04""twin\x04""twil\x04""twim\x04""twib\x05""twing\x03""tyu\x04""tyun\x04""tyul\x04""tyum\x05""tyung\x03""teu\x04""teug\x04""teun\x04""teud\x04""teul\x05""teulm\x04""teum\x04""teub\x04""teus\x04""tyin\x04""tyil\x04""tyim\x04""tyib\x03""tig\x03""tin\x03""til\x03""tim\x03""tib\x03""tis\x04""ting\x03""pag\x04""pagg\x03""pan\x03""pal\x04""palm\x03""pam\x03""pab\x03""pas\x04""pass\x04""pang\x03""pae\x04""paeg\x04""paen\x04""pael\x04""paem\x04""paeb\x04""paes\x05""paess\x05""paeng\x03""pya\x04""pyag\x03""peo\x04""peog\x04""peon\x04""peol\x04""peom\x04""peob\x04""peos\x05""peoss\x05""peong\x03""peg\x03""pen\x03""pel\x03""pem\x03""peb\x03""pes\x04""peng\x04""pyeo\x05""pyeon\x05""pyeol\x05""pyeom\x05""pyeob\x06""pyeoss\x06""pyeong\x03""pye\x04""pyel\x04""pyeb\x04""pyes\x03""pog\x03""pon\x03""pol\x03""pom\x03""pob\x03""pos\x04""pong\x05""pwang\x03""poe\x04""poen\x03""pyo\x04""pyon\x04""pyol\x04""pyob\x04""pyos\x03""pug\x03""pun\x03""pud\x03""pul\x04""pulm\x03""pum\x03""pub\x03""pus\x04""pung\x04""pweo\x06""pweong\x04""pwin\x04""pwil\x04""pwim\x04""pwis\x03""pyu\x04""pyun\x04""pyul\x04""pyum\x04""pyus\x05""pyung\x03""peu\x04""peun\x04""peul\x04""peum\x04""peub\x04""peus\x03""pig\x03""pin\x03""pil\x03""pim\x03""pib\x03""pis\x04""ping\x03""hag\x03""hal\x04""halt\x03""ham\x03""hab\x03""has\x04""hang\x04""haeg\x04""haen\x04""hael\x04""haem\x04""haeb\x04""haes\x05""haess\x05""haeng\x03""hya\x05""hyang\x03""heo\x04""heog\x04""heon\x04""heol\x05""heolm\x04""heom\x04""heob\x04""heos\x05""heong\x03""heg\x03""hel\x03""hem\x03""heb\x03""hes\x04""hyeo\x05""hyeog\x05""hyeon\x05""hyeol\x05""hyeom\x05""hyeob\x05""hyeos\x06""hyeoss\x06""hyeong\x03""hye\x04""hyen\x04""hyel\x04""hyeb\x03""hog\x03""hol\x04""holt\x03""hom\x03""hob\x03""hos\x04""hong\x04""hwag\x04""hwan\x04""hwal\x04""hwas\x05""hwang\x04""hwae\x05""hwaeg\x05""hwaen\x05""hwaes\x06""hwaeng\x04""hoeg\x04""hoen\x04""hoel\x04""hoeb\x04""hoes\x05""hoeng\x03""hyo\x04""hyon\x04""hyol\x04""hyob\x04""hyos\x03""hug\x03""hul\x04""hult\x03""hum\x03""hus\x04""hung\x04""hweo\x05""hweon\x05""hweol\x05""hweom\x06""hweong\x04""hweg\x03""gag\x04""gagg\x04""gags\x04""ganj\x04""ganh\x03""gad\x03""gal\x04""galg\x04""galm\x04""galb\x04""gals\x04""galt\x04""galp\x04""galh\x03""gam\x03""gab\x04""gabs\x03""gas\x04""gass\x04""gang\x03""gaj\x03""gac\x03""gak\x03""gah\x03""gae\x04""gaeg\x05""gaegg\x05""gaegs\x04""gaen\x05""gaenj\x05""gaenh\x04""gaed\x04""gael\x05""gaelg\x05""gaelm\x05""gaelb\x05""gaels\x05""gaelt\x05""gaelp\x05""gaelh\x04""gaem\x04""gaeb\x05""gaebs\x04""gaes\x05""gaess\x05""gaeng\x04""gaej\x04""gaec\x04""gaek\x04""gaet\x04""gaep\x04""gaeh\x04""gyag\x05""gyagg\x05""gyags\x04""gyan\x05""gyanj\x05""gyanh\x04""gyad\x04""gyal\x05""gyalg\x05""gyalm\x05""gyalb\x05""gyals\x05""gyalt\x05""gyalp\x05""gyalh\x04""gyam\x04""gyab\x05""gyabs\x04""gyas\x05""gyass\x05""gyang\x04""gyaj\x04""gyac\x04""gyak\x04""gyat\x04""gyap\x04""gyah\x04""gyae\x05""gyaeg\x06""gyaegg\x06""gyaegs\x05""gyaen\x06""gyaenj\x06""gyaenh\x05""gyaed\x05""gyael\x06""gyaelg\x06""gyaelm\x06""gyaelb\x06""gyaels\x06""gyaelt\x06""gyaelp\x06""gyaelh\x05""gyaem\x05""gyaeb\x06""gyaebs\x05""gyaes\x06""gyaess\x06""gyaeng\x05""gyaej\x05""gyaec\x05""gyaek\x05""gyaet\x05""gyaep\x05""gyaeh\x04""geog\x05""geogg\x05""geogs\x04""geon\x05""geonj\x05""geonh\x04""geod\x04""geol\x05""geolg\x05""geolm\x05""geolb\x05""geols\x05""geolt\x05""geolp\x05""geolh\x04""geom\x04""geob\x05""geobs\x04""geos\x05""geoss\x05""geong\x04""geoj\x04""geoc\x04""geok\x04""geot\x04""geop\x04""geoh\x03""geg\x04""gegg\x04""gegs\x04""genj\x04""genh\x03""ged\x03""gel\x04""gelg\x04""gelm\x04""gelb\x04""gels\x04""gelt\x04""gelp\x04""gelh\x03""gem\x03""geb\x04""gebs\x03""ges\x04""gess\x04""geng\x03""gej\x03""gec\x03""gek\x03""geh\x04""gyeo\x05""gyeog\x06""gyeogg\x06""gyeogs\x05""gyeon\x06""gyeonj\x06""gyeonh\x05""gyeod\x05""gyeol\x06""gyeolg\x06""gyeolm\x06""gyeolb\x06""gyeols\x06""gyeolt\x06""gyeolp\x06""gyeolh\x05""gyeom\x05""gyeob\x06""gyeobs\x05""gyeos\x06""gyeoss\x06""gyeong\x05""gyeoj\x05""gyeoc\x05""gyeok\x05""gyeot\x05""gyeop\x05""gyeoh\x04""gyeg\x05""gyegg\x05""gyegs\x04""gyen\x05""gyenj\x05""gyenh\x04""gyed\x04""gyel\x05""gyelg\x05""gyelm\x05""gyelb\x05""gyels\x05""gyelt\x05""gyelp\x05""gyelh\x04""gyem\x04""gyeb\x05""gyebs\x04""gyes\x05""gyess\x05""gyeng\x04""gyej\x04""gyec\x04""gyek\x04""gyet\x04""gyep\x04""gyeh\x03""gog\x04""gogg\x04""gogs\x03""gon\x04""gonj\x04""gonh\x03""god\x03""gol\x04""golg\x04""golm\x04""golb\x04""gols\x04""golt\x04""golp\x04""golh\x03""gom\x03""gob\x04""gobs\x03""gos\x04""goss\x04""gong\x03""goj\x03""goc\x03""gok\x03""goh\x04""gwag\x05""gwagg\x05""gwags\x04""gwan\x05""gwanj\x05""gwanh\x04""gwad\x04""gwal\x05""gwalg\x05""gwalm\x05""gwalb\x05""gwals\x05""gwalt\x05""gwalp\x05""gwalh\x04""gwam\x04""gwab\x05""gwabs\x04""gwas\x05""gwass\x05""gwang\x04""gwaj\x04""gwac\x04""gwak\x04""gwat\x04""gwap\x04""gwah\x04""gwae\x05""gwaeg\x06""gwaegg\x06""gwaegs\x05""gwaen\x06""gwaenj\x06""gwaenh\x05""gwaed\x05""gwael\x06""gwaelg\x06""gwaelm\x06""gwaelb\x06""gwaels\x06""gwaelt\x06""gwaelp\x06""gwaelh\x05""gwaem\x05""gwaeb\x06""gwaebs\x05""gwaes\x06""gwaess\x06""gwaeng\x05""gwaej\x05""gwaec\x05""gwaek\x05""gwaet\x05""gwaep\x05""gwaeh\x03""goe\x04""goeg\x05""goegg\x05""goegs\x04""goen\x05""goenj\x05""goenh\x04""goed\x04""goel\x05""goelg\x05""goelm\x05""goelb\x05""goels\x05""goelt\x05""goelp\x05""goelh\x04""goem\x04""goeb\x05""goebs\x04""goes\x05""goess\x05""goeng\x04""goej\x04""goec\x04""goek\x04""goet\x04""goep\x04""goeh\x04""gyog\x05""gyogg\x05""gyogs\x04""gyon\x05""gyonj\x05""gyonh\x04""gyod\x04""gyol\x05""gyolg\x05""gyolm\x05""gyolb\x05""gyols\x05""gyolt\x05""gyolp\x05""gyolh\x04""gyom\x04""gyob\x05""gyobs\x04""gyos\x05""gyoss\x05""gyong\x04""gyoj\x04""gyoc\x04""gyok\x04""gyot\x04""gyop\x04""gyoh\x03""gug\x04""gugg\x04""gugs\x03""gun\x04""gunj\x04""gunh\x03""gud\x03""gul\x04""gulg\x04""gulm\x04""gulb\x04""guls\x04""gult\x04""gulp\x04""gulh\x03""gum\x03""gub\x04""gubs\x03""gus\x04""guss\x04""gung\x03""guj\x03""guc\x03""guk\x03""guh\x04""gweo\x05""gweog\x06""gweogg\x06""gweogs\x05""gweon\x06""gweonj\x06""gweonh\x05""gweod\x05""gweol\x06""gweolg\x06""gweolm\x06""gweolb\x06""gweols\x06""gweolt\x06""gweolp\x06""gweolh\x05""gweom\x05""gweob\x06""gweobs\x05""gweos\x06""gweoss\x06""gweong\x05""gweoj\x05""gweoc\x05""gweok\x05""gweot\x05""gweop\x05""gweoh\x04""gweg\x05""gwegg\x05""gwegs\x04""gwen\x05""gwenj\x05""gwenh\x04""gwed\x04""gwel\x05""gwelg\x05""gwelm\x05""gwelb\x05""gwels\x05""gwelt\x05""gwelp\x05""gwelh\x04""gwem\x04""gweb\x05""gwebs\x04""gwes\x05""gwess\x05""gweng\x04""gwej\x04""gwec\x04""gwek\x04""gwet\x04""gwep\x04""gweh\x04""gwig\x05""gwigg\x05""gwigs\x04""gwin\x05""gwinj\x05""gwinh\x04""gwid\x04""gwil\x05""gwilg\x05""gwilm\x05""gwilb\x05""gwils\x05""gwilt\x05""gwilp\x05""gwilh\x04""gwim\x04""gwib\x05""gwibs\x04""gwis\x05""gwiss\x05""gwing\x04""gwij\x04""gwic\x04""gwik\x04""gwit\x04""gwip\x04""gwih\x04""gyug\x05""gyugg\x05""gyugs\x04""gyun\x05""gyunj\x05""gyunh\x04""gyud\x04""gyul\x05""gyulg\x05""gyulm\x05""gyulb\x05""gyuls\x05""gyult\x05""gyulp\x05""gyulh\x04""gyum\x04""gyub\x05""gyubs\x04""gyus\x05""gyuss\x05""gyung\x04""gyuj\x04""gyuc\x04""gyuk\x04""gyut\x04""gyup\x04""gyuh\x03""geu\x04""geug\x05""geugg\x05""geugs\x04""geun\x05""geunj\x05""geunh\x04""geud\x04""geul\x05""geulg\x05""geulm\x05""geulb\x05""geuls\x05""geult\x05""geulp\x05""geulh\x04""geum\x04""geub\x05""geubs\x04""geus\x05""geuss\x05""geung\x04""geuj\x04""geuc\x04""geuk\x04""geut\x04""geup\x04""geuh\x04""gyig\x05""gyigg\x05""gyigs\x04""gyin\x05""gyinj\x05""gyinh\x04""gyid\x04""gyil\x05""gyilg\x05""gyilm\x05""gyilb\x05""gyils\x05""gyilt\x05""gyilp\x05""gyilh\x04""gyim\x04""gyib\x05""gyibs\x04""gyis\x05""gyiss\x05""gying\x04""gyij\x04""gyic\x04""gyik\x04""gyit\x04""gyip\x04""gyih\x03""gig\x04""gigg\x04""gigs\x03""gin\x04""ginj\x04""ginh\x03""gid\x03""gil\x04""gilg\x04""gilm\x04""gilb\x04""gils\x04""gilt\x04""gilp\x04""gilh\x03""gim\x03""gib\x04""gibs\x03""gis\x04""giss\x04""ging\x03""gij\x03""gic\x03""gik\x03""gih\x04""ggag\x05""ggagg\x05""ggags\x04""ggan\x05""gganj\x05""gganh\x04""ggad\x04""ggal\x05""ggalg\x05""ggalm\x05""ggalb\x05""ggals\x05""ggalt\x05""ggalp\x05""ggalh\x04""ggam\x04""ggab\x05""ggabs\x04""ggas\x05""ggass\x05""ggang\x04""ggaj\x04""ggac\x04""ggak\x04""ggah\x04""ggae\x05""ggaeg\x06""ggaegg\x06""ggaegs\x05""ggaen\x06""ggaenj\x06""ggaenh\x05""ggaed\x05""ggael\x06""ggaelg\x06""ggaelm\x06""ggaelb\x06""ggaels\x06""ggaelt\x06""ggaelp\x06""ggaelh\x05""ggaem\x05""ggaeb\x06""ggaebs\x05""ggaes\x06""ggaess\x06""ggaeng\x05""ggaej\x05""ggaec\x05""ggaek\x05""ggaet\x05""ggaep\x05""ggaeh\x04""ggya\x05""ggyag\x06""ggyagg\x06""ggyags\x05""ggyan\x06""ggyanj\x06""ggyanh\x05""ggyad\x05""ggyal\x06""ggyalg\x06""ggyalm\x06""ggyalb\x06""ggyals\x06""ggyalt\x06""ggyalp\x06""ggyalh\x05""ggyam\x05""ggyab\x06""ggyabs\x05""ggyas\x06""ggyass\x06""ggyang\x05""ggyaj\x05""ggyac\x05""ggyak\x05""ggyat\x05""ggyap\x05""ggyah\x05""ggyae\x06""ggyaeg\x07""ggyaegg\x07""ggyaegs\x06""ggyaen\x07""ggyaenj\x07""ggyaenh\x06""ggyaed\x06""ggyael\x07""ggyaelg\x07""ggyaelm\x07""ggyaelb\x07""ggyaels\x07""ggyaelt\x07""ggyaelp\x07""ggyaelh\x06""ggyaem\x06""ggyaeb\x07""ggyaebs\x06""ggyaes\x07""ggyaess\x07""ggyaeng\x06""ggyaej\x06""ggyaec\x06""ggyaek\x06""ggyaet\x06""ggyaep\x06""ggyaeh\x04""ggeo\x05""ggeog\x06""ggeogg\x06""ggeogs\x05""ggeon\x06""ggeonj\x06""ggeonh\x05""ggeod\x05""ggeol\x06""ggeolg\x06""ggeolm\x06""ggeolb\x06""ggeols\x06""ggeolt\x06""ggeolp\x06""ggeolh\x05""ggeom\x05""ggeob\x06""ggeobs\x05""ggeos\x06""ggeoss\x06""ggeong\x05""ggeoj\x05""ggeoc\x05""ggeok\x05""ggeot\x05""ggeop\x05""ggeoh\x04""ggeg\x05""ggegg\x05""ggegs\x04""ggen\x05""ggenj\x05""ggenh\x04""gged\x04""ggel\x05""ggelg\x05""ggelm\x05""ggelb\x05""ggels\x05""ggelt\x05""ggelp\x05""ggelh\x04""ggem\x04""ggeb\x05""ggebs\x04""gges\x05""ggess\x05""ggeng\x04""ggej\x04""ggec\x04""ggek\x04""ggeh\x05""ggyeo\x06""ggyeog\x07""ggyeogg\x07""ggyeogs\x06""ggyeon\x07""ggyeonj\x07""ggyeonh\x06""ggyeod\x06""ggyeol\x07""ggyeolg\x07""ggyeolm\x07""ggyeolb\x07""ggyeols\x07""ggyeolt\x07""ggyeolp\x07""ggyeolh\x06""ggyeom\x06""ggyeob\x07""ggyeobs\x06""ggyeos\x07""ggyeoss\x07""ggyeong\x06""ggyeoj\x06""ggyeoc\x06""ggyeok\x06""ggyeot\x06""ggyeop\x06""ggyeoh\x04""ggye\x05""ggyeg\x06""ggyegg\x06""ggyegs\x05""ggyen\x06""ggyenj\x06""ggyenh\x05""ggyed\x05""ggyel\x06""ggyelg\x06""ggyelm\x06""ggyelb\x06""ggyels\x06""ggyelt\x06""ggyelp\x06""ggyelh\x05""ggyem\x05""ggyeb\x06""ggyebs\x05""ggyes\x06""ggyess\x06""ggyeng\x05""ggyej\x05""ggyec\x05""ggyek\x05""ggyet\x05""ggyep\x05""ggyeh\x04""ggog\x05""ggogg\x05""ggogs\x04""ggon\x05""ggonj\x05""ggonh\x04""ggod\x04""ggol\x05""ggolg\x05""ggolm\x05""ggolb\x05""ggols\x05""ggolt\x05""ggolp\x05""ggolh\x04""ggom\x04""ggob\x05""ggobs\x04""ggos\x05""ggoss\x05""ggong\x04""ggoj\x04""ggoc\x04""ggok\x04""ggoh\x05""ggwag\x06""ggwagg\x06""ggwags\x05""ggwan\x06""ggwanj\x06""ggwanh\x05""ggwad\x05""ggwal\x06""ggwalg\x06""ggwalm\x06""ggwalb\x06""ggwals\x06""ggwalt\x06""ggwalp\x06""ggwalh\x05""ggwam\x05""ggwab\x06""ggwabs\x05""ggwas\x06""ggwass\x06""ggwang\x05""ggwaj\x05""ggwac\x05""ggwak\x05""ggwat\x05""ggwap\x05""ggwah\x05""ggwae\x06""ggwaeg\x07""ggwaegg\x07""ggwaegs\x06""ggwaen\x07""ggwaenj\x07""ggwaenh\x06""ggwaed\x06""ggwael\x07""ggwaelg\x07""ggwaelm\x07""ggwaelb\x07""ggwaels\x07""ggwaelt\x07""ggwaelp\x07""ggwaelh\x06""ggwaem\x06""ggwaeb\x07""ggwaebs\x06""ggwaes\x07""ggwaess\x07""ggwaeng\x06""ggwaej\x06""ggwaec\x06""ggwaek\x06""ggwaet\x06""ggwaep\x06""ggwaeh\x04""ggoe\x05""ggoeg\x06""ggoegg\x06""ggoegs\x05""ggoen\x06""ggoenj\x06""ggoenh\x05""ggoed\x05""ggoel\x06""ggoelg\x06""ggoelm\x06""ggoelb\x06""ggoels\x06""ggoelt\x06""ggoelp\x06""ggoelh\x05""ggoem\x05""ggoeb\x06""ggoebs\x05""ggoes\x06""ggoess\x06""ggoeng\x05""ggoej\x05""ggoec\x05""ggoek\x05""ggoet\x05""ggoep\x05""ggoeh\x04""ggyo\x05""ggyog\x06""ggyogg\x06""ggyogs\x05""ggyon\x06""ggyonj\x06""ggyonh\x05""ggyod\x05""ggyol\x06""ggyolg\x06""ggyolm\x06""ggyolb\x06""ggyols\x06""ggyolt\x06""ggyolp\x06""ggyolh\x05""ggyom\x05""ggyob\x06""ggyobs\x05""ggyos\x06""ggyoss\x06""ggyong\x05""ggyoj\x05""ggyoc\x05""ggyok\x05""ggyot\x05""ggyop\x05""ggyoh\x04""ggug\x05""ggugg\x05""ggugs\x04""ggun\x05""ggunj\x05""ggunh\x04""ggud\x04""ggul\x05""ggulg\x05""ggulm\x05""ggulb\x05""gguls\x05""ggult\x05""ggulp\x05""ggulh\x04""ggum\x04""ggub\x05""ggubs\x04""ggus\x05""gguss\x05""ggung\x04""gguj\x04""gguc\x04""gguk\x04""gguh\x05""ggweo\x06""ggweog\x07""ggweogg\x07""ggweogs\x06""ggweon\x07""ggweonj\x07""ggweonh\x06""ggweod\x06""ggweol\x07""ggweolg\x07""ggweolm\x07""ggweolb\x07""ggweols\x07""ggweolt\x07""ggweolp\x07""ggweolh\x06""ggweom\x06""ggweob\x07""ggweobs\x06""ggweos\x07""ggweoss\x07""ggweong\x06""ggweoj\x06""ggweoc\x06""ggweok\x06""ggweot\x06""ggweop\x06""ggweoh\x05""ggweg\x06""ggwegg\x06""ggwegs\x05""ggwen\x06""ggwenj\x06""ggwenh\x05""ggwed\x05""ggwel\x06""ggwelg\x06""ggwelm\x06""ggwelb\x06""ggwels\x06""ggwelt\x06""ggwelp\x06""ggwelh\x05""ggwem\x05""ggweb\x06""ggwebs\x05""ggwes\x06""ggwess\x06""ggweng\x05""ggwej\x05""ggwec\x05""ggwek\x05""ggwet\x05""ggwep\x05""ggweh\x05""ggwig\x06""ggwigg\x06""ggwigs\x05""ggwin\x06""ggwinj\x06""ggwinh\x05""ggwid\x05""ggwil\x06""ggwilg\x06""ggwilm\x06""ggwilb\x06""ggwils\x06""ggwilt\x06""ggwilp\x06""ggwilh\x05""ggwim\x05""ggwib\x06""ggwibs\x05""ggwis\x06""ggwiss\x06""ggwing\x05""ggwij\x05""ggwic\x05""ggwik\x05""ggwit\x05""ggwip\x05""ggwih\x04""ggyu\x05""ggyug\x06""ggyugg\x06""ggyugs\x05""ggyun\x06""ggyunj\x06""ggyunh\x05""ggyud\x05""ggyul\x06""ggyulg\x06""ggyulm\x06""ggyulb\x06""ggyuls\x06""ggyult\x06""ggyulp\x06""ggyulh\x05""ggyum\x05""ggyub\x06""ggyubs\x05""ggyus\x06""ggyuss\x06""ggyung\x05""ggyuj\x05""ggyuc\x05""ggyuk\x05""ggyut\x05""ggyup\x05""ggyuh\x04""ggeu\x05""ggeug\x06""ggeugg\x06""ggeugs\x05""ggeun\x06""ggeunj\x06""ggeunh\x05""ggeud\x05""ggeul\x06""ggeulg\x06""ggeulm\x06""ggeulb\x06""ggeuls\x06""ggeult\x06""ggeulp\x06""ggeulh\x05""ggeum\x05""ggeub\x06""ggeubs\x05""ggeus\x06""ggeuss\x06""ggeung\x05""ggeuj\x05""ggeuc\x05""ggeuk\x05""ggeut\x05""ggeup\x05""ggeuh\x04""ggyi\x05""ggyig\x06""ggyigg\x06""ggyigs\x05""ggyin\x06""ggyinj\x06""ggyinh\x05""ggyid\x05""ggyil\x06""ggyilg\x06""ggyilm\x06""ggyilb\x06""ggyils\x06""ggyilt\x06""ggyilp\x06""ggyilh\x05""ggyim\x05""ggyib\x06""ggyibs\x05""ggyis\x06""ggyiss\x06""ggying\x05""ggyij\x05""ggyic\x05""ggyik\x05""ggyit\x05""ggyip\x05""ggyih\x04""ggig\x05""ggigg\x05""ggigs\x04""ggin\x05""gginj\x05""gginh\x04""ggid\x04""ggil\x05""ggilg\x05""ggilm\x05""ggilb\x05""ggils\x05""ggilt\x05""ggilp\x05""ggilh\x04""ggim\x04""ggib\x05""ggibs\x04""ggis\x05""ggiss\x05""gging\x04""ggij\x04""ggic\x04""ggik\x04""ggip\x04""ggih\x03""nag\x04""nagg\x04""nags\x03""nan\x04""nanj\x04""nanh\x03""nad\x03""nal\x04""nalg\x04""nalm\x04""nalb\x04""nals\x04""nalt\x04""nalp\x04""nalh\x03""nam\x03""nab\x04""nabs\x03""nas\x04""nass\x04""nang\x03""naj\x03""nac\x03""nak\x03""nat\x03""nae\x04""naeg\x05""naegg\x05""naegs\x04""naen\x05""naenj\x05""naenh\x04""naed\x04""nael\x05""naelg\x05""naelm\x05""naelb\x05""naels\x05""naelt\x05""naelp\x05""naelh\x04""naem\x04""naeb\x05""naebs\x04""naes\x05""naess\x05""naeng\x04""naej\x04""naec\x04""naek\x04""naet\x04""naep\x04""naeh\x04""nyag\x05""nyagg\x05""nyags\x04""nyan\x05""nyanj\x05""nyanh\x04""nyad\x04""nyal\x05""nyalg\x05""nyalm\x05""nyalb\x05""nyals\x05""nyalt\x05""nyalp\x05""nyalh\x04""nyam\x04""nyab\x05""nyabs\x04""nyas\x05""nyass\x05""nyang\x04""nyaj\x04""nyac\x04""nyak\x04""nyat\x04""nyap\x04""nyah\x04""nyae\x05""nyaeg\x06""nyaegg\x06""nyaegs\x05""nyaen\x06""nyaenj\x06""nyaenh\x05""nyaed\x05""nyael\x06""nyaelg\x06""nyaelm\x06""nyaelb\x06""nyaels\x06""nyaelt\x06""nyaelp\x06""nyaelh\x05""nyaem\x05""nyaeb\x06""nyaebs\x05""nyaes\x06""nyaess\x06""nyaeng\x05""nyaej\x05""nyaec\x05""nyaek\x05""nyaet\x05""nyaep\x05""nyaeh\x03""neo\x04""neog\x05""neogg\x05""neogs\x04""neon\x05""neonj\x05""neonh\x04""neod\x04""neol\x05""neolg\x05""neolm\x05""neolb\x05""neols\x05""neolt\x05""neolp\x05""neolh\x04""neom\x04""neob\x05""neobs\x04""neos\x05""neoss\x05""neong\x04""neoj\x04""neoc\x04""neok\x04""neot\x04""neop\x04""neoh\x03""neg\x04""negg\x04""negs\x03""nen\x04""nenj\x04""nenh\x03""ned\x03""nel\x04""nelg\x04""nelm\x04""nelb\x04""nels\x04""nelt\x04""nelp\x04""nelh\x03""nem\x03""neb\x04""nebs\x03""nes\x04""ness\x04""neng\x03""nej\x03""nec\x03""nek\x03""net\x03""neh\x04""nyeo\x05""nyeog\x06""nyeogg\x06""nyeogs\x05""nyeon\x06""nyeonj\x06""nyeonh\x05""nyeod\x05""nyeol\x06""nyeolg\x06""nyeolm\x06""nyeolb\x06""nyeols\x06""nyeolt\x06""nyeolp\x06""nyeolh\x05""nyeom\x05""nyeob\x06""nyeobs\x05""nyeos\x06""nyeoss\x06""nyeong\x05""nyeoj\x05""nyeoc\x05""nyeok\x05""nyeot\x05""nyeop\x05""nyeoh\x04""nyeg\x05""nyegg\x05""nyegs\x04""nyen\x05""nyenj\x05""nyenh\x04""nyed\x04""nyel\x05""nyelg\x05""nyelm\x05""nyelb\x05""nyels\x05""nyelt\x05""nyelp\x05""nyelh\x04""nyem\x04""nyeb\x05""nyebs\x04""nyes\x05""nyess\x05""nyeng\x04""nyej\x04""nyec\x04""nyek\x04""nyet\x04""nyep\x04""nyeh\x03""nog\x04""nogg\x04""nogs\x03""non\x04""nonj\x04""nonh\x03""nod\x03""nol\x04""nolg\x04""nolm\x04""nolb\x04""nols\x04""nolt\x04""nolp\x04""nolh\x03""nom\x03""nob\x04""nobs\x03""nos\x04""noss\x04""nong\x03""noj\x03""noc\x03""nok\x03""noh\x04""nwag\x05""nwagg\x05""nwags\x04""nwan\x05""nwanj\x05""nwanh\x04""nwad\x04""nwal\x05""nwalg\x05""nwalm\x05""nwalb\x05""nwals\x05""nwalt\x05""nwalp\x05""nwalh\x04""nwam\x04""nwab\x05""nwabs\x04""nwas\x05""nwass\x05""nwang\x04""nwaj\x04""nwac\x04""nwak\x04""nwat\x04""nwap\x04""nwah\x04""nwae\x05""nwaeg\x06""nwaegg\x06""nwaegs\x05""nwaen\x06""nwaenj\x06""nwaenh\x05""nwaed\x05""nwael\x06""nwaelg\x06""nwaelm\x06""nwaelb\x06""nwaels\x06""nwaelt\x06""nwaelp\x06""nwaelh\x05""nwaem\x05""nwaeb\x06""nwaebs\x05""nwaes\x06""nwaess\x06""nwaeng\x05""nwaej\x05""nwaec\x05""nwaek\x05""nwaet\x05""nwaep\x05""nwaeh\x03""noe\x04""noeg\x05""noegg\x05""noegs\x04""noen\x05""noenj\x05""noenh\x04""noed\x04""noel\x05""noelg\x05""noelm\x05""noelb\x05""noels\x05""noelt\x05""noelp\x05""noelh\x04""noem\x04""noeb\x05""noebs\x04""noes\x05""noess\x05""noeng\x04""noej\x04""noec\x04""noek\x04""noet\x04""noep\x04""noeh\x04""nyog\x05""nyogg\x05""nyogs\x04""nyon\x05""nyonj\x05""nyonh\x04""nyod\x04""nyol\x05""nyolg\x05""nyolm\x05""nyolb\x05""nyols\x05""nyolt\x05""nyolp\x05""nyolh\x04""nyom\x04""nyob\x05""nyobs\x04""nyos\x05""nyoss\x05""nyong\x04""nyoj\x04""nyoc\x04""nyok\x04""nyoh\x03""nug\x04""nugg\x04""nugs\x03""nun\x04""nunj\x04""nunh\x03""nud\x03""nul\x04""nulg\x04""nulm\x04""nulb\x04""nuls\x04""nult\x04""nulp\x04""nulh\x03""nub\x04""nubs\x03""nus\x04""nuss\x04""nung\x03""nuj\x03""nuc\x03""nuk\x03""nuh\x04""nweo\x05""nweog\x06""nweogg\x06""nweogs\x05""nweon\x06""nweonj\x06""nweonh\x05""nweod\x05""nweol\x06""nweolg\x06""nweolm\x06""nweolb\x06""nweols\x06""nweolt\x06""nweolp\x06""nweolh\x05""nweom\x05""nweob\x06""nweobs\x05""nweos\x06""nweoss\x06""nweong\x05""nweoj\x05""nweoc\x05""nweok\x05""nweot\x05""nweop\x05""nweoh\x04""nweg\x05""nwegg\x05""nwegs\x04""nwen\x05""nwenj\x05""nwenh\x04""nwed\x04""nwel\x05""nwelg\x05""nwelm\x05""nwelb\x05""nwels\x05""nwelt\x05""nwelp\x05""nwelh\x04""nwem\x04""nweb\x05""nwebs\x04""nwes\x05""nwess\x05""nweng\x04""nwej\x04""nwec\x04""nwek\x04""nwet\x04""nwep\x04""nweh\x03""nwi\x04""nwig\x05""nwigg\x05""nwigs\x04""nwin\x05""nwinj\x05""nwinh\x04""nwid\x04""nwil\x05""nwilg\x05""nwilm\x05""nwilb\x05""nwils\x05""nwilt\x05""nwilp\x05""nwilh\x04""nwim\x04""nwib\x05""nwibs\x04""nwis\x05""nwiss\x05""nwing\x04""nwij\x04""nwic\x04""nwik\x04""nwit\x04""nwip\x04""nwih\x04""nyug\x05""nyugg\x05""nyugs\x04""nyun\x05""nyunj\x05""nyunh\x04""nyud\x04""nyul\x05""nyulg\x05""nyulm\x05""nyulb\x05""nyuls\x05""nyult\x05""nyulp\x05""nyulh\x04""nyum\x04""nyub\x05""nyubs\x04""nyus\x05""nyuss\x05""nyung\x04""nyuj\x04""nyuc\x04""nyuk\x04""nyuh\x03""neu\x04""neug\x05""neugg\x05""neugs\x04""neun\x05""neunj\x05""neunh\x04""neud\x04""neul\x05""neulg\x05""neulm\x05""neulb\x05""neuls\x05""neult\x05""neulp\x05""neulh\x04""neum\x04""neub\x05""neubs\x04""neus\x05""neuss\x05""neung\x04""neuj\x04""neuc\x04""neuk\x04""neut\x04""neup\x04""neuh\x04""nyig\x05""nyigg\x05""nyigs\x04""nyin\x05""nyinj\x05""nyinh\x04""nyid\x04""nyil\x05""nyilg\x05""nyilm\x05""nyilb\x05""nyils\x05""nyilt\x05""nyilp\x05""nyilh\x04""nyim\x04""nyib\x05""nyibs\x04""nyis\x05""nyiss\x05""nying\x04""nyij\x04""nyic\x04""nyik\x04""nyih\x03""nig\x04""nigg\x04""nigs\x03""nin\x04""ninj\x04""ninh\x03""nid\x03""nil\x04""nilg\x04""nilm\x04""nilb\x04""nils\x04""nilt\x04""nilp\x04""nilh\x03""nim\x03""nib\x04""nibs\x03""nis\x04""niss\x04""ning\x03""nij\x03""nic\x03""nik\x03""nih\x03""dag\x04""dagg\x04""dags\x03""dan\x04""danj\x04""danh\x03""dad\x04""dalg\x04""dalm\x04""dalb\x04""dals\x04""dalt\x04""dalp\x04""dalh\x03""dam\x03""dab\x04""dabs\x03""das\x04""dass\x04""dang\x03""daj\x03""dac\x03""dak\x03""dah\x03""dae\x04""daeg\x05""daegg\x05""daegs\x04""daen\x05""daenj\x05""daenh\x04""daed\x04""dael\x05""daelg\x05""daelm\x05""daelb\x05""daels\x05""daelt\x05""daelp\x05""daelh\x04""daem\x04""daeb\x05""daebs\x04""daes\x05""daess\x05""daeng\x04""daej\x04""daec\x04""daek\x04""daet\x04""daep\x04""daeh\x03""dya\x04""dyag\x05""dyagg\x05""dyags\x04""dyan\x05""dyanj\x05""dyanh\x04""dyad\x04""dyal\x05""dyalg\x05""dyalm\x05""dyalb\x05""dyals\x05""dyalt\x05""dyalp\x05""dyalh\x04""dyam\x04""dyab\x05""dyabs\x04""dyas\x05""dyass\x05""dyang\x04""dyaj\x04""dyac\x04""dyak\x04""dyat\x04""dyap\x04""dyah\x04""dyae\x05""dyaeg\x06""dyaegg\x06""dyaegs\x05""dyaen\x06""dyaenj\x06""dyaenh\x05""dyaed\x05""dyael\x06""dyaelg\x06""dyaelm\x06""dyaelb\x06""dyaels\x06""dyaelt\x06""dyaelp\x06""dyaelh\x05""dyaem\x05""dyaeb\x06""dyaebs\x05""dyaes\x06""dyaess\x06""dyaeng\x05""dyaej\x05""dyaec\x05""dyaek\x05""dyaet\x05""dyaep\x05""dyaeh\x03""deo\x04""deog\x05""deogg\x05""deogs\x04""deon\x05""deonj\x05""deonh\x04""deod\x04""deol\x05""deolg\x05""deolm\x05""deolb\x05""deols\x05""deolt\x05""deolp\x05""deolh\x04""deom\x04""deob\x05""deobs\x04""deos\x05""deoss\x05""deong\x04""deoj\x04""deoc\x04""deok\x04""deot\x04""deop\x04""deoh\x04""degg\x04""degs\x03""den\x04""denj\x04""denh\x03""ded\x03""del\x04""delg\x04""delm\x04""delb\x04""dels\x04""delt\x04""delp\x04""delh\x03""dem\x03""deb\x04""debs\x03""des\x04""dess\x04""deng\x03""dej\x03""dec\x03""dek\x03""det\x03""deh\x04""dyeo\x05""dyeog\x06""dyeogg\x06""dyeogs\x05""dyeon\x06""dyeonj\x06""dyeonh\x05""dyeod\x05""dyeol\x06""dyeolg\x06""dyeolm\x06""dyeolb\x06""dyeols\x06""dyeolt\x06""dyeolp\x06""dyeolh\x05""dyeom\x05""dyeob\x06""dyeobs\x05""dyeos\x06""dyeoss\x06""dyeong\x05""dyeoj\x05""dyeoc\x05""dyeok\x05""dyeot\x05""dyeop\x05""dyeoh\x03""dye\x04""dyeg\x05""dyegg\x05""dyegs\x04""dyen\x05""dyenj\x05""dyenh\x04""dyed\x04""dyel\x05""dyelg\x05""dyelm\x05""dyelb\x05""dyels\x05""dyelt\x05""dyelp\x05""dyelh\x04""dyem\x04""dyeb\x05""dyebs\x04""dyes\x05""dyess\x05""dyeng\x04""dyej\x04""dyec\x04""dyek\x04""dyet\x04""dyep\x04""dyeh\x03""dog\x04""dogg\x04""dogs\x04""donj\x04""donh\x03""dod\x03""dol\x04""dolg\x04""dolm\x04""dolb\x04""dols\x04""dolt\x04""dolp\x04""dolh\x03""dom\x03""dob\x04""dobs\x03""dos\x04""doss\x04""dong\x03""doj\x03""doc\x03""dok\x03""doh\x04""dwag\x05""dwagg\x05""dwags\x04""dwan\x05""dwanj\x05""dwanh\x04""dwad\x04""dwal\x05""dwalg\x05""dwalm\x05""dwalb\x05""dwals\x05""dwalt\x05""dwalp\x05""dwalh\x04""dwam\x04""dwab\x05""dwabs\x04""dwas\x05""dwass\x05""dwang\x04""dwaj\x04""dwac\x04""dwak\x04""dwat\x04""dwap\x04""dwah\x04""dwae\x05""dwaeg\x06""dwaegg\x06""dwaegs"
+#define UTFASCIILOOKUP {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,2,1,1,2,2,2,2,4,6,8,10,12,14,16,18,20,22,1,2,1,1,1,1,1,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,1,2,1,1,1,1,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,28,76,1,72,1,79,1,28,24,1,1,2,58,2,82,86,8,10,1,64,54,1,2,6,52,1,88,91,94,1,24,24,24,24,24,24,97,28,32,32,32,32,40,40,40,40,30,50,52,52,52,52,52,70,52,64,64,64,64,64,100,79,24,24,24,24,24,24,97,28,32,32,32,32,40,40,40,40,30,50,52,52,52,52,52,2,52,64,64,64,64,72,100,72,24,24,24,24,24,24,28,28,28,28,28,28,28,28,30,30,30,30,32,32,32,32,32,32,32,32,32,32,36,36,36,36,36,36,36,36,38,38,38,38,40,40,40,40,40,40,40,40,40,40,103,103,42,42,44,44,44,46,46,46,46,46,46,46,46,46,46,50,50,50,50,50,50,50,106,106,52,52,52,52,52,52,109,109,58,58,58,58,58,58,60,60,60,60,60,60,60,60,62,62,62,62,62,62,64,64,64,64,64,64,64,64,64,64,64,64,68,68,72,72,72,74,74,74,74,74,74,60,26,26,26,26,16,16,52,28,28,30,30,30,30,30,10,1,32,34,34,36,36,112,40,40,44,44,46,46,68,50,50,52,52,52,115,115,54,54,118,8,8,121,121,62,62,62,62,64,64,72,66,72,72,74,74,124,124,124,124,8,14,14,127,68,1,1,1,1,130,130,130,133,133,133,136,136,136,24,24,40,40,52,52,64,64,64,64,64,64,64,64,64,64,1,24,24,24,24,97,97,36,36,36,36,44,44,52,52,52,52,124,124,42,130,30,130,36,36,112,68,50,50,24,24,97,97,52,52,24,24,24,24,32,32,32,32,40,40,40,40,52,52,52,52,58,58,58,58,64,64,64,64,60,60,62,62,72,72,38,38,50,30,139,139,74,74,24,24,32,32,52,52,52,52,52,52,52,52,72,72,46,50,62,42,142,145,24,28,28,46,62,60,74,148,148,26,64,66,32,32,42,42,56,56,58,58,72,72,24,24,24,26,52,28,30,30,32,1,1,32,32,32,32,42,36,36,36,36,64,72,38,38,40,40,40,46,46,46,153,68,68,48,50,50,50,52,109,52,34,58,58,58,58,58,58,58,58,58,60,60,42,60,60,62,62,64,64,66,1,68,72,72,74,74,74,74,1,1,1,28,1,26,32,36,38,42,44,46,56,1,1,130,130,130,127,127,156,159,162,153,165,1,38,38,44,38,42,58,58,58,58,68,72,1,1,1,1,1,1,1,1,1,1,1,1,66,1,66,1,2,2,2,2,1,2,2,1,2,1,1,1,66,1,2,66,2,1,2,1,1,58,70,36,46,60,70,1,168,179,184,188,193,203,207,66,1,1,212,217,220,225,231,236,236,236,243,249,256,262,256,262,266,266,220,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,272,272,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,272,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,32,40,52,64,28,30,38,48,58,62,66,70,278,278,283,283,1,2,289,289,1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,2,32,32,40,1,52,1,64,52,40,24,26,36,30,32,74,32,100,40,44,46,48,50,300,52,54,58,1,60,62,64,303,306,76,52,40,64,24,32,32,40,64,24,26,36,30,32,74,32,100,40,44,46,48,50,70,52,54,58,60,60,62,64,303,306,76,52,40,64,52,64,52,1,26,100,64,64,64,303,54,1,309,309,315,315,68,68,56,56,318,318,121,121,34,34,306,306,38,38,36,36,321,321,324,324,44,58,28,42,1,1,1,327,327,1,331,331,1,1,1,0,335,338,341,344,335,130,40,347,42,133,136,350,354,40,64,357,24,26,66,36,30,335,124,74,40,40,44,46,48,50,52,54,58,60,62,64,34,306,127,321,121,361,366,72,1,32,371,374,24,26,66,377,30,335,124,74,40,40,44,46,48,50,52,54,58,60,62,64,34,306,127,321,121,361,366,72,1,32,371,374,335,338,341,344,335,130,40,347,42,133,136,350,354,40,64,357,52,52,32,32,335,335,32,32,335,335,52,52,338,338,300,300,76,76,34,34,72,72,72,72,64,64,52,52,52,52,380,380,56,56,383,1,1,1,1,1,388,395,40,40,1,1,58,58,36,36,36,36,36,36,124,124,74,74,44,44,44,44,44,44,44,44,50,50,106,106,54,54,306,306,60,60,62,62,64,64,64,64,306,306,403,403,321,321,321,321,38,38,321,321,321,321,1,124,124,44,44,407,407,50,50,410,410,321,321,413,413,416,24,24,24,24,97,97,335,335,1,1,1,1,124,124,74,74,130,130,40,40,40,40,52,52,52,52,52,52,32,32,64,64,64,64,64,64,321,321,425,425,72,72,425,425,429,429,429,429,432,432,435,435,439,439,443,443,448,448,452,452,456,456,460,460,464,464,407,407,467,467,471,471,475,475,479,479,482,482,485,485,407,407,410,410,1,1,1,1,1,1,1,1,1,1,1,1,1,24,26,36,30,32,74,32,32,62,124,40,46,306,127,44,38,130,377,321,48,72,50,121,52,321,54,42,491,60,66,62,58,127,68,54,44,52,34,1,1,1,1,2,1,2,1,2,1,24,26,36,30,32,74,32,32,62,124,40,46,306,127,44,38,130,377,321,48,72,50,121,52,321,54,42,491,60,66,62,58,127,68,54,44,52,34,494,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,32,24,52,40,32,32,24,24,52,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,497,26,36,30,38,66,74,306,62,72,44,44,46,48,48,50,50,60,1,54,54,127,127,56,58,121,62,1,1,1,1,1,66,502,40,1,1,1,1,1,1,1,1,1,1,1,1,0,1,505,1,511,1,1,1,1,1,1,1,1,2,1,1,517,523,535,542,554,559,1,497,1,1,1,1,2,1,1,1,1,1,569,24,1,68,497,72,497,26,1,62,100,42,38,306,30,575,58,74,60,121,60,30,62,74,1,36,578,578,584,584,584,1,34,56,44,46,48,50,38,68,1,72,590,593,596,24,64,40,68,1,1,1,1,1,1,1,1,66,599,605,1,1,1,4,6,8,10,12,14,16,18,20,22,1,2,2,1,609,613,497,1,1,1,179,1,68,64,72,617,620,26,62,62,54,100,624,38,38,627,630,38,321,633,637,30,30,640,575,643,30,30,30,647,58,58,58,58,58,58,42,58,60,60,60,60,60,62,377,34,34,34,66,34,303,56,56,306,44,44,44,106,44,36,36,50,36,36,36,46,46,46,46,50,50,50,50,50,38,321,650,38,38,1,68,109,109,64,653,653,68,66,72,72,72,68,32,656,72,72,2,97,660,613,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,664,668,4,6,8,10,12,14,16,18,20,22,121,30,377,1,48,672,1,2,2,1,1,2,2,2,2,1,1,1,1,1,1,1,1,676,26,36,36,30,30,38,68,74,38,62,62,72,682,44,46,48,50,60,60,1,54,54,60,56,58,121,62,685,685,685,24,24,24,24,24,24,32,32,32,32,40,40,64,64,64,52,1,1,1,1,1,70,56,1,1,1,1,1,1,693,693,693,609,609,609,609,609,609,609,701,701,664,664,668,705,710,710,710,714,714,578,578,578,718,718,723,723,723,728,668,668,705,701,701,705,668,701,497,497,584,584,584,732,732,656,656,701,705,705,736,38,121,50,58,26,46,44,1,66,48,34,575,100,46,36,627,60,30,74,62,72,54,42,321,617,740,306,100,74,121,60,30,62,74,1,377,56,68,24,743,40,746,64,749,32,752,52,755,1,758,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,8,10,12,14,16,18,20,22,24,746,40,32,64,749,52,762,50,773,776,779,782,785,789,792,795,799,802,806,809,812,815,818,821,815,429,825,828,821,831,831,831,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,848,857,24,24,743,40,865,64,868,58,46,871,32,32,878,871,52,52,881,809,884,888,891,895,899,785,782,902,821,906,910,915,919,924,779,928,789,932,815,936,776,941,773,945,818,828,792,795,812,949,953,958,961,965,799,429,0,0,969,975,743,40,865,64,868,58,647,871,32,32,878,871,52,52,881,984,0,0,0,991,998,0,0,0,0,0,479,1007,1012,1017,1020,471,806,1026,647,1030,46,1030,0,0,0,6,8,10,12,14,16,18,20,22,0,179,871,0,0,0,0,0,0,0,0,1033,1037,148,1041,1046,0,836,848,857,0,24,743,40,865,64,868,58,46,0,0,32,878,0,0,52,881,809,884,888,891,895,899,785,782,902,821,906,910,915,919,924,779,928,789,932,815,0,776,941,773,945,818,828,792,0,812,0,0,0,961,965,799,429,0,0,969,975,743,40,865,64,868,58,647,0,0,32,878,0,0,52,881,984,1050,0,0,0,0,0,0,0,0,0,0,0,0,0,795,471,0,1026,647,1030,46,1030,0,0,0,6,8,10,12,14,16,18,20,22,792,792,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,50,50,38,1,24,743,40,865,64,868,58,46,410,32,32,878,1057,52,52,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1066,54,303,26,624,48,72,58,647,46,46,1070,66,121,79,60,38,1,1,1,1,743,40,865,64,868,58,647,410,32,32,878,1057,52,52,881,984,1,1,1074,1,1,1,1,1,1,1,56,1078,1082,74,1086,491,34,1091,647,1030,46,1030,2,2,4,6,8,10,12,14,16,18,20,22,2,1,1,1,1,1094,1,1,1,1,1,1,1,1,1,1,1,50,50,38,1,24,743,40,865,64,868,58,647,1,1,32,878,1,1,52,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1,54,303,26,624,48,72,58,1,46,949,1,958,121,79,60,38,1,1,1,975,743,40,865,64,868,58,647,871,1,32,878,871,1,52,881,984,1,1,1,1,1,1,1,1,1,1,1,1,1,1,647,491,1,1091,647,1030,46,1030,1,1,4,6,8,10,12,14,16,18,20,22,58,58,1101,1101,6,8,10,12,1104,1108,1,1,1,1,1,0,1,836,50,857,1,24,743,40,865,64,868,58,46,1,1,746,878,1,1,749,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1,54,303,26,1111,48,72,58,1,46,1030,1,66,121,965,60,38,1,1,1,975,743,40,865,64,868,58,647,1,1,746,878,1,1,749,881,984,1,1,1,1,1,1,1,1,1,1,1,1078,1082,74,647,471,34,1026,647,1030,46,1030,1,1,4,6,8,10,12,14,16,18,20,22,50,38,1,1,1114,1,1,1,1,1,1,1,1,1,1,1,1,50,50,38,1,24,743,40,865,64,868,58,1,410,32,32,878,1057,52,52,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,936,54,303,26,624,48,828,58,795,46,1030,953,66,121,79,60,38,1,1,1,1,743,40,865,64,868,58,647,410,32,32,878,1057,52,52,881,984,1,1,1074,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,647,1,1,1,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,50,50,38,1,24,743,40,865,64,868,58,46,1,32,32,878,1,52,52,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1,54,303,26,624,48,72,58,795,46,1030,1,958,121,79,60,38,1,1,1,1,743,40,865,64,868,58,647,1,32,32,878,1,52,52,881,984,1,1,1,1,1,1,1,1,1,1,1118,1122,1,1,647,491,1,1091,647,1030,46,1030,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,6,8,10,6,8,10,1126,1,1,50,38,1,24,743,40,865,64,868,58,46,1,32,746,878,1,52,749,881,44,884,888,891,106,28,785,42,902,627,617,910,915,919,1063,62,928,789,932,50,1066,54,941,773,945,48,72,58,647,46,1030,1070,66,961,79,60,38,1,1,969,975,743,40,865,64,868,58,647,1,32,746,878,1,52,749,881,984,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,806,1,647,1030,46,1030,1,1,4,6,8,10,12,14,16,18,20,22,1132,1135,383,1,1,1,1,1,1,1,1,1,1,1,1,0,1,50,50,38,1,24,743,40,865,64,868,58,46,1,32,746,878,1,52,749,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1,54,303,26,624,48,72,58,647,46,1030,953,66,121,79,60,38,1,1,1,975,743,40,865,64,868,58,647,1,32,746,878,1,52,749,881,984,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,647,1030,46,1030,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,1,1139,1139,1139,1139,1139,1139,1,1,50,38,1,24,743,40,865,64,868,58,46,1146,32,746,878,1155,52,749,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1162,54,303,26,624,48,72,58,647,46,1030,1162,66,121,79,60,38,1173,1181,1,1189,743,40,865,64,868,58,647,1197,32,746,878,1,52,749,881,1,1,1207,1218,1224,1218,1224,1218,1,1,1,1229,1242,1224,1250,1242,1242,1070,1256,647,1030,1,1,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1224,1224,1,1,1,1,1,1,1,1,1,1,1,0,1,1268,50,38,1271,24,743,40,865,64,868,58,46,1275,32,746,878,1278,52,749,881,44,306,36,377,106,28,321,42,1060,627,617,620,637,643,1063,62,100,30,575,50,1282,54,303,26,624,48,72,58,647,46,1030,1070,66,121,79,60,38,1285,1,1,1,743,40,865,64,868,58,878,1293,32,746,878,1305,52,749,881,1309,1318,1327,1,6,8,10,12,14,16,1,20,22,1335,1346,1,1,1,1,647,1030,1,1,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1268,50,38,1271,24,743,97,1353,40,865,64,868,58,647,46,1030,32,746,878,52,749,881,1278,1,1357,44,306,36,377,106,1360,28,321,42,1060,627,1364,1368,617,620,637,643,1063,1372,62,100,30,575,50,743,1377,54,303,26,624,48,1380,72,58,1383,46,1,1,66,121,79,60,38,1030,34,1,1,1,1,1,1,1,1,743,97,1353,40,865,64,14,868,18,58,32,746,878,52,749,881,46,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,647,1030,2,1,1,1,1,1,1,1,1,1,1,0,1386,44,306,306,306,306,306,106,633,321,321,321,321,72,30,62,100,100,100,50,30,62,100,100,100,50,26,54,303,34,303,34,303,48,72,58,58,46,46,68,60,60,60,38,46,1,38,1,24,24,743,1389,40,865,1392,1395,64,868,1,1,1,1,1399,624,32,97,52,878,878,1403,1,782,1,821,906,910,915,48,924,2,928,6,8,10,12,14,16,18,20,22,2,2,1406,825,1411,1017,1415,828,792,812,961,965,799,429,24,1418,1423,1434,795,1,1,1,1,743,40,865,64,868,58,647,46,1030,32,746,52,749,1438,1443,40,44,306,1448,306,1,1452,106,321,1456,60,1461,1,627,1,1,809,884,888,891,30,38,100,100,1,50,26,54,303,34,303,34,928,48,72,58,776,46,773,68,818,1118,60,38,1406,1,1411,1,24,828,743,1389,40,865,72,1091,64,868,1423,52,46,627,1,1,32,1465,52,1468,878,1,1,1,1,1,1,1,1,48,1471,1471,4,6,8,10,12,14,16,18,20,22,1,1,1476,1479,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1074,884,888,891,895,899,785,782,2,2,1482,2,2,2,2,1487,2,1490,1493,1490,2,776,941,773,945,818,828,792,812,825,799,429,949,6,8,10,12,14,16,18,20,22,14,1497,1500,1503,1506,1509,1512,1515,1518,1521,1,1,1,1,857,1,1524,1,1,1,1529,1536,44,306,36,377,106,28,321,42,20,627,617,620,637,643,1063,62,100,30,575,50,54,303,26,624,48,127,350,130,357,68,124,74,1,72,58,46,121,1542,60,38,24,1546,58,1550,1550,1550,1558,1558,1558,743,40,865,64,868,58,647,46,1030,32,746,52,749,48,38,40,865,1566,1566,1566,1566,1566,1566,1566,1566,1566,1566,1566,1566,1571,1571,44,306,36,377,106,28,321,42,20,627,617,620,637,643,1063,62,100,30,575,50,54,303,26,624,48,127,350,130,357,68,124,74,1,72,58,46,121,79,60,38,24,1546,68,72,58,1577,70,1490,1582,1582,1582,1582,1585,1589,1,1,1,1,1,1,1,1,1,1,590,1593,1597,1601,410,1605,1609,1613,596,1617,1621,1625,1629,1057,1633,1637,1642,331,1646,593,1650,1655,1660,1665,1669,1674,1679,1683,1687,1577,1691,1695,1700,1704,1707,482,1585,1589,1711,1714,1717,1597,710,1,1723,1,1,0,44,306,36,377,106,28,321,42,1060,627,1732,617,620,637,643,1063,617,100,30,575,50,54,303,26,624,48,72,58,46,68,60,38,1030,24,1,40,865,64,868,32,1,52,881,1,743,40,865,64,868,32,878,1,1,1,50,1,1,1,1,1,1,1,1,1,4,6,8,10,12,14,16,18,20,22,2,2,50,58,46,32,121,79,58,647,46,1030,58,647,46,1030,1,1,1,1,1,1,1736,24,97,828,475,1743,32,1746,1750,52,825,1753,109,1275,64,1757,482,1761,653,1764,347,40,1767,1771,1775,1780,1786,1791,1796,1802,1808,1814,1819,1823,1828,1832,1836,1842,1849,1856,1861,1866,1870,1875,1883,1888,1892,1897,1903,1908,1915,1921,1926,1931,1936,1942,1947,1951,1956,1960,1964,1969,1977,1983,24,26,36,30,32,66,74,62,40,44,46,48,50,52,54,124,58,60,62,64,54,44,36,56,121,321,28,74,28,321,70,42,38,32,72,68,1992,109,1995,2008,2019,2033,2047,2061,2074,2092,2104,2117,24,26,36,30,32,66,74,62,40,44,46,48,50,52,54,124,58,60,62,64,54,44,36,56,121,321,28,74,28,321,70,42,38,32,72,68,1992,109,34,2136,2148,2160,1,2,1,1,1,0,36,2172,50,30,637,58,48,26,1111,60,79,2175,42,2179,28,44,62,54,38,106,1063,1377,2182,2185,2188,647,491,2188,1380,2191,2194,2197,2200,2204,2207,2211,2215,2219,2223,2227,2230,2233,2236,2197,2239,2243,2246,2249,2252,2255,2258,2261,2265,60,2269,2272,2275,315,318,121,2278,2283,327,2287,74,36,30,48,26,60,74,2292,42,28,62,54,50,42,1,1,2296,2300,2304,321,2307,2312,2316,2319,740,56,2322,2327,2333,2339,1,1,773,24,97,828,475,1743,32,1746,1750,52,825,1753,109,1275,64,1757,482,1761,653,1764,347,40,1767,1771,1775,1780,1786,1791,1796,1802,1808,1814,1819,1823,1828,1832,1836,1842,1849,1856,1861,1866,1870,1875,1883,1888,1892,1897,1903,1908,1915,1921,1926,1931,1936,1942,1947,1951,1956,1960,1964,1960,64,2344,1888,2349,868,743,746,32,52,825,36,2172,2353,50,136,2356,30,46,2359,2362,2365,162,2368,2371,2374,48,26,2204,60,79,106,42,28,44,62,54,38,2377,2380,106,1377,2384,2387,2390,2185,2393,2396,2400,2403,2406,1030,2410,2414,2418,2422,2426,2430,153,2434,2437,2440,2443,1380,2446,2449,2453,2456,2459,2191,2462,2236,303,2319,2243,2249,2465,2258,74,36,79,1275,306,50,2384,2387,2316,2319,1476,2468,1479,2471,56,2474,2478,2483,2488,2492,2496,429,2501,2504,2507,2511,1704,2515,2518,812,2522,2525,2175,2528,2532,1383,2535,2539,2543,2547,2551,2556,2561,2565,2569,818,2574,2577,2580,2584,2588,2591,2594,2200,2598,2602,2606,2611,2616,2620,2624,792,2629,2632,2635,2639,2643,2646,2649,799,2653,2656,2659,2663,2667,1282,2670,961,2674,2678,2682,2278,2283,327,2287,479,2687,2690,2693,2697,2701,2704,2707,2712,2716,2719,2723,2728,2733,2737,2740,2296,2300,2744,2748,2307,2312,2753,2757,2761,2766,2322,2327,2333,2339,1,1,773,2770,2773,2776,2780,2784,2787,2790,958,2794,2797,2800,2804,2808,2811,2814,779,2818,324,2821,2825,2829,2832,2835,899,2839,2842,2845,2849,2853,2856,2859,2863,2866,2869,2872,2876,2880,2883,2886,2890,2894,2898,2902,2907,2912,2916,2921,815,2925,2928,758,2931,2935,1357,2938,821,2942,2946,2950,2955,2960,2964,2968,24,64,40,743,746,32,52,825,809,2973,2976,2979,2983,2987,1268,2504,2990,2501,2994,2998,3003,3008,1383,2522,3012,3016,3020,3024,3029,3034,3038,3042,3046,2935,3051,3056,3062,3068,3073,3077,825,3081,1761,3084,3088,482,3092,2656,24,64,40,743,746,32,52,3095,1017,3098,3101,3104,3108,464,3112,3115,1411,3119,3123,3127,3132,3137,3141,3145,828,653,347,3150,3154,1750,1275,828,789,3158,3095,3161,3165,432,3169,3172,915,3176,2474,2478,2483,2488,2492,2496,782,3180,3183,3186,3190,3194,3197,2518,888,3200,3203,3206,3210,3214,3217,1,3220,1,3224,3228,3233,3238,1,1,1033,3242,3246,3250,3255,3260,3264,1,928,3268,3272,3276,3281,3286,1278,3290,785,3295,3299,3303,3308,3313,3317,3321,941,3326,3330,3334,3339,3344,3348,3352,1118,3357,3361,3365,3370,3375,3379,3383,3388,3392,3396,3400,3405,3410,3414,1,806,2716,1711,3418,3422,3426,2737,2740,776,3429,3432,3435,3439,3443,3446,2757,3449,2766,3453,1,1,1,1,1,1,2,2,2,2,1,2,1,1,6,8,10,12,14,16,18,20,22,1132,3457,3460,3463,3466,3469,3472,3475,3478,1135,3481,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,32,40,52,64,66,888,809,3214,3203,3217,3200,3487,429,1704,2504,2515,2501,112,812,2532,2525,1383,2522,3490,818,2588,2577,2591,2574,815,3042,3493,2935,2928,1357,2925,3497,3073,3077,3500,3504,3508,3512,799,60,2667,2656,1282,2653,3516,789,779,432,2829,3095,324,3169,3158,3519,3522,3526,3530,3534,3538,3542,3546,1118,3375,3361,3379,3357,3550,825,482,1761,3092,3081,3554,828,1750,347,1275,653,3557,1,1,1,1,1,1,1,1,1,1,0,1,32,3560,40,865,52,749,749,746,40,24,743,482,482,1761,1761,3564,3564,3092,3092,3568,3568,3568,825,825,3084,3084,3084,878,68,1,62,44,121,60,50,68,50,1,68,28,1,46,410,596,1057,590,3443,3572,3432,3577,3446,3581,3581,2511,2504,776,3435,2921,2921,3585,3585,3589,3589,3594,3594,3598,3598,2757,2757,3603,3603,3603,54,54,38,2829,3608,324,3613,2832,3617,3617,3165,3095,779,2821,3621,3621,3625,3625,3629,3629,3634,3634,3638,3638,2835,2835,3643,3643,3643,62,3648,3652,3656,906,2987,3660,2976,3665,1268,3669,3669,809,2979,3008,3008,2994,2994,3673,3673,3678,3678,3682,3682,2990,2990,2998,2998,2998,44,3687,3690,3694,3698,3702,2853,3706,2842,3711,2856,3715,3715,899,2845,3719,3719,3723,3723,3727,3727,3732,3732,3736,3736,2859,2859,3741,3741,3741,28,100,2588,3746,2577,3751,2591,3755,3755,818,2580,3759,3759,3763,3763,3767,3767,3772,3772,3776,3776,2594,2594,3781,3781,3781,48,48,2459,48,48,2935,3786,2928,3791,1357,3795,3795,815,758,3799,3799,2938,2938,3803,3803,3803,50,106,2356,2532,3808,2525,3813,1383,3817,3817,812,2175,3821,3821,3825,3825,3829,3829,3834,3834,3838,3838,2535,2535,3843,3843,46,46,46,2667,3848,2656,3853,1282,3857,3857,799,2659,3861,3861,3865,3865,3869,3869,3874,3874,3878,3878,2670,2670,3883,3883,3883,60,60,3888,60,2275,3891,3888,3895,3900,3905,3910,2283,2678,3915,327,3920,961,2682,3925,3925,3930,3930,3935,3935,3941,3941,3946,3946,2287,2287,3952,3952,121,1750,3958,347,3963,1275,3967,3967,828,3150,3971,3971,3975,3975,3979,3979,3984,3984,3988,3988,3993,3993,3997,3997,3997,72,72,72,347,2643,2643,2532,4002,2632,4007,2646,4011,1383,792,2635,812,4015,4015,58,58,58,3426,4020,1711,4025,2737,4029,806,3418,4033,4033,34,3286,3286,3272,3272,4038,4038,1278,4043,928,3276,4048,4048,100,4054,4059,4064,910,620,4069,4073,4077,4081,1704,2504,4085,2515,4089,429,2507,38,38,4093,4096,2690,4101,2704,4105,479,2693,56,4109,4114,4119,4124,2643,2632,2646,792,4129,4135,4139,4144,4148,895,4153,106,1360,2283,2678,327,961,3286,3272,1278,928,100,4158,4162,4167,4171,467,4176,2374,3286,3272,4038,1278,4043,928,3276,100,26,32,40,52,24,482,1761,3092,825,2935,2928,1357,815,2987,2976,1268,809,1704,2504,2515,429,4181,4185,425,4189,4194,891,2629,2646,2643,2639,2632,792,3081,3092,482,3088,1761,825,4198,4202,4206,4210,4215,4219,3268,1278,3286,3281,3272,928,4223,3656,3648,4227,3652,906,3429,3446,3443,3439,3432,776,54,3200,3217,3214,3210,3203,888,4232,1271,4236,4240,4245,884,4249,4253,4257,4261,4266,1434,4270,2925,1357,2935,2931,2928,815,2574,2591,2588,2584,2577,818,653,1275,1750,3154,347,828,3180,3180,3197,3194,3190,3183,3183,782,4273,4277,4281,4285,4290,1037,2522,1383,2532,2528,2525,812,4294,4298,4302,4306,4311,3522,4315,4167,4319,4323,4158,467,4328,4119,4109,4333,4114,4124,3542,3538,3530,4339,3534,3526,3098,3112,464,3108,3101,1017,74,74,4344,4348,4352,4356,4361,1122,2653,1282,2667,2663,2656,799,2674,327,2283,2278,2678,961,121,3357,3379,3375,3370,3361,1118,3295,3317,3313,3308,3299,785,4365,4370,4375,4380,4386,4391,70,2,4396,4400,4405,4410,4416,4421,4427,4432,1,1,1,1,1,1,1,1,1,2,26,46,34,60,50,38,30,62,28,56,48,36,106,74,58,24,52,64,32,40,321,100,303,54,70,54,1,1,961,4438,799,34,66,64,118,72,68,100,100,24,52,4442,97,52,52,52,109,1057,58,44,28,44,36,106,36,36,68,38,38,38,38,50,50,50,40,32,42,36,97,24,1743,54,74,60,60,60,28,74,62,62,30,26,26,54,54,32,48,48,48,46,46,106,106,30,52,4445,4449,2687,2687,2687,60,118,118,118,56,70,2,1,1,4453,4456,4459,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,2,4462,1,1,1,1,1,1,1,1,1,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,24,32,40,52,64,109,1392,746,815,4471,773,776,479,888,818,812,799,961,779,789,785,782,828,792,825,806,809,884,1118,1017,2507,4475,467,3123,3299,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4479,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4484,4489,4489,4489,4489,4489,1,1,1,1,1,1,1,1,44,306,36,377,106,28,321,42,1060,627,62,620,30,643,1063,62,100,30,575,50,54,303,26,624,48,72,58,46,66,121,79,60,38,46,56,24,743,40,865,64,4496,868,4499,4503,4506,4510,4513,32,878,749,749,881,24,743,743,40,865,72,1091,64,868,4517,109,828,335,32,97,878,749,881,48,38,24,1,1,1,58,1,1,1,1,1,1,1,2,2,1,1,1,2,2,4520,1,1,1,1,4,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,809,884,888,891,895,899,785,782,902,4523,779,928,789,932,815,776,941,773,945,818,828,792,812,825,961,965,799,429,0,0,0,24,40,64,746,878,749,881,32,52,828,792,825,0,0,0,0,809,895,848,779,815,776,818,792,812,4527,4537,4547,0,0,0,0,3817,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,809,2863,895,1118,799,828,779,928,812,776,941,818,806,958,429,479,884,4552,815,24,40,746,4557,64,749,52,1392,32,4560,878,0,0,4564,4564,4564,4564,4564,0,0,0,0,0,0,0,0,0,0,0,179,479,179,179,179,809,2863,895,179,179,179,1118,799,828,179,179,179,779,928,815,179,179,179,776,941,818,179,179,179,806,958,812,179,179,179,429,789,773,179,179,4570,4574,0,0,0,0,0,0,4578,743,865,64,868,32,97,52,755,1392,1468,4584,4588,502,4591,4595,4599,4602,4602,4602,4602,4602,4602,4602,0,0,0,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,0,0,0,0,4608,4612,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,809,888,895,4617,776,773,818,4622,779,789,815,4626,899,782,821,4630,828,792,812,958,799,24,429,40,64,32,52,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4635,4635,4639,4645,4652,4658,4658,4664,4664,4670,4670,792,792,812,812,4676,4682,4689,4689,809,809,888,888,895,899,899,782,782,821,779,779,789,789,815,779,779,789,789,815,776,776,773,773,818,828,792,812,825,799,799,799,429,4695,4703,4635,4635,4710,4710,792,792,812,812,4715,4715,4715,4715,4722,4722,0,736,4728,4733,4738,2808,4741,4745,0,0,0,0,0,6,8,10,12,14,16,18,20,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4752,4761,4771,24,40,64,97,52,32,1764,809,479,888,895,899,782,1017,821,779,789,815,776,806,958,773,818,828,792,812,825,799,2863,429,4781,4791,4800,4808,4817,4825,4836,4845,4853,4864,0,0,0,884,4872,0,6,8,10,12,14,16,18,20,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,809,4876,884,888,4880,895,899,785,782,821,779,928,789,815,776,4884,941,806,4888,773,4892,818,4896,1118,4552,1122,828,792,812,429,4900,958,799,961,825,24,828,792,743,40,52,749,64,868,32,44,48,46,50,54,58,62,4904,4912,4917,969,0,0,0,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,0,0,0,906,910,915,0,6,8,10,12,14,16,18,20,22,812,4921,4924,4471,4927,2175,4930,4934,4938,4942,2525,4946,4949,4952,4956,2522,4959,4962,4965,4588,2532,4969,4972,410,4976,1383,4980,4984,4987,4990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4993,4993,97,4993,4993,4993,4993,4993,5001,40,4993,4993,4993,4993,4993,4993,4993,5006,5006,5006,109,4993,5015,5019,4993,4993,4993,4993,4993,5006,5006,5006,4993,4993,4993,4993,5026,710,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,4993,24,5033,5040,5033,26,30,32,5046,5001,5033,36,5033,44,48,5052,52,5001,5015,5019,54,62,64,5006,5033,66,710,5056,5061,5067,5061,3299,40,58,64,66,5056,5073,5079,3330,3299,1392,26,30,34,48,50,54,58,58,60,62,74,36,5083,5092,100,40,5100,54,64,5105,26,30,34,36,44,46,48,50,54,58,60,5113,66,70,74,24,5040,30,32,32,5001,5046,40,52,5113,64,5117,5033,28,28,5121,5125,34,5134,5142,5033,40,5100,4993,4993,42,46,46,4993,48,5033,50,50,4993,5149,3330,60,5113,62,64,5105,4993,66,5033,74,74,74,5117,5156,0,0,0,0,0,0,0,0,0,0,58,0,0,0,0,0,0,0,0,5162,97,1403,5172,28,5092,5121,36,4993,44,46,4993,4993,50,4993,4993,58,60,60,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,26,2,2,2,30,30,30,30,30,30,30,6,8,10,12,14,16,18,20,22,32,32,32,32,34,34,24,32,40,52,64,52,64,746,50,106,26,54,56,36,48,46,60,121,62,30,321,42,72,58,68,34,44,884,127,74,38,5175,2374,124,321,2,32,40,52,64,52,64,106,26,54,56,36,48,62,30,321,42,127,72,68,44,36,38,5178,627,130,32,40,4599,64,64,106,44,36,38,54,121,62,30,42,34,36,38,127,74,58,321,124,40,44,58,34,124,64,64,64,64,66,66,66,66,68,38,70,68,48,5181,5184,24,40,44,106,28,617,620,637,1063,62,30,54,303,79,124,74,24,62,124,377,106,28,1060,906,643,62,575,79,5189,124,74,64,72,624,1,24,24,24,24,24,24,24,24,24,24,24,24,24,24,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,40,40,40,40,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,64,64,64,64,64,64,64,64,64,64,64,64,64,64,72,72,72,72,72,72,72,72,5192,5192,5192,5192,72,72,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5205,5205,5205,5205,5205,5205,0,0,5205,5205,5205,5205,5205,5205,0,0,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5100,5217,5217,5217,5217,5217,5217,0,0,5217,5217,5217,5217,5217,5217,0,0,5105,5105,5105,5105,5105,5105,5105,5105,0,5105,0,5105,0,5105,0,5105,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5040,5040,5205,5205,5213,5213,5100,5100,5217,5217,5105,5105,5225,5225,0,0,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5040,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5213,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5225,5040,5040,5040,5040,5040,0,5040,5040,5040,5040,5040,5040,5040,0,0,0,0,0,5213,5213,5213,0,5213,5213,5205,5205,5213,5213,5213,0,0,0,5100,5100,5100,5100,0,0,5100,5100,5100,5100,5100,5100,0,0,0,0,5105,5105,5105,5105,5079,5079,5105,5105,5105,5105,5105,5105,5079,0,0,0,0,0,5225,5225,5225,0,5225,5225,5217,5217,5225,5225,5225,0,0,0,5231,0,2,2,2,2,5235,2,2,5239,5243,2,2,2,2,2,2,2,2,2,2,0,0,0,5248,1,1,1,1,1,1,1,1,1,1,1,0,0,0,2,0,0,5254,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,5260,0,0,2,0,0,0,0,0,0,5264,0,1,1,0,0,5267,0,0,5271,0,0,0,0,0,0,5278,0,0,0,5285,2,2,0,0,0,0,0,0,0,0,0,0,5291,0,0,5297,5297,5304,40,0,5310,0,0,0,0,0,0,0,5315,0,0,0,50,0,0,0,0,0,0,0,0,0,0,5321,0,0,0,0,0,24,32,52,70,5046,0,0,0,0,0,0,0,0,0,5326,0,0,0,0,0,0,0,0,5331,0,0,0,0,0,0,0,0,0,5335,0,5339,0,0,0,5344,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5355,0,0,0,0,0,0,0,0,0,0,0,0,0,5359,0,0,0,0,0,0,0,0,0,0,4993,5363,0,0,0,4993,0,0,0,0,2,0,0,0,0,0,4993,0,0,0,0,5367,2,0,0,0,0,0,4993,5100,0,0,0,4993,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5372,0,0,5377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5382,0,0,0,0,0,0,0,0,0,0,5388,0,0,0,0,0,0,0,0,0,0,5355,0,0,0,0,0,0,0,5392,0,0,0,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5402,0,0,0,0,0,0,0,0,0,5350,0,0,0,0,5407,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5411,0,0,0,0,0,0,0,5416,0,0,0,0,0,0,0,0,0,5421,0,0,0,0,0,0,0,0,0,5426,5431,5431,0,0,0,5437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5456,5416,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5278,0,0,5467,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5478,0,0,0,0,0,0,0,0,0,0,0,0,0,5483,5489,0,0,0,0,0,0,0,5483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5278,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5494,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5501,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5506,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5355,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,26,26,26,26,26,26,28,28,30,30,30,30,30,30,30,30,30,30,32,32,32,32,32,32,32,32,32,32,34,34,36,36,38,38,38,38,38,38,38,38,38,38,40,40,40,40,44,44,44,44,44,44,46,46,46,46,46,46,46,46,48,48,48,48,48,48,50,50,50,50,50,50,50,50,52,52,52,52,52,52,52,52,54,54,54,54,58,58,58,58,58,58,58,58,60,60,60,60,60,60,60,60,60,60,62,62,62,62,62,62,62,62,64,64,64,64,64,64,64,64,64,64,66,66,66,66,68,68,68,68,68,68,68,68,68,68,70,70,70,70,72,72,74,74,74,74,74,74,38,62,68,72,24,60,24,26,28,30,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,40,40,40,40,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,64,64,64,64,64,64,64,64,64,64,64,64,64,64,72,72,72,72,72,72,72,72,16,18,20,22,1,0,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,32,32,32,32,32,32,1,1,32,32,32,32,32,32,1,1,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,52,52,52,52,52,52,1,1,52,52,52,52,52,52,2,2,64,64,64,64,64,64,64,64,1,64,1,64,1,64,1,64,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,24,24,32,32,32,32,40,40,52,52,64,64,52,52,1,1,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,24,24,24,24,24,1,24,24,24,24,24,24,24,1,40,1,1,1,32,32,32,1,32,32,32,32,32,32,32,1,1,1,40,40,40,40,1,1,40,40,40,40,40,40,1,1,1,1,64,64,64,64,58,58,64,64,64,64,64,64,58,1,5510,1,1,1,52,52,52,1,52,52,52,52,52,52,52,1,1,0,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,5515,5515,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,2,4,5518,1,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,1,5515,2,86,86,1,1,1,18,5521,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,12,14,16,18,20,22,1,2,1,2,2,50,4,6,8,10,12,14,16,18,20,22,1,2,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5524,5528,5531,5534,46,5537,50,5541,1101,68,2384,30,1764,44,62,5545,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5548,5552,5556,5560,5564,5568,5572,5576,5580,5584,5588,5592,6,40,865,5596,5600,66,2797,5603,5607,5612,70,2869,5615,46,28,30,48,40,865,5596,5600,66,2797,5603,5607,5612,70,2869,5615,46,28,30,48,30,30,1,2,14,16,18,20,22,1,6,8,10,12,14,16,2,1,2,1,2,1,2,2,2,2,2,2,1,1,2,1,2,1,2,2,2,1,2,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,66,2,1,66,1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,2,1,2,1,2,2,2,1,2,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5619,5619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5624,0,0,0,0,5629,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,5634,5640,0,0,0,0,5646,0,0,0,0,0,0,0,0,0,0,5651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5657,0,0,0,0,0,0,5321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5506,5662,5662,0,0,0,0,0,0,0,0,0,0,0,5666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5670,0,0,5675,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5679,5679,5679,5679,5679,5679,5679,5679,5679,5679,5679,596,596,0,5679,5679,0,0,596,596,5679,5684,0,596,596,596,0,5494,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5651,0,0,0,0,0,0,0,0,5688,0,0,2,2,0,0,0,0,0,0,0,0,5679,0,0,0,0,0,0,0,0,0,0,5640,5640,5640,0,0,0,5679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,272,272,272,272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,5640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5693,5697,5702,5707,5715,5721,5727,5735,5741,5748,5753,40,5761,5768,5773,5781,5789,5795,5799,5806,5812,5818,5825,5829,5835,5840,3443,5844,3361,5849,961,5856,5861,5866,5871,653,5879,5879,1275,5883,5891,5883,5895,5900,5908,5916,5927,0,5693,5697,5702,5707,5715,5721,5727,5735,5741,5748,5753,40,5761,5768,5773,5781,5789,5795,5799,5806,5812,5818,5825,5829,5835,5840,3443,5844,3361,5849,961,5856,5861,5866,5871,653,5879,5879,1275,5883,5891,5883,5895,5900,5908,5916,5927,0,46,46,46,54,58,24,62,38,38,44,44,74,74,5040,48,24,0,66,68,68,66,5936,5936,5941,32,58,52,4993,42,4993,0,0,5950,5950,5955,5955,5073,5073,5960,5960,5966,5966,5970,5970,5974,5974,5979,5979,5984,5984,5991,5991,5997,5997,6002,6002,2577,2577,2928,2928,6008,6008,52,52,3432,3432,2646,2646,6012,6012,6017,6017,4517,4517,1711,1711,4245,4245,6021,6021,6025,6025,6029,6029,6039,6039,6043,6043,6029,6029,6029,6029,6043,6043,6039,6039,283,283,6057,6057,6039,6039,6039,6039,6065,6065,6029,6029,6039,6039,6039,6039,6074,6074,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,6039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,1593,1597,1601,410,1605,1609,1613,596,1617,1621,1625,1629,1057,1633,1637,1642,331,1646,593,1650,1655,1660,1665,1669,1674,1679,1683,1687,1577,1691,1695,1700,1704,1707,482,1585,1589,0,0,0,0,0,0,0,0,0,0,828,6083,6087,6092,6096,6102,6109,6113,6117,6122,6127,6133,6137,6141,6145,6152,6158,6102,6145,6162,3150,6167,6145,6172,6145,347,6176,6181,6145,6189,6193,4523,6145,6145,6197,653,1399,6201,6206,6145,6211,6216,6220,6225,6230,6234,6239,6244,6249,6253,6257,6261,6265,6276,0,0,0,0,0,0,0,0,0,6281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6295,6299,6303,6307,6311,6316,6320,6324,6328,6332,755,6337,6341,6345,6350,6354,6359,6364,6369,6373,6378,6383,6389,0,0,0,0,0,0,0,0,0,965,6394,6398,6402,6407,6412,4438,0,6416,6420,6424,6428,6433,6438,6442,0,6446,6450,6454,6458,6463,6468,6472,0,6476,6481,6486,6491,6497,6503,6508,0,6513,6517,6521,6525,6530,6535,6539,0,6543,6547,6551,6555,6560,6565,6569,0,6573,6577,6581,6585,6590,6595,6599,0,6603,6607,6611,6615,6620,6625,6629,0,2784,2808,425,432,3137,464,809,407,413,410,52,3443,6633,6636,2829,429,3375,3313,961,6639,5895,6645,24,335,6651,6657,6230,653,6667,6676,5891,6667,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,220,5640,220,5640,6683,6688,6688,6688,6688,6688,6688,6697,1,1,1,0,2,2,1,1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,70,2,1,2,1,2,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,2987,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,66,66,66,66,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,52,1,1,1,1,1,1,1,1,2797,2808,2811,1,1,1,1,0,1,1,1,1,1,26,54,48,34,30,62,50,46,36,44,38,42,56,70,124,321,121,58,74,28,60,24,52,32,4557,878,1465,881,139,590,410,4471,5052,6633,40,64,371,66,106,6706,4949,1,1,1,6709,6716,6728,6740,6746,6758,6770,6777,6789,6795,6808,6820,6832,6843,6857,6871,6883,6889,6895,6906,6917,6922,6932,6938,6944,6955,6963,6971,6979,6987,24,97,828,475,1743,32,1746,1750,52,825,1753,109,1275,64,1757,482,1761,653,1764,347,40,1,6993,1995,2008,2019,2074,2104,7004,7021,7035,7053,7065,7076,7090,7104,7117,7130,7148,7166,7178,7192,7206,7225,7237,7248,7260,7271,7282,7290,7301,7310,7324,7341,7357,2160,1836,1842,1861,1908,1915,1926,1977,7368,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2770,3101,3183,3200,746,7375,749,7379,4956,7383,7387,4965,7391,7394,7398,7403,1389,1386,7408,7412,54,62,44,38,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2973,2656,2653,2832,2925,429,2504,2501,1704,2515,2574,792,2632,2629,2643,2646,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7417,52,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7423,7430,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,24,6,26,1,44,8,46,1,28,40,34,2,48,60,54,1,32,10,38,22,52,16,58,1,30,42,36,1,50,62,56,2,1,14,1,2,64,20,66,2,1,1,1,1,70,1,1,2,1,12,2,4,74,18,2,1,1,68,1,1,72,2,1,7436,7439,7443,7447,7452,7456,7461,7466,7472,7476,7481,7486,7492,7497,7503,7509,7516,7520,7525,7530,7536,7541,7547,7553,7560,7565,7571,7577,7584,7590,7597,7604,7612,7616,7621,7626,7632,7637,7643,7649,7656,7661,7667,7673,7680,7686,7693,7700,7708,7713,7719,7725,7732,7738,7745,7752,7760,7766,7773,7780,7788,7795,7803,7811,7820,7823,7827,7831,7836,7840,7845,7850,7856,7860,7865,7870,7876,7881,7887,7893,7900,7904,7909,7914,7920,7925,7931,7937,7944,7949,7955,7961,7968,7974,7981,7988,7996,8000,8005,8010,8016,8021,8027,8033,8040,8045,8051,8057,8064,8070,8077,8084,8092,8097,8103,8109,8116,8122,8129,8136,8144,8150,8157,8164,8172,8179,8187,8195,8204,8208,8213,8218,8224,8229,8235,8241,8248,8253,8259,8265,8272,8278,8285,8292,8300,8305,8311,8317,8324,8330,8337,8344,8352,8358,8365,8372,8380,8387,8395,8403,8412,8417,8423,8429,8436,8442,8449,8456,8464,8470,8477,8484,8492,8499,8507,8515,8524,8530,8537,8544,8552,8559,8567,8575,8584,8591,8599,8607,8616,8624,8633,8642,5646,8652,0,0,8658,8663,8667,0,0,0,0,0,8672,0,0,0,0,0,0,0,0,0,8676,0,0,0,0,0,5472,0,0,0,0,8680,0,0,5646,0,0,0,8685,5456,0,8689,8696,8701,8706,5248,8713,8718,8724,8663,8729,0,0,8734,8738,5506,8744,8751,8754,0,0,0,0,5344,8761,5666,8663,8767,0,8772,8778,8784,5506,8788,8795,5624,5416,8801,0,0,0,0,8685,0,0,0,5411,5489,8680,8784,5506,8806,8812,5443,0,0,0,5377,8818,5506,5331,5355,8824,8828,8833,0,0,0,8839,8685,5326,8844,0,8772,0,8849,5267,8854,8859,5326,8863,8734,8868,8871,8877,8883,8889,8824,8894,8898,8902,8908,8912,8917,8849,8871,8921,0,8925,5624,8932,0,0,5326,8936,8940,5350,0,8944,8854,0,8948,8954,8959,8824,8965,8863,5483,5619,5367,0,0,8970,0,5624,5331,0,8828,0,5355,0,0,0,0,8975,0,8981,8986,8993,8997,0,9002,5372,0,0,8997,9007,0,5421,5331,0,8795,9012,9017,8718,0,0,0,5254,9023,8778,9029,0,0,5431,8788,5359,5456,0,9035,5619,0,5388,5411,8784,0,0,0,5367,5456,8908,0,9040,9046,8828,5310,5411,0,0,9050,9055,0,9059,0,0,9065,0,5331,5426,9069,9074,0,8863,9080,9083,5506,5321,9088,5437,0,8912,5278,8912,0,8868,0,8701,5321,8784,8877,9093,0,0,8801,9099,5437,8772,9104,5619,5331,0,8912,5267,5437,0,5355,0,9109,9114,9119,9012,0,9125,8986,9129,0,9065,0,5321,5624,9135,9141,9145,8868,9151,9080,5359,0,0,9156,8680,9161,9167,8824,0,9173,5506,5304,9029,9178,0,5363,5421,0,9183,9188,5411,9193,0,5657,8667,0,9198,9203,9208,9212,5688,9216,0,9220,8859,0,9080,9114,5619,9114,9226,0,0,9023,8784,5367,0,8863,9231,8685,5421,0,0,9237,0,9065,5629,9050,5646,5506,5426,0,9242,9247,9099,8761,9254,5666,9046,9260,9065,5367,5426,0,9265,9271,9276,5426,5331,9280,9284,9289,0,8672,0,0,5363,8701,5506,5688,0,8685,5684,8898,0,0,0,0,0,0,0,9260,9226,5619,5407,9294,9300,9305,9309,8667,0,0,0,0,0,0,9314,9319,9125,8676,5355,9069,8849,8788,8778,8954,5359,5478,9271,9325,0,8652,9331,0,0,0,0,0,0,0,8676,5421,9336,9341,9346,9352,9104,9357,9080,5619,0,9080,9361,8954,9007,9208,5675,5397,9007,5388,5355,5688,9198,0,0,0,0,9368,8859,0,0,9373,9099,9368,9305,9378,5331,8877,9382,0,0,0,0,0,8778,5407,9387,9391,9396,9198,8859,5267,0,9083,0,0,0,0,9114,5355,9401,8940,9050,8685,0,9406,0,0,0,0,8676,8706,0,5397,8767,5506,9055,0,0,5304,8854,9411,5506,9198,5506,5304,9417,5355,8849,0,9421,5331,0,5377,9426,8849,9050,0,0,9050,8849,0,8912,9431,9401,0,5388,5397,9437,9443,0,5367,9449,8685,9260,5388,9284,9220,5666,5666,0,0,0,0,9417,0,8767,9454,5411,8859,9458,9055,9280,0,0,0,0,9309,8696,9464,9470,0,5388,9475,0,9114,8849,8652,9480,0,0,0,0,9046,9104,8824,8676,9237,8849,9129,0,9129,0,8806,0,9454,8912,5619,9309,9059,5506,0,9007,9247,5397,9487,0,0,5355,9492,8676,5355,8667,0,9498,5506,5619,9284,5248,8849,9093,8854,8871,9198,9475,9502,9173,9093,5624,0,5267,0,0,9508,9514,9520,0,8806,9046,0,0,8993,0,0,5426,9271,0,9525,9530,0,5291,9535,9309,9046,9525,9083,9540,0,0,5267,8685,9237,9502,9545,0,5355,9551,8877,5506,8824,5506,9050,0,9555,9284,9560,0,5367,0,8713,5388,0,9040,0,9454,0,8672,8898,0,8997,9520,0,0,9508,0,9421,0,0,8680,5411,0,8898,9104,0,0,0,9104,0,0,9083,0,8944,5478,9426,9565,0,5382,5506,0,8767,9570,9083,9574,8713,5367,9151,8806,0,0,0,0,0,0,8940,5377,9007,9580,8772,9050,0,5359,0,9587,8948,0,9088,9280,9592,5416,0,5472,0,5350,9074,0,9237,9560,0,5304,9198,0,0,0,5431,9597,8685,9602,5326,8917,0,9606,5506,9373,8871,8908,9520,5350,9046,5506,9498,0,5431,9612,9426,9417,5359,8784,5392,5666,9617,8738,0,0,0,0,9555,9135,9621,8849,9626,8898,5666,5304,8734,0,0,5377,0,9626,8778,9437,9631,9502,5483,9637,9602,9309,5684,9642,5431,9198,5239,9647,8685,9284,9597,9198,9242,9346,9373,0,9346,9652,8801,9319,9492,5411,5619,5651,5411,9411,9464,0,5675,9188,9658,5506,9059,5248,8667,0,8784,0,8701,9664,8997,9668,9674,8824,8676,9373,9602,8863,8954,0,0,9040,8806,0,5456,9679,9508,8948,9502,9449,0,9637,9684,8859,0,9688,9694,5431,5339,0,9017,8767,9305,0,9188,9699,5355,0,9271,5355,9226,0,0,8685,9431,9520,0,9125,9704,9417,9226,5267,8908,5506,5619,9055,5646,9300,5483,8908,5355,0,0,0,9040,9396,9709,0,0,8667,9715,5355,5326,5467,5377,5416,9417,9449,8724,0,5411,8685,0,5248,9565,8912,0,9720,5494,5372,9216,9725,9284,8754,9336,9729,8912,5431,9617,8912,0,8706,9145,5426,9733,5646,9396,9046,9470,9464,9059,9738,8849,9464,9305,0,8908,8849,0,8806,0,8883,9396,8908,9642,9602,9743,9709,8706,9748,0,8908,0,5359,0,9520,9080,8975,9720,9226,8975,5350,9720,0,0,9668,9188,5321,5331,9129,9748,9754,9498,0,9396,9178,8738,5666,9760,0,9464,9766,0,5666,0,5267,9046,0,9771,9776,9574,5684,9080,0,5355,5355,5426,5315,9674,9760,9502,9368,9226,5355,5666,8824,9284,9470,9781,9729,9785,0,5331,5359,5483,5426,9535,0,8868,0,9602,8824,0,9417,0,0,9709,0,5506,0,5355,5388,0,9791,0,9242,5675,8894,5411,8818,0,0,9574,0,9055,5388,9796,5331,0,9183,8680,0,5355,9801,5304,5310,9080,8997,0,0,9069,0,9508,0,0,8663,0,9806,5407,5431,5388,0,9464,9336,9814,5624,0,5271,9114,9007,8806,0,8667,0,5271,8738,9652,9309,5506,0,5355,5355,9820,8824,9771,9023,9826,0,9325,5355,9830,8889,9055,9099,9492,5506,9231,5304,8912,9055,8912,9050,9059,9565,8806,9093,0,9699,9592,8859,8912,0,8812,9592,9069,0,9699,9592,9188,9835,0,0,9508,5431,9449,5359,9050,0,0,5506,9093,8788,5449,0,9220,0,8778,0,5634,8849,9826,0,0,9294,0,8912,9720,5388,0,9597,5359,0,8970,5388,0,5388,0,5304,9226,5462,8898,5634,0,8718,9151,5506,8824,5684,9642,9602,9729,8672,0,0,0,5291,8854,8917,9220,9688,9411,9841,9426,0,0,0,0,0,9826,9574,8940,5456,0,9104,5267,9574,0,5407,5291,5437,9198,0,8667,0,0,9023,8744,8908,0,0,5619,5619,9357,9226,0,0,8940,9709,9658,0,0,0,5506,9791,5350,9592,5344,0,8948,5355,8761,9743,8859,9242,5666,9449,5310,8877,0,0,9508,0,9574,0,5367,0,9830,9046,9114,8801,0,9114,0,9847,9853,5321,0,9592,9858,9864,5331,8685,0,8824,9647,5331,5688,9029,9216,9754,9684,5326,0,9869,8788,9642,9046,9083,9151,5267,9055,9606,0,5267,5646,5494,0,0,5472,9876,0,9684,9684,9881,9801,9325,9319,9040,9426,5489,9156,5382,0,9417,5355,9535,8652,9754,0,8981,8908,8824,5431,0,0,0,0,8824,5355,9226,9602,9679,5619,8685,5267,5646,5326,0,8824,9083,9885,9017,9104,9178,0,9606,8854,8772,8667,0,9109,9135,9754,5506,8839,8921,8676,9720,9341,9065,0,8667,9891,9729,5666,9814,5431,9480,9093,8734,9826,0,5359,0,5506,5426,0,9699,9080,5426,9183,9729,5431,5331,5304,9050,8806,9801,5437,0,0,9688,8824,9401,8818,5472,9647,0,5363,5411,9226,5506,9023,9065,9426,5377,8667,5619,0,8828,9325,8738,9401,0,9781,0,0,5675,0,5489,5248,5355,9895,9900,5267,9904,8685,5506,9208,5355,5684,8652,0,8738,8917,0,8997,8667,5629,9125,5304,8997,8761,9664,0,9254,9226,9336,0,9912,9771,9080,5239,9679,5388,9918,0,9864,0,0,9129,0,9647,0,8801,5278,5304,9443,0,5646,9743,9173,8898,9029,8925,0,9396,5331,9265,9876,9305,9781,9289,0,9104,0,9881,8940,9198,9760,8993,0,0,5254,9198,8778,8754,9231,9260,8701,9570,5355,9720,9226,9156,9373,0,9900,0,9454,0,9237,9396,8849,8812,9198,5411,5456,5619,9597,5291,8738,5619,8784,9647,9602,8839,0,0,5326,9378,9254,9830,8696,5411,5494,5377,0,9208,9565,9401,5675,9188,9891,9173,5437,5437,5472,5339,8734,5326,9801,9426,8868,9141,9145,9417,9417,5657,0,0,9922,0,9771,5426,5304,5619,0,8784,9109,9891,8676,0,0,0,9449,5326,9300,0,9580,5267,5506,0,9502,9928,5377,9284,9055,9820,9934,8828,9602,0,0,0,5619,9305,5326,8908,5619,0,0,9305,8738,9540,5315,5321,9940,9254,9417,9080,9309,0,5489,5489,0,9173,0,8908,9017,0,8824,9449,0,9216,9046,0,9826,5304,9173,9065,9945,8849,9574,9305,5291,5388,5359,8676,9729,9950,9876,8959,5359,9069,5431,9216,9876,8718,9950,5431,8997,0,8738,9216,9957,9508,5388,0,8667,0,5291,8784,8932,9088,5344,5359,9325,9592,0,9023,0,0,9203,9540,9208,9565,0,9178,0,5634,9216,9963,5675,9704,5651,9968,8801,9050,9606,9592,0,0,0,0,5506,0,0,5367,9487,9188,9188,5421,9029,8908,9974,0,0,5688,9602,9046,9208,9979,9099,0,0,9050,0,0,5684,0,9480,9668,0,9475,0,0,0,5304,0,0,0,8997,9059,9035,9743,9265,0,0,9986,0,9083,8724,0,9940,5489,5359,0,0,0,0,8824,8854,9093,9007,8948,9023,0,9991,9023,5688,9220,9305,5304,5331,5339,0,9464,9934,9284,9145,0,5304,8784,9226,9156,0,5339,9841,9065,0,9922,9325,0,9470,0,8936,9626,9305,0,5326,5489,9050,9417,5315,9129,9864,8824,5407,0,8663,9294,8877,9284,0,0,0,0,5494,9046,0,0,5501,0,9997,5315,0,8713,0,0,9754,5321,5426,0,9119,10003,0,0,9226,0,5670,8672,9688,5359,0,0,0,9065,8970,8868,5243,9411,5646,9864,9029,5304,5267,0,0,5483,0,0,0,5619,5624,0,9785,5344,9109,8767,5489,5355,9065,5355,0,0,0,0,0,10008,5304,9050,8871,8940,9826,5321,9895,8849,9188,9417,9088,9119,0,9309,8652,10012,0,0,5367,8948,0,0,10012,5456,8908,0,9974,9574,8898,9203,9449,8997,9080,5331,8912,0,9065,5411,5355,0,10017,5688,5629,0,9341,8921,0,5355,0,8925,9065,0,5304,5411,5426,5388,0,0,8718,0,0,5421,0,9254,9198,9830,0,0,0,9059,5388,5304,9119,8724,0,0,9141,9093,5388,8784,9401,10023,8812,10028,5449,5392,8993,8761,0,0,8940,9679,0,9684,9555,10035,9156,9498,9208,9679,5359,5634,5359,8738,9421,8718,0,5331,9612,8908,0,0,5407,9325,5684,5431,5359,5350,9029,9704,9760,5339,10041,0,0,9835,8936,5339,9760,5437,9487,0,0,0,9864,5331,8828,9135,8948,5437,9826,9151,0,5431,0,9597,10047,5657,8806,9674,0,5321,0,8970,0,5619,0,5377,9387,5506,8680,5331,9626,0,5506,0,5355,10052,5619,0,5239,9216,5326,5684,0,0,0,9918,0,9597,0,9135,9012,9083,9560,8685,9664,9570,9725,5367,5239,5431,5339,5397,5506,9083,9602,5315,0,8912,5421,0,8667,5335,5506,0,8921,5339,8676,0,5657,9156,9652,0,5271,0,0,0,0,0,0,9679,0,9617,9382,9426,10028,8889,0,5355,9305,0,0,9059,9699,0,9325,9080,9781,5431,10058,9801,5377,9226,9968,9129,8859,5467,5326,5506,5335,5239,9830,5443,0,5388,5331,5359,8828,0,9099,0,5657,9265,0,8754,9771,9012,5355,9325,0,9957,9796,9088,9545,10062,0,9178,9475,0,0,9475,9411,0,5624,0,0,5684,0,0,9198,10068,9411,9725,8812,8997,10012,9688,0,0,8871,8849,5402,9411,0,0,8936,0,10068,0,9555,9658,9864,5489,5489,8744,0,8868,9099,0,9173,5355,9729,5506,9431,8824,8795,9271,9357,9050,9679,5304,5315,5350,9046,9743,0,0,0,0,9454,9688,8912,8932,5506,9688,0,9470,5377,0,8833,0,9443,8824,8824,0,0,0,0,8940,0,0,0,0,9417,5619,5267,5437,0,8729,8940,9443,5304,5483,0,0,0,0,0,9602,5355,9373,8954,0,8795,5367,9357,5388,9602,0,5619,9242,5506,0,5624,8812,0,5339,8970,8667,5355,0,8784,0,0,0,8795,8948,8784,5506,5467,8921,5355,8828,0,8997,8889,5372,9198,9688,5331,0,0,0,0,0,0,0,9508,10017,0,8718,0,9309,8863,5619,9188,5619,0,10062,0,0,8806,9265,9602,5657,0,9378,0,0,0,8784,5619,9305,5651,9785,0,9806,9156,8849,9099,9284,0,0,0,9135,9602,9093,9801,8849,9679,5321,9065,9109,5421,9156,9135,8751,9046,9007,0,0,0,0,5506,5472,0,0,9475,5624,9216,9040,5388,5372,5675,5388,5506,5304,9729,8812,8801,9346,9814,8685,9934,8663,9492,10073,9193,0,9688,9188,9023,5243,5478,0,9470,9220,5267,0,9271,0,0,9050,9336,9114,9167,8812,0,0,0,5431,5304,9023,0,0,5431,5291,10073,9151,5437,5350,9242,9040,0,9125,8824,0,0,8902,5624,5506,8724,0,9093,10079,0,5339,5392,0,0,0,9492,5670,9771,0,8696,8849,0,5248,5339,8912,9791,10085,0,0,9294,8652,0,0,0,0,9305,8925,0,5350,9679,5326,10079,9565,9912,9080,9226,9341,10068,0,9331,9065,5248,5326,0,8824,9835,9050,5646,9231,8788,8854,0,0,0,0,0,0,9699,8701,8788,8889,0,9065,0,8685,0,0,0,9679,10041,5335,0,0,5443,5331,0,0,9050,5675,5335,9151,5634,5489,9957,0,8663,9050,0,5321,0,8854,8849,0,9040,5355,5411,0,0,0,5619,9212,9242,9401,5267,9309,9602,9555,9785,8667,9602,0,5321,0,9574,9637,0,5331,9957,9858,10091,9540,0,8883,0,9151,8676,9074,9093,9208,10096,0,9617,9346,8738,9151,0,9341,0,9738,9738,8767,9325,0,9173,0,5421,5688,9864,0,8672,0,9151,9791,10058,9305,8986,9055,5388,5355,9835,0,9065,5331,9754,9626,0,9093,9826,5624,5339,5278,8672,8936,5506,0,0,9023,9530,9900,8812,8812,8844,8667,5421,8667,5321,9300,9443,0,0,9083,8801,0,0,5367,0,0,5267,5421,5506,5335,0,0,9208,8877,8663,0,9220,10101,5421,9729,0,8940,0,9114,9093,9934,8959,5416,5416,10107,9373,8824,5688,0,0,0,9208,9145,0,5304,0,9411,9178,9231,9426,9492,9934,9647,9242,8849,9099,9709,0,8940,8801,9540,5437,8824,5344,5367,5331,0,0,0,9093,5431,0,0,9771,8936,5646,9029,5239,8824,0,0,9997,10112,5670,0,9771,0,8685,5285,9688,8997,0,0,0,0,5506,5367,0,5285,0,9475,5326,0,0,0,9454,9464,9212,10008,8663,5331,9325,0,5355,8863,0,9104,5321,8724,9151,0,0,0,0,0,9212,9688,5372,10008,5489,0,0,0,0,0,9104,0,0,5372,5388,10008,8921,9426,10008,8948,0,8868,0,0,9709,5388,5355,9715,0,5331,0,0,5372,0,5350,0,0,9080,0,0,0,0,8925,8828,8667,9300,8993,8824,5624,9151,9260,9074,5431,5646,5431,0,0,5331,5651,9918,8772,0,5456,9895,9242,5382,9368,9738,0,9080,9368,8908,9114,9029,9574,8849,8754,9203,9023,5456,9040,9621,8778,9080,10117,9864,9361,8944,9826,8824,10028,9411,0,8871,10123,9934,9904,5359,9574,5271,5331,8932,0,0,0,0,9912,5506,8849,5619,8828,8696,0,9099,0,0,10068,0,0,0,5367,9035,0,9748,8863,8912,9012,9637,5331,8696,9864,5397,0,9617,8824,9417,9352,9597,0,9733,9426,10129,5248,9046,10117,0,5267,5350,5315,5315,8849,9247,0,0,10135,9265,9242,5355,0,0,8993,8663,0,9083,5350,0,9738,10058,8672,9555,8917,9046,9325,5355,9382,9443,10012,0,5411,5331,9498,5355,0,8868,9135,5331,9059,10141,8667,0,9449,9083,9156,5367,9454,5494,5657,9535,0,0,8685,9119,9216,8908,0,9361,0,0,8772,5494,9699,9208,9151,0,0,0,5355,8993,0,9525,8833,8734,8801,9699,9699,5431,9059,0,0,0,8724,8859,5304,0,5267,0,9699,9426,9587,0,5411,9341,9945,0,9188,9766,9203,5624,9050,5359,9699,8812,9141,8828,5331,5462,0,8997,9368,0,0,9188,9065,9346,9208,9658,5472,5331,8871,9023,5388,0,9156,9145,9498,5666,9336,0,0,0,9555,0,5402,9637,8940,9475,0,9050,0,8801,9664,9242,5367,0,9699,9502,8970,5339,8993,8908,9508,5315,9050,0,10091,8948,5304,9876,9378,0,9023,10112,8754,0,5321,5267,8908,9895,5670,8993,0,0,9242,5684,9093,9885,5388,8997,10147,8993,9294,9023,8828,9847,9203,8975,0,9464,9454,8993,0,8917,8859,8812,9885,9059,5411,9826,9203,0,10047,9791,9050,10058,9826,0,9059,5304,0,5456,9151,9617,9602,8908,8908,9781,8970,8824,9203,8754,9188,8812,9145,5355,5411,8849,9720,9178,9796,9188,9050,9183,9173,5494,8812,9361,9592,5431,0,9443,10028,9156,9729,5684,8818,9401,8824,9035,9208,9841,0,8738,8970,5449,5666,9621,9464,9709,9688,5315,5321,10085,5388,5421,5331,5335,9864,8965,5335,5267,9093,5684,5315,9401,0,8685,8902,9574,5688,8824,0,0,9305,10153,0,9545,0,5411,0,5456,5326,5421,0,0,0,9188,8824,9119,5411,9704,0,8970,9826,8778,9055,9046,9720,8718,8718,0,9050,8959,9294,9029,0,8868,9912,9212,9679,9280,9733,9050,0,5411,0,9271,9963,9637,5271,9309,8959,9535,8940,9679,0,9487,0,0,0,0,8948,0,9720,9417,8824,0,9231,9357,0,0,8729,9065,9373,9294,9396,8663,9545,0,5359,9387,5431,0,9508,5350,0,0,9715,0,5326,8784,9806,0,8806,0,5416,10068,9099,9226,10107,9498,5331,0,5304,8729,9212,0,5483,9631,8812,5304,5377,5335,9125,0,9046,5388,0,9401,5506,8696,0,0,5634,9401,8754,9565,9080,0,9050,10159,10058,8908,8824,8975,9401,9309,9167,9417,8970,0,0,5382,9668,9612,9178,5331,9346,0,9679,5291,0,8908,0,9535,9325,9492,9997,8824,5416,9545,8908,5506,9431,0,5437,9664,0,9017,0,0,0,5388,9099,9570,9431,9198,10079,8652,8652,9352,5506,9864,9617,9065,8925,5331,0,5239,8784,9754,9664,10058,9637,0,8778,5367,5326,5437,9088,9464,9417,0,0,9617,5372,9535,8839,9580,0,9104,0,9378,9426,5407,8685,9771,5494,8908,5411,8997,9050,0,9198,9699,0,8859,9606,10073,8871,10165,8839,8908,9114,9963,5344,9694,10008,9725,9178,8818,5331,9007,8993,9715,5426,5670,0,5431,9766,5291,9055,0,0,9198,9125,9679,5646,0,8806,0,9109,9271,8754,9771,9080,0,5321,9294,5315,9785,9188,9574,9592,5367,5350,9188,5675,9023,9059,5321,9265,0,0,9135,0,9668,9668,0,9806,9520,0,5339,9545,0,10068,0,8925,0,8754,0,8824,8754,9574,0,9508,0,9417,5377,5506,9411,0,0,8672,0,9280,0,9502,9173,0,0,9647,9508,9545,5657,9470,5331,9125,5411,0,8828,0,9520,0,9208,8667,0,9198,5431,0,10107,5437,8772,8801,8894,9378,9470,9357,9145,8801,9029,5506,0,0,9806,9396,9791,9411,0,9378,9891,0,0,5506,5321,5388,8754,8863,5472,5326,8912,9198,9050,0,0,9331,5254,9231,8849,8824,8724,9231,9109,9560,9325,8940,0,9464,8676,9475,9237,9002,9035,5675,0,8912,0,9963,9055,8772,8854,9129,9449,0,10058,9891,9023,0,9406,5271,8738,0,0,9226,0,0,5267,9378,8936,9631,9417,0,0,0,8729,8940,8738,0,9411,8828,9208,5478,0,8936,8965,0,10147,9621,5350,9325,5624,5449,10169,9198,8959,0,9876,9208,9242,5670,5372,5437,8871,5619,0,5335,9242,5624,0,9841,9325,0,10123,9520,9502,8824,9198,8908,9099,9401,9226,10068,8921,5619,5478,9254,0,8696,5506,0,5624,5331,9109,9864,8701,5304,9188,0,5462,5304,9514,10175,0,9099,9688,9325,9294,8908,9492,9540,9602,9208,9208,0,9891,9743,8925,9668,9771,9454,5670,9876,5670,0,0,5331,8975,0,10165,8706,0,5421,0,0,5377,5494,9771,9050,0,8932,9928,5619,9704,9801,5267,9007,0,5494,10068,8877,9664,5388,8828,9242,5331,9679,9592,5472,9826,9869,9114,0,9093,9602,8738,5646,8718,0,0,0,8993,9050,8912,9912,8917,9305,8658,10141,9188,8997,8795,0,0,0,9900,5321,0,9720,5449,0,9709,8767,9626,5254,0,8772,5388,9791,8824,0,9545,8898,5506,9602,10041,0,8795,5355,9454,0,5462,9242,9188,5331,9242,5684,9046,8898,0,0,0,9401,5339,8908,9417,9535,9156,9151,10112,5506,8685,8696,9597,9046,0,9853,10101,5443,8889,0,0,0,8944,10147,10141,8871,9173,5326,8940,0,9188,0,8908,8849,8868,9602,9602,0,5359,9242,8944,9602,5411,9046,9602,5494,8784,9188,9309,5339,5431,5388,10041,5407,9325,10153,9198,8667,9766,5472,8981,9602,9050,5377,5278,0,0,10017,8970,8828,0,0,8828,8801,0,5472,5634,8788,8898,5506,9088,8981,9791,9046,5377,5372,8824,9188,9040,9325,8801,8940,5285,8738,5321,9017,9454,8993,10182,0,8849,8849,10003,9208,9294,9826,9046,9443,9602,5670,9059,8993,9231,8940,8824,9835,5331,9492,8663,5624,5355,5624,5331,0,9305,9895,9237,9738,0,0,9231,9173,0,8685,10012,9545,9104,0,8778,9173,9305,0,9023,9443,9426,5331,9699,5494,9336,9208,9475,9555,8883,9046,9492,0,5506,5350,9570,9065,9387,0,9378,9617,10079,5359,9709,8940,0,0,0,9508,8784,0,10017,0,0,9114,0,8898,8898,9991,8908,8672,9114,0,9050,9119,9617,0,10187,9806,9125,0,5407,8849,8767,9125,9704,9918,9361,5388,8898,8801,8663,8954,9198,8772,5359,8954,9487,5646,9212,5467,5478,8948,9198,8908,9612,9934,5431,0,8806,8784,8908,9754,9814,0,5321,9826,9074,10017,10112,9791,8718,5629,9141,10068,10079,9346,0,9346,5335,5462,8908,5421,5388,5321,8672,0,5426,9378,5326,0,8898,0,10003,0,5267,9198,9791,9417,5489,9704,9957,9502,5388,8849,8824,5304,0,10062,9426,9454,0,8908,5355,5483,5359,8788,8849,5506,8981,9346,9198,5239,9498,0,8652,8772,0,9346,0,9704,0,9352,10191,5355,5506,10058,5321,5675,5355,0,0,9963,10196,8706,5494,8908,8801,9733,8912,9437,0,10201,8993,9796,9242,0,9612,9198,9093,5624,0,0,9704,8824,9173,5494,5339,0,9271,9587,10068,0,5267,9007,9104,5666,9141,8663,8859,9502,9141,9502,9145,9198,9305,8812,9226,5416,5377,9050,9093,8975,8718,8936,0,8854,9109,5350,0,10206,9592,9555,8652,8912,8940,9203,9885,5494,9492,0,0,0,5339,9080,0,9046,9104,0,9080,0,9188,9826,0,9826,9454,9007,9156,9331,8908,8917,9426,0,0,0,0,5367,0,9498,0,8784,9046,5355,5449,9612,9305,10212,9156,9046,9454,8663,0,9145,9668,9606,9464,0,9502,9612,8883,9796,9368,8877,8713,8908,0,0,9957,9167,10112,8877,9265,0,9242,8667,9895,9555,10218,9280,9242,5684,5421,9065,9688,8724,5335,10222,0,0,0,0,9592,9104,5367,9284,0,0,5304,5624,5339,8908,0,5670,0,0,0,0,9050,5506,8667,8908,9704,5267,5506,8676,9080,0,9198,8849,9545,0,9346,5254,9129,5472,0,9738,8925,0,9771,0,9387,9046,0,9502,5331,9864,8940,0,8993,8986,0,9212,9040,9055,0,0,0,5355,0,9592,8997,10058,0,8833,9088,10023,10117,0,9535,5456,0,5506,5670,0,9065,5355,0,8849,0,5331,5239,9725,9188,0,5331,8908,10107,5331,0,0,0,0,8784,5472,0,5619,9151,8685,9220,8936,9325,8706,8767,8959,9346,10041,9035,0,8868,8912,9957,8824,5426,5331,0,0,0,5331,0,0,9470,0,5506,9658,0,9208,9046,0,8754,9035,9891,0,5407,9449,9760,5372,9226,0,8921,8859,9080,5411,10035,9109,0,8667,0,9587,9565,5326,5619,9357,10068,9480,9198,5506,9046,9080,0,8863,0,9592,5304,9007,0,5388,9325,5411,9237,9203,0,0,9059,0,9109,5359,8889,9065,0,9729,8812,8877,10212,9396,9357,9237,0,8738,9417,9934,9540,9565,8701,9602,5344,5619,9208,9602,0,10228,10123,5675,9035,8801,9050,8849,0,5506,9652,9626,9555,9325,10232,8824,8751,0,5506,8751,9449,8738,5397,9114,5339,9602,0,9378,8849,9725,5397,9050,10008,0,0,9963,8667,5278,8772,9464,9754,8751,8818,9587,9637,5331,0,9378,5421,5388,9055,9119,0,5634,8706,9173,5243,0,9597,8889,9188,0,0,0,9080,9145,8883,5367,5321,5331,0,5331,0,5355,9208,9709,9046,9480,10017,9417,9502,0,8754,10003,0,5331,0,0,0,5506,5254,0,5688,9637,8912,0,5675,8849,9305,0,8696,9426,9426,5506,9443,9050,9963,9525,5248,0,0,0,8824,0,9704,8734,0,0,9904,5339,10017,8936,8701,0,10101,0,9212,5506,0,9055,9050,5411,0,9226,5304,9658,9046,5675,0,5335,9046,10012,5304,8954,5331,9426,8965,0,9729,8833,0,8685,8751,9621,0,10091,0,9847,0,0,8824,9226,8801,0,0,5506,0,0,9046,5388,8801,5239,5350,5397,9729,0,5315,9443,0,9694,9411,5489,8932,0,0,8824,0,0,0,5359,8849,0,5506,9674,9709,8784,9637,9729,10017,5321,5443,9426,0,9104,8908,9188,9173,9991,5688,9597,5619,0,5326,0,5619,9305,9216,0,8685,9368,0,9114,0,5407,9114,8912,5483,10017,9814,5619,0,9104,5321,5326,10129,8932,9104,9325,9502,0,9271,9502,8806,0,8812,0,10017,9387,5331,10058,0,9080,0,0,0,9684,9684,5449,5431,0,9957,5267,0,9226,0,0,9065,5367,5359,9535,8944,9361,5634,8908,0,9520,0,8908,0,10169,5355,9621,9806,9431,0,5331,9325,0,9265,0,5304,9208,0,9725,8724,8724,8839,0,9156,5407,0,8680,9198,8696,9109,5315,0,5666,8701,0,9997,9530,9141,8713,5291,5619,9918,9530,0,5267,5619,9141,9188,9188,8751,9284,9853,8667,9242,9035,8912,8795,9754,5397,8772,9754,5421,9602,0,5675,9421,9109,9208,9729,9055,9602,9688,0,9378,8824,9080,9198,9853,8685,8868,5326,9597,5416,8849,9203,9565,5426,0,0,9387,5267,9254,9602,8713,8663,8925,5271,5472,5456,9771,9417,8839,5407,9007,5437,8908,9319,5624,9637,9156,9426,5411,5367,5326,8889,8784,5675,5416,5267,0,0,8912,9226,5335,9487,0,0,5402,5326,9652,9492,9396,0,0,5310,5666,9309,5372,9621,10068,8713,9220,9617,8940,9093,9226,9928,5355,9265,9156,8685,5304,8713,0,0,0,5416,0,9050,5646,9294,9254,8863,9492,9417,0,9007,9864,0,9114,8912,8706,0,5670,5350,9891,8912,8993,8824,0,0,9492,9396,5350,9704,0,0,0,0,9080,0,9560,9835,5321,8863,0,9178,9226,0,8801,9212,0,9704,9231,0,5506,0,9729,0,0,5506,9284,9664,9023,9007,9007,5684,9396,9284,0,9801,5304,8718,5350,8767,8801,9373,9443,5506,5407,0,5339,9426,0,9454,8986,9198,5355,9637,10017,0,10041,8859,9046,9173,9373,5304,10117,9198,9760,5506,9963,5489,9173,9361,9597,9265,8970,10041,0,0,9346,9294,8778,8754,9226,5489,5350,0,5355,10228,8908,0,9046,5666,9046,9570,0,10068,8889,9156,5684,5367,9065,5688,9173,9080,5449,9520,9069,5646,0,9046,8767,9208,0,9305,0,5321,9826,5321,9046,5494,0,5248,9017,9963,8912,0,0,0,9007,10239,8908,5437,5388,0,9198,8801,5684,9709,5355,9040,0,5331,5331,9212,8975,0,9046,9592,8871,5421,9847,9083,8908,9305,9378,9069,9114,9387,9626,9826,9265,9114,5388,9464,9125,8652,9720,9864,9814,0,5646,8883,9046,9391,5437,0,0,0,8718,5646,9733,8912,9237,9864,9119,10058,8663,0,5321,5359,9480,0,9114,8986,8652,9940,9480,5321,10008,5426,9109,5388,0,5310,9781,5355,5684,9237,9208,9387,5372,0,0,5646,9141,9151,9918,5315,9411,0,9387,5489,8912,9733,9502,9443,9104,5462,9704,9114,9093,9173,9968,9193,10222,9535,10212,9626,8975,5350,9325,0,9449,9046,8970,8883,0,8859,0,8925,8959,9647,5291,9314,9709,8806,9771,5331,0,9720,9411,9626,5321,10052,9242,8908,9294,9046,5359,9294,9738,9720,8652,5634,8908,5271,9220,9029,8652,9059,8997,8667,5359,9520,9417,9141,0,5619,9688,0,0,9411,10243,8663,9592,8993,9093,5382,9007,0,0,9904,10249,10175,9093,0,9806,5372,9151,9796,0,9198,9226,9720,9325,0,9260,9325,8908,9626,0,5506,5267,9265,0,9411,9265,10085,5367,5355,9305,8761,0,0,9387,9826,0,8824,5675,8685,8868,9065,0,9368,9029,8788,0,9664,9551,5367,9254,5619,10073,9188,5350,9050,10255,9492,0,8824,9305,5372,0,9050,5624,8701,8854,10058,9626,5355,0,9520,0,0,0,9417,0,9265,0,8706,5304,0,9173,8824,5624,0,10008,9265,5456,5646,9847,0,10206,8981,9826,9050,0,0,0,9093,0,5331,9963,8734,8734,0,8871,9743,9178,0,9733,10008,9080,9426,5411,5407,5355,10206,5315,5388,5624,5506,9346,9346,9570,5331,5467,8854,9570,8652,9417,8685,9242,0,8685,8898,9401,0,9555,9280,0,0,8986,5407,9602,0,0,9715,5670,8667,8948,10008,9237,0,0,9602,9411,9271,0,9602,9417,9141,5339,8795,5355,9502,5437,9336,9475,10107,9093,5331,5331,5646,5501,8812,9520,9265,5355,9555,0,8868,0,9173,9626,5326,9141,9592,9104,9093,0,10035,8970,5456,9437,5421,8912,8676,8849,9109,8676,9050,10153,0,8667,9104,5304,0,0,9083,9093,8849,9502,9626,9387,8738,5339,5291,8917,0,0,0,5271,9198,9346,8824,10003,9637,5472,0,8784,10262,8652,10035,9387,5372,0,5411,5437,5666,5315,8676,0,8676,8806,5402,9475,5431,0,9023,8868,9226,5304,10267,9305,5271,8801,9125,9502,5619,0,0,0,8877,5331,8889,9602,0,8676,0,0,0,5619,0,0,0,5291,0,0,5291,5321,5355,8761,0,5483,5666,9114,8663,10017,5619,10101,5619,10206,0,10068,0,5397,8685,5388,8672,9401,5271,8663,0,9776,9950,5421,9023,9391,9046,9950,5304,9449,9083,5377,0,9664,0,5657,0,9346,9198,0,9237,8738,9847,5506,9729,5271,9950,0,5421,0,9055,5321,8685,9520,0,0,9114,9766,9040,5675,5407,9294,9729,0,5331,0,5304,0,5267,9443,0,0,0,9535,0,8917,8754,5437,5388,8908,9325,9284,9119,8871,9826,9046,5304,10272,0,0,0,8936,5326,9226,5506,8676,0,9156,9284,0,0,5304,9093,8839,0,8849,9055,0,8908,9237,9352,0,0,8689,0,9208,9679,0,5657,9826,9156,0,0,9050,9492,5388,0,0,0,0,8751,9475,8812,9294,9055,5310,5407,8824,5624,9475,0,5355,9046,5304,9715,0,8921,0,0,8824,0,8859,8849,9099,5675,9826,9208,9606,0,0,9325,9621,9621,5431,0,9336,8718,9570,9046,9694,5267,9470,9099,9520,5304,8667,0,9470,5443,9208,9109,9109,8738,9151,0,0,5421,8652,9709,5437,0,5326,9046,9637,5335,9508,9492,0,8965,5675,9294,8824,8908,9104,9895,0,9125,9826,9443,9826,5388,8772,9421,9431,5506,0,9203,9498,9104,5267,9099,8883,5619,9480,9754,10017,8986,5443,0,5359,5355,9443,5350,0,5350,9208,9520,9093,0,9411,9080,0,9125,9814,0,9704,9341,10017,9454,5675,0,5494,10058,5407,9305,8738,9212,8806,9226,9709,5377,0,9378,5388,9738,5315,0,9454,9417,9570,5397,9226,9046,9065,9242,9093,9208,10228,0,0,0,0,0,9242,5489,9294,8912,9475,8667,0,0,9305,10117,5472,8812,0,5629,0,9520,8718,9664,0,5688,9720,9743,5675,9688,0,9284,9602,9361,9974,5388,9104,9346,10279,9876,8754,9555,10285,8997,9305,9699,9141,9046,0,0,8701,0,9801,8663,8908,9198,9265,5397,9065,10243,0,5688,0,9046,8844,8839,9743,8738,0,5267,9668,9237,5675,0,5666,9876,9904,9178,8718,5326,9426,0,8701,9378,8849,10058,5339,8948,9242,9080,5416,9294,9294,9336,9336,0,5388,0,5367,5506,9336,8932,8824,5331,5331,9754,9470,9284,9083,10169,0,0,9271,9454,9226,9226,0,9617,8685,10290,9167,9145,0,9188,0,5388,0,9167,9530,8696,0,8801,0,8908,10079,5506,9565,9754,9387,0,9305,9426,9145,0,5506,9431,9957,9830,0,9540,5335,8859,10165,8970,0,9198,9145,5437,9754,9470,5407,9226,9597,9198,5506,9791,5421,9208,10187,5506,5437,5372,8812,9475,9208,9208,5619,0,9145,5431,0,10165,0,5437,8801,8812,9050,5339,9806,9099,0,9129,5506,8676,5437,10165,9658,9055,8738,9336,9305,9602,10135,9602,8986,8908,8908,9319,5388,9305,5443,5462,9729,9226,9023,9242,8908,8696,9046,9895,9895,0,8908,9945,9738,5506,9305,9074,9305,0,9443,0,0,8824,8912,5359,5506,5331,0,5483,5267,8663,0,5624,0,9231,9674,9545,0,9617,8898,8824,10169,9046,9560,9023,9114,5478,0,5388,5489,0,9826,5331,0,8849,5467,8993,8754,9178,5335,9602,9621,5666,9099,8801,5494,9242,10222,9574,0,10058,9208,9226,5355,8912,8701,0,9606,5437,9309,8828,5355,0,0,9309,5506,0,9637,9664,5310,9305,0,9325,10107,9401,9647,0,9167,9237,9715,0,9059,5388,9023,9570,8944,5437,5407,5372,0,9470,5666,5437,5335,9173,9129,9617,8734,10041,9341,0,10201,9284,9104,0,10012,0,5411,9046,10297,0,9480,9309,9007,0,9055,0,9391,0,9826,9046,8883,9725,9781,9109,8981,5382,5421,0,9352,8908,9592,8729,9305,9007,9835,9055,9173,5355,5377,0,9502,8948,8729,5359,9785,0,8696,5506,8954,5331,5331,10129,8801,8839,9135,8912,5456,8795,0,9401,9141,0,5670,9156,5670,10079,9417,9694,0,9729,9900,9325,9664,0,8908,0,0,9119,0,9357,5411,8824,8713,9151,9125,9738,0,9508,5367,9826,5411,5335,9361,5291,8908,5291,9602,9099,5506,10141,10141,9069,0,9336,5506,10101,8883,10003,8696,0,5331,0,5359,8685,9733,9125,8696,9417,9709,9417,0,9725,5304,9198,0,0,9198,0,0,9212,0,10141,9080,8917,8744,9826,9050,0,10141,0,9059,8824,0,9378,9647,5426,9709,0,9178,9093,5489,9226,9443,5402,9720,0,0,0,0,0,9738,9715,10035,10212,9260,9396,5359,5506,5619,9050,10041,8936,5472,5304,10017,5411,9535,9502,8676,0,5331,8667,0,0,10212,8824,0,0,9592,10058,9294,0,5267,0,8908,0,9754,5355,9520,8761,0,9847,8718,9208,0,0,5411,9743,10107,9443,0,9766,9508,9055,5489,9125,8883,9637,9055,9198,9368,8663,9475,9099,9125,9574,0,0,9771,9173,9055,5367,9754,9396,9771,10301,9260,9080,9080,5456,9065,9050,10008,9454,5443,9012,9017,0,8908,9754,0,0,0,5688,5494,0,5634,9237,9080,5355,5335,5278,9475,8663,8718,8685,9498,8912,0,10123,8734,9012,9050,9426,0,9065,0,5377,9574,8824,9847,5416,5331,9341,8936,9325,5666,9443,5506,9443,9502,0,5624,9050,9475,5489,9325,5421,5315,9864,9220,9417,5407,9141,9748,5315,9631,9454,9826,9023,9188,5331,9602,0,0,0,9791,0,0,9934,5359,9325,5506,8981,5291,0,5350,9738,5335,9065,10267,5254,5382,8839,0,9271,9454,5331,9093,9368,9733,9502,9963,9580,9198,9869,5388,5666,9502,5304,0,9069,0,9226,0,0,0,9396,9093,9729,9729,5331,8778,9417,5437,9046,9560,8889,9530,5437,10085,9664,9220,10107,9826,5437,5670,9498,5437,8970,5619,5467,9464,5331,9487,8824,8940,9704,9145,9928,0,9065,8959,9226,9520,8889,5684,0,0,0,10101,8993,0,10239,9046,10267,8940,8940,5344,8849,5285,9065,0,8772,9305,8696,8751,0,9421,9826,9560,5407,9129,5407,8908,5355,8912,10297,5339,9216,5331,9417,5684,9212,8993,5310,8908,5304,5437,5421,5304,8859,5426,9417,9357,9188,0,5355,9592,10091,0,0,9050,0,0,9574,9035,9626,0,8912,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5506,5651,10201,8908,10290,5397,0,5335,9247,9876,10290,5397,5355,9454,8824,8948,5629,5472,5472,10175,9083,9141,5421,5421,5646,5254,8676,10123,8778,8672,8754,10306,5646,8986,10306,5367,8986,9050,5254,10243,9487,9771,5675,9664,9580,8744,5355,5411,9814,10017,10028,9093,8701,5344,8801,0,9637,9099,9226,8801,9220,5331,9417,10262,9046,5506,5506,10012,0,9771,9771,9704,9188,5506,0,9198,8663,8889,9208,9280,5363,8744,5285,9606,9508,9208,9912,8754,8754,5506,8667,0,8965,9771,8908,8676,5267,8706,5629,9771,0,0,5350,0,5421,5355,8902,9203,0,5421,0,0,9621,9652,0,9900,9336,9050,9046,9560,9378,10107,0,0,0,0,10107,8912,9173,10107,9652,8701,5506,5321,5363,0,8824,5271,5421,5421,8898,9114,8824,8824,8824,9520,9208,8908,8663,9220,8672,5372,9974,9974,9664,5619,9664,8908,9664,5355,9069,8795,10052,8940,5315,9647,5506,9093,9167,8917,0,8706,9220,10101,8986,8706,9220,8676,9449,9305,5367,5619,9099,5431,9104,9226,9791,9791,5355,0,8795,5506,5421,9791,5363,5651,9357,5339,8936,5472,9125,9247,5339,5411,5254,9997,10123,10311,9876,9331,0,10073,5239,5421,8940,9247,9046,5304,5304,9738,9294,9574,9791,8738,10107,5506,9826,8724,9325,5506,10079,9480,8932,10290,5506,8917,9801,9791,9203,10079,9145,8738,8744,9141,9637,8663,5437,5411,9188,9814,10073,9791,8795,9341,9826,8761,8744,8908,9743,8824,8959,5501,8954,5506,8713,10052,5506,5355,8859,8663,5355,9046,9280,9382,5339,9151,9099,9046,8871,8744,5367,9401,5326,8824,9679,10028,9876,9226,10028,9156,9664,5304,10290,9480,10315,10073,9597,8713,9226,8801,8912,9443,9551,9305,8993,9729,9729,5619,9540,8685,9325,8772,9135,5684,8672,5443,8672,9203,9141,5506,8672,8859,5271,9040,8849,9621,9099,8801,9454,5684,5388,9957,9055,9226,9826,8801,8767,5367,9145,5407,9709,9065,5388,9738,8970,8824,5506,10311,8767,9012,9658,9574,9729,9443,5684,5248,9918,8738,0,10320,0,9743,9631,9065,9396,8706,5675,9145,9368,9280,9668,9203,8898,5254,5355,10023,9401,9173,8975,8883,5315,9055,5506,5421,5456,9135,9738,10091,9198,5629,9535,5506,8912,8658,9979,5331,8667,5421,9602,8801,8685,5367,9617,5359,10003,8898,9331,9574,9592,8912,9597,9029,8772,5506,9900,5437,5397,9203,5467,5359,0,5315,8718,9891,9508,9129,8833,9658,10085,5339,8663,5688,8788,8754,8718,8767,5472,9449,5359,9417,5350,10101,9135,9738,9305,9035,9284,9688,9699,8824,5267,9387,9080,5646,8685,9869,8894,8663,8863,5506,9046,9059,9725,9508,5331,5248,8839,9220,5304,9876,5243,8784,9046,5267,5331,9046,5285,9475,8824,8672,5397,8713,9382,8824,5407,9156,5472,0,9050,10324,5331,9535,8672,5437,9382,9046,9065,9417,8877,5243,5437,9760,9114,9109,9814,9664,9617,9151,8824,8713,5388,5437,9480,8912,5254,9642,9188,9679,10324,9637,9535,10073,9835,5675,10017,9151,8652,5350,5350,9801,9766,10068,5321,9017,5456,5382,8871,5688,5506,8908,5407,10107,9220,5411,5372,9480,5411,8761,9198,9858,5634,9835,9417,8738,9729,9331,5344,9226,8828,9254,10169,8839,8778,5239,9830,8663,9417,10012,8981,5437,9820,8676,9198,9560,10041,0,8812,8754,5437,9050,9991,8744,9346,9203,5411,9226,8824,5254,10196,5407,9226,9074,9050,9814,8871,9781,9080,5619,9156,9361,10091,9826,8767,9592,10101,9151,8676,5494,9188,9709,5472,9050,5367,5437,8685,8889,9055,9046,5388,9198,9835,8948,5355,5506,5619,9597,8672,9968,9891,8718,8944,9069,9069,9151,10228,5359,5411,9226,9341,9480,9173,5478,9198,8784,5397,9046,9754,9411,5331,9900,9520,9373,8734,9119,9040,8871,9284,5411,5267,5291,8738,5321,10073,9114,9876,9151,8877,5248,9188,10068,9963,9145,9280,5254,9203,8724,5467,8871,0,10191,9114,8680,9426,5624,9679,5248,5402,9835,5382,9254,5666,10028,8824,9820,9986,10290,9580,9220,8912,9560,8849,9247,10041,9050,9826,5267,5359,9151,9934,5339,5431,5359,9007,8738,5304,10068,8812,8778,10175,8706,5291,9508,8788,9699,10329,8936,5267,9396,9480,9979,9492,8908,10222,9093,9226,5355,9242,5326,10028,5437,9099,5315,9771,10334,9341,5304,5321,9080,5315,5437,9574,8701,9305,8993,0,8784,5304,5449,9720,8676,5339,9203,9508,9141,9814,8772,8859,9406,5506,8863,10085,9093,5506,10206,9220,9443,9129,5437,9114,9099,5315,9560,5467,0,10191,9617,9900,8854,5472,8833,5377,9729,5339,8738,9502,8663,9658,8925,9729,9480,9864,5624,5359,9869,9475,10058,9760,9642,9198,8672,5367,9284,9265,9265,5331,10212,9226,8806,9114,9093,9514,5350,5326,5331,8828,9642,8680,8871,9050,5624,8902,8898,8663,9520,9642,9754,8689,5278,9231,8689,5304,9979,9470,9216,9470,8948,10008,9480,8898,9470,8898,8713,10008,8672,9050,9050,5421,5421,10206,8738,9565,9341,8997,9135,9565,9368,9220,5331,5494,9900,8795,9260,8975,8986,8824,9125,9029,8696,5267,0,5377,9029,8652,10017,5456,5254,8908,9417,9040,5239,0,9145,5437,9319,5355,5506,5355,9093,8788,0,9555,9260,9754,8997,9748,9555,9891,8788,9891,5467,9002,8788,8997,8772,10003,9373,8685,8948,9602,9411,8667,5619,10091,8863,10085,5506,9602,5421,10017,9502,8744,9417,9754,9668,9012,0,9046,5619,9602,5254,8778,8854,9748,9814,5254,9208,5278,5321,9208,9869,8676,10169,8729,9046,9720,8778,5304,9864,5397,5437,9220,5350,5670,10008,8908,8993,10340,9254,9220,8986,10041,8959,9325,8778,10107,5437,8667,9986,5506,5331,10073,9668,10346,9679,8672,9104,5339,8701,8701,9658,5267,10058,5355,9242,9242,9242,9814,9417,9114,0,9814,0,0,9046,9814,5285,9814,9796,5494,9796,10107,10222,5285,5684,8689,9129,10008,5666,9114,5355,10206,8849,8849,5402,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,8663,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,9294,2,2,2,1,10353,1,2,4,1,2,1,2,1,2,1,2,1,2,1,1490,1,2,1,2,1,2,1,2,2,1,1,1,1,6,8,10,12,14,16,18,20,22,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1132,3457,3460,1,1,1,1,1,1,24,24,40,40,64,64,32,32,52,52,809,888,2976,3203,2973,3200,2987,3214,1268,3217,799,1017,2656,3101,2653,3098,2667,464,1282,3112,779,789,324,3095,2818,2818,3158,2829,432,2832,3169,815,2928,2925,2935,1357,429,773,776,2504,2773,3432,2501,2770,3429,1704,2784,3443,2515,2787,3446,818,2577,2574,2588,2591,828,828,653,653,1275,1275,792,2632,2629,2643,2646,825,825,1761,482,3092,50,2794,1,1,1,1,1,1,1,1,1,1,1,1,24,24,40,40,64,64,32,32,52,52,809,888,2976,3203,2973,3200,2987,3214,1268,3217,799,1017,2656,3101,2653,3098,2667,464,1282,3112,779,789,324,3095,2818,2818,3158,2829,432,2832,3169,815,2928,2925,2935,1357,429,773,776,2504,2773,3432,2501,2770,3429,1704,2784,3443,2515,2787,3446,818,2577,2574,2588,2591,828,828,653,653,1275,1275,792,2632,2629,2643,2646,825,825,1761,482,3092,50,2794,809,2987,958,2797,2808,2811,1,1,1,1,5675,1,1,1,1,1,26,54,48,34,30,62,50,46,36,44,38,42,56,70,124,321,121,58,74,28,60,24,52,32,4557,878,1465,881,139,590,410,4471,5052,6633,40,64,371,66,106,6706,1,1,1,1,36,2172,2353,50,136,2356,30,637,58,2359,2362,2365,162,2368,2371,491,48,26,1111,2204,60,79,1,42,2179,28,44,62,54,38,24,97,828,475,1743,32,1746,1750,52,825,1753,109,1275,64,1757,482,1761,653,1764,347,40,1,1063,1377,2384,2387,2396,2403,2418,153,2437,1380,2446,2453,2191,2194,1,2207,2211,2227,2233,2197,2239,2243,2246,2249,2258,2269,74,1,50,2384,2387,2319,740,56,1836,1842,1861,1908,1915,1926,64,2349,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2770,3101,3183,3200,746,7375,749,7379,4956,7383,7387,4965,7391,7394,7398,7403,1389,1386,7408,7412,54,62,44,38,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10068,36,50,30,58,48,26,60,2,42,28,44,62,54,38,888,815,789,792,818,773,799,24,782,899,809,779,776,429,3180,1,1,1,10357,10360,5181,10363,10366,10369,10372,10375,10378,10381,9626,9401,10135,8917,5339,10008,10218,8801,5367,8970,9668,9881,8981,8801,9396,8724,9208,9336,5437,8908,5239,5619,5355,9382,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,50,30,58,48,26,60,2,42,28,44,62,54,38,888,815,789,792,818,773,799,24,782,899,809,779,776,429,1,1,1,10385,10357,10360,5181,10363,10366,10369,10372,10375,10378,10381,9626,9401,10135,8917,5339,10008,10218,8801,5367,8970,9668,9881,8981,8801,9396,9602,9035,9551,5421,5367,8667,8801,8706,9382,5619,5271,10290,8744,5397,8767,5367,5506,9835,9336,5437,8908,5239,5619,8676,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10390,10393,10396,10399,10402,10405,10408,10411,10414,10417,10421,10425,1,1,1,1,24,40,64,64,52,809,2976,2973,2987,1268,799,2656,2653,2667,1282,779,324,2818,2829,2832,815,2928,2925,2935,1357,429,2504,2501,1704,2515,818,2577,2574,2588,2591,828,653,1275,792,2632,2629,2643,2646,825,1761,482,3092,5367,10429,5040,10439,10446,10450,10457,10462,10466,10473,10478,10484,10488,10495,10501,10509,5073,10516,10521,10528,10534,10542,10547,10556,10566,10575,10580,10588,10597,10603,10608,10615,10621,10627,10635,10644,10650,10655,10661,10666,10673,10677,10682,10687,10695,10703,10709,10716,10724,10730,10735,10744,10750,10755,10762,10768,10776,10781,10789,10795,10801,5056,10806,10812,10817,10821,10827,10832,10837,10843,10848,10853,10858,10866,10873,10879,10888,10893,10901,10907,10907,10912,10917,10923,10928,10934,10940,10944,10953,10958,10961,10964,10967,10970,10973,10976,10979,10982,10985,10988,10992,10996,11000,11004,11008,11012,11016,11020,11024,11028,11032,11036,11040,11044,11048,789,881,11052,4987,11056,1,1,1,1,11059,11066,11073,11081,11087,776,815,11091,818,809,11100,1380,11103,11106,11110,11115,11118,11121,11132,2440,11142,11145,11148,11152,11156,11160,11164,2443,11175,11178,11181,11184,11187,11198,11201,11204,11207,11211,11215,11218,11222,11226,11230,11233,2446,11237,776,11241,4622,11245,11249,11253,11258,76,2384,11264,2446,11276,3497,11279,11289,11292,11289,11295,11298,11301,11311,3687,11311,11314,11319,1389,11324,11327,11330,11333,2856,142,11337,429,11340,596,4270,11204,11343,2362,2400,11346,11350,1380,5537,11353,303,11357,11360,11364,2252,3516,11367,1,1,11370,11373,11376,11379,11382,11385,11388,11391,11394,11397,11401,11405,11409,11413,11417,11421,11425,11429,11433,11437,11441,11445,11449,11453,11457,11461,11465,11469,11473,11477,11481,9729,8894,9216,8871,9940,9729,5437,9470,5339,9748,8824,9080,5382,8993,10008,10169,0,9664,8738,0,9617,0,9104,5416,10008,8754,8667,8839,5388,5431,9271,5489,10175,5688,9475,9475,8824,9826,8997,5411,10117,9080,10141,10091,9835,8824,5494,9080,9188,9050,9475,5355,5670,9480,10058,9738,8667,9814,8744,5411,8718,9814,9748,10028,5437,0,0,8706,5494,10169,9968,0,9443,5355,5355,9129,8812,8940,8754,5248,9796,8784,8784,5421,9602,8940,9437,8754,10008,8871,5657,8744,5331,5382,9119,9406,9458,9470,8652,8663,8754,9597,5675,8718,8859,9029,9050,10091,8652,9754,8954,5619,8696,0,9059,9480,5382,5443,9265,9387,5359,8944,8738,5670,5335,10175,9904,5350,9178,8912,9007,9760,9220,8908,5350,9826,9247,10091,5248,9040,9265,9198,5267,9271,9580,5339,9826,10290,8917,9679,9050,8940,10129,8908,9580,8986,0,10159,9508,10129,8685,5291,5291,9125,8936,9129,8778,9242,5657,5335,5501,5501,5501,9826,9361,9104,9104,10068,10222,8663,9341,5494,10068,9498,8676,0,0,8824,9580,5355,9508,10096,5506,9141,5388,9040,5449,8676,5248,9305,10068,5377,9417,9631,10206,9514,8738,9597,5377,5267,9065,8859,9664,9766,9284,10117,0,5624,9869,5359,9050,10068,9226,9631,8806,8806,9088,5331,8701,9514,0,9597,9050,5624,9125,0,5421,9791,0,11485,11485,9361,5506,9621,9216,8801,11485,9208,9208,9940,5506,9208,8685,9940,9319,9464,10329,9319,5506,9198,8993,9114,5449,9814,9151,0,9688,5372,9945,9325,9046,8767,5397,8689,0,5416,5397,9237,5267,9314,9754,8997,8784,9104,9104,8676,10041,0,9373,9373,8908,9502,9502,8667,9401,9265,9498,9357,8652,8854,9046,9912,9188,9145,9847,9525,5421,9830,8854,9069,9050,5388,5506,8658,9203,9104,0,9869,9520,9203,10297,10165,5431,9023,9826,9050,9421,8975,8908,10012,9814,5619,9341,9040,0,9237,9193,9023,8908,9796,8889,9830,5506,5449,9530,9458,9830,5267,8706,9109,8959,9597,10249,9040,5666,8970,9437,8729,5666,8663,5666,5449,5431,9104,9520,5449,5421,9341,9401,5388,5431,9104,9551,9551,5651,10012,8738,5437,8940,9771,9035,9592,9284,5304,9242,5355,10147,9900,9109,8795,9294,11485,9046,8734,9099,9791,9046,9220,9050,5619,8954,8744,10297,10058,5355,10249,8744,9188,5339,9520,8818,9743,0,9626,11485,10112,9050,9378,8713,9341,5388,8824,9738,9814,9754,8761,8663,8824,9173,10058,9125,9729,8772,5344,9231,9498,10012,9754,9069,9443,9198,9080,5670,5335,8908,5388,9135,9083,9080,9065,8685,9280,5271,9720,9540,8917,9046,9325,5239,5239,5421,9555,5291,9145,9007,5411,8993,8672,5456,9226,5239,9417,5291,10047,9791,9188,9574,5449,5350,5355,5629,10290,9391,5634,5315,9373,8917,5437,5437,5506,9431,9198,5355,5355,5304,9167,9979,8863,8658,9050,9668,9864,9743,9050,5367,9050,9592,9135,8667,8912,9173,8975,5239,9254,9226,9294,9918,9178,9664,8844,5315,9652,5285,5304,9957,5331,8754,8877,9464,0,9963,8663,9226,9216,9535,9545,5651,10232,5456,9035,8824,8680,9743,9260,5634,9135,9198,8849,9826,11485,9080,10047,9699,8849,8948,8663,9050,8663,5267,9050,8824,8672,8824,9918,0,5304,9417,5684,10135,8908,5304,10159,8778,9480,5359,8859,9080,9080,9178,8948,10123,9289,9417,9570,8981,5651,9637,9760,8877,5350,8908,5326,9046,9080,9781,10068,9109,0,5411,8652,9729,8975,9220,8839,9220,8738,9040,5456,9208,9918,9535,5388,8667,5472,9545,9046,9220,9331,9050,5377,9940,8667,9664,0,5331,9040,5304,0,5426,8812,9093,9135,10101,10206,9188,8663,9035,10196,9203,9069,8685,8824,9226,5407,9352,5670,9099,10117,9449,0,8663,8738,9346,8997,9046,5411,9968,5267,8744,5670,5494,8948,9617,8812,9443,0,9226,5670,9754,8718,5646,5407,5619,9738,5431,8997,9555,8672,9074,9226,9918,9771,9208,5666,0,0,8685,9069,9173,9193,9188,9141,5267,9754,8812,9411,9900,8912,8696,5670,8729,5666,8734,9373,9237,9449,9203,9587,8718,9754,9592,5248,9668,8812,5355,8784,5483,5304,9530,9606,9059,5416,9475,8859,9141,10047,5506,9934,8824,5624,9443,9007,5506,9247,10052,5248,9729,5331,9826,9173,9050,5339,10175,9480,9891,8849,5392,9396,5335,9704,9208,9208,5666,5392,9580,0,10262,8993,8663,5315,9738,9709,8997,5304,5304,5335,9492,5431,5426,9173,10222,9198,8685,0,5426,5267,5326,8844,5267,9050,9093,5315,5670,9242,9242,5304,5506,9226,5315,9046,5421,5388,5291,5372,9580,5431,9023,0,5483,8778,5506,9426,8859,10232,10062,8734,8883,5472,5339,9055,8824,10047,0,8685,10012,9050,8854,8812,9426,5483,0,8812,8948,0,8734,9135,5456,9729,10058,8696,9754,5377,9050,9904,9325,5315,10232,5377,5304,8812,9904,10255,8975,9602,5331,9652,9050,8801,5377,5239,5411,5321,5321,9858,9520,5239,5239,10182,9183,9046,9151,5239,8877,8713,9502,8672,8854,9475,5355,8993,9551,9336,0,10175,9647,9652,9183,9631,8965,10123,8738,5350,9093,9664,5239,9729,9046,5239,5331,9336,9305,9900,9535,9309,9309,8812,9652,8948,8801,9411,8940,9173,9820,8925,8824,9319,9617,10008,9254,9637,9352,9188,9294,5506,9220,10340,9602,8801,10206,9294,9835,10017,8772,5651,9637,5506,9475,5421,5421,5278,9135,9216,9443,5421,5367,9023,5506,8883,5421,5304,9029,8754,9945,9029,8877,5467,8889,9475,9647,9050,8877,9203,9135,9265,9411,5494,9602,9012,10035,10191,8784,8981,9642,5355,9754,5355,8667,9602,9012,10041,5657,8718,5437,9046,9658,5254,9023,5670,9449,8849,8824,5421,9658,9449,9658,9198,8824,9475,10035,9658,9449,5335,9592,9417,9002,9449,9208,8663,9492,5421,8801,9820,9135,9226,5619,10035,5326,9492,8863,9023,5506,5506,9475,9449,5278,9475,9814,10182,9470,8672,9597,9766,8868,9470,9319,9570,9814,10175,9046,8970,9216,5449,5449,10175,9226,10329,9597,5350,9470,9766,8877,5355,9957,8898,8898,8898,5235,5437,5350,9265,10290,10290,0,5235,9480,9492,5304,5304,0,8795,8795,5367,9492,9492,9188,9464,8795,8795,8795,5235,9188,9104,9237,8744,9771,10107,8993,10107,9699,10107,10107,5421,8667,8912,10201,9729,5339,9226,5483,9417,9141,9841,5267,5388,9417,5411,8652,5684,5407,5411,8663,8959,5421,5421,5285,5355,5619,9265,5267,9729,9709,5267,0,9007,9080,9178,5285,5407,9109,5350,5619,10008,5359,5359,5267,9841,5359,9417,5619,9417,5321,9492,5321,5350,5267,9156,9300,9729,5291,0,5304,5331,9336,0,0,8806,5506,8908,9791,8663,8849,9135,8824,9114,5372,8908,0,9626,9540,9188,9895,9664,8663,5411,9080,5355,8738,9341,9754,8908,9715,8738,8908,9592,5411,5684,9748,5304,5666,5377,9766,9125,8767,8767,9145,9417,9748,9216,9373,9336,9151,5331,8883,9417,9050,9046,9382,9203,9325,9738,9743,5367,8724,9869,9626,5684,9208,9570,9720,9617,8883,9325,8912,0,8778,0,9237,9382,8997,9574,9336,5506,0,9065,9216,8828,9080,9046,9597,5489,5359,9617,8898,5629,8975,9574,5506,8917,5421,9617,9226,9208,9198,9602,5331,5355,9574,9226,5367,0,5397,5331,9188,5315,5271,9652,5315,9080,9080,8824,8676,9454,9508,9945,9814,9814,5416,5331,5367,5304,9294,9766,9135,8754,10008,10141,8863,9284,5397,8667,8824,9059,10091,9396,9535,5304,5657,9858,5278,5278,8940,0,5426,9417,9535,8908,9720,9940,9940,9725,8993,9679,9664,9664,9748,9331,9331,10169,5321,9104,5271,9271,8667,8778,8849,5271,9226,9188,9141,9050,9254,5411,5443,9725,5321,8778,9709,8993,8667,0,9357,5494,8824,9226,9145,9814,5646,5501,5407,5506,9198,5421,5467,9188,9080,8801,10091,5359,9050,5670,10107,5355,5355,9023,10101,9361,5670,8738,8663,8824,9835,5377,5321,9050,9050,9226,9835,9592,5372,9411,0,9449,8824,0,9178,10008,9470,5267,9437,10073,10206,9294,5411,8859,8696,8663,9254,9508,5239,9226,5443,9040,9733,8738,5248,9309,9733,5355,0,0,9254,9835,5449,9492,0,9093,5489,9715,5651,10008,9178,9247,9709,9709,5666,9612,5684,9580,9674,9674,9766,9766,5267,8824,9305,8806,8706,9841,9305,9449,5315,9050,9396,9709,8701,9492,9492,5339,10222,9104,10329,5315,9173,9188,9508,9188,5321,9709,5506,9336,5416,8676,8676,5506,9080,5304,5355,5619,9216,5267,9826,5666,9674,0,9729,9411,9766,9325,10228,8824,9626,8667,0,5411,5331,5372,8806,8806,9040,8812,5267,9417,9093,8812,9237,9050,9226,5416,8975,10079,9785,9652,9040,9040,0,9050,9050,9050,5416,9050,10028,9173,10028,8772,5494,9220,9597,10079,10079,9864,9029,8767,9508,9417,9029,0,8663,0,0,8833,5646,5646,5355,5506,8672,9125,9198,9231,8706,5506,5339,9597,5634,0,9597,5339,9046,10228,5388,5421,9454,5651,10255,9242,9309,5421,9341,10297,9198,5267,9208,9099,9226,9247,8871,8724,8734,9743,10297,10267,9046,5431,9198,8772,9305,9198,9826,5335,5506,5506,5285,5310,5634,9900,10255,8724,5271,10135,9508,8718,5421,9945,5267,9119,8724,9173,5472,5285,9247,9560,9637,8724,9226,9480,9560,8908,9357,9271,8997,10058,5688,5271,8685,9602,9226,9781,9046,5506,9119,5285,0,9029,8729,5494,9766,9602,9203,10212,5326,8744,5291,9007,8917,9760,9271,9357,8917,9119,9247,8788,9093,9046,9198,9208,9242,9806,5388,0,0,9602,9508,9093,9341,9502,9119,5472,8965,9114,5411,5304,5377,10107,5285,9431,8738,5254,5254,5456,10107,9188,9023,5367,5367,5355,9050,9141,10101,9357,9979,11485,5335,10041,5388,9449,5501,9806,9173,9664,9368,5411,8685,5359,8663,0,8894,8812,9826,9421,9040,9664,8818,10141,9055,9046,9574,9606,9109,8706,5506,9198,8883,9198,9382,10058,8767,8877,10008,9173,8894,9606,10101,5367,9454,5651,8754,9535,9151,5355,9617,5350,10052,5248,9738,9254,5350,10041,8824,8824,8818,5478,9891,8706,9109,9771,9065,5326,8696,9560,5431,9059,5478,5437,9289,10041,9771,9771,9449,5666,9391,9178,8667,9492,8724,5359,5506,9114,9093,10008,8672,8713,8818,9480,8663,9109,9979,0,9129,5388,9580,5619,8701,8701,9492,5359,0,8812,5304,10101,5248,5331,10101,8667,9597,9050,10101,9826,9570,5437,5326,10012,5326,9029,9431,9796,9688,5506,8908,10085,9341,9417,9050,5506,9458,5388,5506,5506,8898,9876,5421,8898,5421,5421,9029,8959,8667,9208,9046,9294,8663,9699,8912,5449,9125,9135,9826,9247,5321,9530,9046,9826,9602,5304,9208,10079,9551,9220,8718,5506,9602,8975,9637,9957,10196,9443,9220,5501,9247,5449,9580,5382,9099,9580,5388,5388,8970,9099,5437,9373,0,9280,5388,9012,0,5462,8877,9099,9391,9580,9294,9602,9391,9637,5321,5355,5355,9173,10206,5359,5359,9928,5326,9198,5326,5326,5506,5506,5506,5506,9401,9401,5291,5456,8954,9574,9050,9050,8824,8912,8981,9760,8959,10191,5382,5248,9934,9247,8812,8912,8912,5344,9738,5355,9606,8744,5506,8795,9156,5388,8912,9325,9046,8795,5271,9387,8795,9220,8724,5267,9597,10023,9145,9631,5359,5688,9918,8754,9198,8685,9220,10008,10123,0,9535,10123,9684,5243,5267,0,8908,9480,9198,10123,8772,9535,8824,5619,5411,5437,8912,9203,9688,5494,9046,9597,9226,9606,9188,9226,5267,5271,9934,8912,9684,5271,5271,5462,9684,5278,9156,5315,9226,5315,5326,5670,8806,8706,9475,5684,8713,5350,5388,5506,5363,9791,9766,5651,5629,5355,9791,9791,9093,10068,9881,9881,10107,8908,5421,10182,9198,8795,9464,5267,9242,8812,8652,9720,9720,8744,5278,8663,5355,8663,5267,8676,5367,9637,10123,8744,9129,8824,9688,9198,8908,9679,9265,8854,9300,8738,9431,8839,8689,10112,8795,5304,8713,10052,9208,9796,9341,9631,8854,9254,8663,8944,9480,9806,9417,5506,9475,10079,9720,9743,8767,10285,9145,9012,9540,9551,5416,5271,10297,9454,10267,8993,9208,9417,9498,5431,8672,5472,9826,8724,5506,10008,5367,9046,5355,5382,5456,9754,9729,9912,9046,5267,5388,5367,9083,9443,10123,5254,5494,8685,9114,9141,5267,5267,10068,0,9835,9470,0,0,5506,8912,9791,9597,5421,5267,9396,9167,9869,8917,9198,5619,5431,8883,5494,5489,9284,9858,9173,9167,5267,8877,5350,0,8658,5646,9145,5326,5326,8912,9203,5506,8689,9912,8701,5326,5239,8685,8912,8706,9551,10023,10165,9216,9574,8652,9029,8975,5267,5310,9626,5382,10096,9684,5326,9080,0,9574,9050,9796,9891,5416,9520,9464,5248,5248,9754,9141,9940,9508,9626,8824,8824,5411,5267,9704,8701,5407,8849,9284,9083,5407,9454,5506,8738,5326,5267,9151,9007,5506,9167,9254,8975,8754,5326,8663,8663,5367,5331,8986,9023,10123,5506,9626,5331,9853,5416,9080,5657,9443,8738,8663,9720,10123,9109,9151,9104,9679,9480,9801,5331,5355,10017,10017,5456,9766,8908,9858,8652,9331,5267,10091,9940,9729,10041,5472,5501,9271,9093,8986,9637,9754,5339,5355,8701,8824,9401,9065,8975,10068,5407,5407,9309,8795,9545,9454,8839,5267,8871,8713,9226,5326,9080,9088,9835,5437,5248,9040,9417,9426,8754,9684,9151,9083,9426,9099,10017,9104,5416,9520,8706,10159,5489,5494,9346,8925,11493,5456,9891,9688,8839,9835,5407,9508,5472,9151,9443,9226,5675,8738,9226,8824,8824,5388,9443,9023,9720,5388,5506,8948,5248,9796,10206,8667,9080,9265,10003,9216,9216,8824,8859,9083,9050,8680,10107,9520,9835,9406,10169,9341,0,9237,9237,5657,9029,9520,8784,8784,8908,9188,9254,5494,5355,8993,9417,9806,9729,5619,9796,5271,5248,9612,9183,9135,9305,9796,9754,5619,8839,5248,9145,5331,9587,9530,8667,9055,8685,8738,8854,5494,9520,9135,9668,0,8970,10123,9934,5335,8917,9271,8912,9426,9426,9426,9679,9720,9881,9247,9574,5666,9904,9007,10017,5657,5402,9771,5326,9796,5431,8944,9254,5339,8667,5359,10290,9226,9928,9007,8738,8970,5248,10041,10052,9826,9198,9178,5634,8908,8908,8824,5285,9492,10123,5367,5278,9198,9574,8754,8908,5684,5382,9151,5462,9346,5315,10129,8912,5431,5285,9237,5326,9508,8754,8667,8667,5267,5267,9099,10068,9104,9470,9470,8784,5321,9891,8877,9242,9341,9396,9396,5278,8849,8908,5304,9720,9220,9492,8663,9426,5321,9387,5304,10068,9361,9141,5506,9114,5304,5416,9099,10068,9220,9254,8849,5315,9314,9023,8778,9449,9449,5684,9612,10096,5619,8812,5666,8997,5506,8701,8921,8863,9631,9801,5377,8859,8701,9050,9002,5397,8912,8824,8667,8724,9502,8859,9502,9470,8908,5335,5377,9801,5472,9198,8680,8680,9050,9145,9305,9198,9869,9869,5367,9046,8696,8965,8754,0,9093,9502,5377,9631,9443,9514,9093,5355,9417,9023,8970,5506,5431,9035,9602,8871,5321,9748,9748,9748,5675,9626,8663,5437,8685,5350,9411,5267,8754,9781,5411,5675,5437,9580,9401,9580,9709,8778,8908,9203,5489,11497,9203,5355,5421,10091,5355,9237,5629,10222,9709,9806,5675,5437,5411,8824,5437,9050,5359,5267,9709,5267,5267,9545,8724,5684,9208,9208,9208,9080,5421,5331,8997,9208,5331,8761,9963,9688,9040,8788,10290,5506,5506,5291,9208,9109,9050,9319,11502,8981,8889,5646,5363,9454,9125,9498,9997,9046,0,5467,9738,9247,8959,10052,8824,8894,8849,9135,9592,5506,8993,9012,8663,9738,8738,9198,9791,9391,9801,9587,9145,10112,9540,9156,8844,5267,8738,9540,9203,8824,9046,5666,5267,9141,9198,5239,9080,5501,9231,8754,5355,9050,9869,9688,10079,9417,8954,9208,9626,5321,9125,9449,8718,5271,9520,9637,9551,5506,5350,11505,9289,9069,9565,10052,9704,9289,9046,9421,9125,5666,9357,9928,9012,9331,9580,0,9208,9475,5254,9198,5382,10068,8936,9141,8854,9188,8718,8889,9145,9475,9065,9729,5506,9826,8912,9141,10228,5335,5670,9135,9664,5472,5684,9720,9114,9203,9046,9709,8801,9099,8833,8917,9431,9212,9046,9421,9540,5243,9325,9378,9912,8738,9417,9738,9125,9738,9738,5666,9417,5344,8729,9231,9368,9368,9826,9729,9417,9391,8806,5437,0,5248,5377,9658,9305,9357,8738,10023,9002,5421,5411,5271,9853,9029,9029,8975,10272,10182,9642,10201,8912,5619,9891,5326,10047,11511,5421,9378,9305,8912,9002,9198,9391,9104,9104,9198,9083,9617,10085,8718,5675,5315,8894,8778,9900,8883,9864,8889,5359,5489,9918,5321,0,9417,9198,9652,9664,11505,8940,5619,5416,10206,5315,5271,5355,5326,9597,0,8859,9738,8680,9733,9305,10141,5407,8718,8754,9963,9963,10249,5670,8806,9417,5382,5437,5506,10101,5291,8680,9637,5619,9592,9814,5315,8663,8863,9771,9574,9940,9401,10008,5344,9289,5363,9125,8849,9957,9309,5634,9357,9254,8676,5321,9454,9023,9454,10329,5506,9820,8868,5478,9738,9396,9183,9119,5437,9023,9766,0,9637,9449,5382,8970,9864,9720,9801,9046,9368,9417,9766,9781,8859,5634,9626,9835,9265,9017,5411,10008,9830,9378,9431,8680,9725,9781,5267,5304,8754,9040,9587,9331,10041,9748,9104,9319,8959,9289,9826,9247,9487,5355,9530,5310,8908,5243,5350,8738,9325,5506,9664,5321,5271,8986,9002,5506,9401,5291,5271,5359,8981,10068,9156,5254,5411,5407,9858,9699,9050,9733,9193,9417,8652,8738,10096,9368,9319,5411,5359,9271,0,0,9198,9099,0,5304,9587,10017,5382,9754,8680,5437,8718,9771,5437,8824,9050,9237,9035,9294,9352,9141,9226,9406,9193,9443,8818,5407,9309,9592,5421,9835,8718,5506,9885,9167,9688,9145,9023,9050,10153,9617,8685,9664,9781,9216,9950,5355,5407,9212,9212,8754,9796,9771,9771,10008,5411,5326,10141,5278,10147,8970,5619,9754,8738,8676,9592,8889,9151,9188,0,0,5377,8954,9449,9093,5675,9178,9835,10141,5315,9373,9449,5248,5657,5472,8912,9709,9183,9183,9305,9114,9411,5443,9733,9587,9216,9188,9766,9198,9551,5619,5437,5478,5646,9525,5304,10147,10243,5339,8965,9080,9017,8680,5291,8940,5411,8871,8729,9540,9498,5331,9530,9208,9198,9918,5397,8738,8954,9580,8652,8718,9080,5267,8680,8975,9592,8889,5675,8663,10165,8970,10052,8970,5350,9368,9188,10191,5478,10068,8932,9093,9963,9492,5278,9806,9271,5254,9814,10255,9826,8908,0,9820,5431,8871,8912,10017,5359,8828,9178,9835,5629,9208,8889,9806,8871,5426,9679,10012,5335,5449,9173,8812,9198,5666,9198,9309,9007,5291,9012,5350,9963,9928,5315,5335,5335,9704,5304,10249,9934,5449,8667,9373,8738,5359,5355,8812,5321,10262,10262,9396,5501,5304,10117,9237,9642,5506,9597,8754,8754,8932,5416,9167,8672,8738,5494,9498,10329,9431,8701,5271,5326,11485,5315,5355,9612,9099,9099,9156,9305,9156,5321,8877,9492,9830,9046,9508,9305,9733,5344,10175,9738,8936,9449,5501,9431,0,5619,5359,5315,9785,8940,8849,9508,11505,5437,10107,5248,5624,9391,5359,5291,5344,9357,8936,9545,5355,10206,9963,9612,10041,9220,9023,5411,9449,9129,9099,5267,5675,9141,9305,5666,9417,8676,0,0,5478,9602,5355,8854,5344,9766,5456,5377,10239,9417,8676,9900,8676,8676,9729,9208,5355,10191,9658,5675,9198,5411,9391,5335,5437,5619,9864,10068,9368,5478,5359,5359,8844,9198,8729,9145,5624,8932,5350,9642,9431,5304,8863,9401,5331,9212,8849,8812,5359,8806,8738,8738,9642,8738,5377,9876,8812,5670,9514,9093,0,9785,5267,8970,8828,8863,9602,5331,9642,5359,10068,10153,5331,9040,9918,10206,5315,5321,5377,5331,8902,9198,9173,9173,8908,8713,8936,5372,9319,10201,5367,5629,5506,9029,10107,9540,8761,5271,9305,9040,9012,9720,8663,8993,9065,9891,8877,9602,9114,5675,9826,8685,5315,9720,9265,9771,8718,9104,8824,8912,5666,9368,8685,5315,9104,5431,9309,5388,9480,9040,9104,5506,10107,9876,9216,9050,5501,8908,9565,8877,9104,5315,9220,9145,5397,9720,5350,8859,9508,8859,5271,9826,8718,9046,5350,9492,5684,8689,5267,5315,0,5315,5344,5506,5431,5388,5331,8877,8877,8954,9336,8908,8908,9820,10191,5321,9820,0,9109,9540,9540,5377,8824,5377,9226,9565,9361,9492,9203,9208,5619,9203,8824,8718,5315,9781,9069,9114,5339,8912,8667,9046,9580,9709,5684,5344,9709,9968,5344,8672,8713,5344,5344,9449,8701,5344,9114,9968,8801,8761,5619,9847,8824,5421,9743,5367,0,9606,8908,9709,8997,5359,9743,9141,8696,9046,8761,9443,9220,9220,9729,9725,9231,5506,8696,9957,5437,0,5506,8908,9198,9242,9934,9242,9709,9912,5372,8824,8663,5355,5355,5355,9401,10218,9099,9771,9198,5402,5619,8883,9597,8685,8685,8685,10107,8849,8854,9826,8685,9093,5421,9869,9145,5421,8795,9720,9720,9300,9346,8663,9520,9151,9895,9357,9540,5411,9940,9361,9208,8761,9284,9173,9480,9443,9668,8839,9341,9449,9208,5506,5267,8713,9050,9357,8761,10068,9135,9417,9145,9642,5254,5456,8812,9443,9743,8718,9325,9346,9284,5670,8767,5335,9688,8685,8839,9231,9835,5421,5421,8824,9109,5489,8997,9729,9480,8954,8778,8859,5254,9895,8772,8806,5304,9869,8883,10079,5421,5494,5494,9443,9237,8685,5315,5339,9198,5339,10290,9574,9294,9050,5629,8706,9922,8877,8676,9520,5326,8849,8849,8863,9637,5304,9940,8772,5267,8754,9361,9454,9704,9704,8663,8849,5326,9284,9265,9637,8652,5344,9674,8772,8936,9220,5267,5291,5506,5267,10041,8908,9220,9173,8718,5506,9198,9617,9637,8701,8986,9480,8795,8877,9642,0,9443,9443,5506,5397,9520,5326,9046,9720,9237,9065,8812,10058,9226,5350,10041,8997,9035,5437,9991,9617,9145,9346,9188,9963,5339,9668,5315,9796,9525,9437,9480,8908,9284,9050,5331,8859,5355,9173,9801,9642,5619,9284,8917,5335,10123,9729,9247,5326,9475,8849,9443,10028,9492,5304,9099,9220,10262,8701,9300,5267,5506,5355,5494,8854,8676,8676,5331,10068,9574,8877,9109,9449,9231,9284,5506,8706,5456,11518,5315,9475,9220,9050,8859,8676,9900,5350,9502,9597,9188,8936,5331,9265,9869,5489,0,9050,9401,5359,5267,9411,8806,8902,8828,9652,9922,8871,9050,9114,9626,9626,5684,5506,10141,8676,9208,9065,5350,9612,9612,0,9007,9841,9841,5407,9674,9426,8685,5326,8667,9083,9341,9141,9626,5367,10117,5382,9540,9046,9325,9109,5684,0,9551,8883,10147,8718,9059,9059,5634,9668,5494,8795,9300,9231,5355,8908,8812,9835,8795,9574,9059,0,9502,8806,8917,10222,9226,5335,9830,8889,8801,8801,0,8801,9791,9125,9570,9104,9104,9766,5331,5646,5355,9771,5388,9382,10101,9055,9560,0,10228,8975,8738,8824,10107,8663,9592,5291,9597,9242,8663,5239,5331,5456,8981,10182,9791,9957,9738,9826,9247,9464,8912,5506,8993,9029,10058,5506,8908,5350,9748,8883,0,0,0,9535,0,9464,9145,8734,8818,8672,9754,9847,9109,9151,5411,8778,9525,9188,5304,9114,9945,10297,5350,5426,8713,5472,8801,5472,9254,9540,9254,5355,9626,5339,9373,5355,8997,9141,5388,8795,9895,8761,9341,5506,9046,9035,5267,9208,9664,9565,9597,8718,9188,8701,9088,9080,5670,9231,9271,9198,10123,9520,0,9565,5350,5402,0,5331,0,5437,8754,0,9580,9814,9035,8877,5304,8894,5285,5506,5267,9198,9912,8877,9203,9203,9373,9046,5335,5506,8676,8676,5421,9309,5388,9104,5506,9325,5254,9729,9212,9065,8729,9242,8744,8724,9055,9145,9046,9305,10003,10107,8908,9555,9352,8997,9231,9254,9704,5397,5367,9135,9417,9738,8767,9035,9658,5248,9826,9198,8889,9592,9099,8993,0,9771,5666,9046,5437,9305,9104,9216,10012,8801,5388,8696,8833,8889,8672,8801,9743,5421,9912,9592,9188,5321,9771,5421,9198,8696,5670,0,9411,8889,0,9760,9709,5411,8806,8778,5359,0,5331,5377,5248,5350,9597,10272,8908,8718,8908,5331,5506,8706,8718,5331,8784,9002,10091,5254,9791,8877,9305,9791,5254,5239,5472,5506,5411,8685,8801,5437,9674,8898,8898,5367,9280,9029,10201,9396,9709,5331,0,9145,9065,9974,9198,8912,5675,5467,9652,9046,5411,9847,9173,9530,9979,9226,9869,9900,9617,9617,5634,5506,5344,8894,9198,8925,9574,10243,10243,9023,5411,9771,9336,9104,10159,8824,9642,0,8812,0,0,9709,9664,5416,8718,10206,8908,9508,5426,9129,5449,11485,9597,9963,9560,8718,9151,10101,9002,9220,9305,9830,9046,9088,9574,5321,5267,9059,8696,9814,8908,8954,8863,10107,9387,8986,5646,10101,5367,5670,9119,8806,5382,11485,9826,9443,10008,5402,5666,8993,5388,9826,8849,5239,9198,9791,9151,10141,5437,9023,9637,8680,9203,8883,5355,8877,5359,9023,9957,9715,9341,9254,9502,8663,5331,5331,9565,9715,8812,9963,9417,5407,5411,9940,5344,5350,9093,9242,9226,9220,5331,5254,0,0,9530,9198,9535,5431,5437,5344,9325,5331,8908,5254,10340,10123,8738,8948,8908,8908,8981,9487,9093,9881,9109,5243,9119,9289,8839,9835,8754,5402,5355,5331,5382,8824,8824,8993,8839,8778,8871,9748,8795,9826,5267,9242,8754,9709,8908,9754,9050,8824,8975,5506,11518,9791,9017,10169,8908,5344,9046,9216,9535,9193,9193,5344,10017,9341,9341,9265,8925,9309,9637,9271,5359,9284,5411,5506,5472,9417,9417,8754,8767,8986,9580,9198,10159,9664,9417,9151,5315,5344,5239,10191,5382,5651,9114,0,0,0,5437,9173,5267,10058,8738,0,0,0,8828,9198,0,0,0,0,5382,9709,0,9738,11518,9104,8676,10301,9226,9226,9968,9203,9835,5437,5506,9135,5267,9050,9050,10028,9709,9346,8824,9065,8889,9781,9074,5388,9188,9401,8685,10196,9145,9212,9050,9830,8839,9237,5411,9237,8672,9814,5619,9738,9198,5437,8917,8997,9114,9208,9208,5431,10169,10101,9035,8824,5367,5670,9254,9443,9443,8812,8718,9074,8676,5355,5411,8676,9114,9885,8824,9986,9226,5670,9826,5355,5411,9796,5646,8812,9352,9167,9178,5363,0,0,10047,0,5629,10068,5377,9520,8824,9265,5359,9417,0,0,0,5619,9203,5506,9709,9046,10012,9602,9059,9411,8993,5437,9417,8940,9188,8718,9119,9560,9754,5239,9668,8784,9203,9188,5411,5494,10107,9109,8889,8738,8734,9183,9754,5619,9411,5421,9198,9679,9520,10101,8696,9411,8871,5657,9820,8672,9361,8940,9216,5267,8993,8908,10201,9525,9183,8729,9530,5675,9597,9040,9694,5355,10147,9373,9017,9580,9592,8738,9631,5670,8685,9748,9525,5344,9738,0,9145,9040,9203,5437,9674,0,0,10191,8801,0,5267,8908,5431,5326,5248,8738,9271,5629,5629,9928,5426,9387,11518,9679,5443,5367,9208,5449,9208,9023,9237,5506,9309,9525,10052,9173,9173,9612,9007,5339,9826,11485,5363,9059,9265,10123,5331,9382,10041,9904,9242,9574,10017,5355,9963,5624,5359,8986,9602,9178,10079,8784,9216,5350,8871,9760,5359,9771,5350,8889,5350,9247,9801,5335,5483,9145,8883,5382,8801,9560,5267,8975,9167,5437,10123,0,0,9580,0,8812,8898,8713,9198,9508,9674,10123,8936,5350,5426,9237,8718,10329,9626,9709,5267,9597,9040,9280,10107,5335,8663,9508,5416,8701,8696,9508,5304,9776,9242,9709,9738,9396,9520,9885,9699,8754,8871,9502,9417,8754,8784,5321,5321,10068,5326,5355,8680,8706,9738,9658,9088,8801,9806,10129,9341,8925,9555,9167,9715,8993,8696,9396,9525,9114,0,0,0,0,5355,9565,0,5359,0,0,9754,8940,5350,5449,10068,8701,10085,8667,5267,5372,5291,9674,9443,8754,10107,9417,9674,5506,9449,8936,9050,5624,9814,5326,10206,5355,5372,9305,5388,5651,9114,11505,9129,5355,5411,9203,10041,9704,5437,9580,9766,5506,9760,9254,8970,8701,0,9592,9502,8667,9530,8854,8948,8908,0,10191,9401,5355,8738,9602,9658,5506,9525,5437,8667,8898,10041,9050,8908,9602,9231,9173,9346,5355,9237,9570,10222,9114,0,8948,5367,9198,9979,8738,5624,5624,8932,5359,5331,9785,8868,8965,5326,8944,5359,5411,9525,10058,9754,5331,9109,5344,5478,5431,0,9114,0,8801,5359,9050,5331,8801,9265,5411,9080,8784,9631,9309,8824,8806,9535,0,5304,0,9417,8877,9325,8812,5437,8667,5367,8812,8706,10085,9305,9093,5377,9417,9904,8970,9226,10123,8975,5684,0,0,8824,8828,5331,9642,9652,10206,5321,0,5377,5377,8801,5624,5331,9125,8902,8824,9325,0,8738,9055,9023,8713,8824,8824,8738,8944,8685,10079,9114,8912,9796,5506,5321,5267,8685,5397,8824,9129,9059,10035,10147,5267,8859,5506,8908,9208,8912,9449,10035,10091,10035,10091,10028,9560,0,8667,8713,5619,8824,8738,8877,5506,5675,8663,10068,5339,8944,9208,5407,9023,8685,11523,5267,8877,8685,5267,0,5431,9114,5506,10091,8824,9545,9023,9198,5271,9055,9454,8663,8908,9454,9454,9314,9417,8738,8912,8921,8912,8921,8744,5372,5372,5331,9733,8824,5331,9173,8724,8724,8672,5437,9704,5335,5335,9188,5335,9387,9145,8652,9361,8724,10290,8685,9597,5350,9426,5321,9934,5310,5646,8784,10041,9520,5431,5506,10301,9198,8676,9426,8839,9099,5355,8676,0,9520,8954,5472,10191,5407,5339,10290,8667,8959,9387,5326,9785,5506,9099,10058,5449,5431,10191,10058,0,5437,5350,8944,9968,8801,8667,10041,5506,9560,5657,9216,9188,8863,9040,5326,5326,8993,5657,5355,5506,8944,5326,9968,5506,8877,8663,10017,8917,5670,5670,8859,8767,10058,8824,5388,5388,5388,9141,9141,5388,9093,8997,0,0,8936,0,9203,9709,9406,8917,9738,9597,8898,9411,5304,9417,8917,9284,5646,9565,0,10068,9743,9417,9104,9679,5388,9876,0,8997,5372,8824,8824,9738,9065,5437,8940,9876,5359,8917,5331,9574,9411,9480,8936,8828,9709,9587,9709,9502,8828,5684,5489,5421,9826,9720,5321,9464,8908,10262,10012,8908,9766,5304,10028,9341,10218,9260,0,9046,9135,8778,10041,8908,8667,5267,9647,9145,9617,9664,9216,10041,9664,8778,9099,5359,10041,9145,9520,9520,10135,9876,5271,5254,5248,10206,0,5363,9729,9300,9242,9173,10101,9198,5646,10191,9357,8948,9785,5326,8959,5506,9592,5344,10028,9637,9242,8724,5267,9738,9464,5646,8908,5291,5243,8849,8738,8663,8663,9597,8672,9900,9029,5449,8912,8663,0,0,8871,9198,8912,8738,9602,8824,8795,10041,9220,9088,8863,9294,8854,8975,5355,9688,9688,10107,8954,8744,8761,8689,5321,9847,0,8908,9341,8685,8685,9449,5506,9781,9520,9754,9847,9050,9265,9265,9099,5367,5501,9208,9401,9083,8917,9352,5670,8940,8948,8663,5278,8652,5388,9560,9198,9743,8729,10159,10228,9373,8696,5670,9357,9814,8944,5331,9331,10073,9814,9226,9208,5335,5670,5350,9417,9642,9738,9738,9738,9065,5331,9602,5506,9280,9109,5367,8652,9198,9231,8993,9709,9050,8672,9869,8788,9417,5619,5646,5506,9203,8744,8975,9305,5326,9602,9830,5344,9114,5363,5367,8993,9294,10107,9280,8997,8672,9208,5285,9055,9242,8912,8784,9658,8754,9325,9421,9305,8908,8672,9729,9417,9626,8801,9361,5624,9443,9336,9046,8729,9720,8854,9145,5355,5248,10017,5443,9336,8806,5359,0,9305,5619,9570,9357,9220,8667,8772,5355,5506,5326,5326,9674,8754,8667,9226,5688,5437,9145,9864,8672,5355,8898,5456,9046,8932,9963,9198,8667,8663,5267,10201,8801,5449,8828,0,9617,8778,5506,10003,5624,5506,9602,8975,5339,5335,9226,8877,5619,9294,8685,10147,9869,9530,9083,9417,8898,8772,9900,5285,9597,8689,9198,9979,9023,9668,9401,9918,5310,5243,8663,5684,8696,5506,9203,9220,8738,5449,5315,8754,5421,5344,9891,0,9129,5355,8696,9093,8839,9208,10085,9597,5339,9864,5646,9226,9704,8863,8849,9119,9464,5344,5367,5267,9305,9565,9637,9294,5506,8936,8812,5377,9284,9059,8849,5331,10141,9046,8663,5431,9346,9814,5506,8824,9574,9396,9647,5339,9203,5278,9437,5670,5372,8754,9743,5304,9135,10008,9940,10047,9309,8849,9220,8877,8970,9431,10008,5248,8877,5304,10101,9080,8784,9300,5634,9715,5407,5331,10135,8672,5624,10135,9530,10058,9396,9535,5431,9226,9781,9520,9023,9826,0,9776,5437,9247,8921,9046,10017,5456,9319,10272,9664,9545,9247,8676,9858,9781,8849,9738,8778,9065,9781,9417,10107,8986,8839,8940,5344,9040,9083,9684,5634,5239,5267,9188,8908,8993,9271,8849,8701,8871,8772,5382,9284,9480,5350,8908,8761,8912,5359,5416,9417,9530,10123,5624,9198,5382,9109,9254,8652,9141,9099,8824,9729,8824,5359,10107,9602,9220,9325,9331,8667,9679,5684,9631,8824,9431,9135,9934,9346,9918,9754,9535,8839,10041,9050,8738,8652,8818,9198,8667,9602,9830,9754,8954,11493,9109,10041,9754,9216,5355,8970,9754,0,5359,5239,10058,0,5437,9720,9141,0,8824,9754,9135,9135,9352,9023,8801,5437,9991,8824,5646,10101,5684,10058,9814,8889,9305,9781,9781,9826,9226,8954,9900,5619,9891,9226,5675,9748,9050,9294,9443,9602,9216,8997,8812,9050,5367,9294,8818,5456,5670,5467,8839,10012,9237,5421,9080,5243,5670,5431,8908,8908,5670,8652,9986,9226,9426,9928,8948,5326,5335,8685,5355,11523,5437,5437,9208,9814,8706,5506,8667,9709,5421,5411,8754,5494,10068,8824,5388,9720,5421,10008,9361,5248,5684,8744,0,9771,5315,0,8667,8871,8806,9401,9754,9035,9540,5367,8975,9017,8986,9093,9050,9346,9309,5239,9637,5421,9007,8812,0,9237,0,5437,8685,8868,9173,5629,0,0,9570,5339,9173,8871,9754,9963,9754,5431,9188,9502,10340,9361,9216,8854,9498,9918,8696,9373,9587,9668,8889,5421,5506,9331,8734,8936,9226,5331,8981,8663,5267,8954,9580,9357,5421,8784,5506,8718,5478,9520,9382,8667,9411,8839,8784,8784,9729,8940,5421,9900,9226,8729,9114,9114,9606,9437,10073,8965,9065,9040,9284,5494,5267,5239,9826,9198,8812,9046,5411,5426,5675,5239,9530,10212,5372,5388,5315,5326,9487,8667,9525,8806,9198,9050,8970,9007,8812,9346,5359,5377,9652,0,10191,10068,8824,5478,9208,5388,9760,9198,5449,9012,9135,10290,9826,9602,5666,5359,9208,9208,5367,9093,9242,5248,9487,9007,10041,8824,9934,5355,9664,5315,8908,5267,5355,5359,5359,8806,5339,9271,10123,9178,9198,5629,9580,5331,9050,9612,5315,10123,9945,9928,8944,10212,8676,5267,9602,8871,5335,10290,8849,5431,5377,9918,5331,8738,9814,9443,5506,9007,5239,9464,10052,5624,5382,5350,9247,9247,5278,8685,9023,9391,5437,9050,9806,9492,9679,5407,9145,5449,10123,8812,9294,9597,5350,10017,8812,8877,0,0,8685,5431,9198,9226,9141,5321,5315,9570,10206,5326,5411,8663,10297,5355,8729,9173,8877,8738,8738,5267,5359,5267,9443,5501,5494,9720,9776,8784,9492,8718,8744,5506,9826,9637,9099,10068,10079,9597,9237,0,9957,10008,8801,9876,11528,5388,5291,9093,9093,5350,9574,8936,8701,9226,8921,8921,8754,8788,8754,5426,5315,9396,9156,10107,10182,9167,8672,5350,5382,8849,9520,8696,9294,9046,9284,9065,5304,5437,5291,5267,0,0,5377,0,8824,8701,9720,5402,10206,9637,9357,5619,8824,5331,5421,9336,9325,9007,5239,5248,9129,9426,5431,9040,8676,5666,9023,8718,9093,9007,9099,9099,5506,5372,9141,9417,8940,9449,5355,5344,5431,10085,9271,5339,9341,8921,5355,5372,5326,9114,8940,9254,5651,0,8801,9535,10191,5431,9602,5421,5350,9602,9658,8812,8812,9502,5339,8908,9141,5355,9284,9900,9674,9781,9530,8667,8667,9470,9055,9401,9220,5377,8863,8859,8936,5344,9226,10191,8993,8738,5456,0,9391,9109,0,0,5437,9226,8828,9642,5359,5331,5367,9145,5359,8672,5411,8812,10058,8795,5326,5619,8729,9135,9760,9093,5335,8696,5437,8936,8921,8754,8993,10191,9401,5304,5359,9449,8849,8812,5248,5331,9220,8877,8812,5372,9226,5619,9631,9284,8801,8806,9535,9470,9242,9208,9535,0,0,8812,9602,5355,5431,5437,8812,9341,8701,5506,5437,9626,9093,8724,9514,5437,5377,9242,9904,9754,5344,9814,8970,5624,5377,10123,5684,5248,8738,9280,10017,5657,9050,9284,0,8932,9642,9652,9050,5331,9602,5291,10068,10206,5315,9093,0,9284,9125,8801,5377,5377,8902,9637,9652,9597,5304,9050,10107,9050,8824,9401,8672,8965,9979,10222,5326,8877,8877,0,9294,9325,5402,10175,9771,8889,5619,8912,5344,5467,5467,9426,9145,8908,8744,9341,10112,8788,8954,9570,5506,5359,9017,9141,9796,8729,9050,9796,9606,8917,10079,9492,9173,10052,9300,9979,8713,9198,9979,9979,9226,9580,0,9498,5397,5271,8801,9216,9231,9046,9125,9104,9104,9325,5344,9443,9417,10068,9421,8788,9421,8854,8854,5254,9145,9574,8849,8801,8889,9040,9226,5421,5431,8912,5494,0,9208,10147,5377,9220,5315,8685,5456,8975,9864,9023,9145,8877,9382,5304,8667,8663,8772,9188,5421,9226,9574,9336,5467,9796,9294,8828,5397,8801,9443,5271,9570,9050,5326,9979,9704,5326,10201,0,9242,9957,8676,5326,0,8871,5339,11493,0,5267,9046,8788,9156,8936,9220,5344,10101,9637,9647,5382,9059,5291,9208,9814,8912,9411,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9188,2,5651,10201,8908,10290,5397,2,5335,9247,9876,10290,5397,5355,9454,8824,8948,5629,5472,5472,10175,9083,9141,5421,5421,5646,5254,8676,10123,8778,8672,8754,10306,5646,8986,10306,5367,8986,9050,5254,10243,9487,9771,5675,9664,9580,8744,5355,5411,9814,10017,10028,9093,8701,5344,8801,5231,9637,9099,9226,8801,9220,5331,9417,10262,9046,5506,5506,10012,11533,9771,9771,9704,9188,5506,2,9198,8663,8889,9208,9280,5363,8744,5285,9606,9508,9208,9912,8754,8754,5506,8667,2,8965,9771,8908,8676,5267,8706,5629,10306,11540,2,5350,11545,5421,5355,8902,9203,11551,5421,2,11556,9621,9652,11560,9900,9336,9050,9046,9560,9378,10107,11565,11570,11574,2,10107,8912,9173,10107,9652,8701,5506,5321,9492,8734,8824,5271,5421,5421,8898,9114,8824,8824,8824,9520,9208,8908,8663,9220,8672,5372,9974,9974,9664,5619,9664,8908,9664,5355,9069,8795,10052,8940,5315,9647,5506,9093,9167,8917,2,8706,9220,10101,8986,8706,9220,8676,9449,9305,5367,5619,9099,5431,9104,9226,9791,9791,5355,9212,8795,5506,5421,9791,5363,5651,9357,5339,8936,5472,9125,9247,5339,5411,5254,9997,10123,10311,9876,9331,11580,10073,5239,5421,8940,9247,9046,5304,5304,9738,9294,9574,9791,8738,10107,5506,9826,8724,9325,5506,10079,9480,8932,2,5506,8917,9801,9791,9203,10079,9145,8738,8744,9141,9637,8663,5437,5411,9188,9814,10073,9791,8795,9341,9826,8761,8744,8908,9743,8824,8959,5501,8954,5506,8713,10052,5506,5355,8859,8663,5355,9046,9280,9382,5339,9151,9099,9046,8871,8744,5367,9401,5326,8824,9679,10028,9876,9226,10028,9156,9664,5304,10290,9480,9331,10073,9597,8713,9226,8801,2,9443,9551,9305,8993,9729,9729,5619,9540,8685,9325,8772,9135,5684,8672,5443,8672,9203,9141,5506,8672,8859,5271,9040,8849,9621,9099,8801,9454,5684,5388,9957,9055,9226,9826,8801,8767,5367,9145,5407,9709,9065,5388,9738,8970,8824,5506,10311,8767,9012,9658,9574,9729,9443,5684,5248,9918,8738,2,10320,2,9743,9631,9065,9396,8706,5675,9145,9368,9280,9668,9203,8898,5254,5355,10023,9401,9173,8975,8883,5315,9055,5506,5421,5456,9135,9738,10091,9198,5629,9535,5506,8912,8658,9979,5331,8667,5421,9602,8801,8685,5367,9617,5359,10003,8898,9331,9574,9592,8912,9597,9029,8772,5506,9900,5437,5397,9203,5467,5359,11585,5315,8718,9891,9508,9129,8833,9658,10085,5339,8663,5688,8788,8754,8718,8767,5472,9449,5359,9417,5350,10101,9135,9738,9305,9035,9284,9688,9699,8824,5267,9387,9080,5646,8685,9869,8894,8663,8863,5506,9046,9059,9725,9508,5331,5248,8839,9220,5304,9876,5243,8784,9046,5267,5331,9046,5285,9475,8824,8672,5397,8713,9382,8824,5407,9156,5472,2,9050,10324,5331,9535,2,5437,9382,9046,9065,9417,8877,5243,5437,9760,9114,9109,9814,9664,9617,9151,8824,8713,5388,5437,9480,8912,5254,9642,9188,9679,10324,9637,9535,10073,9835,5675,10017,9151,8652,5350,5350,9801,9766,10068,5321,9017,5456,5382,8871,5688,5506,8908,5407,10107,9220,5411,5372,9480,5411,8761,9198,9858,5634,9835,9417,8738,9729,9331,5344,9226,8828,9254,10169,8839,8778,5239,9830,8663,9417,10012,8981,5437,9820,8676,9198,9560,10041,2,8812,8754,5437,9050,9991,8744,9346,9203,5411,9226,8824,5254,10196,5407,9226,9074,9050,9814,8871,9781,9080,5619,9156,9361,10091,9826,8767,9592,10101,9151,8676,5494,9188,9709,5472,9050,5367,5437,8685,8889,9055,9046,5388,9198,9835,8948,5355,5506,5619,9597,8672,9968,9891,8718,8944,9069,9069,9151,10228,5359,5411,9226,9341,9480,9173,5478,9198,8784,5397,9046,9754,9411,5331,9900,9520,9373,8734,9119,9040,8871,9284,5411,5267,5291,8738,5321,10073,9114,9876,9151,8877,5248,9188,10068,9963,9145,9280,5254,9203,8724,5467,8871,2,10191,9114,8680,9426,5624,9679,5248,5402,9835,5382,9254,5666,10028,8824,9820,9986,10290,9580,9220,8912,9560,8849,9247,10041,9050,9826,5267,5359,9151,9934,5339,5431,5359,9007,8738,5304,10068,8812,8778,10175,8706,5291,9508,8788,9699,10329,8936,5267,9396,9480,9979,9492,8908,10222,9093,9226,5355,9242,5326,10028,5437,9099,5315,9771,10334,9341,5304,5321,9080,5315,5437,9574,8701,9305,8993,2,8784,5304,5449,9720,8676,5339,9203,9508,9141,9814,8772,8859,9406,5506,8863,10085,9093,5506,10206,9220,9443,9129,5437,9114,9099,5315,9560,5467,2,10191,9617,9900,8854,5472,8833,5377,9729,5339,8738,9502,8663,9658,8925,9729,9480,9864,5624,5359,9869,9475,10058,9760,9642,9198,8672,5367,9284,9265,9265,5331,10212,9226,8806,9114,9093,9514,5350,5326,5331,8828,9642,8680,8871,9050,5624,8902,8898,8663,9520,9642,9754,8689,5278,9231,8689,5304,9979,9470,9216,9470,8948,10008,9480,8898,9470,8898,8713,10008,8672,9050,9050,5421,5421,10206,8738,9565,9341,8997,9135,9565,9368,9220,5331,5494,9900,8795,9260,8975,8986,8824,9125,9029,8696,5267,2,5377,9029,8652,10017,5456,5254,8908,9417,9040,5239,11589,9145,5437,9319,5355,5506,5355,9093,8788,8997,9555,9260,9754,8997,9748,9555,9891,8788,9891,5467,9002,8788,8997,8772,10003,9373,8685,8948,9602,9411,8667,5619,10091,8863,10085,5506,9602,5421,10017,9502,8744,9417,9754,9668,9012,11596,9046,5619,9602,5254,8778,8854,9748,9814,5254,9208,5278,5321,9208,9869,8676,10169,8729,9046,9720,8778,5304,9864,5397,5437,9220,5350,5670,10008,8908,8993,10340,9254,9220,8986,10041,8959,9325,8778,10107,5437,8667,9986,5506,5331,10073,9668,10346,9679,8672,9104,5339,8701,8701,9658,5267,10058,5355,9242,9242,9242,9814,9417,9114,11601,9814,11607,9055,9046,9814,5285,9814,9796,5494,9796,10107,10222,5285,5684,8689,9129,10008,5666,9114,5355,10206,8849,8849,5402,9766,8959,9766,9791,9791,9806,9341,9083,5506,5355,10091,8738,10182,9114,8954,5355,9099,5456,5426,9637,5321,5331,9626,9864,8696,9357,9748,9806,9046,9114,5684,9417,5291,9720,9325,8744,8729,5462,5411,5411,9475,5331,5291,5462,9093,9220,9002,9974,9766,9806,9237,8894,9104,8898,9198,11612,8975,9592,9055,9216,5411,9173,9055,9173,9796,9104,5355,5407,9220,9178,9974,9357,9754,9733,9336,9216,9212,8738,9592,9806,9002,5437,9733,5331,5407,9109,9289,9093,8908,9806,5239,9748,9637,9305,5355,9104,10041,9050,5344,5437,5355,9305,9050,9417,9401,9361,5437,9104,9968,8663,9002,9046,9361,5437,5675,8889,9796,9806,5634,9093,9928,5359,5331,10301,5291,9934,9012,5315,9002,9508,5321,5426,8889,5344,5431,9417,9141,8696,9173,5315,9173,5437,5437,8871,9401,5355,5437,5506,5437,9198,9093,9785,5335,5331,8801,5331,9664,8975,9540,9029,9203,8663,9621,9864,5339,10249,5619,9198,8778,8801,9551,5411,5684,9957,5506,8801,8818,5331,9220,9396,9396,5634,9012,9145,9918,8877,10003,9869,5411,9864,9065,5421,9216,9220,9284,9305,9720,8912,9059,5248,5248,8948,9216,9597,5634,10041,5359,9289,9502,9535,5363,9796,8948,8778,8685,8685,10091,8663,5506,9597,9437,9361,9396,8917,5359,9934,5421,5355,9449,9580,5315,8975,9145,5506,5321,9242,5634,9574,9417,9099,5619,9621,9597,9597,5359,5331,9156,9514,8975,9475,9957,9520,9771,9475,9373,8663,9520,11618,11624,5629,5629,9475,10123,2,8689,5382,9417,9530,5675,8936,9617,9421,9046,9029,9498,9771,8925,5388,5426,9151,5416,8912,8761,9771,5506,10228,5449,10052,5449,9869,9208,5397,5684,9688,9173,9083,9458,9869,9109,9208,9069,9173,9173,5326,9099,9173,5431,5431,9161,10058,9771,5684,5267,9141,5684,5506,5310,9050,9688,9729,5684,5421,8713,8738,9431,8932,9725,9361,8663,5326,9540,5421,5267,9637,5426,5619,9637,9151,9725,5344,5619,9099,9621,9035,9099,5355,9305,10255,9454,9869,9688,9454,9709,5310,5359,5367,5359,5267,9002,9781,5619,5411,5411,9226,9895,8925,9198,8997,8667,9226,9957,5355,5657,9652,5421,5634,5619,8685,5339,5657,8663,5355,9080,10041,5267,2,8849,9709,9080,10101,5331,9704,8849,5331,9664,9664,9050,8970,9198,8889,9606,2,9065,9664,9198,9891,9606,5407,5331,8970,5688,10101,9674,9733,9109,9754,9891,9754,8706,9050,5331,5321,9560,9040,9114,9771,9449,5666,9173,9050,8672,5331,9480,5377,5331,9050,9050,9754,8672,9029,8701,5646,5684,5684,11629,5624,10058,5304,10175,9876,9426,9426,9426,9426,8859,8724,5367,9592,5355,5367,9904,9242,9319,9912,9125,9280,10196,5421,5350,5344,5684,9319,9688,8685,9203,8729,5478,9525,9226,5478,5489,9088,10123,9012,8993,9417,9325,9002,9530,9012,9198,5315,9231,9125,5651,9216,8854,8912,5421,5367,5646,9570,5619,9284,8672,10068,8912,5363,8959,5355,2,9294,8965,8685,9464,8912,5675,9443,9188,5239,9065,5355,8959,10182,9574,9668,5688,5331,10008,8706,8889,5397,8676,5359,11633,8734,8944,9336,5506,8863,5472,8701,9300,8667,9109,5388,9449,9449,5411,9454,10301,9125,5501,9341,9080,8849,10101,9847,9885,8908,9294,9198,9135,8663,8663,10079,10187,9336,5267,9017,9565,8954,5688,8944,8663,9525,9664,8863,5359,9080,5675,5670,8859,8908,8754,8663,9525,9046,5315,9294,8912,9361,10187,9300,9046,5506,8724,8944,5331,9368,9754,9129,2,9580,8663,9080,5421,8975,11523,8954,9729,11636,9325,9555,5367,9826,8772,5421,8772,10267,5267,5506,8908,5285,5239,8993,5239,9226,8685,9065,5416,5397,9743,5506,8877,9135,9208,9668,9498,5684,9417,11639,10228,9738,9104,9289,9421,5388,9046,9145,9065,8889,9065,9647,9771,5248,9046,5657,8772,9918,10320,8993,10320,8767,9454,8806,8778,9658,11644,8672,5304,9401,8908,8898,9080,9979,8889,5267,5506,9864,5239,8965,9602,9198,9188,5355,8772,5675,10255,9642,8877,9216,5326,8658,9631,9530,5304,9080,9443,9382,9314,9050,9396,5506,8859,10047,9135,9574,9294,8689,8912,9918,5231,5467,8824,9826,5243,8706,8859,10023,9869,9664,9498,8877,5388,9626,2,5426,11649,9129,9104,2,5355,10085,10003,11656,9284,9754,8806,9289,9464,5675,9080,8912,9957,5331,9378,9725,9065,8894,8877,5304,9396,9305,9704,8889,8986,9125,8965,5363,5372,10301,9454,8849,9167,10141,10147,5675,5367,9050,8993,8993,9368,8849,9963,9346,5506,8859,9203,10008,5304,9023,5331,5267,8871,8767,5646,9156,8663,5402,9664,9565,8908,9826,9449,8734,11660,9294,9565,11665,9396,8986,9963,5402,9023,9059,9560,5355,8767,9781,9814,8667,9208,8908,9319,9226,11612,9480,8898,5331,9580,9617,5411,11656,9431,8824,8652,9535,9560,5267,9738,9208,8859,8772,9694,10096,5344,5344,10290,9826,9167,5377,11633,8877,8706,9300,8663,8954,9679,9560,9208,8908,8908,9530,9099,9099,8676,5239,5388,9679,9545,9065,9664,8908,9704,9743,8986,5304,9141,9560,9212,9357,10041,9002,10297,9704,8921,10175,9309,9271,8828,9050,9826,8975,10068,9305,5651,9059,8877,2,8871,8912,5407,9617,9771,9099,9216,5248,9226,9035,5291,8824,9704,9212,5411,5688,8849,5489,8772,8833,9314,11493,8824,8667,9642,9188,9781,8948,9208,9520,10028,5326,9023,9023,5267,9065,5355,9237,8744,9226,9560,8685,5494,10058,9309,9443,8986,8824,10243,8912,9508,9050,9099,11523,9426,5331,11656,8889,9226,8818,8812,11523,11670,9237,5267,8824,5411,9178,8894,9587,9401,5407,9188,9065,11633,9382,9580,8921,5248,8784,9294,5619,5506,9963,8734,9592,9647,9216,8940,10243,8652,9900,5478,9918,5355,9606,8663,5304,5421,5675,5239,5411,8828,9437,9918,8672,8912,9284,9963,9203,9647,9963,9449,9309,9065,11676,9406,9276,5675,9378,11681,8859,2,9574,5388,5666,5666,5431,9679,9704,5335,5478,5478,10068,9826,8908,5315,5278,5315,9796,10068,9876,9612,9203,8859,8877,9934,9178,5235,8993,8877,9208,5326,9271,8944,5304,9357,9480,8685,9570,9684,8734,8734,9208,5624,10058,5235,8871,8676,5443,8812,11686,5315,9602,8877,5426,9621,9555,8767,5382,9396,8877,5355,8801,10079,9237,9674,8877,8672,9284,9046,9492,9508,5267,9382,10068,10068,5335,9597,9080,10329,9242,8912,5326,9642,9806,9387,9099,8824,9300,8754,5315,8676,5267,8908,9284,5431,8685,10222,5326,8667,8936,5321,9449,9597,9309,5359,8672,9050,8812,9498,9099,8824,8772,5339,10085,9626,5326,8908,9080,5402,5506,5421,5315,9754,8859,5248,5321,9129,8824,11523,9766,5675,8713,5501,10206,11692,9406,9141,9141,8667,9674,9658,9826,5377,8940,9401,9900,9284,5397,9664,9104,5267,5472,5355,5339,9284,5407,9480,2,2,10239,5407,5359,5326,9305,5367,9309,8667,9208,5335,5494,9704,5331,8696,11697,8902,8877,5335,9050,5331,5359,8806,9046,9099,9265,10047,9141,8706,9401,5335,5267,9104,8894,9050,9093,8812,9514,9040,9212,8940,8877,5315,9545,9023,9401,10175,9309,8877,10239,5331,9093,8833,5331,5506,8828,8902,9642,8784,5267,11703,5437,10228,8801,5377,9309,8902,2,2,9226,5326,8667,5646,8672,9853,5437,5326,8713,8667,9035,9928,9928,5501,10052,9754,8788,9074,9520,10123,9208,5326,9754,5367,9271,9940,10123,9226,10008,9226,9331,9271,9945,10218,9325,8993,9271,8854,9271,10008,5367,9271,8667,8839,8936,8824,8849,9754,9331,8975,8824,10041,9271,10028,9226,9754,8975,8894,9046,9754,9754,9080,10008,10008,10008,9928,11707,5326,5506,9754,9652,9652,10008,9664,10008,10101,9361,8936,5359,11712,9664,5467,9226,5675,8824,8663,9173,9141,5506,9826,8738,8738,8718,5344,10206,5310,11717,11725,9869,9480,8908,9309,5335,5355,9203,9198,9198,9540,9597,9069,9449,9341,8863,10249,9300,8761,9341,9830,10068,10091,9141,8767,10249,5388,5456,9826,9220,5355,9129,9826,9220,5437,10068,5331,9125,8663,9341,10159,9570,8729,8871,9940,5684,10068,9198,9738,10107,5285,9040,9002,9729,8854,9141,8788,9145,10311,5666,8696,5646,8917,9216,9373,9336,9125,8912,9156,9325,8801,9046,9208,9198,9017,9212,8806,8806,5359,5666,11731,9421,2,5456,8778,5355,9216,5359,9055,8912,5624,5629,8667,5688,9470,9231,9046,9979,9188,9104,9104,9173,9592,9145,8667,9280,9373,9754,5489,5619,10096,8788,9319,9080,5231,9040,9294,8663,8658,2,9530,10206,9796,11736,5416,9617,5456,5304,9023,9119,9743,9125,5506,8667,8849,8685,9017,9715,10141,8859,5382,8761,5657,5248,9597,9203,9826,9621,9059,9443,8754,9050,5339,9704,5624,9864,9454,8754,11742,9454,5421,9597,9271,8788,8676,9431,9826,8824,9454,9664,5634,5372,9141,8754,9637,9417,9331,5271,9858,5278,8778,8724,10068,9617,8981,5350,5443,10091,9198,9104,5506,9198,5506,9743,5355,10340,8908,9587,9417,9729,8894,9216,8871,9940,9729,5437,9470,5339,9748,8824,9080,5382,8993,10008,10169,2,9664,8738,2,9617,2,9104,5416,10008,8754,8667,8839,5388,5431,9271,5489,10175,5688,9475,9475,8824,9826,8997,5411,10117,9080,10141,10091,9835,8824,5494,9080,9188,9050,9475,5355,5670,9480,10058,9738,8667,9814,8744,5411,8718,9814,9748,10028,5437,11748,11755,8706,5494,10169,9968,2,9443,5355,5355,9129,8812,8940,8754,5248,9796,8784,8784,5421,9602,8940,9437,8754,10008,8871,5657,8744,5331,5382,9119,9406,9458,9470,8652,8663,8754,9597,5675,8718,8859,9029,9050,10091,8652,9754,8954,5619,8696,11763,9059,9480,5382,5443,9265,9387,5359,8944,8738,5670,5335,10175,9904,5350,9178,8912,9007,9760,9220,8908,5350,9826,9247,10091,5248,9040,9265,9198,5267,9271,9580,5339,9826,10290,8917,9679,9050,8940,10129,8908,9580,8986,2,10159,9508,10129,8685,5291,5291,9125,8936,9129,8778,9242,5657,5335,5501,5501,5501,9826,9361,9104,9104,10068,10222,8663,9341,5494,10068,9498,8676,11768,11773,8824,9580,5355,9508,10096,5506,9141,5388,9040,5449,8676,5248,9305,10068,5377,9417,9631,10206,9514,8738,9597,5377,5267,9065,8859,9664,9766,9284,10117,11773,5624,9869,5359,9050,10068,9226,9631,8806,8806,9088,5331,8701,9514,11779,9597,9050,5624,9125,2,5421,9791,2,11485,11485,9361,5506,9621,9216,8801,11485,9208,9208,9940,5506,9208,8685,9940,9319,9464,10329,9319,5506,9198,8993,9114,5449,9814,9151,11784,9688,5372,9945,9325,9046,8767,5397,8689,2,5416,5397,9237,5267,9314,9754,8997,8784,9104,9104,8676,10041,11789,9373,9373,8908,9502,9502,8667,9401,9265,9498,9357,8652,8854,9046,9912,9188,9145,9847,9525,5421,9830,8854,9069,9050,5388,5506,8658,9203,9104,11794,9869,9520,9203,10297,10165,5431,9023,9826,9050,9421,8975,8908,10012,9814,5619,9341,9040,2,9237,9193,9023,8908,9796,8889,9830,5506,5449,9530,9458,9830,5267,8706,9109,8959,9597,10249,9040,5666,8970,9437,8729,5666,8663,5666,5449,5431,9104,9520,5449,5421,9341,9401,5388,5431,9104,9551,9551,5651,10012,8738,5437,8940,9771,9035,9592,9284,5304,9242,5355,10147,9900,9109,8795,9294,11485,9046,8734,9099,9791,9046,9220,9050,5619,8954,8744,10297,10058,5355,10249,8744,9188,5339,9520,8818,9743,5421,9626,11485,10112,9050,9378,8713,9341,5388,8824,9738,9814,9754,8761,8663,8824,9173,10058,9125,9729,8772,5344,9231,9498,10012,9754,9069,9443,9198,9080,5670,5335,8908,5388,9135,9083,9080,9065,8685,9280,5271,9720,9540,8917,9046,9325,5239,5239,5421,9555,5291,9145,9007,5411,8993,8672,5456,9226,5239,9417,5291,10047,9791,9188,9574,5449,5350,5355,5629,10290,9391,5634,5315,9373,8917,5437,5437,5506,9431,9198,5355,5355,5304,9167,9979,8863,8658,9050,9668,9864,9743,9050,5367,9050,9592,9135,8667,8912,9173,8975,5239,9254,9226,9294,9918,9178,9664,8844,5315,9652,5285,5304,9957,5331,8754,8877,9464,9046,9963,8663,9226,9216,9535,9545,5651,10232,5456,9035,8824,8680,9743,9260,5634,9135,9198,8849,9826,11485,9080,10047,9699,8849,8948,8663,9050,8663,5267,9050,8824,8672,8824,9918,2,5304,9417,5684,10135,8908,5304,10159,8778,9480,5359,8859,9080,9080,9178,8948,10123,9289,9417,9570,8981,5651,9637,9760,8877,5350,8908,5326,9046,9080,9781,10068,9109,9226,5411,8652,9729,8975,9220,8839,9220,8738,9040,5456,9208,9918,9535,5388,8667,5472,9545,9046,9220,9331,9050,5377,9940,8667,9664,9417,5331,9040,5304,11799,5426,8812,9093,9135,10101,10206,9188,8663,9035,10196,9203,9069,8685,8824,9226,5407,9352,5670,9099,10117,9449,5326,8663,8738,9346,8997,9046,5411,9968,5267,8744,5670,5494,8948,9617,8812,9443,5411,9226,5670,9754,8718,5646,5407,5619,9738,5431,8997,9555,8672,9074,9226,9918,9771,9208,5666,2,11804,8685,9069,9173,9193,9188,9141,5267,9754,8812,9411,9900,8912,8696,5670,8729,5666,8734,9373,9237,9449,9203,9587,8718,9754,9592,5248,9668,8812,5355,8784,5483,5304,9530,9606,9059,5416,9475,8859,9141,10047,5506,9934,8824,5624,9443,9007,5506,9247,10052,5248,9729,5331,9826,9173,9050,5339,10175,9480,9891,8849,5392,9396,5335,9704,9208,9208,5666,5392,9580,8734,10262,8993,8663,5315,9738,9709,8997,5304,5304,5335,9492,5431,5426,9173,10222,9198,8685,5506,5426,5267,5326,8844,5267,9050,9093,5315,5670,9242,9242,5304,5506,9226,5315,9046,5421,5388,5291,5372,9580,5431,9023,8713,5483,8778,5506,9426,8859,10232,10062,8734,8883,5472,5339,9055,8824,10047,5248,8685,10012,9050,8854,8812,9426,5483,9781,8812,8948,11809,8734,9135,5456,9729,10058,8696,9754,5377,9050,9904,9325,5315,10232,5377,5304,8812,9904,10255,8975,9602,5331,9652,9050,8801,5377,5239,5411,5321,5321,9858,9520,5239,5239,10182,9183,9046,9151,5239,8877,8713,9502,8672,8854,9475,5355,8993,9551,9336,2,10175,9647,9652,9183,9631,8965,10123,8738,5350,9093,9664,5239,9729,9046,5239,5331,9336,9305,9900,9535,9309,9309,8812,9652,8948,8801,9411,8940,9173,9820,8925,8824,9319,9617,10008,9254,9637,9352,9188,9294,5506,9220,10340,9602,8801,10206,9294,9835,10017,8772,5651,9637,5506,9475,5421,5421,5278,9135,9216,9443,5421,5367,9023,5506,8883,5421,5304,9029,8754,9945,9029,8877,5467,8889,9475,9647,9050,8877,9203,9135,9265,9411,5494,9602,9012,10035,10191,8784,8981,9642,5355,9754,5355,8667,9602,9012,10041,5657,8718,5437,9046,9658,5254,9023,5670,9449,8849,8824,5421,9658,9449,9658,9198,8824,9475,10035,9658,9449,5335,9592,9417,9002,9449,9208,8663,9492,5421,8801,9820,9135,9226,5619,10035,5326,9492,8863,9023,5506,5506,9475,9449,5278,9475,9814,10182,9470,8672,9597,9766,5359,9470,9319,9570,9814,10175,9046,8970,9216,5449,5449,10175,9226,10329,9597,5350,9470,9766,8877,5355,9957,8898,8898,8898,5235,5437,5350,9265,10290,10290,5335,5235,9480,9492,5304,5304,2,8795,8795,5367,9492,9492,9188,9464,8795,8795,8795,5235,9188,9104,9237,8744,9771,10107,8993,10107,9699,10107,10107,5421,8667,8912,10201,9729,5339,9226,5483,9417,9141,9841,5267,5388,9417,5411,8652,5684,5407,5411,8663,8959,5421,5421,5285,5355,5619,9265,5267,9729,9709,5267,2,9007,9080,9178,5285,5407,9109,5350,5619,10008,5359,5359,5267,9841,5359,9417,5619,9417,5321,9492,5321,5350,5267,9156,9300,9729,5291,2,5304,5331,9336,11815,2,8806,5506,8908,9791,8663,8849,9135,8824,9114,5372,8908,2,9626,9540,9188,9895,9664,8663,5411,9080,5355,8738,9341,9754,8908,9715,8738,8908,9592,5411,5684,9748,5304,5666,5377,9766,9125,8767,8767,9145,9417,9748,9216,9373,9336,9151,5331,8883,9417,9050,9046,9382,9203,9325,9738,9743,5367,8724,9869,9626,5684,9208,9570,9720,9617,8883,9325,8912,11821,8778,11827,9237,9382,8997,9574,9336,5506,11832,9065,9216,8828,9080,9046,9597,5489,5359,9617,8898,5629,8975,9574,5506,8917,5421,9617,9226,9208,9198,9602,5331,5355,9574,9226,5367,10243,5397,5331,9188,5315,5271,9652,5315,9080,9080,8824,8676,9454,9508,9945,9814,9814,5416,5331,5367,5304,9294,9766,9135,8754,10008,10141,8863,9284,5397,8667,8824,9059,10091,9396,9535,5304,5657,9858,5278,5278,8940,8701,5426,9417,9535,8908,9720,9940,9940,9725,8993,9679,9664,9664,9748,9331,9331,10169,5321,9104,5271,9271,8667,8778,8849,5271,9226,9188,9141,9050,9254,5411,5443,9725,5321,8778,9709,8993,8667,2,9357,5494,8824,9226,9145,9814,5646,5501,5407,5506,9198,5421,5467,9188,9080,8801,10091,5359,9050,5670,10107,5355,5355,9023,10101,9361,5670,8738,8663,8824,9835,5377,5321,9050,9050,9226,9835,9592,5372,9411,11838,9449,8824,11849,9178,10008,9470,5267,9437,10073,10206,9294,5411,8859,8696,8663,9254,9508,5239,9226,5443,9040,9733,8738,5248,9309,9733,5355,2,9530,9254,9835,5449,9492,10052,9093,5489,9715,5651,10008,9178,9247,9709,9709,5666,9612,5684,9580,9674,9674,9766,9766,5267,8824,9305,8806,8706,9841,9305,9449,5315,9050,9396,9709,8701,9492,9492,5339,10222,9104,10329,5315,9173,9188,9508,9188,5321,9709,5506,9336,5416,8676,8676,5506,9080,5304,5355,5619,9216,5267,9826,5666,9674,2,9729,9411,9766,9325,10228,8824,9626,8667,2,5411,5331,5372,8806,8806,9040,8812,5267,9417,9093,8812,9237,9050,9226,5416,8975,10079,9785,9652,9040,9040,2,9050,9050,9050,5416,9050,10028,9173,10028,8772,5494,9220,9597,10079,10079,9864,9029,8767,9508,9417,9029,11859,8663,11864,11864,8833,5646,5646,5355,5506,8672,9125,9198,9231,8706,5506,5339,9597,5634,11869,9597,5339,9046,10228,5388,5421,9454,5651,10255,9242,9309,5421,9341,10297,9198,5267,9208,9099,9226,9247,8871,8724,8734,9743,10297,10267,9046,5431,9198,8772,9305,9198,9826,5335,5506,5506,5285,5310,5634,9900,10255,8724,5271,10135,9508,8718,5421,9945,5267,9119,8724,9173,5472,5285,9247,9560,9637,8724,9226,9480,9560,8908,9357,9271,8997,10058,5688,5271,8685,9602,9226,9781,9046,5506,9119,5285,11875,9029,8729,5494,9766,9602,9203,10212,5326,8744,5291,9007,8917,9760,9271,9357,8917,9119,9247,8788,9093,9046,9198,9208,9242,9806,5388,11528,2,9602,9508,9093,9341,9502,9119,5472,8965,9114,5411,5304,5377,10107,5285,9431,8738,5254,5254,5456,10107,9188,9023,5367,5367,5355,9050,9141,10101,9357,9979,11485,5335,10041,5388,9449,5501,9806,9173,9664,9368,5411,8685,5359,8663,2,8894,8812,9826,9421,9040,9664,8818,10141,9055,9046,9574,9606,9109,8706,5506,9198,8883,9198,9382,10058,8767,8877,10008,9173,8894,9606,10101,5367,9454,5651,8754,9535,9151,5355,9617,5350,10052,5248,9738,9254,5350,10041,8824,8824,8818,5478,9891,8706,9109,9771,9065,5326,8696,9560,5431,9059,5478,5437,9289,10041,9771,9771,9449,5666,9391,9178,8667,9492,8724,5359,5506,9114,9093,10008,8672,8713,8818,9480,8663,9109,9979,11883,9129,5388,9580,5619,8701,8701,9492,5359,2,8812,5304,10101,5248,5331,10101,8667,9597,9050,10101,9826,9570,5437,5326,10012,5326,9029,9431,9796,9688,5506,8908,10085,9341,9417,9050,5506,9458,5388,5506,5506,8898,9876,5421,8898,5421,5421,9029,8959,8667,9208,9046,9294,8663,9699,8912,5449,9125,9135,9826,9247,5321,9530,9046,9826,9602,5304,9208,10079,9551,9220,8718,5506,9602,8975,9637,9957,10196,9443,9220,5501,9247,5449,9580,5382,9099,9580,5388,5388,8970,9099,5437,9373,11888,9280,5388,9012,11893,5462,8877,9099,9391,9580,9294,9602,9391,9637,5321,5355,5355,9173,10206,5359,5359,9928,5326,9198,5326,5326,5506,5506,5506,5506,9401,9401,5291,5456,8954,9574,9050,9050,8824,8912,8981,9760,8959,10191,5382,5248,9934,9247,8812,8912,8912,5344,9738,5355,9606,8744,5506,8795,9156,5388,8912,9325,9046,8795,5271,9387,8795,9220,8724,5267,9597,10023,9145,9631,5359,5688,9918,8754,9198,8685,9220,10008,10123,2,9535,10123,9684,5243,5267,2,8908,9480,9198,10123,8772,9535,8824,5619,5411,5437,8912,9203,9688,5494,9046,9597,9226,9606,9188,9226,5267,5271,9934,8912,9684,5271,5271,5462,9684,5278,9156,5315,9226,5315,5326,5670,8806,8706,9475,5684,8713,5350,5388,5506,5363,9791,9766,5651,5629,5355,9791,9791,9093,10068,9881,9881,10107,8908,5421,10182,9198,8795,9464,5267,9242,8812,8652,9720,9720,8744,5278,8663,5355,8663,5267,8676,5367,9637,10123,8744,9129,8824,9688,9198,8908,9679,9265,8854,9300,8738,9431,8839,8689,10112,8795,5304,8713,10052,9208,9796,9341,9631,8854,9254,8663,8944,9480,9806,9417,5506,9475,10079,9720,9743,8767,10285,9145,9012,9540,9551,5416,5271,10297,9454,10267,8993,9208,9417,9498,5431,8672,5472,9826,8724,5506,10008,5367,9046,5355,5382,5456,9754,9729,9912,9046,5267,5388,5367,9083,9443,10123,5254,5494,8685,9114,9141,5267,5267,10068,11899,9835,9470,2,11908,5506,8912,9791,9597,5421,5267,9396,9167,9869,8917,9198,5619,5431,8883,5494,5489,9284,9858,9173,9167,5267,8877,5350,11912,8658,5646,9145,5326,5326,8912,9203,5506,8689,9912,8701,5326,5239,8685,8912,8706,9551,10023,10165,9216,9574,8652,9029,8975,5267,5310,9626,5382,10096,9684,5326,9080,11915,9574,9050,9796,9891,5416,9520,9464,5248,5248,9754,9141,9940,9508,9626,8824,8824,5411,5267,9704,8701,5407,8849,9284,9083,5407,9454,5506,8738,5326,5267,9151,9007,5506,9167,9254,8975,8754,5326,8663,8663,5367,5331,8986,9023,10123,5506,9626,5331,9853,5416,9080,5657,9443,8738,8663,9720,10123,9109,9151,9104,9679,9480,9801,5331,5355,10017,10017,5456,9766,8908,9858,8652,9331,5267,10091,9940,9729,10041,5472,5501,9271,9093,8986,9637,9754,5339,5355,8701,8824,9401,9065,8975,10068,5407,5407,9309,8795,9545,9454,8839,5267,8871,8713,9226,5326,9080,9088,9835,5437,5248,9040,9417,9426,8754,9684,9151,9083,9426,9099,10017,9104,5416,9520,8706,10159,5489,5494,9346,8925,11493,5456,9891,9688,8839,9835,5407,9508,5472,9151,9443,9226,5675,8738,9226,8824,8824,5388,9443,9023,9720,5388,5506,8948,5248,9796,10206,8667,9080,9265,10003,9216,9216,8824,8859,9083,9050,8680,10107,9520,9835,9406,10169,9341,2,9237,9237,5657,9029,9520,8784,8784,8908,9188,9254,5494,5355,8993,9417,9806,9729,5619,9796,5271,5248,9612,9183,9135,9305,9796,9754,5619,8839,5248,9145,5331,9587,9530,8667,9055,8685,8738,8854,5494,9520,9135,9668,2,8970,10123,9934,5335,8917,9271,8912,9426,9426,9426,9679,9720,9881,9247,9574,5666,9904,9007,10017,5657,5402,9771,5326,9796,5431,8944,9254,5339,8667,5359,10290,9226,9928,9007,8738,8970,5248,10041,10052,9826,9198,9178,5634,8908,8908,8824,5285,9492,10123,5367,5278,9198,9574,8754,8908,5684,5382,9151,5462,9346,5315,10129,8912,5431,5285,9237,5326,9508,8754,8667,8667,5267,5267,9099,10068,9104,9470,9470,8784,5321,9891,8877,9242,9341,9396,9396,5278,8849,8908,5304,9720,9220,9492,8663,9426,5321,9387,5304,10068,9361,9141,5506,9114,5304,5416,9099,10068,9220,9254,8849,5315,9314,9023,8778,9449,9449,5684,9612,10096,5619,8812,5666,8997,5506,8701,8921,8863,9631,9801,5377,8859,8701,9050,9002,5397,8912,8824,8667,8724,9502,8859,9502,9470,8908,5335,5377,9801,5472,9198,8680,8680,9050,9145,9305,9198,9869,9869,5367,9046,8696,8965,8754,2,9093,9502,5377,9631,9443,9514,9093,5355,9417,9023,8970,5506,5431,9035,9602,8871,5321,9748,9748,9748,5675,9626,8663,5437,8685,5350,9411,5267,8754,9781,5411,5675,5437,9580,9401,9580,9709,8778,8908,9203,5489,11497,9203,5355,5421,10091,5355,9237,5629,10222,9709,9806,5675,5437,5411,8824,5437,9050,5359,5267,9709,5267,5267,9545,8724,5684,9208,9208,9208,9080,5421,5331,8997,9208,5331,8761,9963,9688,9040,8788,10290,5506,5506,5291,9208,9109,9050,9319,11502,8981,8889,5646,5363,9454,9125,9498,9997,9046,11921,5467,9738,9247,8959,10052,8824,8894,8849,9135,9592,5506,8993,9012,8663,9738,8738,9198,9791,9391,9801,9587,9145,10112,9540,9156,8844,5267,8738,9540,9203,8824,9046,5666,5267,9141,9198,5239,9080,5501,9231,8754,5355,9050,9869,9688,10079,9417,8954,9208,9626,5321,9125,9449,8718,5271,9520,9637,9551,5506,5350,11505,9289,9069,9565,10052,9704,9289,9046,9421,9125,5666,9357,9928,9012,9331,9580,2,9208,9475,5254,9198,5382,10068,8936,9141,8854,9188,8718,8889,9145,9475,9065,9729,5506,9826,8912,9141,10228,5335,5335,9135,9664,5472,5684,9720,9114,9203,9046,9709,8801,9099,8833,8917,9431,9212,9046,9421,9540,5243,9325,9378,9912,8738,9417,9738,9125,9738,9738,5666,9417,5344,8729,9231,9368,9368,9826,9729,9417,9391,8806,5437,2,5248,5377,9658,9305,9357,8738,10023,9002,5421,5411,5271,9853,9029,9029,8975,10272,10182,9642,10201,8912,5619,9891,5326,10047,11511,5421,9378,9305,8912,9002,9198,9391,9104,9104,9198,9083,9617,10085,8718,5675,5315,8894,8778,9900,8883,9864,8889,5359,5489,9918,5321,11929,9417,9198,9652,9664,11505,8940,5619,5416,10206,5315,5271,5355,5326,9597,8894,8859,9738,8680,9733,9305,10141,5407,8718,8754,9963,9963,10249,5670,8806,9417,5382,5437,5506,10101,5291,8680,9637,5619,9592,9814,5315,8663,8863,9771,9574,9940,9401,10008,5344,9289,5363,9125,8849,9957,9309,5634,9357,9254,8676,5321,9454,9023,9454,10329,5506,9820,5359,5478,9738,9396,9183,9119,5437,9023,9766,2,9637,9449,5382,8970,9864,9720,9801,9046,9368,9417,9766,9781,8859,5634,9626,9835,9265,9017,5411,10008,9830,9378,9431,8680,9725,9781,5267,5304,8754,9040,9587,9331,10041,9748,9104,9319,8959,9289,9826,9247,9487,5355,9530,5310,8908,5243,5350,8738,9325,5506,9664,5321,5271,8986,9002,5506,9401,5291,5271,11707,8981,10068,9156,5254,5411,5407,9858,9699,9050,9733,9193,9417,8652,8738,10096,9368,9319,5411,5359,9271,11938,2,9198,9099,9464,5304,9587,10017,5382,9754,8680,5437,8718,9771,5437,8824,9050,9237,9035,9294,9352,9141,9226,9406,9193,9443,8818,5407,9309,9592,5421,9835,8718,5506,9885,9167,9688,9145,9023,9050,10153,9617,8685,9664,9781,9216,9950,5355,5407,9212,9212,8754,9796,9771,9771,10008,5411,5326,10141,5278,10147,8970,5619,9754,8738,8676,9592,8889,9151,9188,2,2,5377,8954,9449,9093,5675,9178,9835,10141,5315,9373,9449,5248,5657,5472,8912,9709,9183,9183,9305,9114,9411,5443,9733,9587,9216,9188,9766,9198,9551,5619,5437,5478,5646,9525,5304,10147,10243,5339,8965,9080,9017,8680,5291,8940,5411,8871,8729,9540,9498,5331,9530,9208,9198,9918,5397,8738,8954,9580,8652,8718,9080,5267,8680,8975,9592,8889,5675,8663,10165,8970,10052,8970,5350,9368,9188,10191,5478,10068,8932,9093,9963,9492,5278,9806,9271,5254,9814,10255,9826,8908,5478,9820,5431,8871,8912,10017,5359,8828,9178,9835,5629,9208,8889,9806,8871,5426,9679,10012,5335,5449,9173,8812,9198,5666,9198,9309,9007,5291,9012,5350,9963,9928,5315,5335,5335,9704,5304,10249,9934,5449,8667,9373,8738,11707,5355,8812,5321,10262,10262,9396,5501,5304,10117,9237,9642,5506,9597,8754,8754,8932,5416,9167,8672,8738,5494,9498,10329,9431,8701,5271,5326,11485,5315,5355,9612,9099,9099,9156,9305,9156,5321,8877,9492,9830,9046,9508,9305,9733,5344,10175,9738,8936,9449,5501,9431,2,5619,5359,5315,9785,8940,8849,9508,11505,5437,10107,5248,5624,9391,5359,5291,5344,9357,8936,9545,5355,10206,9963,9612,10041,9220,9023,5411,9449,9129,9099,5267,5675,9141,9305,5666,9417,8676,2,9464,5478,9602,5355,8854,5344,9766,5456,5377,10239,9417,8676,9900,8676,8676,9729,9208,5355,10191,9658,5675,9198,5411,9391,5335,5437,5619,9864,10068,9368,5478,5359,11707,8844,9198,8729,9145,5624,8932,5350,9642,9431,5304,8863,9401,5331,9212,8849,8812,5359,8806,8738,8738,9642,8738,5377,9876,8812,5670,9514,9093,2,9785,5267,8970,8828,8863,9602,5331,9642,9652,10068,10153,5331,9040,9918,10206,5315,5321,5377,5331,8902,9198,9173,9173,8908,8713,8936,5372,9319,10201,5367,5629,5506,9029,10107,9540,8761,5271,9305,9040,9012,9720,8663,8993,9065,9891,8877,9602,9114,5675,9826,8685,5315,9720,9265,9771,8718,9104,8824,8912,5666,9368,8685,5315,9104,5431,9309,5388,9480,9040,9104,5506,10107,9876,9216,9050,5501,8908,9565,8877,9104,5315,9220,9145,5397,9720,5350,8859,9508,8859,5271,9826,8718,9046,5350,9492,5684,8689,5267,5315,11518,5315,5344,5506,5431,5388,5331,8877,8877,8954,9336,8908,8908,9820,10191,5321,9820,2,9109,9540,9540,5377,8824,5377,9226,9565,9361,9492,9203,9208,5619,9203,8824,8718,5315,9781,9069,9114,5339,8912,8667,9046,9580,9709,5684,5344,9709,9968,5344,8672,8713,5344,5344,9449,8701,5344,9114,9968,8801,8761,5619,9847,8824,5421,9743,5367,11944,9606,8908,9709,8997,5359,9743,9141,8696,9046,8761,9443,9220,9220,9729,9725,9231,5506,8696,9957,5437,11949,5506,8908,9198,9242,9934,9242,9709,9912,5372,8824,8663,5355,5355,5355,9401,10218,9099,9771,9198,5402,5619,8883,9597,8685,8685,8685,10107,8849,8854,9826,8685,9093,5421,9869,9145,5421,8795,9720,9720,9300,9346,8663,9520,9151,9895,9357,9540,5411,9940,9361,9208,8761,9284,9173,9480,9443,9668,8839,9341,9449,9208,5506,5267,8713,9050,9357,8761,10068,9135,9417,9145,9642,5254,5456,8812,9443,9743,8718,9325,9346,9284,5670,8767,5335,9688,8685,8839,9231,9835,5421,5421,8824,9109,5489,8997,9729,9480,8954,8778,8859,5254,9895,8772,8806,5304,9869,8883,10079,5421,5494,5494,9443,9237,8685,5315,5339,9198,5339,10290,9574,9294,9050,5629,8706,9922,8877,8676,9520,5326,8849,8849,8863,9637,5304,9940,8772,5267,8754,9361,9454,9704,9704,8663,8849,5326,9284,9265,9637,8652,5344,9674,8772,8936,9220,5267,5291,5506,5267,10041,8908,9220,9173,8718,5506,9198,9617,9637,8701,8986,9480,8795,8877,9642,11953,9443,9443,5506,5397,9520,5326,9046,9720,9237,9065,8812,10058,9226,5350,10041,8997,9035,5437,9991,9617,9145,9346,9188,9963,5339,9668,5315,9796,9525,9437,9480,8908,9284,9050,5331,8859,5355,9173,9801,9642,5619,9284,8917,5335,10123,9729,9247,5326,9475,8849,9443,10028,9492,5304,9099,9220,10262,8701,9300,5267,5506,5355,5494,8854,8676,8676,5331,10068,9574,8877,9109,9449,9231,9284,5506,8706,5456,11518,5315,9475,9220,11957,8859,8676,9900,5350,9502,9597,9188,8936,5331,9265,9869,5489,2,9050,9401,5359,5267,9411,8806,8902,8828,9652,9922,8871,9050,9114,9626,9626,5684,5506,10141,8676,9208,9065,5350,9612,9612,11963,9007,9841,9841,5407,9674,9426,8685,5326,8667,9083,9341,9141,9626,5367,10117,5382,9540,9046,9325,9109,5684,2,9551,8883,10147,8718,9059,9059,5634,9668,5494,8795,9300,9231,5355,8908,8812,9835,8795,9574,9059,2,9502,8806,8917,10222,9226,5335,9830,8889,8801,8801,2,8801,9791,9125,9570,9104,9104,9766,5331,5646,5355,9771,5388,9382,10101,9055,9560,11971,10228,8975,8738,8824,10107,8663,9592,5291,9597,9242,8663,5239,5331,5456,8981,10182,9791,9957,9738,9826,9247,9464,8912,5506,8993,9029,10058,5506,8908,5350,9748,8883,11978,11984,11990,9535,11997,9464,9145,8734,8818,8672,9754,9847,9109,9151,5411,8778,9525,9188,5304,9114,9945,10297,5350,5426,8713,5472,8801,5472,9254,9540,9254,5355,9626,5339,9373,5355,8997,9141,5388,8795,9895,8761,9341,5506,9046,9035,5267,9208,9664,9565,9597,8718,9188,8701,9088,9080,5670,9231,9271,9198,10123,9520,12003,9565,5350,5402,2,5331,12009,5437,8754,12015,9580,9814,9035,8877,5304,8894,5285,5506,5267,9198,9912,8877,9203,9203,9373,9046,5335,5506,8676,8676,5421,9309,5388,9104,5506,9325,5254,9729,9212,9065,8729,9242,8744,8724,9055,9145,9046,9305,10003,10107,8908,9555,9352,8997,9231,9254,9704,5397,5367,9135,9417,9738,8767,9035,9658,5248,9826,9198,8889,9592,9099,8993,8936,9771,5666,9046,5437,9305,9104,9216,10012,8801,5388,8696,8833,8889,8672,8801,9743,5421,9912,9592,9188,5321,9771,5421,9198,8696,5670,12022,9411,8889,2,9760,9709,5411,8806,8778,5359,12027,5331,5377,5248,5350,9597,10272,8908,8718,8908,5331,5506,8706,8718,5331,8784,9002,10091,5254,9791,8877,9305,9791,5254,5239,5472,5506,5411,8685,8801,5437,9674,8898,8898,5367,9280,9029,10201,9396,9709,5331,8667,9145,9065,9974,9198,8912,5675,5467,9652,9046,5411,9847,9173,9530,9979,9226,9869,9900,9617,9617,5634,5506,5344,8894,9198,8925,9574,10243,10243,9023,5411,9771,9336,9104,10159,8824,9642,12034,8812,12041,2,9709,9664,5416,8718,10206,8908,9508,5426,9129,5449,11485,9597,9963,9560,8718,9151,10101,9002,9220,9305,9830,9046,9088,9574,5321,5267,9059,8696,9814,8908,8954,8863,10107,9387,8986,5646,10101,5367,5670,9119,8806,5382,11485,9826,9443,10008,5402,5666,8993,5388,9826,8849,5239,9198,9791,9151,10141,5437,9023,9637,8680,9203,8883,5355,8877,5359,9023,9957,9715,9341,9254,9502,8663,5331,5331,9565,9715,8812,9963,9417,5407,5411,9940,5344,5350,9093,9242,9226,9220,5331,5254,12047,12055,9530,9198,9535,5431,5437,5344,9325,5331,8908,5254,10340,10123,8738,8948,8908,8908,8981,9487,9093,9881,9109,5243,9119,9289,8839,9835,8754,5402,5355,5331,5382,8824,8824,8993,8839,8778,8871,9748,8795,9826,5267,9242,8754,9709,8908,9754,9050,8824,8975,5506,11518,9791,9017,10169,8908,5344,9046,9216,9535,9193,9193,5344,10017,9341,9341,9265,8925,9309,9637,9271,5359,9284,5411,5506,5472,9417,9417,8754,8767,8986,9580,9198,10159,9664,9417,9151,5315,5344,5239,10191,5382,5651,9114,9480,12064,12072,5437,9173,5267,10058,8738,12064,12080,12086,8828,9198,10096,12093,12100,2,5382,9709,2,9738,11518,9104,8676,10301,9226,9226,9968,9203,9835,5437,5506,9135,5267,9050,9050,10028,9709,9346,8824,9065,8889,9781,9074,5388,9188,9401,8685,10196,9145,9212,9050,9830,8839,9237,5411,9237,8672,9814,5619,9738,9198,5437,8917,8997,9114,9208,9208,5431,10169,10101,9035,8824,5367,5670,9254,9443,9443,8812,8718,9074,8676,5355,5411,8676,9114,9885,8824,9986,9226,5670,9826,5355,5411,9796,5646,8812,9352,9167,9178,5363,12106,12113,10047,12122,5629,10068,5377,9520,8824,9265,5359,9417,12128,2,9141,5619,9203,5506,9709,9046,10012,9602,9059,9411,8993,5437,9417,8940,9188,8718,9119,9560,9754,5239,9668,8784,9203,9188,5411,5494,10107,9109,8889,8738,8734,9183,9754,5619,9411,5421,9198,9679,9520,10101,8696,9411,8871,5657,9820,8672,9361,8940,9216,5267,8993,8908,10201,9525,9183,8729,9530,5675,9597,9040,9694,5355,10147,9373,9017,9580,9592,8738,9631,5670,8685,9748,9525,5344,9738,12136,9145,9040,9203,5437,9674,12143,12150,10191,8801,2,5267,8908,5431,5326,5248,8738,9271,5629,5629,9928,5426,9387,11518,9679,5443,5367,9208,5449,9208,9023,9237,5506,9309,9525,10052,9173,9173,9612,9007,5339,9826,11485,5363,9059,9265,10123,5331,9382,10041,9904,9242,9574,10017,5355,9963,5624,5359,8986,9602,9178,10079,8784,9216,5350,8871,9760,5359,9771,5350,8889,5350,9247,9801,5335,5483,9145,8883,5382,8801,9560,5267,8975,9167,5437,10123,2,12155,9580,12163,8812,8898,8713,9198,9508,9674,10123,8936,5350,5426,9237,8718,10329,9626,9709,5267,9597,9040,9280,10107,5335,8663,9508,5416,8701,8696,9508,5304,9776,9242,9709,9738,9396,9520,9885,9699,8754,8871,9502,9417,8754,8784,5321,5321,10068,5326,5355,8680,8706,9738,9658,9088,8801,9806,10129,9341,8925,9555,9167,9715,8993,8696,9396,9525,9114,12169,12175,10239,9876,5355,9565,9319,5359,2,2,9754,8940,5350,5449,10068,8701,10085,8667,5267,5372,5291,9674,9443,8754,10107,9417,9674,5506,9449,8936,9050,5624,9814,5326,10206,5355,5372,9305,5388,5651,9114,11505,9129,5355,5411,9203,10041,9704,5437,9580,9766,5506,9760,9254,8970,8701,12064,9592,9502,8667,9530,8854,8948,8908,12181,10191,9401,5355,8738,9602,9658,5506,9525,5437,8667,8898,10041,9050,8908,9602,9231,9173,9346,5355,9237,9570,10222,9114,2,8948,5367,9198,9979,8738,5624,5624,8932,5359,5331,9785,5359,8965,5326,8944,5359,5411,9525,10058,9754,5331,9109,5344,5478,5431,12187,9114,2,8801,5359,9050,5331,8801,9265,5411,9080,8784,9631,9309,8824,8806,9535,2,5304,12193,9417,8877,9325,8812,5437,8667,5367,8812,8706,10085,9305,9093,5377,9417,9904,8970,9226,10123,8975,5684,10073,2,8824,8828,5331,9642,9652,10206,5321,12198,5377,5377,8801,5624,5331,9125,8902,8824,9325,12202,8738,9055,9023,8713,8824,8824,8738,8944,8685,10079,9114,8912,9796,5506,5321,5267,8685,5397,8824,9129,9059,10035,10147,5267,8859,5506,8908,9208,8912,9449,10035,10091,10035,10091,10028,9560,9002,8667,8713,5619,8824,8738,8877,5506,5675,8663,10068,5339,8944,9208,5407,9023,8685,11523,5267,8877,8685,5267,11518,5431,9114,5506,10091,8824,9545,9023,9198,5271,9055,9454,8663,8908,9454,9454,9314,9417,8738,8912,8921,8912,8921,8744,5372,5372,5331,9733,8824,5331,9173,8724,8724,8672,5437,9704,5335,5335,9188,5335,9387,9145,8652,9361,8724,10290,8685,9597,5350,9426,5321,9934,5310,5646,8784,10041,9520,5431,5506,10301,9198,8676,9426,8839,9099,5355,8676,8718,9520,8954,5472,10191,5407,5339,10290,8667,8959,9387,5326,9785,5506,9099,10058,5449,5431,10191,10058,12209,5437,5350,8944,9968,8801,8667,10041,5506,9560,5657,9216,9188,8863,9040,5326,5326,8993,5657,5355,5506,8944,5326,9968,5506,8877,8663,10017,8917,5670,5670,8859,8767,10058,8824,5388,5388,5388,9141,9141,5388,9093,8997,2,2,8936,11929,9203,9709,9406,8917,9738,9597,8898,9411,5304,9417,8917,9284,5646,9565,11929,10068,9743,9417,9104,9679,5388,9876,2,8997,5372,8824,8824,9738,9065,5437,8940,9876,5359,8917,5331,9574,9411,9480,8936,8828,9709,9587,9709,9502,8828,5684,5489,5421,9826,9720,5321,9464,8908,10262,10012,8908,9766,5304,10028,9341,10218,9260,2,9046,9135,8778,10041,8908,8667,5267,9647,9145,9617,9664,9216,10041,9664,8778,9099,5359,10041,9145,9520,9520,10135,9876,5271,5254,5248,10206,12218,5363,9729,9300,9242,9173,10101,9198,5646,10191,9357,8948,9785,5326,8959,5506,9592,5344,10028,9637,9242,8724,5267,9738,9464,5646,8908,5291,5243,8849,8738,8663,8663,9597,8672,9900,9029,5449,8912,8663,12229,2,8871,9198,8912,8738,9602,8824,8795,10041,9220,9088,8863,9294,8854,8975,5355,9688,9688,10107,8954,8744,8761,8689,5321,9847,12237,8908,9341,8685,8685,9449,5506,9781,9520,9754,9847,9050,9265,9265,9099,5367,5501,9208,9401,9083,8917,9352,5670,8940,8948,8663,5278,8652,5388,9560,9198,9743,8729,10159,10228,9373,8696,5670,9357,9814,8944,5331,9331,10073,9814,9226,9208,5335,5670,5350,9417,9642,9738,9738,9738,9065,5331,9602,5506,9280,9109,5367,8652,9198,9231,8993,9709,9050,8672,9869,8788,9417,5619,5646,5506,9203,8744,8975,9305,5326,9602,9830,5344,9114,5363,5367,8993,9294,10107,9280,8997,8672,9208,5285,9055,9242,8912,8784,9658,8754,9325,9421,9305,8908,8672,9729,9417,9626,8801,9361,5624,9443,9336,9046,8729,9720,8854,9145,5355,5248,10017,5443,9336,8806,5359,2,9305,5619,9570,9357,9220,8667,8772,5355,5506,5326,5326,9674,8754,8667,9226,5688,5437,9145,9864,8672,5355,8898,5456,9046,8932,9963,9198,8667,8663,5267,10201,8801,5449,8828,2,9617,8778,5506,10003,5624,5506,9602,8975,5339,5335,9226,8877,5619,9294,8685,10147,9869,9530,9083,9417,8898,8772,9900,5285,9597,8689,9198,9979,9023,9668,9401,9918,5310,5243,8663,5684,8696,5506,9203,9220,8738,5449,5315,8754,5421,5344,9891,12243,9129,5355,8696,9093,8839,9208,10085,9597,5339,9864,5646,9226,9704,8863,8849,9119,9464,5344,5367,5267,9305,9565,9637,9294,5506,8936,8812,5377,9284,9059,8849,5331,10141,9046,8663,5431,9346,9814,5506,8824,9574,9396,9647,5339,9203,5278,9437,5670,5372,8754,9743,5304,9135,10008,9940,10047,9309,8849,9220,8877,8970,9431,10008,5248,8877,5304,10101,9080,8784,9300,5634,9715,5407,5331,10135,8672,5624,10135,9530,10058,9396,9535,5431,9226,9781,9520,9023,9826,2,9776,5437,9247,8921,9046,10017,5456,9319,10272,9664,9545,9247,8676,9858,9781,8849,9738,8778,9065,9781,9417,10107,8986,8839,8940,5344,9040,9083,9684,5634,5239,5267,9188,8908,8993,9271,8849,8701,8871,8772,5382,9284,9480,5350,8908,8761,8912,5359,5416,9417,9530,10123,5624,9198,5382,9109,9254,8652,9141,9099,8824,9729,8824,5359,10107,9602,9220,9325,9331,8667,9679,5684,9631,8824,9431,9135,9934,9346,9918,9754,9535,8839,10041,9050,8738,8652,8818,9198,8667,9602,9830,9754,8954,11493,9109,10041,9754,9216,5355,8970,9754,12248,5359,5239,10058,2,5437,9720,9141,12256,8824,9754,9135,9135,9352,9023,8801,5437,9991,8824,5646,10101,5684,10058,9814,8889,9305,9781,9781,9826,9226,8954,9900,5619,9891,9226,5675,9748,9050,9294,9443,9602,9216,8997,8812,9050,5367,9294,8818,5456,5670,5467,8839,10012,9237,5421,9080,5243,5670,5431,8908,8908,5670,8652,9986,9226,9426,9928,8948,5326,5335,8685,5355,11523,5437,5437,9208,9814,8706,5506,8667,9709,5421,5411,8754,5494,10068,8824,5388,9720,5421,10008,9361,5248,5684,8744,12262,9771,5315,12268,8667,8871,8806,9401,9754,9035,9540,5367,8975,9017,8986,9093,9050,9346,9309,5239,9637,5421,9007,8812,12274,9237,2,5437,8685,5359,9173,5629,2,2,9570,5339,9173,8871,9754,9963,9754,5431,9188,9502,10340,9361,9216,8854,9498,9918,8696,9373,9587,9668,8889,5421,5506,9331,8734,8936,9226,5331,8981,8663,5267,8954,9580,9357,5421,8784,5506,8718,5478,9520,9382,8667,9411,8839,8784,8784,9729,8940,5421,9900,9226,8729,9114,9114,9606,9437,10073,8965,9065,9040,9284,5494,5267,5239,9826,9198,8812,9046,5411,5426,5675,5239,9530,10212,5372,5388,5315,5326,9487,8667,9525,8806,9198,9050,8970,9007,8812,9346,5359,5377,9652,2,10191,10068,8824,5478,9208,5388,9760,9198,5449,9012,9135,10290,9826,9602,5666,5359,9208,9208,5367,9093,9242,5248,9487,9007,10041,8824,9934,5355,9664,5315,8908,5267,5355,5359,5359,8806,5339,9271,10123,9178,9198,5629,9580,5331,9050,9612,5315,10123,9945,9928,8944,10212,8676,5267,9602,8871,5335,10290,8849,5431,5377,9918,5331,8738,9814,9443,5506,9007,5239,9464,10052,5624,5382,5350,9247,9247,5278,8685,9023,9391,5437,9050,9806,9492,9679,5407,9145,5449,10123,8812,9294,9597,5350,10017,8812,8877,2,2,8685,5431,9198,9226,9141,5321,5315,9570,10206,5326,5411,8663,10297,5355,8729,9173,8877,8738,8738,5267,5359,5267,9443,5501,5494,9720,9776,8784,9492,8718,8744,5506,9826,9637,9099,10068,10079,9597,9237,12281,9957,10008,8801,9876,11528,5388,5291,9093,9093,5350,9574,8936,8701,9226,8921,8921,8754,8788,8754,5426,5315,9396,9156,10107,10182,9167,8672,5350,5382,8849,9520,8696,9294,9046,9284,9065,5304,5437,5291,5267,12286,2,5377,2,8824,8701,9720,5402,10206,9637,9357,5619,8824,5331,5421,9336,9325,9007,5239,5248,9129,9426,5431,9040,8676,5666,9023,8718,9093,9007,9099,9099,5506,5372,9141,9417,8940,9449,5355,5344,5431,10085,9271,5339,9341,8921,5355,5372,5326,9114,8940,9254,5651,2,8801,9535,10191,5431,9602,5421,5350,9602,9658,8812,8812,9502,5339,8908,9141,5355,9284,9900,9674,9781,9530,8667,8667,9470,9055,9401,9220,5377,8863,8859,8936,5344,9226,10191,8993,8738,5456,12291,9391,9109,2,12297,5437,9226,8828,9642,5359,5331,5367,9145,5359,8672,5411,8812,10058,8795,5326,5619,8729,9135,9760,9093,5335,8696,5437,8936,8921,8754,8993,10191,9401,5304,5359,9449,8849,8812,5248,5331,9220,8877,8812,5372,9226,5619,9631,9284,8801,8806,9535,9470,9242,9208,9535,2,2,8812,9602,5355,5431,5437,8812,9341,8701,5506,5437,9626,9093,8724,9514,5437,5377,9242,9904,9754,5344,9814,8970,5624,5377,10123,5684,5248,8738,9280,10017,5657,9050,9284,12303,8932,9642,9652,9050,5331,9602,5291,10068,10206,5315,9093,2,9284,9125,8801,5377,5377,8902,9637,9652,9597,5304,9050,10107,9050,8824,9401,8672,8965,9979,10222,5326,8877,8877,9208,9294,9325,5402,10175,9771,8889,5619,8912,5344,5467,5467,9426,9145,8908,8744,9341,10112,8788,8954,9570,5506,5359,9017,9141,9796,8729,9050,9796,9606,8917,10079,9492,9173,10052,9300,9979,8713,9198,9979,9979,9226,9580,2,9498,5397,5271,8801,9216,9231,9046,9125,9104,9104,9325,5344,9443,9417,10068,9421,8788,9421,8854,8854,5254,9145,9574,8849,8801,8889,9040,9226,5421,5431,8912,5494,2,9208,10147,5377,9220,5315,8685,5456,8975,9864,9023,9145,8877,9382,5304,8667,8663,8772,9188,5421,9226,9574,9336,5467,9796,9294,8828,5397,8801,9443,5271,9570,9050,5326,9979,9704,5326,10201,2,9242,9957,8676,5326,2,8871,5339,11493,2,5267,9046,8788,9156,8936,9220,5344,10101,9637,9647,5382,9059,5291,9208,9814,8912,9411,9208,5267,5350,9065,9597,8894,5321,8877,5267,9050,8849,11485,8863,9826,5619,5355,8663,2,2,8849,9050,9023,9801,9417,5472,9151,9341,8701,9940,8839,9300,5267,9679,8663,9294,9417,9046,9781,5315,10123,9814,5285,8925,10196,5267,8925,8713,5344,9050,9050,5506,5321,8824,9748,9555,9141,8993,2,9361,9480,9957,2,2,2,2,9265,9065,9237,8744,9968,5397,5326,9814,5431,9443,5456,5494,5315,5437,5388,8812,8801,9226,9928,8652,5267,9991,9991,9093,9050,8788,8788,8824,5670,9560,9226,8676,8713,8925,9352,5670,9023,8685,9231,9226,9242,5646,5372,9145,9864,8801,5411,9525,9002,9475,9208,9520,5397,2,2,9688,9373,9699,8871,10079,5291,8751,9305,5494,5619,5267,8663,5267,9520,9065,9065,5267,9520,8689,10012,5291,8925,9188,9597,9602,5431,8812,8954,9411,12310,2,9580,8696,5267,5388,9760,9835,5359,5437,9319,5506,9178,9814,5372,5506,9574,5321,9835,9520,9208,5506,9198,5666,9226,9492,8849,8944,11493,8788,9007,2,10290,9785,10129,5437,5267,5267,5267,5506,8877,8912,5494,9093,8676,8738,9555,9050,5304,9508,10329,10222,5501,9135,5315,9341,8672,9492,8824,8701,9574,9957,9341,9242,9050,9597,5377,5670,8871,5506,9220,9801,2,2,8812,8824,5506,9336,5377,8854,5402,9426,5372,5267,5657,10123,5431,5326,8801,5619,9325,9226,5506,5619,9231,5326,12319,12326,5377,9900,5304,10201,9597,5339,5472,5472,9188,9065,5377,9760,9411,5331,5335,9475,10196,5359,9212,5666,9597,9869,10147,2,5331,5359,5321,9492,9050,5267,5619,8806,8676,2,9514,9626,5377,10123,5321,9574,10017,2,9156,9602,8871,5377,8801,2,9325,9785,8824,11505,12332,10297,5271,9421,8754,9754,8859,9226,2,5321,5321,9046,8676,9125,5489,8676,9188,9725,9904,8898,9580,9806,5675,9458,5489,9580,5248,9580,9074,9540,8729,9957,5437,5243,10058,9806,9069,8889,9688,5489,9119,9305,9806,5367,2,10058,9664,8754,10112,12346,10047,9771,10003,9738,8917,9396,9791,9464,8761,8997,8917,9748,8663,9050,5675,9151,8672,5437,8993,5367,5675,9361,8917,9826,8738,8975,8975,5239,9881,5267,9464,10249,8738,8663,8993,5267,5331,5331,9289,5355,9748,9198,9830,8975,9776,10058,9417,9203,5437,9814,9074,9216,9417,10201,9114,5267,9151,8828,5411,8734,9876,9226,5331,5501,9574,2,5449,12355,5331,10058,9864,9141,9934,9475,5267,5472,9226,9237,5472,8975,9242,9125,9242,5646,5355,8981,9545,9617,5411,11485,9979,8734,5367,10052,9305,5688,9664,8667,9023,11485,9520,9869,10112,9826,10041,8744,8917,9151,9141,9417,9729,9361,9421,5397,9738,9208,9325,9109,9141,9729,5666,5367,9373,9626,9417,9099,9570,8993,5304,9658,9023,10023,5315,9065,9231,5355,9597,5291,8940,9411,9319,9574,9396,10058,5397,5421,5426,5271,8824,9183,8824,5388,9464,5267,5634,5331,5397,8667,9161,9059,9151,9198,9050,9560,5331,8849,5304,9220,5243,9109,9188,9125,8908,9729,9760,8667,9535,5267,5437,9580,9940,9050,9271,9835,9602,9480,5506,9198,5271,9664,9502,8981,9387,8970,12363,9715,8828,9208,9835,5355,9226,9814,9781,9754,5456,8801,8997,9226,9754,5304,9928,9664,5416,5619,9203,5688,9688,5367,5367,5670,8889,9188,9183,9305,9668,5426,9754,5478,8734,9754,8724,8824,5421,9284,2,5506,8718,9806,9284,9007,9220,5449,8917,9247,9093,5666,5666,9284,9679,9341,5321,5388,5388,5494,8936,8701,8824,9574,9188,9492,10147,8877,12369,12374,5267,5675,5634,10058,5326,9129,5304,5619,8940,5304,9597,9658,10047,9401,9694,9502,9864,5416,9979,9319,5359,8940,5304,9602,9514,9023,5416,8828,5304,8908,5321,9443,8818,5239,5359,5359,8824,8784,8795,5646,5235,5651,5363,9125,5355,9294,9826,8975,10107,9771,8824,5355,8824,9145,8734,9029,8663,9046,8954,5411,9664,9341,9688,5443,9626,5321,9520,5321,9637,5437,5670,9099,9141,9226,9023,5304,9580,9325,8724,5506,9617,5285,9040,9046,9443,5267,9305,9055,9373,9203,9957,9570,9055,9216,9555,9361,9135,5506,9725,9203,9720,5291,8696,5388,8718,8718,5321,9280,8806,5339,5315,5437,5331,9979,5304,8772,9029,9050,9382,9145,8685,8828,8784,8801,9449,10096,9597,9475,8898,8706,9188,5397,9167,9173,5278,8685,9540,9743,2,10206,12379,8839,8954,9080,8754,5407,8663,8663,8754,8863,5670,9151,10101,5304,9545,8849,9443,9050,5646,8975,9059,5331,9382,9046,8696,8676,5267,9325,5331,5339,5431,9963,12383,2,9637,9040,10047,9709,9679,9720,8824,9417,9265,9535,8954,9361,9226,9040,9114,5344,9743,8754,9208,8908,9080,9940,9480,8908,5443,9637,5359,10123,10017,9050,8959,9151,8701,9449,9141,10297,5657,5344,9449,9280,2,8925,10058,5411,8839,8824,8997,5670,9346,9443,5407,5456,8724,9352,9720,8718,9226,10117,9023,5411,10028,5437,10175,9145,5431,8975,5397,9968,9754,8676,5416,9208,8812,8824,5494,9088,8921,8696,5421,9411,9963,9188,8954,8663,5339,5339,8812,8734,9530,8696,8871,5331,9059,9173,8718,9580,9733,5321,9231,9188,8859,10191,10008,9480,9940,10175,10123,5339,5506,9679,10123,8908,5331,8812,9963,5646,9443,5666,5431,9007,9247,8667,2,8812,9198,5359,8663,10222,12392,10129,9597,5684,10206,8701,9492,8925,8784,5494,9173,8936,9220,9242,5339,8696,5355,2,9220,8859,5388,9426,5684,5402,10206,5315,9487,10068,5326,9023,8921,5372,8652,2,8824,5339,5359,10191,9319,8954,9674,5377,5267,5355,9443,10117,9401,5629,5624,10058,5331,9198,9352,5331,9642,8925,9704,9173,5372,9212,8806,5359,5331,9642,5377,8812,9602,8706,5267,10017,9766,9642,9023,9002,9305,5489,9475,9208,9198,9934,9540,9514,5331,9918,12398,5449,8738,9242,11523,8761,9099,9437,8944,12410,12423,12435,9208,9325,5506,5285,9055,12441,5634,9480,8912,12453,10206,9502,9289,10159,5285,9688,8772,8718,12461,9055,8812,8908,5304,9178,9826,8944,9502,10175,5382,8701,10129,8663,9141,9099,9437,8812,9050,10107,8724,9135,8652,8652,8849,9480,9361,10041,9361,9093,9093,9088,9361,8784,11518,5248,10255,5359,9046,5248,5443,9814,9658,8652,5367,9203,9135,8889,9040,9046,9035,9040,5285,10101,5426,10101,8975,5239,9502,5388,8908,8696,9597,8696,9480,8917,9520,9242,9046,10141,8652,5411,5411,8975,9226,9046,8652,8917,12473,8729,5449,9918,9498,9035,8696,9830,8718,9114,8917,8917,9891,9715,5629,5388,9498,9198,11707,8908,11707,8729,12478,9242,5426,8824,8824,8917,8863,5506,8696,8824,5489,5472,5426,10206,9545,5355,9637,5449,9361,9480,9928,5624,5355,9592,8696,12484,9928,8701,5449,5449,5472,9305,5489,5489,9141,9309,9099,5350,5350,9198,5506,9806,10012,5651,5388,5411,9492,9029,5675,9771,8772,5397,5291,8685,12492,5331,9145,9265,5367,9125,5411,5321,9198,5397,9679,5388,5506,5331,9835,9806,9814,8801,9421,9141,10107,9216,9055,5619,8908,9099,8718,9280,9198,10212,9417,5355,9109,5684,9040,9203,5304,9592,5254,9729,5271,5248,9220,8975,5278,9574,5506,9796,9226,5326,9104,9145,8912,9198,10023,9664,5670,9565,9220,8877,9574,10008,9464,9141,8877,9161,8936,5331,9198,9733,9104,8663,9560,9396,9319,9023,5304,5506,5382,9247,10017,10068,9109,8734,8701,8912,5355,9040,9617,8912,5388,9151,9720,8993,9470,9080,9226,8824,9679,9664,8801,9387,9099,9135,12497,5355,8824,5688,9814,9212,9145,9135,10008,8824,9002,8954,9023,8894,9203,8667,5506,5359,9587,5321,8912,5267,10017,5506,8954,5355,9806,9540,5624,8696,8833,9319,12492,9040,9498,10262,10068,9247,9760,9135,9387,8828,5506,9835,5472,9247,9820,5478,9963,5657,8959,9178,5359,5335,5339,8667,8812,5494,9046,9492,8806,9508,8696,9396,5304,9109,9099,8667,9065,9050,9540,5304,10017,9912,10085,8824,9226,5506,5248,9141,5624,5331,5350,9099,8701,9040,8701,9535,10262,5355,8912,9145,5304,5411,5271,2,5331,9401,9535,12504,9040,5304,8812,8667,5684,5248,10068,9040,8828,9652,9652,9305,2,9173,9570,9280,10222,9280,9368,9368,9083,5388,5402,5402,8997,9684,10297,5411,5494,9173,9055,9325,9525,5335,5355,5315,5382,9525,8859,9080,9284,8849,5388,9637,5472,8738,5267,8859,8788,9284,5494,9284,9357,9679,9284,8877,8676,9570,9284,5315,8859,5456,5494,5331,9934,9065,5315,9141,10107,9421,8772,8863,5646,10182,5657,8889,8993,8863,8863,8772,8889,8993,9709,10058,9720,8908,8812,8824,9151,9231,8744,11523,9065,8812,9065,5506,9305,9637,9065,9895,9709,9050,5437,9065,8824,9237,9242,5629,9766,8729,9046,5646,9361,9766,5359,9709,9502,5331,5339,8685,5437,8729,10017,9617,5359,5350,8772,10206,9617,8993,5331,8917,8754,10107,8685,9464,9464,9198,8908,10117,8652,8706,5501,8713,5267,8729,9814,5501,9720,9668,9361,5421,9520,8948,8729,8761,8818,9099,5670,8997,10091,5304,8944,5421,9145,5271,9188,9135,9401,9498,8718,9869,9417,9135,8912,9361,5670,5335,8801,8718,8718,8948,9826,9754,5489,5506,5239,5239,10079,8889,9443,5254,9602,8806,5372,8778,9602,5489,5506,8898,9668,9443,8912,9869,5634,10003,8718,8883,9145,9050,5335,8744,9621,9231,5271,5670,8863,9957,8849,9023,9826,8754,9733,5634,9080,9637,5304,5267,9940,9535,5437,5291,8652,8839,9637,9325,5421,8925,9864,12511,9220,5271,5331,9535,5372,5634,10135,5372,10058,5388,5388,8917,8839,9729,5359,5506,5411,8981,8772,8824,8839,8734,5397,5456,5267,9487,8981,9346,5437,5670,10058,5688,9443,5407,9237,9525,9088,10003,8685,9280,8954,8818,5472,9237,9602,9437,9012,10206,9265,9216,5478,5397,8925,8997,9668,9007,10135,9357,9247,5506,8959,8944,5335,9885,10123,9178,8912,9007,9934,8754,5355,9502,2,9776,10262,5267,9508,8936,8801,10222,9135,9885,9492,9156,5304,10091,8676,8685,9574,10003,8701,9237,5304,8676,8859,5326,9709,5437,8993,9231,5684,9226,5472,9587,9658,9597,9188,9401,9502,8948,10191,8948,5331,9869,5321,9443,8948,9401,5359,9502,8806,10017,9007,5267,9114,8871,10091,8801,8997,5339,8701,8824,10147,9891,5321,5421,5506,9135,9198,5688,9135,8812,9417,8772,5315,9733,9968,8859,5315,10129,9401,9368,5421,5651,8908,5355,5239,10107,8663,9738,8894,9580,5267,9242,9869,10206,8734,9560,9099,5321,5331,9046,9720,8680,9401,10052,9198,8908,10091,5411,9341,9080,9664,9141,9704,9050,5372,10175,9156,5501,8729,9050,2,9814,9280,5335,8889,5684,8824,8828,9738,9738,9826,9820,8718,8859,9109,8917,8801,5331,9688,9551,5285,5382,9325,9421,5363,9570,9305,9570,9135,10228,8680,5331,8806,9574,2,5331,12516,9114,10249,8975,8801,9869,9401,9080,5416,9203,5359,9226,8859,8828,10096,5456,9050,9574,5382,5267,2,9294,10147,5397,9508,2,9226,9508,2,10249,8877,5657,9093,9059,9294,8824,8877,5397,9464,8806,12525,9156,9156,9080,8696,8812,9464,5657,9050,9560,9940,8824,2,12531,5359,9265,5437,12492,9254,5344,10249,5382,9050,10159,9858,9841,8908,9835,10041,8701,8863,9305,5651,9720,8959,5437,9065,5359,8859,5372,5657,9325,9151,8667,9470,8663,8908,9331,9637,9040,9748,9743,8908,9265,10117,9050,5489,5651,10058,9738,5411,8812,9688,9216,5388,9226,10147,8718,9968,5397,10206,5407,5416,5382,5437,9826,10068,9592,12537,8908,2,9814,9443,5657,5657,8734,9029,9431,8784,9080,9055,8696,8672,8871,9119,5426,9141,9226,10243,5624,9733,8718,5397,8908,5431,8729,9226,9520,9470,9704,9216,9212,2,10041,9487,10175,9093,8908,5666,5382,5359,5359,10091,9580,9265,8667,5624,9760,8908,5335,8908,9679,9835,10041,9545,2,5355,5291,9396,5684,10129,10222,5437,5267,8701,5651,9040,5494,8729,10228,9508,9826,5331,12256,5315,2,9247,9508,5501,5304,8824,10159,9065,9401,9820,5624,9216,9114,5355,5657,10206,5506,5449,9141,9141,8824,10047,8908,8859,9796,5437,8824,10117,9502,9421,9055,2,2,8965,10239,5304,9869,5624,5624,9198,5331,5331,9242,5657,9421,8812,5331,8806,8806,5335,9305,9904,10017,5377,9642,9050,5421,5421,5331,9997,8970,9626,8672,8908,8940,8734,5619,5304,5304,9198,8908,9198,5443,9470,8744,2,5506,5421,5367,9198,8883,9046,9046,9602,9725,9198,9161,5670,8767,5684,9208,8801,9135,5372,9055,8833,9602,5359,8824,8706,8663,8883,9934,8801,9173,5397,9198,5355,9525,8718,9525,10135,5339,9265,5629,9940,9826,9766,9401,9530,8908,8993,10017,9674,9325,5359,5254,5339,9766,9198,5359,5291,9151,9704,5326,5367,5267,8667,5239,9401,8718,9046,9754,8663,5304,9145,5407,5506,5670,8672,9826,2,5344,8718,5248,5355,9525,8871,8672,8734,8940,2,9443,8908,8824,5267,5355,8672,9093,10068,9129,5372,5331,10085,9729,9766,5331,9514,9626,5407,9642,5624,9352,8824,8824,8912,5619,9449,9065,10008,9382,8672,9791,10008,5239,9592,10107,5506,5304,5254,9431,5646,5646,5278,9341,9284,9520,9216,8818,9198,10141,5388,9198,8824,9602,8894,9540,9141,9729,5331,5367,9725,9141,9125,9325,5335,8754,9431,9449,9145,8767,9198,9198,5350,9417,5239,9401,5355,8754,9574,9198,9401,9065,8667,5239,9198,5411,9791,10058,5506,8801,5326,10085,9046,5267,10201,9059,9046,9357,10135,5359,9940,10107,10141,5407,8754,10008,9957,10135,9664,9331,5359,8993,8767,9791,10340,9119,9368,5355,9198,9198,9940,10169,5382,9216,5254,5472,9725,8824,8784,11707,2,5506,5267,9688,5355,9046,5388,8680,5411,8744,9835,8685,8754,9766,8954,5431,5239,8824,5355,8685,8718,9198,9766,9203,5355,9525,9525,8993,9411,5372,5367,5355,10052,8917,5291,9801,9198,5355,5359,8784,5355,8812,8954,5646,8921,2,5506,5494,9083,5355,5372,8877,8936,5315,5344,9574,9406,5359,5372,10085,8921,5326,9514,8680,8824,10191,5355,9699,8954,8754,9401,9029,5359,9760,2,9514,5344,5331,9642,9336,9918,9771,8925,5267,8925,9858,8824,11518,9220,9188,10028,10340,10008,9396,9083,9820,9188,9688,9475,9188,5254,9918,8801,5315,9508,8959,8663,9173,9188,9198,9806,9188,8883,5315,9806,8788,8877,8754,9012,9785,9781,9099,8894,9216,10159,8685,8784,10017,9237,9565,2,8667,9781,9918,9664,8824,9417,8925,9188,9188,8883,10079,8824,8652,8959,9417,9492,5267,8663,9237,9806,9231,2,10035,8806,8754,9679,9934,5402,9785,9508,8925,9565,5402,8806,9083,5331,9114,5421,10301,8738,9114,9294,8908,8738,9029,5421,5350,8818,9417,9709,8801,9325,8806,5254,9220,9220,9247,5506,8672,8863,9294,9574,9254,9220,8959,5506,5350,9220,5684,5411,5285,9968,9957,10175,9841,10222,9679,9631,9220,10091,9220,8801,8801,5363,5382,8824,8912,10107,9464,8801,12543,10058,5355,8877,9125,9161,5355,8718,9231,9183,9664,10159,9754,9208,9748,8877,9715,9141,5388,5437,5506,8778,5291,9361,5397,9826,8801,9378,8912,8993,5331,9083,9720,9475,8883,8672,9046,9891,9830,9743,9498,5239,9826,9325,9357,9551,9046,9373,9242,9203,5675,9242,5421,8997,9570,12551,5437,8925,8806,12556,9688,8828,9173,5684,8912,8667,9188,5304,5388,8925,9002,10222,5315,5339,8975,9183,9900,9280,9869,8801,9574,5355,9498,5456,9891,8744,9012,9535,5388,9922,10206,5271,9891,9046,9520,10008,10297,5331,9059,9417,10017,5437,8849,9574,5397,9198,8754,9161,5421,8801,8767,8877,9957,10101,9891,9050,9525,9129,10107,5472,12563,9748,9520,1582,8738,8877,5437,8936,9535,9193,5388,5388,5388,5675,8912,9912,8824,5437,9231,8993,8912,5271,9220,9560,8772,5359,9305,5355,8701,9161,8863,9046,8889,8993,9858,8738,8975,8863,9017,10017,9754,9891,9417,9305,9357,9083,9738,8828,9099,8877,10196,5437,9443,9688,9183,8706,5304,5285,8718,9361,9208,5421,8801,9626,9346,5359,8663,8778,8877,5355,5411,5494,5456,5670,9242,9017,10175,9074,9814,8801,9294,9083,5688,5646,8818,8738,2,9237,12569,9178,9520,9065,8871,9626,5472,9525,9109,10196,5271,9373,9309,8738,8877,9785,9029,9606,10058,5331,5388,5344,9114,9922,8912,8801,9580,8806,5377,5437,9454,5331,5326,5388,9826,10123,9050,5382,11518,10175,5243,9934,9565,8824,8965,10175,9357,5267,9271,5506,9208,9093,9012,9387,5285,5472,5355,9173,8784,9178,8889,5359,9431,9963,9785,12574,9963,5363,9968,12582,8877,9305,9602,8672,10206,9492,9099,9040,9046,5437,9720,9237,8724,9508,10222,5494,9183,9396,9642,8877,10058,5421,9642,2,5243,12588,5243,10107,9417,10058,5359,9050,9305,10206,9406,9216,8806,8738,5431,9305,8772,9535,2,5377,9237,8824,9626,9284,8718,8854,5407,9602,5472,5355,2,12588,10212,10175,8772,9242,5478,8772,12594,5344,10212,5359,5359,5437,9738,8812,8824,9535,8806,12600,5431,5377,8738,9626,8744,5684,5431,9688,9968,10153,5331,8672,8828,8812,9626,5344,8685,9602,9826,9242,9135,9704,9135,9551,5619,5624,5304,5239,9729,10182,2,8738,12609,5388,9540,8663,9560,10052,9352,9341,5388,9679,2,5331,8912,12615,12625,9125,5331,10107,9417,9570,5335,9387,9431,8772,5331,8784,8883,5331,8908,8784,9294,9574,5239,9891,9626,8772,8701,11485,9368,2,9341,5355,2,12629,8986,5304,9046,8986,9426,10141,5331,9626,5359,9417,8908,9679,9368,9247,8701,9835,9220,9271,12637,9876,9876,8871,9688,9352,8948,5688,8685,9835,9208,5437,9642,9055,5331,5619,9046,9729,9151,8993,9382,9525,8871,5646,12629,9612,11485,8871,9602,9876,9341,5402,10052,5449,5335,9876,9876,8680,5267,8986,5449,9129,9305,9023,2,9835,5304,8680,9928,9309,5331,8767,9826,9309,8883,5377,9602,5315,9771,5267,9029,5271,9771,5367,5355,9592,8772,9597,9626,9294,8824,9065,9637,9791,8954,8954,5646,9378,5239,9069,10112,10301,5411,5350,9346,9141,8667,9560,9294,9198,5355,9341,9520,9791,9099,5339,8784,8761,9963,9679,9771,8889,12644,5339,9046,9198,9055,5239,5472,9294,8889,5624,5267,9046,5619,9135,9151,8801,5684,9325,8801,9957,10107,9145,9046,9738,8718,8724,5344,5421,8744,5304,9725,8788,9540,9417,5335,5350,9674,12650,9220,9791,9167,5619,5411,8801,5472,9002,9368,5321,9869,9208,9055,10141,10141,9530,5619,8894,5315,8975,5629,8828,9443,5254,5304,9046,12656,9574,9411,8883,8667,5624,5619,8975,8685,9331,5489,9574,8672,5449,8706,5326,5321,9198,5437,5634,8912,8948,8718,5359,8754,5646,5350,9119,9574,8877,9637,9449,10141,9382,5407,9382,5619,9294,5267,9046,10101,5372,9470,9940,9046,9220,9208,9198,9050,8788,9814,5355,12661,12666,9835,8701,9104,5331,5359,8986,5472,8975,9957,8908,8908,10340,8908,9637,8738,5304,9319,9226,8908,9530,9637,9748,8795,5443,10159,8981,9271,9679,9331,8696,8908,9709,9151,9545,9325,8948,8908,9083,10068,9835,9487,9193,5506,5239,5456,8986,5339,9109,9088,9720,8824,9835,9242,5359,8685,12672,9247,12679,8685,8706,5437,9216,5304,10117,8948,8908,9968,8744,9826,9720,8818,9754,5619,9475,8672,5646,9688,9023,10141,10123,8948,9226,9046,9226,8824,9373,8818,5619,5431,9835,9688,9520,8667,5407,9002,9198,9520,8754,9093,8724,5397,9754,9835,8685,12687,12693,10141,11518,8812,5339,5506,10159,9729,9119,8993,8729,8772,5437,9733,8975,9904,9520,5397,10255,5267,9411,9530,9046,9520,8718,9525,9900,9208,5467,10212,5304,8784,8718,9835,9530,12701,8981,5388,9814,9387,5331,9963,8667,5267,9835,5624,10175,8738,9007,9198,5359,5335,9934,5431,9602,9443,9835,5355,5291,5372,9242,10255,5443,5506,9587,10003,8772,9580,8839,12707,5267,12712,9382,9555,9443,5326,9508,10129,8767,9198,5291,9876,8701,8824,9242,9492,9545,10329,5437,8844,9093,9088,9382,5326,5426,10153,5267,9580,12718,9498,9361,5326,5267,8921,5437,5449,9023,5402,10123,5411,5315,9305,9093,5506,5416,5372,5506,9922,8685,5355,10191,8738,5377,8936,9597,10153,8908,5382,5331,5335,5624,5619,10153,9869,5367,8685,5624,5304,9093,9012,5359,9093,8812,8981,8706,5304,9674,10153,8828,5267,9766,5377,5624,5431,8672,9771,8824,9294,8772,5304,9065,9626,5355,9637,9869,5355,9791,9226,9520,9294,9346,9141,9560,9748,9378,9791,9835,9331,9341,9198,8954,8761,8801,8667,10112,5350,5304,10107,5619,9046,5431,9725,9135,5267,9198,8744,8772,9540,9046,5344,9957,5506,9220,8724,9119,9411,5411,8894,8844,5489,9167,5326,12656,9443,5449,8828,5321,5315,9574,10141,8877,5634,9382,5267,5372,9530,5355,5407,5355,8685,9325,2,8685,8908,9109,9545,9247,9487,9361,9226,8948,9319,5443,5472,9530,8696,8975,9835,9709,9637,5359,10159,5239,9216,8706,5437,8948,5377,5407,8818,8908,9520,5326,8672,9104,9968,9688,5304,9373,10159,9023,9826,5359,9688,9720,9754,5339,9046,9900,8718,9814,10255,9525,9093,5331,5506,5437,10191,9934,9007,5624,8812,9963,10003,9587,5619,9492,5291,10129,5449,8738,5402,9023,5315,10153,10301,5619,9748,10301,5657,10301,12722,9305,5285,5688,2,9748,8812,8812,10041,5397,10017,10329,10068,9480,8908,9437,8812,5624,10068,5359,10017,8795,8795,9748,8795,8849,2,8828,9046,9602,9280,8993,8801,9417,8997,8993,9720,9748,9125,9002,5407,5634,9046,8701,9050,9231,9674,9002,5344,8824,9198,9617,9280,9035,5350,8672,9141,8734,8696,9125,9280,5331,10079,9226,5388,5355,10129,9574,8696,5355,5634,9602,9231,8828,9141,5355,5355,9652,9145,8965,9580,8940,5670,9145,5367,5367,9341,9125,9525,9145,8993,9580,9458,9525,9325,5506,8801,9826,9382,8738,5506,5304,9411,9945,9945,8738,9023,9674,5304,5506,12731,9580,5304,8824,10141,5411,8871,9754,5267,9242,5291,9341,5291,5431,5624,10141,9694,9580,9093,8824,9029,5506,5278,9437,9341,9294,8912,8912,9679,9046,5397,11523,5506,9212,5506,9141,9325,8696,9198,5684,5267,5619,8706,5267,5267,8908,9508,5326,5326,8877,8921,9294,5449,9826,9679,9109,9530,9560,8912,8801,5437,9443,5421,9074,9835,9637,5326,5688,9065,9065,8849,5666,9934,5506,5431,5684,2,8701,11523,9508,5666,9242,5506,5326,9443,9766,9188,9396,2,10201,8997,9704,8908,9373,9373,9373,5489,5489,8898,11612,10117,8898,10012,10175,5624,10101,5239,10141,10079,9284,9520,10297,9141,8912,8672,9114,9203,9417,9065,9114,9396,9331,5355,8871,8944,9178,9694,9373,9606,9357,9178,5355,9396,9401,5367,5335,9631,8898,9704,10101,8676,9498,9254,9449,9520,8912,9099,9099,9294,10141,9198,2,9309,9099,8718,9156,9325,5271,5367,9918,9492,8806,9198,9658,8883,8898,9664,5489,9002,2,5431,9284,9361,9864,10047,9220,9417,5388,9826,9271,8954,8685,5285,10123,12741,2,10101,8824,10123,9237,12750,9237,10123,5431,9437,9237,5431,5431,10123,5666,9361,9254,10101,9237,9309,9198,9099,9658,9083,5355,10101,10101,8806,8824,8824,9231,8672,8784,5506,8784,8672,9231,9231,9352,5506,5363,5355,5646,10096,9612,5675,9826,9023,5494,5506,9791,8877,9900,8772,9754,10058,9748,9411,10107,9592,9781,9480,8993,9198,8849,9046,9109,9341,9743,9606,5437,8761,10340,5367,9378,9847,10096,9555,9029,8824,8954,9188,5339,9141,8738,5267,5267,9109,10096,9220,8854,9135,8744,9247,5619,9135,9226,8772,5489,9099,9109,9125,9305,5684,8652,9151,9002,8854,5239,8894,9198,9729,5285,5239,9046,9606,8718,5304,8767,9743,9203,9361,9198,9475,8917,5684,9208,9216,5506,8667,8685,9145,8806,8778,10320,5359,9220,9551,9050,9606,8658,5506,9979,5629,5675,8778,9198,8877,8689,8689,8898,9080,5456,9074,10062,5239,9173,746,12761,2511,3088,12765,3439,12770,2780,12775,12780,12785,12791,3422,2804,2825,3281,12796,12801,2528,2639,3165,12807,2663,2278,3108,3132,2849,3190,12812,3154,2983,12817,3210,2584,2931,2955,40,596,2504,12823,1761,12827,3432,12831,2773,12835,12839,12843,12848,1711,2797,324,3272,12852,12856,2525,2632,3095,12861,2656,2678,3101,3123,2842,3183,12865,347,2976,12869,3203,2577,2928,2946,24,590,12874,429,12879,825,12883,776,945,773,12887,11241,12891,12896,802,806,958,779,928,932,12901,812,792,789,12906,799,961,1017,1411,899,782,12910,828,809,1617,12914,888,818,815,821,749,12919,4089,3568,12923,3581,12928,12933,12937,12942,12947,12953,4029,12958,3617,4043,12962,12967,3817,4011,12973,12977,3857,3920,12982,12986,3715,12991,12995,3967,3669,13000,13006,3755,3795,13010,64,593,2501,13015,3081,13019,3429,13023,2770,13027,13031,13035,13040,2716,2794,2818,3268,13044,13048,2522,2629,3158,13053,2653,2674,3098,3119,2839,3180,13057,653,2973,13061,3200,2574,2925,2942,52,1057,13066,2515,10817,3092,10462,3446,13071,2787,13075,13079,13083,13088,13092,2737,2811,2832,1278,13097,13101,1383,2646,3169,13106,1282,327,3112,3141,2856,3197,13110,1275,1268,13114,3217,2591,1357,2964,32,410,13119,1704,13124,482,13128,3443,13132,2784,13136,13140,13144,13149,13154,13158,3426,2808,2829,3286,13163,13167,2532,2643,432,13172,2667,2283,464,3137,2853,3194,452,1750,2987,13176,13181,3214,13187,2588,2935,2960,106,13191,0,0,0,13202,13202,13202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,13202,13202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13208,13208,5735,5735,4352,4352,5100,5100,6651,6651,6657,6657,13215,13215,13221,13221,5856,5856,6667,6667,653,653,6667,6667,13229,13229,13236,13236,6667,6667,1714,1714,0,0,13244,13244,13244,13244,13244,13244,13249,13249,13259,13259,13269,13269,13276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13288,13288,13292,13292,13297,13297,6503,6503,13302,13302,2829,2829,3621,3621,13307,13307,13312,13312,13317,13317,4206,4206,3925,3925,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13322,13322,13322,13322,13322,13322,13322,13322,168,179,184,13330,193,168,179,184,13330,193,168,179,184,13337,193,605,605,605,13347,249,249,249,249,13353,13362,13362,13369,13369,13369,13369,13383,13383,13388,13388,13391,13391,13400,13400,13400,13400,4993,4993,743,743,1403,1403,881,881,5172,5172,5172,5172,1468,1468,28,28,44,44,44,44,44,44,13410,13410,46,46,52,52,52,52,749,749,54,54,54,54,54,54,56,56,56,56,58,58,13417,13417,66,66,13421,13421,13424,13424,13435,13435,13435,13435,13441,13441,5264,5264,4946,4946,13446,13446,13450,13453,13457,13461,13465,13417,4993,13469,13473,5092,5092,5092,5092,5092,5092,5092,46,46,5092,5092,5092,5092,5092,5092,13476,13487,13493,13500,13500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,54,48,40,48,24,40,13509,64,32,52,13518,1268,1271,3217,4185,848,2856,3317,3197,13526,3656,4064,2492,13530,2832,1278,3169,13097,1357,3446,3348,2787,13071,2591,2646,1383,13535,1282,2515,24,40,64,32,749,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,809,884,888,895,899,785,782,821,779,928,789,815,776,941,773,818,1118,4552,1122,825,1411,1017,24,828,792,812,961,799,429,24,40,64,32,52,479,2863,806,1033,746,825,828,906,910,915,924,13539,13549,5026,13559,792,792,836,0,0,0,0,0,0,0,0,0,0,0,0,848,857,24,743,40,865,64,868,58,647,46,1030,32,746,878,52,749,881,809,884,888,891,895,899,785,782,902,821,906,910,915,919,924,779,928,789,932,815,776,941,773,945,818,828,792,812,958,961,965,799,429,949,13569,743,40,865,64,868,58,647,46,1030,32,746,878,52,749,881,984,0,0,0,0,0,0,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,10,12,14,16,18,20,22,809,884,888,895,799,961,1017,821,779,13575,815,776,941,818,789,773,792,828,812,825,928,429,958,899,24,109,40,749,0,0,0,0,0,0,0,0,3723,13579,809,888,895,779,789,815,776,773,818,899,782,821,799,792,812,828,825,429,12887,12914,12906,13584,24,40,64,32,878,52,881,1764,13589,106,50,58,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,40,64,32,878,52,809,884,888,891,13592,895,785,13597,782,902,13602,13607,13611,779,928,789,932,13616,815,915,776,13620,941,773,945,13624,818,1046,828,792,812,958,965,799,429,743,40,865,1465,64,109,52,878,881,1392,828,792,812,825,0,0,0,0,0,0,0,0,0,4602,4602,4602,4602,4602,4602,4602,4602,4602,4602,4602,4602,4602,4602,0,0,0,6,8,10,12,14,16,18,20,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8754,8883,9198,9679,5670,5619,9679,5619,5335,9621,5355,13628,2,9129,8932,9458,8908,5416,9602,10085,9652,9637,9305,8954,10017,5646,5315,9220,9352,9167,9733,9864,5291,10101,5670,9346,9135,5619,9684,9674,9387,9382,8713,9738,9421,8754,9260,9046,9565,9738,5483,13640,9141,8993,9002,5331,5431,9247,9679,5411,8986,8772,9141,9760,9331,9074,9271,9237,9017,9099,8652,9260,9220,5411,9212,5506,9617,9791,9135,9545,9046,9046,9417,9109,9580,9637,8778,9141,9271,9835,5651,8663,5670,10117,10175,9198,9986,9002,8944,9826,9617,5456,5416,8824,10028,9035,9520,8744,9352,9080,9406,10008,9188,5437,9226,5315,8824,9203,9968,5388,9480,9046,5304,9729,8948,9918,10212,9699,9119,8738,5359,9918,5478,8871,8784,10159,5675,5506,9305,9492,5355,9141,5619,9525,5359,10191,8944,9480,5359,9271,9606,9950,9934,5449,9046,8871,5335,5267,10175,5359,5315,8812,5359,9198,12163,9346,5431,9574,5382,9729,8889,9492,9679,9173,8877,10212,9242,9198,5315,5291,8663,9679,9776,8706,5372,9341,8812,10068,11505,9099,9129,10085,9300,5431,5388,5248,5321,9114,5506,5634,9212,5431,9587,9300,8993,8908,9679,10191,9597,9900,9401,9458,5304,9760,5456,10035,9212,9050,5359,9401,9458,8828,5684,9458,9652,9729,9458,9265,8738,9781,9979,9458,8701,9979,5239,5315,9309,5472,5355,9525,5472,8948,9309,9198,9198,5675,5437,5489,9198,9382,8854,8718,9771,5304,8824,9592,9188,8824,5278,5267,5267,9771,8824,8824,5456,9417,9771,8713,8970,8970,13645,9771,5421,10068,5350,5421,8652,9099,8936,8936,10017,5426,10068,10028,9885,5397,8663,8772,9766,9748,5291,5506,2,10297,8854,9242,9540,10028,9847,8761,9540,5657,13653,8744,5437,10073,9325,8801,9357,9104,9305,5304,5675,10028,9203,5359,9294,9606,5267,2,9046,5402,9814,5331,9957,8824,9059,10101,2,9226,9305,9502,9431,9417,5494,9319,9835,9688,8997,5489,2,9119,9592,5506,9587,10073,9612,9178,8724,13661,9188,9574,13667,10206,10068,5359,5506,5411,5437,9401,9502,8908,5359,5359,9093,9904,9974,8986,5437,5437,8921,9050,9046,5285,9050,9050,9612,9612,5506,5363,10101,5646,8859,10012,8883,5315,5411,5382,9637,5506,8833,8948,8965,10107,8738,8824,8824,10147,8925,10008,5397,8908,9464,5239,5326,5372,9198,8706,5388,9046,9300,9226,8663,9198,8908,5291,8954,8738,9791,10301,9012,5411,5359,8685,5355,9449,8908,9754,9341,9125,9088,8713,5355,5426,5426,8761,8663,5321,9373,9198,9520,9449,5666,9114,8997,9664,9109,9997,9847,10123,8667,5367,9688,5506,13675,9226,5331,9141,9080,5304,9480,10073,9502,8784,5506,9754,9555,9325,8854,8883,9826,8818,8925,5331,5248,9216,8917,9743,9475,9373,9720,5506,5506,9417,9141,10196,8894,8801,9729,9305,5254,5291,5646,9188,5304,9830,9294,8812,8889,8778,9417,5489,9309,10107,9208,5285,5670,9046,9361,8993,5388,9226,9046,5344,8997,9242,9083,8997,8997,9125,5239,5335,5239,9826,8912,5355,9220,8806,2,5483,2,9336,8812,8925,5675,9668,5331,9411,8667,9974,8738,8833,9265,8824,9382,5239,9864,8663,5355,9237,9891,5278,9055,9373,9979,9464,8912,5315,5315,9046,8824,8801,5239,5449,5326,8667,9592,9280,9411,9900,5278,9464,9574,8744,2,8801,9597,9023,8658,8975,5629,9498,9220,5456,8975,9612,9220,8898,9617,9319,8912,9791,5437,5407,5494,5285,5331,5339,9396,5350,11485,9498,9203,8844,5388,9357,9508,5326,8908,10206,2,9411,8839,8812,8828,8812,9597,5339,9183,8667,9621,9294,8772,9188,10058,9226,9114,9565,9046,9791,8667,9065,5388,9454,9520,9826,10008,5372,5372,8754,9265,8663,5462,5267,10141,5331,9046,8801,5335,5331,11485,5355,9104,5646,9560,9963,9265,9814,9417,5670,9502,5456,9220,9156,8713,8863,9050,10101,8959,9733,9637,8849,5367,9733,9203,8795,5367,10112,9957,5304,9059,9046,9080,5335,8954,5411,9035,8917,10091,9535,5431,5421,9781,13681,5431,9401,5367,8812,8812,13688,9346,9464,9464,9055,9637,9220,9826,5684,8778,5437,9193,8993,9212,5359,9417,9226,8863,9309,9940,9065,8936,5239,9525,9271,9046,9331,9480,5472,9254,9017,9709,9801,8981,9125,5331,10008,9305,8849,9475,9449,5634,5267,9449,9826,5411,8936,10206,5339,9231,8854,10141,5426,8993,9325,9109,5339,9617,8795,5443,8772,9050,9417,5437,8701,10068,5350,8652,9766,9208,8908,9065,9679,9530,9346,9151,9480,9023,9109,9535,8908,9502,5285,9226,9099,9560,9023,9050,5506,8883,8908,9637,9891,10012,13693,9738,9771,10267,8828,2,2,9502,2,13705,2,8812,8812,8812,8877,8932,5646,9216,8706,9637,8824,8824,9046,5431,9443,9754,9035,9357,9781,9346,8877,8824,9074,8997,9617,9080,8828,8812,9401,9002,5449,8948,8767,8767,9417,9475,9352,5267,5619,9617,5684,5437,9046,5359,9220,11523,9814,9294,9294,5688,9050,10008,8801,5239,8706,9135,5675,5411,9220,9602,5494,9135,8936,5629,8778,8772,8738,9226,9305,9226,10297,5355,9208,9458,9203,9968,9188,8863,10123,8975,9226,5304,9237,10101,8839,5267,5421,8908,5377,9835,9188,9754,5670,9520,5350,9826,10175,10017,12629,9336,9093,9796,9237,2,5449,9178,9226,5243,2,5478,8667,5421,9346,5421,9520,8718,9059,9551,9502,9065,5657,9161,9754,5331,9417,5267,9606,9114,8685,10008,8696,9781,8718,8738,9725,9570,9733,9754,9114,8824,9129,8729,8936,8936,9378,10147,5267,9341,9520,5271,5437,5355,10196,10073,10165,9602,9284,9183,8718,9668,5478,8685,8696,5267,8993,9059,9411,9437,5629,9733,5421,8871,8828,9900,9963,5304,9151,9188,9173,5388,9835,9487,10228,9382,9891,9647,5377,2,5355,5331,9426,9059,8824,2,8812,5335,8959,8883,8997,9574,8801,5382,9617,5431,10123,5267,5285,5646,5339,9346,5411,9226,9699,9612,8824,5506,5355,9492,5388,5359,8784,9454,9247,8828,5449,9007,9050,9325,5355,9934,9487,8849,9826,8784,5359,8970,10290,9826,8965,9597,9007,9305,9826,9733,9704,11518,9443,9226,9208,5666,9602,9178,9387,8744,8981,9570,5449,9602,10123,5483,5326,8863,8667,5437,9050,5350,8667,9237,9265,9208,9560,9012,8738,8734,9458,13711,9580,9565,5431,8701,9012,8859,5388,5331,9226,5355,9597,9361,9242,9502,8944,9093,9040,9597,5315,9088,9088,5624,8824,9508,9114,5426,5437,9621,9520,9475,5367,5684,5359,8844,5326,9080,10212,9109,5321,9674,9280,9900,9341,9237,9885,9088,9664,8685,9046,5321,10206,8663,9574,8672,8877,5267,8806,9520,2,8908,5437,9520,9183,9325,8824,5397,5248,5355,9294,8672,10085,5624,9443,9520,8824,5267,9284,9305,9284,8859,9226,5326,9226,5355,9055,8706,9652,8965,5506,10169,5449,9426,9135,9580,5431,9216,9754,9498,5407,8871,5619,5388,9709,9183,5431,9242,5651,5411,8993,5619,5350,5437,10201,9294,8932,8713,9597,9188,13719,5478,5350,9597,9470,10047,9226,10062,5472,9621,9900,9934,8854,8908,5402,9265,8718,8898,9729,8812,9525,10123,8877,8908,9280,5437,8685,9237,5411,9688,8959,9602,5377,5339,10073,8818,8925,9083,5304,2,8944,5304,8784,5359,5506,8685,5619,5331,5506,9212,5624,8877,9826,9198,9151,10212,9188,5335,9023,9934,9242,5478,10068,9699,8925,9508,9226,8696,5326,2,9525,9520,2,5331,5350,9114,8859,8701,5402,9443,9265,9535,9401,9738,8663,9088,9088,8908,9167,5359,8784,9699,9464,9520,10047,8824,9597,5355,8788,5304,5335,13724,8784,8788,2,9309,9305,9514,5506,5304,8824,9417,5431,5431,8667,9580,8812,8806,9574,9226,9626,9325,5684,9188,9242,9602,5377,9237,5377,5355,10206,12113,5624,5624,5426,9814,9198,9226,9237,9709,9631,5331,5355,9602,5624,9631,8828,5355,9237,5359,5437,9876,2,5624,8975,8877,5506,9652,9801,5462,9208,9208,5359,12492,5359,8672,8877,8738,9114,9208,8685,9733,9046,8685,8685,5359,9208,8824,9284,5315,9417,9271,9475,9050,9709,9709,9237,9540,5267,5350,5278,5646,8959,5355,5646,8754,5421,2,9826,9704,8970,8824,10107,5239,9294,5326,9502,5675,5372,5397,8833,5421,5506,8734,8706,8761,9080,10297,8912,8738,8954,8954,9088,9119,5388,9626,9626,8863,8908,9555,8667,8908,8652,9754,5321,5326,9449,8908,8744,9664,9055,8917,8795,9341,9341,9847,9029,5402,9046,9555,5411,9046,8912,9565,9934,5304,9729,9881,5646,5367,8889,5285,8912,5367,9065,8849,9417,5331,9046,9555,8889,9373,9141,9305,5304,8801,8959,5462,5254,8993,9555,5684,8970,10267,9325,8993,9099,8993,8812,5331,8754,5684,10003,5675,9055,5326,5326,9464,9046,9145,9918,9864,8801,5506,5304,9391,5315,5331,5506,5285,5355,5231,8970,5506,8795,5335,8925,9083,9173,9029,9198,9007,13730,9198,9203,8844,8672,8908,5456,9864,5646,9957,5248,9203,10135,9156,9368,9080,8849,5350,9443,9814,9135,8718,9046,5304,9704,8663,9046,5331,9059,5388,9114,9754,5367,5411,9099,9050,10101,9040,10135,5326,9002,9198,9254,9109,9417,9602,8908,8908,8824,8863,8889,9502,9580,8672,5267,9331,5331,5489,8883,9530,9940,10107,8849,8824,9119,9109,9141,9226,5501,5506,9754,8784,8975,8738,9088,9729,10041,9226,8986,9271,9637,8778,9080,9540,9826,8795,9426,9145,8812,9271,9093,2,9212,9216,5355,9065,10101,9621,8685,8948,8824,5411,5421,9443,5494,9050,9688,9352,9226,9046,9754,5670,9226,9046,10117,5619,5367,5646,8997,5397,8812,5421,5278,8871,8801,9835,5407,9046,9754,5326,9502,9212,10058,9208,5646,5489,5331,9002,9520,9417,9035,9178,9945,9411,8812,5449,2,9059,9606,8672,5267,9055,5267,9754,9437,5431,5478,9540,9411,9411,5355,8663,5646,8849,9449,5506,5388,5426,8871,5506,10058,10012,9065,9208,5326,8734,9668,5506,8954,8812,10212,8824,10073,11703,13730,9007,2,10290,9704,9612,8912,9826,5666,5359,9226,9198,8871,9265,9934,5684,9141,8824,5437,8828,9178,9449,8744,8667,5449,10255,8954,5315,9637,9198,9704,8734,8734,9271,8696,8997,5267,10123,5331,9007,8877,13735,9247,9464,8706,5335,9674,8672,5646,9881,9198,5382,5382,5315,5684,5462,9492,8729,9173,5267,5355,10175,5494,9109,9396,5321,5321,5326,8667,9093,5315,5291,8844,8877,10003,5278,9597,8672,2,8754,10206,5331,5619,5291,5506,9220,9498,9093,8908,9055,8706,8970,8828,9449,8812,8833,5331,9357,9443,5431,8801,9357,5619,9464,5619,8908,9411,5437,9502,9284,10117,9401,5344,5411,10191,9065,8965,9242,5624,5411,9212,9602,5331,9346,5331,5646,9309,5359,10058,8877,8801,8806,5331,8806,9814,8676,5443,10290,8993,5634,8812,2,5267,9426,5684,8975,10058,9426,9007,5321,5411,8801,8889,5619,5494,10112,9743,9551,8713,8744,5335,8898,9216,8965,5267,5456,9050,10091,9754,2,9325,9443,5350,5304,9574,8806,5411,5304,9664,9208,9226,9766,5278,9226,9766,10340,9167,5684,5506,5506,9454,10107,8824,9760,9592,5506,5291,9265,9046,9487,9341,10255,5411,9378,8744,9099,10218,8744,8744,5619,8908,5619,9555,9198,9791,9449,5339,8863,9754,5670,8833,5666,5483,5326,9555,9203,9738,9325,8724,9475,9421,9188,8767,5388,9957,10068,9417,9065,5350,9382,8718,5506,10297,9305,9826,9918,9046,9487,9198,9198,9555,8729,5506,8997,9738,9378,9012,5304,9093,5684,9151,9487,5267,10187,9305,12701,9046,5506,8912,8894,9791,5449,9203,10182,5335,5411,8898,8828,9900,8801,9173,8667,8981,9864,13745,13756,11485,10206,2,9940,10096,5483,5350,9203,9940,8754,5331,5634,9135,9289,5675,5506,8824,8718,8696,5646,9945,5355,5506,9454,11485,10135,9560,9945,5331,5431,5431,8894,5437,10301,9093,5388,9487,9530,9754,9325,8912,9480,5472,9104,9760,8986,9480,9743,9743,9109,9754,8828,9271,9050,10058,5267,9198,9417,8908,5355,9198,9002,10096,9156,5407,5407,9046,5278,5619,9688,5489,9940,9968,9382,9382,9065,9754,9475,9475,9046,8824,9928,9050,5326,9151,9114,5359,13762,13767,9520,9498,9373,9498,9631,9411,9754,9900,10012,8788,9963,9540,9300,8912,10243,5483,8812,5411,8738,9631,8894,5431,9475,5331,9704,5421,5359,5506,5489,5619,5304,9226,9760,9612,5355,5449,11518,9475,8706,13774,8936,5437,10175,5437,9674,5355,9099,10228,9242,9305,8706,8713,5462,8844,9007,5377,5666,9104,9173,9612,5372,10085,9093,5431,5388,5339,10206,5350,10068,5388,5377,8936,9900,9198,2,5350,9918,5421,9368,5619,9305,9265,9535,8806,5267,5304,5377,9704,8724,13783,9642,5421,5437,8729,5506,9555,9664,5267,5267,9188,9814,10068,2,9760,9046,9125,9065,5355,5355,5437,10017,9688,9050,9173,5321,9074,8997,9602,9602,8965,5421,8672,9709,8828,5321,9602,8883,5431,9188,9198,8863,5267,5291,9226,5267,8652,8824,5377,9080,10058,9449,9606,5355,9668,8812,9373,5684,9709,5339,10017,10222,5437,8828,5684,5437,9226,5321,5684,8828,5377,9135,9826,10017,5437,10017,9050,9173,9602,5421,9709,5377,5321,5355,5267,9826,8652,8824,9373,5339,5684,5315,9771,5339,9387,5321,9198,10079,5355,8993,9099,9674,9826,10290,5426,8975,5675,8912,5411,9173,9029,9294,5411,8839,5646,5456,8784,9729,5355,5359,9198,8889,5388,5456,9208,10290,9029,9198,9336,9114,5267,5506,5359,5321,5267,9050,5267,9050,9050,5651,9046,5646,5646,5315,9294,5355,9242,9597,8959,9294,9592,9530,8685,5411,5506,9791,9597,8667,5291,8908,9738,5355,9597,8667,9080,9341,9664,9188,9254,9135,8667,8713,5321,8877,10187,9265,5367,9198,8689,8761,8713,10079,8970,5304,9560,9300,8685,5506,5506,8784,8912,9065,9135,9065,8685,8718,8801,5271,9373,5239,5239,9709,8993,9046,8975,5489,9325,9826,9145,5331,5416,8729,8772,10107,5506,9417,5666,8889,9738,5506,5684,9231,5285,5388,8689,5684,9125,9498,9725,9530,8801,9055,9704,5248,8685,9597,5506,5494,9065,5421,9592,5315,5421,10023,9592,9373,9173,8975,5326,5411,5426,5629,8706,9226,9135,5472,9574,9602,9709,9668,9080,5326,9050,8689,9002,8898,5443,8883,8912,5624,8801,9869,8658,8663,8824,10212,5355,9198,9791,8784,9059,9080,9869,9080,5421,10101,9099,9305,9093,5367,9167,9508,9449,11612,9617,8824,8877,8754,5411,5304,8663,8663,9525,9254,8936,5326,9220,10147,8718,10147,10058,13791,9480,10135,5411,9216,5684,10123,8877,5372,8795,9443,9109,8912,8940,5506,9378,8667,8959,9141,9545,9093,9265,10340,5355,8908,10068,10159,9226,9417,10041,5437,5271,9357,9193,8738,5344,8986,5437,8801,9284,9331,9135,9760,9631,9074,8824,5489,8685,9074,5421,9443,5421,8839,5426,9080,8744,9826,5619,9046,8936,10101,5437,8908,8824,5239,10028,5267,5326,8667,9617,5304,9035,9265,9814,8801,9145,9050,9167,9443,5675,8680,8908,10003,8676,9226,2,10212,9193,5291,5437,9305,8894,5494,9401,5675,8812,9602,8877,9602,5267,9580,9265,12492,5407,8784,9119,8912,8738,5421,5449,9754,5619,9336,9530,9188,9188,2,8824,9760,10123,10041,5331,5335,5335,10290,9704,13800,5437,9357,5411,5431,9178,9426,8944,10017,5267,5344,5666,5666,5339,9704,5506,9208,5449,9007,10079,8849,5426,9093,8685,10129,8921,5267,8970,9470,5271,5416,5377,9080,8812,5321,5355,10329,5315,9305,5326,10175,8917,10285,8889,5421,9508,10068,10285,8936,9361,9443,5402,10068,10206,5372,8738,5355,5315,9220,5431,9694,5506,8859,9709,9141,5326,5426,5506,5506,5291,9514,9694,8738,10159,8940,9208,8772,9284,8676,8812,5437,8824,5437,5326,10058,9704,9443,9642,5624,9135,9226,9093,5331,5506,9688,9704,9050,9080,5472,9226,5472,9188,9093,9514,8667,5377,9265,9401,9704,9023,9642,5506,10206,9709,9050,10058,9050,5355,5651,9046,9791,5355,5411,9294,9530,9514,5291,8908,9738,9597,5506,9597,5355,9791,5449,5326,8944,9417,9664,10187,8685,9080,9331,8689,9254,9814,8970,8761,5321,5271,8993,9065,5285,9725,5421,8689,8889,8784,8718,9826,9193,9055,5684,9231,5388,5506,5506,9869,5624,5421,9002,5421,5411,5326,8754,8801,9135,5426,9099,9373,8975,9173,9597,5506,5271,5629,8706,9592,8839,8685,8772,5411,8663,8824,9508,8663,9525,5367,5326,9869,10147,9254,8859,10041,8801,9193,8680,10058,5344,9109,9216,9226,8824,10135,9135,8959,9093,8986,10340,5372,10068,9135,5506,10003,9265,5489,5494,5437,5619,12492,8676,9226,9080,8824,9443,9093,5239,9617,9050,9826,9602,9074,8685,5335,10206,8784,5619,9188,9119,5421,8738,9602,5339,9007,9704,5437,13800,10068,10285,9508,5377,8936,5321,9050,8738,9709,9265,8993,8738,9294,5397,5321,9294,8849,9294,5267,5267,9401,9492,8849,10058,8806,9565,5449,8908,5421,5331,10222,9637,5388,5350,5304,9814,9198,9198,9050,9050,5421,9114,5326,9300,5506,9300,5506,5437,9125,5688,9080,9387,8706,9023,5437,10096,5629,5684,9046,5267,10191,9284,8824,8801,9203,2,5267,9305,8954,9023,10191,9826,9835,9341,5506,9198,9475,8833,8849,9141,9378,9141,9373,9378,5367,8959,5335,8672,9382,9023,9940,9065,9065,5335,8849,8997,5331,9729,5388,8824,9203,9928,8997,9141,5267,9080,9417,5335,9114,10068,9023,5321,9151,8718,9754,9046,8981,9029,9881,5506,9847,9637,10047,9401,9242,10068,10017,9357,9198,8898,8801,5421,5388,5239,8898,9173,9074,9688,9621,8724,9361,9869,9109,10267,5506,8912,8997,9065,5388,5359,9791,5326,5629,9074,5239,9203,8685,11497,5315,5629,9458,5437,8812,9597,8718,8970,10191,10191,5646,8970,10028,9458,8772,9535,9642,8672,9265,10290,8652,9743,10141,5304,9621,5437,5372,9046,10068,10123,10123,9198,5355,9247,10058,5339,8689,9885,9520,9475,5467,9535,9814,10073,5355,9361,8859,10175,9046,9373,9406,9357,9492,9226,9368,9265,10175,9198,10159,9760,9520,10129,10068,9642,9050,2,5291,9637,8812,5339,10107,5304,9458,5388,10058,5350,9050,2,9443,8806,10107,9458,9151,8718,9046,9754,9029,8981,9357,5304,9368,9247,9401,9198,9242,10068,10047,9688,9373,8801,10017,8898,5437,5388,5421,10267,9173,9869,8724,8997,9109,9065,5506,11497,9198,9203,5326,5239,9791,5359,9458,5239,5629,5339,5646,8718,9535,8970,9046,10058,5355,5350,10290,8672,5388,8772,10141,9743,10068,9535,9814,10159,9046,10175,9406,9357,9050,9642,9520,10129,5291,8812,10107,8912,5267,8970,9035,8689,5267,8754,9065,8754,9704,5397,8871,9193,9193,5331,9771,9046,9231,10107,8908,5291,8925,9449,5304,9055,5321,9449,8912,9055,9265,9265,5489,9417,10079,9826,8921,9709,8801,9626,5684,5411,8912,9114,9002,9336,9055,8883,9104,9864,10107,9963,9387,5267,9231,8784,8667,9417,5437,5657,8871,9545,9679,5359,5684,10206,5646,5239,5407,5684,8912,5494,9508,9508,9188,5402,5407,2,9642,9642,9725,10297,9475,8894,9216,5501,5321,9046,9265,5437,8761,9198,8932,9626,10297,8908,9626,9580,9738,8854,5506,9431,9325,5670,9125,5489,8894,9738,9203,9055,9421,5310,8801,9417,5489,9198,9046,8729,9417,5291,9305,9729,9417,5331,9974,5506,5355,8724,5304,5315,9104,8801,10175,8658,11511,9173,8925,9237,8706,8912,5359,5443,9198,9203,8883,8981,5437,8940,9508,5388,5304,9104,5355,9417,5355,5350,10008,9114,9220,9309,8877,9305,8912,9945,10003,5350,9059,5248,5315,5472,9508,2,8940,5437,8908,9781,9226,5344,5411,5355,9309,9417,9417,9331,5359,10169,9631,9417,8912,9637,8975,5407,9305,9725,9083,5355,9387,9835,8981,9835,5382,9198,5271,9040,9198,8824,9104,5501,9346,5248,8744,9826,9704,9265,9950,5437,9002,8871,9417,9046,9725,5489,9074,9352,8680,5407,9592,9699,5437,9766,9733,5267,8940,9580,9709,9040,5407,5355,9309,9007,8696,9709,5388,5278,5359,9492,9387,8871,8724,9963,5267,9237,5355,9198,9580,9826,9007,9835,5431,5443,5402,9431,5462,9699,9417,10222,9841,5304,9242,9114,8744,5501,9305,9387,9725,5321,5321,8701,8940,9508,9508,8936,9492,5501,9785,9869,5402,8940,5388,5388,8801,9417,9114,9508,5501,5472,5355,8663,9626,9431,8701,9864,9198,5331,9198,9093,9114,9968,9226,8806,8701,5304,9226,10153,5377,5619,9514,5619,9309,8940,5684,5411,9785,10153,5267,9237,5321,8701,9135,9029,9099,13805,5684,5407,9104,9104,9029,9059,13813,8828,8859,5355,9417,8871,13820,2,9050,13828,10052,5684,9178,9396,9738,9198,13838,5407,9766,13838,8824,9156,9664,9173,8863,9226,9626,8713,9826,9443,9242,9791,5291,9580,5350,9300,9265,8724,9080,9378,8908,8997,10117,9791,9242,10175,9294,9208,5684,5494,9826,9325,8724,5666,8718,9242,9869,9895,5382,9151,8993,8894,9421,8801,9411,9080,9125,8772,9198,9188,9216,5506,10041,5421,5285,8898,8925,9417,5315,9979,5359,9796,8975,8772,5467,9198,8970,8986,8824,9957,5367,9023,9520,9704,9637,9046,10041,8772,9729,9325,9704,9709,8986,5239,5326,8795,9545,9271,10091,5506,5382,8738,9487,9431,9074,10017,9151,9331,5243,8986,10117,9352,5355,9145,5304,10028,9986,9945,5675,5367,9294,5350,9046,5239,9046,8954,9830,9709,8824,8954,9530,8993,8718,5397,9754,5359,9771,10079,10175,9226,8839,13661,9156,5315,9709,8936,9396,9341,9242,8701,5675,8921,10091,9023,5506,5355,9470,8898,8824,5304,9294,5624,9743,5331,5331,5359,8701,9156,9664,9173,9443,9826,9791,10175,9080,9331,10117,9294,8894,9216,5359,8772,9198,5506,9208,8718,5331,9188,10041,5421,5467,9198,5315,8772,8975,5359,5315,9704,9046,8986,9431,9151,5326,9487,8795,8986,9545,5239,9986,9046,5355,8954,5350,9743,9754,5397,9709,5359,9156,8701,8713,8993,9055,9055,9141,9674,9688,9212,9212,9055,9336,9540,9688,9688,9688,2,9688,9540,9055,9688,9688,9265,9900,10085,10085,8718,9545,9545,13846,9997,9688,9688,13854,13859,9492,9498,9093,10107,8738,8824,8824,8908,9597,5506,9271,9621,8908,10228,8795,9203,10340,8812,5407,9520,5339,9847,9664,9242,8663,9498,9080,9023,9704,13863,5339,9754,9226,5431,8912,9156,9729,8883,9198,5506,8788,9203,9265,8724,8898,9826,9570,8795,5489,9357,9530,5350,9738,13871,9220,5326,9574,5367,9602,5443,5355,10012,5506,5411,10159,9864,9597,9699,9254,9002,9530,9606,5688,9729,5501,8788,9443,9597,9454,5367,8877,5646,9069,8801,5646,9826,9826,10008,9220,5407,9565,5506,9704,9574,9979,8663,5421,8754,8784,5402,9945,9814,5431,9963,5326,5331,13876,9535,9830,9733,5321,5443,9023,8724,5359,5367,8772,5339,8824,9545,9237,9226,5407,5506,9498,9754,8828,5388,8680,8824,10206,5372,5501,5372,9050,10028,8912,5407,8824,5421,8718,5367,9520,9080,9688,9271,9080,5397,5494,5646,9766,9498,9226,13882,5506,9373,9188,9114,8696,9597,8940,9826,8912,9754,8784,8940,8738,2,9188,10017,9247,5666,5421,9891,8912,8784,5402,9704,5501,9826,9178,8912,9733,8701,10329,8844,8738,9443,8824,5506,8663,9492,9417,5421,5388,9188,9621,5619,5372,9023,9709,10212,8898,8818,9688,9688,9212,5331,9754,9188,8828,5331,5506,10101,10222,8908,5248,5291,8849,8824,9464,9900,8925,2,9869,9046,10052,10191,8761,5456,9378,8713,9135,9119,9754,10182,9401,5619,9119,8663,9417,5367,8849,8854,5646,5388,9743,5254,9957,9151,9918,9826,9193,8676,8701,9869,9173,8801,5421,8894,8824,5629,5675,5267,9198,5355,9597,5688,5456,5315,5267,9173,8680,9059,9203,9129,5271,13890,9520,9050,8754,9565,8912,5359,9046,8663,9046,9525,9284,9059,9203,10141,8863,8812,9305,5267,9151,5331,9520,9454,8877,8908,9141,10041,9271,8772,10068,9193,5285,9535,9729,9265,5367,9454,8706,9099,9417,5248,9508,5506,10058,9050,5670,10196,9151,9080,8824,5634,8824,9520,5688,9237,8706,8706,5478,8871,9668,5267,9900,9114,5239,9193,9417,8663,8706,9520,9284,5248,5388,5335,10079,9046,9492,8667,10175,9208,9508,9050,9247,9242,9508,8685,10222,5388,8713,5388,9841,9226,5271,8997,5291,8701,9570,9099,9502,8676,9612,9129,9814,9502,9193,9869,5431,9642,9093,5367,8908,9050,9093,9642,9325,9023,5267,9814,9642,5331,5367,5651,5646,5344,9743,8772,5506,9847,8824,9771,9050,9674,8997,9099,8685,9069,8718,9341,13897,2,9520,8854,8652,5310,9738,8767,8849,8993,8784,9570,5472,5467,9668,8828,9545,5472,5367,9574,9198,5304,5449,8754,8667,10008,8877,5670,8894,9161,5624,8936,9674,9647,9050,5267,10232,9226,5359,5377,9050,9530,9743,9709,9346,10068,9674,9545,9387,9940,5407,8948,10058,9208,8685,5456,10068,9771,9346,9520,9570,9216,5478,9602,8975,5472,9733,9520,5248,9895,8889,9647,8871,5449,9934,5291,8824,5331,5402,9396,5506,5449,8936,5315,5267,10068,9570,10085,5506,5331,9417,5315,5506,10232,9900,9597,5472,9050,9325,9602,9602,10232,8713,5315,5267,9602,9050,9688,8981,5421,5367,5421,5421,5331,8744,8676,8986,5331,5339,5339,5646,5506,8959,9766,9231,5651,9570,5646,9065,9046,8718,9198,9125,9652,9046,10012,8959,5291,9508,9012,10028,5239,9242,8824,5426,8849,9029,8908,9464,10218,9826,8672,5267,5506,8833,5421,10008,5267,9551,8738,13909,5437,9141,8676,8667,9125,8761,9265,5456,9069,9626,9050,9046,9141,9378,8713,9080,5321,5501,9373,8667,8738,9540,5355,9791,10079,10112,9341,9520,5355,9449,9141,9271,9294,8667,8863,5421,5506,8744,9309,5629,10218,9401,8854,10052,13919,13927,13934,2,9104,5239,9729,10008,5421,9720,8993,9080,9325,5254,5506,8993,9125,9141,8824,8672,8767,9454,5367,9040,9203,8718,5421,5421,10267,9417,9709,5421,8970,9443,9231,9475,9065,5388,9361,9114,5421,9305,8801,8912,10228,9570,9574,8738,9046,9820,8696,8738,9046,5331,9626,9141,9145,9540,9305,5411,9373,5350,5271,8917,9729,9309,9826,9203,8917,9099,9135,5506,8672,9869,10320,9151,5437,9574,5456,9294,5315,8912,8898,5675,5254,5421,10003,9203,8667,8863,8772,5278,10290,9574,5335,5624,5355,8824,8685,9791,10329,9198,8925,5291,8912,5304,5456,8975,9141,10267,8801,5688,9668,8658,9188,5304,5304,9382,8863,9592,9396,5355,9141,9900,9602,5506,8667,9979,9617,13941,5367,8921,10201,8738,9652,13947,8859,8959,8849,9088,5421,10249,5646,8877,9704,9382,9458,5407,9733,9002,9029,8744,9565,5359,5670,9059,9637,8713,9520,9151,8663,8784,8824,9093,10101,9305,8849,9203,9294,9785,9814,9093,9637,9198,8672,9443,8663,8663,8883,9029,5344,11707,5456,8738,9135,8849,11707,5619,9114,5271,9417,5304,10267,9464,8936,5331,8729,9088,8754,9525,5331,9881,11748,8801,2,10008,8696,9674,9417,9480,9754,5437,9748,8959,9530,9480,9331,8658,9325,9151,5359,5331,9580,9289,5634,9720,9674,5382,9617,9141,5304,9664,10159,5624,11633,9858,8940,9940,10058,9226,9017,5239,5271,9830,9309,10123,9945,10068,5651,8908,8738,5344,8908,8824,5339,10017,8997,9480,8652,5267,5431,9530,8993,9733,5350,8718,5359,9502,5359,5426,9760,5235,9535,10096,13956,9454,10012,9637,9642,2,9684,5304,2,9401,8986,2,9801,9796,8812,9826,5431,9271,5304,10058,10008,9226,10123,9046,9352,5355,9080,9352,9265,5407,8889,9294,9145,9968,5397,8824,10249,5456,5494,9226,9046,9231,9592,9083,8970,9294,9237,8652,10003,9508,9508,5688,9069,10123,9023,8676,9720,5437,9968,5437,9254,9237,9208,9443,9104,5411,8718,9688,8744,5239,9382,8676,5670,5243,8859,5411,2,5670,9545,8940,9119,5397,5431,9963,5267,8696,9725,8676,9694,9437,9411,8871,9963,9580,5675,10147,9017,9305,8729,8932,5388,10243,9748,5239,8663,8812,5494,8883,8696,9796,9183,9560,5478,9637,9284,8718,8718,8828,5506,9754,8871,9309,5267,9203,5675,8734,5634,13947,13919,9963,2,2,2,9378,5359,9963,8944,9725,9928,9382,10017,9443,5431,9319,5666,9007,5335,8828,5388,9226,8696,9826,9508,10123,5506,5359,5666,10249,9580,9679,8908,9480,8871,9007,5248,9093,9814,9220,9760,5350,9178,9382,10123,8806,9642,5437,9612,5331,5397,5267,10052,2,5443,2,2,5271,5359,5426,5355,8936,5326,9580,9570,8701,9963,9382,9876,8754,9237,8672,8696,5416,9167,10262,5372,9242,9508,8975,9145,8871,8706,5321,5315,10329,9492,5411,9396,9470,10068,9642,5355,5437,8744,10222,9664,8812,9470,5321,9694,5407,8936,10267,2,2,5651,5291,9796,5437,9109,5372,5359,5634,5326,8824,5431,5344,9508,8738,5344,5624,5388,10267,9023,8676,9104,9271,10206,9417,9341,9498,9151,5506,8859,9835,9597,8959,8801,9167,10159,5355,9309,8940,9401,10041,10191,8812,9237,9658,8685,5437,5437,13964,9592,9198,8965,5331,5624,5355,10153,9869,10290,5382,9212,10058,10147,9545,5359,9760,9475,5359,2,2,8806,9080,5359,8713,5437,5377,9305,5437,9188,9093,8706,5437,5267,10017,10073,9309,5624,9785,5684,8729,8828,10153,9652,5402,9309,5321,8871,5350,5377,5339,5646,5506,8718,5651,9231,9570,8959,10008,8738,10028,5291,5355,9242,8959,9801,9551,5267,8833,5456,5629,9454,8854,9417,5501,10079,8744,9378,9151,9748,9540,8738,9188,9449,8863,8663,9373,10052,8761,9401,9069,10112,9125,8824,8738,5271,8738,8993,9305,9080,9570,9454,9125,9626,10153,8917,9099,9203,9040,5367,10267,9305,9325,10147,8738,8696,9475,5421,9443,8970,5388,9729,9141,9104,5456,10201,9396,8898,9464,9664,5367,8754,9203,8676,5416,9198,10206,9574,5359,8959,8667,9796,8889,8801,5304,10101,10306,5304,5426,8975,9560,9203,9188,5675,9668,5271,8921,5315,5506,9093,5278,8871,9617,8667,9900,8801,9396,8936,8663,9535,9881,5431,10249,8877,9963,5331,5271,9114,9271,9525,10267,9382,9733,11707,9814,8713,8696,9796,5437,9088,5407,9059,8738,9417,11633,9580,9104,8652,9733,8997,9830,8908,9684,8658,9940,9480,5267,8993,8828,9017,10159,5339,9198,5304,5634,9401,9289,10068,5651,5437,9417,9502,5239,9083,8812,9796,9580,9254,9080,9592,9508,8744,9968,5478,5494,9023,8859,10058,5670,9178,5239,9109,5670,5335,8718,9305,5675,9309,8871,5634,9309,9378,8696,9284,9119,5506,9203,10191,9411,9760,8871,9007,8828,5443,5248,9220,9826,9725,9443,8696,10068,5321,9492,8936,5359,9470,5377,8936,9785,9580,10222,9401,5624,9023,5344,5431,5506,9592,9760,9212,9093,8706,9480,9480,9771,5666,5489,5684,9492,9602,9480,9801,8734,10272,5291,9401,9801,9050,5388,8849,5388,9876,9796,10052,5443,9294,9776,9876,5304,5304,5437,9720,5397,13970,9565,8889,5416,5437,5382,5397,9325,9688,5388,9776,9065,10017,5675,5675,9280,9114,9294,9173,9720,8921,9940,9059,5359,10101,9560,9417,9626,9626,9093,5684,8701,9480,9922,9940,9050,9720,9050,9080,8839,8824,8954,8706,9475,8706,5684,9188,8954,9540,9617,9226,8667,9391,5657,5377,10058,2,13976,8652,9309,8940,9796,9065,5657,9806,10017,9565,8908,9237,8871,10017,9934,10091,5267,5326,9093,9141,10206,9023,8940,8954,2,9801,10272,5291,9050,8849,5388,8954,9806,9776,9226,5304,9294,5437,9720,10052,9801,8889,5416,9173,8954,8940,9720,5359,9796,9280,5675,9065,9940,9771,9626,9059,10058,8824,9050,9480,5267,8954,8839,9050,9080,9093,5377,5684,5326,9391,5657,5675,8652,8940,5657,10091,9023,9046,9046,5363,9470,8713,8738,8663,5506,9738,8667,9145,9565,9080,9361,9540,9743,10249,9520,10117,9198,9141,9220,8761,9145,8667,8718,5411,8754,9080,5684,9826,9725,8767,9040,9325,11633,9738,9738,9570,5254,9046,5355,5359,8806,9265,5456,9104,9178,5335,5449,5350,9104,5304,8898,9173,8824,5629,5291,9597,9508,5456,9346,9046,5388,5397,5291,9361,9198,8936,9565,9754,8718,9114,5304,9069,9309,9520,5304,9743,9743,9193,5506,9470,9331,8667,9417,9017,9265,9141,9325,9530,5304,5359,9361,5304,8667,8801,9145,9997,5291,5278,9050,8667,8824,5407,8824,8806,9226,9226,9309,9470,5372,9617,5494,5411,5372,8667,5629,9050,5326,5675,9520,8663,9226,8859,5267,8871,5355,9247,9766,5666,5267,8667,2,8844,8701,9699,10222,9141,5372,5372,8824,5304,9341,9729,8898,5355,9766,5267,8667,9080,5326,8806,5267,5331,5331,5331,10159,9065,9198,10340,8863,9035,5506,5657,9050,8738,9664,8689,9664,5355,8993,9023,9198,9373,8863,9055,5248,9417,9114,9208,10228,8828,8824,5472,8959,5372,8849,9401,9904,10017,9114,10228,5248,5355,5267,5472,8696,5331,9035,9336,10228,5355,5355,8824,8824,9336,9378,10301,8921,8917,8954,9341,9606,9520,5331,5331,9895,9325,5624,9617,9475,9502,9040,10206,5456,8663,9231,8685,5355,8917,9265,8877,8889,10101,8718,9743,5670,9325,8908,5472,9401,9560,9109,9437,9709,8667,9729,5472,9300,8701,2,8778,8812,8663,9325,9904,9325,5397,9294,8667,5335,9621,9520,8696,9502,10191,8663,9226,9401,8667,5267,5506,8859,9099,10222,5304,8824,5359,8806,8724,5355,9606,9145,9125,9141,9226,2,5267,5355,9621,9502,9502,5624,5331,9401,8859,9109,8724,8806,9325,8859,9814,5331,9475,2,9065,9065,5254,10041,10041,9220,8652,8718,9220,8754,10041,9220,9220,9040,9220,8652,9109,9109,10201,9602,8948,8948,9421,8676,8652,5326,8676,5675,5651,9592,5437,9791,9826,10058,8663,9791,9449,5339,9336,10112,9125,8667,8932,9378,5335,9725,9498,9540,5506,9188,9530,9738,9203,9294,9421,9145,13984,8667,9203,9530,5355,5619,9617,9617,10023,9029,13990,9498,9508,10101,9637,8812,5372,8883,9508,9443,9858,5443,8940,9247,5254,9391,9417,9212,5619,9352,9119,5506,5646,5646,9065,8877,8917,9417,5437,9688,9826,5437,13998,9530,9373,8940,9151,5619,8729,5675,5388,9391,8871,9178,9173,9508,9336,5355,5437,5449,9093,9498,9401,5304,8738,10058,9918,5437,5377,9226,9791,9046,5670,5634,5675,9226,9508,8849,9480,2,9352,9597,8970,9226,5675,9151,9530,9373,9520,2,5388,9226,5326,10058,9918,10058,9226,9791,9046,8849,9226,9520,9530,9771,9771,5304,5619,5304,5355,8667,10228,9520,9957,5363,5382,9167,8812,9520,5382,8667,8667,8706,9208,8676,5651,10041,8729,8706,9885,8849,8685,5506,8685,8993,9254,9237,8908,9847,8824,9637,9540,5501,9826,9099,8729,9570,9325,9891,9220,5624,9065,9508,9080,9080,9226,5411,9002,9135,5506,9135,9647,9470,9074,5285,5624,9046,9203,9069,5326,9237,9203,5363,8652,8754,8812,8863,9208,8849,9220,9699,9699,10047,9535,9699,5239,5239,9017,5651,9535,9050,8849,5437,9216,9679,8788,9449,5506,9406,5407,9080,9080,9050,8839,10091,5248,10175,9050,5304,8713,5506,9754,10243,9040,9040,5449,8894,5624,9492,9934,5506,9007,8908,8844,9284,9508,8993,9597,8738,5326,9709,9900,9294,10191,5304,10047,5359,5377,9309,8975,8676,5651,10041,8849,8706,9885,8685,8685,9637,8993,5501,8908,9540,9254,9847,8824,5359,9325,9570,9220,5411,9203,8652,8849,8812,8788,9647,5506,10047,5326,9699,8849,8812,8812,9216,5407,5248,9080,10175,9050,9080,9309,9007,9040,10243,9284,5624,9709,9900,10047,8975,9814,9760,14002,9046,5397,9709,9760,8932,9125,8854,9864,9002,9443,9957,9417,5388,8672,9226,9145,9188,5478,9796,9587,9242,8696,5267,9492,9934,9934,8696,9760,9760,9760,9492,2,8921,9814,9760,9814,9145,9709,9760,8932,9417,8672,5478,9188,8696,9934,9760,9760,9109,9242,9109,9109,5421,5421,9426,5355,5651,8672,9738,9709,9183,8706,9300,9791,8824,5634,8912,8667,9242,9242,9183,8667,8801,5506,9820,5388,5411,9530,8696,9055,10267,8672,9475,5421,9104,9647,9791,8652,5315,9203,5254,9188,9574,9055,8706,9145,9145,8898,9050,5363,5506,9426,9305,9260,9080,9454,8863,9565,8784,8824,5421,9188,8839,9271,5421,5437,10159,5254,5304,9454,8676,10068,9109,9247,9226,10017,9080,9991,8839,9208,5494,10267,5326,5437,5688,9065,5456,9341,9226,8993,9592,9254,8871,9305,9525,5267,9237,8696,5478,9530,8676,9520,5335,8871,9007,5388,8824,9382,5339,9876,9237,10175,5291,8912,9099,5506,5355,8844,8754,5248,9530,5326,8706,9709,9341,9647,9502,9050,5335,9093,8706,8828,10153,8902,5421,5651,5355,9738,5456,9300,5267,9791,8824,8912,9242,8667,5437,5421,9475,8672,9104,5506,8898,8844,8706,9203,5363,5315,5506,5254,9305,9565,9080,8824,9260,8863,9271,8839,5304,10017,9592,9237,8993,5478,9093,8676,5335,9305,8696,9382,5339,9007,9876,10175,8902,9319,9237,9271,8706,9341,9125,9729,5388,9305,10008,8849,9109,5437,9617,8859,9046,5304,8954,8713,9341,10191,5456,8734,8824,9814,8849,9826,9738,9738,8912,9597,8801,9198,9743,8713,10218,8932,8667,8954,9198,9099,5359,5367,9305,9475,9129,9738,5506,5684,2,5684,8788,9305,9231,9754,5382,8772,9417,8801,9551,9417,9141,9458,9203,9325,8718,8854,9046,9145,5421,5388,9738,9738,8672,8696,8734,9074,9530,9198,9411,10212,8778,9597,8975,9135,8788,8898,9647,9305,8801,8667,8828,14010,9099,5619,8696,9417,9254,9449,9464,8986,8849,10008,9443,9699,8863,9080,8754,8713,8859,5359,10159,8772,8970,9074,9940,9530,9535,9835,9216,8908,8908,9050,9109,9587,9050,5411,9188,8663,9074,10123,9074,8738,9109,5494,5437,9401,8824,5407,8975,5397,9835,9237,9352,8672,9002,9738,9237,5478,8738,8754,9198,8696,9606,10212,5267,9612,10058,9050,9754,9193,9587,5291,5331,9198,9904,5359,5267,8828,9247,5335,5666,9426,9934,10123,5684,5388,9198,8824,8685,5426,9305,8784,8877,8701,9093,5501,8696,9738,10129,10068,5315,10267,9050,8828,9709,9220,5506,8676,9738,10191,9193,9050,5382,5359,10212,8706,5355,9904,9417,5267,9023,5331,9760,8734,8824,9738,9597,8912,5684,10218,9305,5359,9458,5421,8672,9046,9417,9193,8801,9738,9551,9203,5506,8854,8877,8734,8667,5315,5426,8828,9647,9074,9760,5331,8754,9050,8713,9449,8863,8908,8908,9216,10159,9835,8784,9426,9074,9198,9237,9587,8663,5666,8696,8738,5291,9934,8828,10123,9093,9193,5355,9904,8706,8993,9226,9226,9226,8824,10107,5506,9895,9069,5619,9475,5388,8912,5407,9826,8894,9647,9508,9373,8658,5675,9699,10141,9074,5388,9216,10320,8824,5372,9178,9305,8877,9606,9305,9055,10035,10191,5335,9492,9178,5416,10058,9458,5372,5407,10191,10035,5359,9525,9525,9508,10201,9508,9396,5402,9760,9940,9940,5407,8761,9382,9555,8997,9099,9940,10191,9280,8883,5382,5239,9280,9555,5407,9421,9141,8997,9046,8898,9411,5684,9029,9382,9002,5355,5382,11505,9957,9560,5407,5331,10191,9835,5407,5382,9254,5271,8975,9835,9885,5437,9104,9208,9212,9771,8908,5431,8718,10191,5382,5335,9876,9007,9007,10334,8685,9864,8738,8738,10085,9023,9129,9658,10191,9864,9514,9565,9565,5416,9294,5267,9565,8849,9565,9565,9771,9480,8824,8824,5331,5634,9046,8738,9173,9835,8696,9173,10290,8824,9173,5670,5355,8908,5411,9237,8839,9125,9570,5670,8685,9050,8877,8986,8824,9699,8908,8795,8986,9226,5437,8912,9934,5388,5335,5355,8685,5472,9050,9709,8824,9766,9791,5355,14016,9029,9738,8959,5355,8685,9080,9080,9560,9847,9300,5335,5411,9135,9242,9754,5388,5359,8954,9208,5359,10228,8761,9341,9378,5367,14021,14029,9065,5397,5684,8849,9141,9325,9738,9305,5646,5285,9046,5388,5355,9226,9417,8959,9305,5367,9487,9141,9431,5456,8854,9475,9046,8889,9417,8993,14035,9574,2,8940,5411,5350,5688,8706,8898,9617,9226,8883,8801,8667,9864,8828,9574,5506,8908,5254,9226,5315,9454,9173,5304,5675,5326,14043,14049,10201,14055,9104,8863,5407,9007,8877,10228,9560,9449,8824,9260,9704,9487,10141,8784,8663,5646,10101,9046,9637,5367,5331,9560,9560,9525,9502,14061,14067,14074,14085,5248,9729,5239,8908,10041,8706,9260,9346,5355,8959,9083,8993,8772,8778,9535,9109,9729,5506,9940,5359,9771,9480,9220,9331,9325,9193,5331,9502,9835,9198,9431,14095,14103,14110,5421,9135,8839,5421,5688,5456,8801,9212,9835,5355,9688,9688,9023,8975,9357,9226,9226,8824,9945,9352,5489,5494,5431,9050,5646,5646,5437,5388,9080,9145,9046,9406,5437,5397,9738,9208,14119,10196,14128,8954,5437,9284,8663,8761,9587,8696,8734,5421,5421,8667,14136,10212,8940,9188,5675,9411,8738,8908,8954,10196,14139,5431,5666,5363,5326,9720,5355,8883,5684,5437,9587,9007,5267,5646,9760,5355,5355,8801,5449,5646,10175,5248,9247,10052,9336,5462,5321,5684,8706,9305,5315,9597,8784,5494,10329,5291,5291,9242,5321,8701,9597,8818,5267,14149,14154,9341,10017,5688,9129,11497,9587,9709,10107,9173,9361,5331,9480,14139,14160,14168,9900,5355,8685,9401,14160,5331,9864,5331,8965,8718,8706,9080,5359,10017,5331,5304,8824,9766,5355,5367,9300,5359,8761,9125,9065,9305,5285,9431,5359,5367,8889,9046,9305,9475,5688,9141,8854,9173,5411,10201,9226,8898,9574,9357,5688,9129,5355,5315,5304,10228,8706,9597,10141,5331,5431,5437,5331,5421,8883,9487,9560,9637,8863,5355,5248,10041,9325,8908,9193,9109,9940,9480,8993,9729,9431,8959,9220,9135,5421,5239,9341,5489,5388,9480,5421,8954,9226,9406,9080,5646,9046,5494,8975,5449,9688,9587,5666,8908,8940,8667,9188,8761,5437,5363,9760,9336,5462,9007,9720,5248,9226,5267,5321,5291,8701,10329,9401,10107,5331,9709,10017,5483,5506,9046,5331,9771,9454,9050,9046,8959,5355,9814,14175,10107,5421,9814,9668,9475,9754,9198,9208,9449,9046,9341,8954,5437,5421,8824,10301,14180,5321,5321,9141,9023,8718,9475,9050,9664,5271,8761,9814,8954,8944,9881,9203,9551,9325,8965,9046,9738,8954,5331,9688,9198,5675,9754,5239,5684,8877,9198,9099,9417,5367,8993,8744,8824,9145,9411,9664,10267,8824,14186,8812,10159,8663,8898,9002,8859,9198,9050,9167,5315,5355,9864,8801,9791,5506,9294,8828,9900,10003,5675,9791,5315,9382,8772,9198,8828,14193,14202,11779,9652,9203,5355,8824,9023,9738,9454,8663,5634,8824,9305,9597,9597,5388,5267,8863,9417,10008,9220,5407,9080,9080,9869,9208,8663,9135,9535,14208,14217,5359,5285,5350,9046,9617,9231,5382,9449,8738,9151,8959,5359,5657,5437,9417,10008,9664,9754,8908,5331,8676,10159,9858,10159,9940,9361,8908,9220,5506,5506,9220,5239,9535,8778,8908,9346,10141,9417,5684,14225,14232,5355,5350,2,8912,8818,9352,9617,5646,5407,9208,5407,9080,5411,8997,9046,9346,10008,9050,9065,9754,9074,9520,5670,9208,8812,5501,8917,9417,14245,10073,8761,8993,8812,9754,9443,9437,5421,9065,9114,8871,5397,10196,8696,5355,8993,5437,10340,8849,5239,5239,9729,9188,9050,5355,5331,8652,9012,5407,5407,9729,10008,8734,5315,9525,8652,9265,5331,10175,9704,5666,9188,5506,8944,8912,9198,9492,9411,9178,5388,9904,5344,8824,8663,5321,8667,8975,8672,5315,5506,5426,5388,8812,8784,5494,9242,5315,9492,9050,10201,9771,5304,5304,10008,9621,10329,8824,8812,5359,9928,5304,9336,5506,9141,5350,8828,8908,5506,5355,9704,8824,9709,8676,9145,9141,9658,9401,9602,8812,9502,9826,9626,8824,5624,9475,5359,9065,8806,9904,9626,8812,10017,5684,5331,9652,5483,9771,5355,9754,9668,5421,8944,9664,10073,9475,8718,8993,8778,5359,9664,8877,9145,9325,9198,5684,9754,9336,9738,8672,9198,8898,9002,9382,9167,8772,5675,9652,9294,8663,9305,5331,5634,9208,9080,8824,5304,5407,8663,5657,8818,9617,9940,9151,5382,8738,9346,10141,9754,8784,9208,9065,9080,8993,5646,5239,5670,8917,9729,9188,9437,8696,5355,9729,5437,9065,5506,8812,9704,9492,9492,5315,9771,8824,5359,9443,9709,8812,9401,9502,10017,9904,5359,5339,9325,5437,5304,9733,5437,5437,9050,9733,5359,5367,9387,5355,9760,9387,9760,8801,8863,8801,5437,9602,9602,8663,8696,9265,8863,8701,9729,8908,5359,9771,8863,9220,5331,8706,9050,9203,9602,5331,8970,9247,8701,9220,5355,9325,9050,9387,9621,9621,5675,10079,9046,8948,8948,9046,9421,5684,5684,10003,9046,5304,9535,5684,8948,2,9814,9046,5684,8948,8734,5335,5335,5326,8734,9193,5392,9341,5494,5494,5339,9979,8652,9069,9167,5267,9869,9167,5350,5331,9431,8912,11528,11528,5506,8738,9099,5267,9928,5335,5335,8738,8724,9114,5367,9040,5506,5397,9050,5684,5670,9050,9220,8824,5331,10206,10058,9426,8667,9617,9050,10068,9617,8718,8724,9426,5506,5670,9099,9050,10058,5359,9198,9341,9046,9046,9720,9720,9754,9387,5684,10079,9918,8801,9198,9464,5666,5462,9738,5388,9754,10079,9738,5651,9602,10012,5651,5239,8993,8993,8778,9341,9530,9754,9141,9480,9525,8908,9754,8871,10212,5350,5350,9341,9109,8954,9125,8959,9738,9574,5684,9361,5421,5367,5421,10101,8663,9431,9220,8839,9417,9050,10008,5407,5267,5304,9050,5624,5388,9188,5646,8849,8663,8663,5688,5267,5675,8889,9382,9437,8889,10085,8902,8908,9820,5355,5239,5355,5355,8908,5355,8912,9265,9265,9065,9664,10096,5619,9421,9733,5421,5239,8912,9431,9417,8883,9325,9325,9114,8975,5619,10096,9309,9771,9188,9545,9940,8824,9114,5506,9729,9733,9193,5684,5392,5304,8944,9080,9781,5506,9545,9193,9040,9114,5339,9664,8912,9265,9065,10096,9417,9325,9421,8883,5239,10096,8824,9545,5684,9781,8806,9606,9029,9606,9050,8806,8806,9029,10091,8940,9325,8940,8806,9029,10091,9173,5646,5462,9173,9626,9017,9065,5321,5619,8824,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4277,14254,1,1,14259,1,1,1,14264,1,1,1,1,1,1,1,14269,14274,1,14279,1,14284,1,14290,1,1,1,1,14295,14300,1,1,1,1,1,1,14306,1,1,1,1,1,1,1,1,1,1,1,14312,1,1,1,1,1,1,1,14319,1,1,1,1,1,1,1,1,1,1,0,14325,5612,40,14328,14331,14335,335,14339,4921,14343,24,14346,14349,14353,14356,380,14360,52,14363,14366,32,3081,14369,14373,2773,14377,14381,14386,14391,14395,14400,14404,773,14408,14412,14417,14421,14426,14430,2787,14434,14438,2784,14442,14446,14450,2770,14454,14458,14463,14467,14471,14475,14478,14482,14487,14491,14495,3432,14499,14503,14508,14512,14517,14521,776,14525,14529,14534,14538,14543,14547,3446,14551,14555,14559,3429,14563,14567,14572,14576,14580,14584,14587,14591,14596,14600,14605,14610,14614,14619,14625,14631,14636,14642,14647,1046,14652,14657,14663,14668,14674,14679,14684,14688,14693,14698,14702,14707,14712,14717,14721,14726,14732,14737,14742,14747,14751,14756,14761,14766,14770,14775,14781,14786,14792,14797,14802,14806,14811,14816,14821,14825,14830,14835,14840,14844,14849,14855,14860,14865,14870,14874,14879,14885,14890,14895,14900,14904,14909,14915,14920,14926,14931,14936,14940,14945,14951,14956,14962,14967,14972,14976,14981,14986,14991,14995,15000,15006,15011,15016,15020,15025,15031,15036,15040,2577,15044,15048,15053,15057,15062,15066,818,15070,15074,15079,15084,15088,15093,15097,2591,15101,15105,2588,15109,15113,2574,15117,15121,15126,15130,15134,15138,15141,15145,15149,1711,15153,15157,15161,806,15165,15169,2737,15173,15177,15181,2716,15185,15189,15194,15198,15202,15206,15209,15213,15217,2797,15221,15225,15230,15235,15239,15244,15248,958,15252,15256,15260,2811,15264,15268,15272,15276,15280,2794,15284,15288,15293,15297,15301,13421,15305,15309,15314,15318,15322,3095,15326,15330,15335,15339,15344,15348,789,15352,15356,15361,605,15365,3169,15369,15373,432,15377,15381,15385,3158,15389,15393,15398,15402,15406,324,15410,15414,5260,15419,15424,15428,779,15432,15436,15441,15446,15450,15455,15459,2832,5015,15463,2829,15467,15471,15475,2818,15479,15483,15488,15492,15497,2474,15502,15507,15513,15518,15524,15529,915,15534,15539,15545,15550,15556,15561,2492,15566,15571,2488,15576,15581,15586,3176,15591,15596,15602,15607,15612,12861,15617,15622,15628,15633,15638,12906,15643,15648,15653,13106,15658,15663,13172,15668,15673,15678,13053,15683,15688,15694,15699,15704,15709,15713,15718,15724,15730,15735,15741,15746,3042,15751,15756,15762,15767,15772,15777,15782,15787,15791,15796,15801,15805,2928,15809,15813,15818,15822,15827,815,15831,15835,15840,15844,15849,15853,1357,15857,15861,2935,15865,15869,15873,2925,15877,15881,15886,15890,15895,15900,15904,15909,15915,15920,15926,15931,4900,15936,15941,15947,15952,15958,15963,15967,15972,15977,15981,15986,15991,15996,16000,16005,16011,16016,16021,16026,16030,16035,16041,16046,16050,2525,16054,16058,16063,16068,16072,16077,16081,812,16085,16089,16094,16099,16103,16108,16112,1383,16116,16120,2532,16124,16128,16132,2522,16136,16140,16145,16149,16153,4510,16157,16161,16166,16170,16174,3203,16178,16182,16187,16192,16196,16201,16205,888,16209,16213,16218,16223,16227,16232,16236,3217,16240,16244,16248,3214,16252,16256,16260,3200,16264,16268,16273,16277,16281,2976,16285,16289,16294,16298,16303,16307,809,16311,16315,16320,16324,16329,16333,1268,16337,16341,16345,2987,16349,16353,16357,2973,16361,16365,16370,16374,16379,3246,16384,16390,16395,16401,16406,1033,16411,16416,16422,16428,16433,16439,16444,3264,16449,16454,16459,3260,16464,16469,16474,3242,16479,16484,16490,16495,16501,16506,16511,16516,16520,16525,16531,16536,16542,16547,16552,16556,16561,16566,16570,16575,16580,16585,16589,16594,16600,16605,16610,16615,16619,16624,16630,16636,16641,16647,16652,16657,16661,16666,16672,16678,16683,16689,16694,16699,16703,16708,16713,16717,16722,16728,16733,16739,16744,895,16749,16754,16760,16766,16771,16776,4144,16781,16786,16791,16795,16800,16804,1707,16809,16813,429,16817,16821,16826,16831,16835,16840,16844,2515,16848,16852,1704,16856,16860,16864,825,16868,16872,16877,16881,16886,3092,16890,16894,482,16898,16902,16906,3101,16910,16914,16919,16923,16928,16932,1017,16936,16940,16945,16949,16954,16958,3112,16962,16966,464,16970,16974,16978,3098,16982,16986,16991,16995,16999,17003,17006,17010,17015,17019,17023,2842,17027,17031,17036,17041,17045,17050,17054,899,17058,17062,17067,17071,17076,17080,2856,17084,17088,2853,17092,17096,17100,2839,17104,17108,17113,17117,17121,5189,17125,17129,17134,17138,17143,6454,17148,17153,17159,17165,17170,17176,17181,6446,17186,17191,6472,17196,17201,6468,17206,17211,6450,17216,17221,17227,17232,17237,17242,17246,17251,17257,17262,17267,17272,17276,17281,17287,17292,17298,17303,17308,17312,17317,17323,17328,17333,17338,17343,17347,17352,17356,17361,17367,17372,17377,17382,17386,17391,17397,17402,17406,2656,17410,17414,17419,17423,17428,17432,799,17436,17440,17445,17449,17454,17458,1282,17462,17466,2667,17470,17474,17478,2653,17482,17486,17491,17495,17499,17503,17506,17510,17515,17519,17524,6398,17529,17534,17540,17545,17551,17556,965,17561,17566,17571,4438,17576,17581,6412,17586,17591,17596,6394,17601,17606,17611,17616,17620,17625,17631,17636,17641,1411,17646,17651,17657,17662,17668,17673,3141,17678,17683,17688,3137,17693,17698,17703,3119,17708,17713,17719,17724,17729,17734,17738,17743,17749,17754,17759,785,17764,17769,17775,17781,17786,17792,17797,3317,17802,17807,17812,3313,17817,17822,3295,17827,17832,17838,17843,17848,17853,17857,17862,17868,17873,795,17878,17884,17889,17894,13535,17899,17904,17909,17914,17918,17923,17928,17933,17937,17942,17948,17953,17958,17963,17967,17972,17978,17983,17988,4626,17993,17998,18003,18007,18012,18017,18022,18026,18031,18036,18041,18045,18050,18056,18061,18066,18071,18075,18080,18086,18091,18096,961,18101,18106,18112,18117,18123,18128,327,18133,18138,18143,2283,18148,18153,18158,2674,18163,18168,18174,18179,18184,18189,18193,18198,18204,18209,18213,792,18217,18221,18226,18230,18235,18239,2646,18243,18247,2643,18251,18255,18259,2629,18263,18267,18272,18276,18280,4503,18284,18288,18293,18297,18301,3183,18305,18309,18314,18319,18323,18328,18333,18338,18342,18347,18351,3197,18355,18359,18363,3180,18367,18371,18376,18380,18384,5178,18388,18392,18397,18401,18405,2690,18409,18413,18418,18423,18427,18432,18437,3504,18442,18447,18451,2704,18455,18459,18463,2687,18467,18471,18476,18480,18484,18488,18491,18495,18500,18504,18509,4290,18514,18519,18525,18531,18536,18542,18548,18553,18559,18564,4277,18569,18574,18579,4273,18584,18589,18595,18600,18605,18610,18614,18619,18624,12865,18629,18634,18640,18646,18651,18657,18663,18668,18673,13110,18678,18683,13057,18688,18693,18699,18704,18709,18714,18718,18723,18729,18734,18739,2946,18744,18749,18755,18761,18766,18772,18778,18783,18789,18794,2964,18799,18804,18809,2942,18814,18819,18823,2869,18827,18831,18836,18841,18845,18850,18855,18859,18863,2883,18867,18871,18875,18879,18882,18886,18891,18895,18899,347,18903,18907,18912,18917,18921,18926,18931,18936,18940,18945,18949,1275,18953,18957,18961,653,18965,18969,18974,18978,18982,1091,18986,18990,18995,1,1,1,18447,2525,16277,18744,17125,6398,16449,16252,2577,16605,16166,14707,15101,1275,14555,16678,15424,888,1,1,15602,14463,16428,18799,2818,14363,18574,16954,14576,14972,18895,15293,18189,15272,1017,3197,1,18610,16232,18531,3092,3158,18174,16068,5189,17071,17027,16703,18091,1,18133,3313,17153,1,2987,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2973,18999,1,1,19003,1,1,1,19007,1,1,1,1,1,1,1,19011,19015,1,19019,1,19023,1,1,1,1,1,1,19028,1,1,0,19033,0,0,0,19039,0,0,0,0,0,0,0,0,0,0,0,0,19045,0,0,0,0,0,0,3008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19052,0,0,0,0,0,0,2994,19058,0,0,19063,0,0,0,19068,0,0,0,0,0,0,0,19073,19078,0,19083,0,19088,0,0,0,0,0,0,6547,0,0,0,19094,0,0,0,19099,0,0,0,0,0,0,0,19104,0,0,0,0,0,0,0,0,0,0,0,19109,19113,0,0,19118,0,0,0,19123,0,0,0,0,0,0,0,19128,19133,0,0,0,19138,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2976,19144,0,0,19148,0,0,0,19152,0,0,0,0,0,0,0,19156,19160,0,19164,0,19168,0,0,0,0,0,0,779,19173,0,0,1613,0,0,0,19177,19181,0,0,0,0,0,0,19186,19190,0,19194,19198,19203,0,0,0,0,0,0,19208,19212,0,0,19217,0,0,0,19222,0,0,0,0,0,0,0,19227,19232,0,19237,19242,19248,0,0,0,0,0,0,4081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19260,19264,0,0,19269,0,0,0,19274,0,19279,0,0,0,0,0,19285,19290,0,19295,19300,19306,0,0,0,0,0,0,2829,19312,0,0,19316,0,0,0,19320,0,0,0,0,0,0,0,19324,19328,0,19332,0,19336,0,0,0,0,0,0,19341,0,0,0,19346,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19352,0,0,0,0,0,0,0,4069,0,0,0,19359,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2832,19364,0,0,10673,0,0,0,19368,0,0,0,0,0,0,0,19372,19376,0,19380,0,19384,0,0,0,0,5015,0,2835,0,0,0,19389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19394,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19399,0,0,0,19403,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19408,0,19413,0,0,0,0,0,0,4077,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2818,19419,0,0,19423,0,0,0,19427,0,0,0,0,0,0,0,13469,19431,0,19435,0,19439,0,0,0,0,0,0,19444,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19449,0,0,0,0,0,0,0,3621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3625,19456,0,0,19461,0,0,0,19466,0,0,0,0,0,0,0,19471,19476,0,0,0,19481,0,0,0,0,0,0,19487,0,0,0,19491,0,0,0,19496,0,0,0,0,0,0,0,19501,0,0,0,0,19506,0,0,0,0,0,0,19512,19516,0,0,19521,0,0,19526,19531,0,19536,0,0,0,0,0,19542,19547,0,19552,0,0,0,0,0,0,0,0,4073,0,0,0,19557,0,0,0,19562,0,0,0,0,0,0,0,19567,19572,0,0,0,0,0,0,0,0,0,0,324,19577,0,0,19581,0,0,0,19585,0,0,0,0,0,0,0,19589,19593,0,19597,0,19601,0,0,0,0,0,0,776,19606,19610,0,19615,0,0,0,19619,0,19623,0,0,0,0,0,19628,19632,0,19636,19640,19645,0,0,0,14517,0,0,19650,19654,0,0,19659,0,0,0,19664,0,0,0,0,0,0,0,19669,19674,0,19679,19684,19690,0,0,0,0,0,0,19696,19700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19705,19709,0,0,19714,0,0,0,19719,0,0,0,0,0,0,0,19724,19729,0,19734,19739,19745,0,0,0,0,0,0,3443,19751,0,0,19755,0,0,0,19759,0,0,0,0,0,0,0,19763,19767,0,19771,0,19775,0,0,0,0,0,0,19780,0,0,0,19785,0,0,0,19791,0,0,0,0,0,0,0,19797,19803,0,0,19809,19816,0,0,0,0,0,0,19823,0,0,0,0,0,0,0,19827,0,0,0,0,0,0,0,0,19832,0,19837,0,0,0,0,0,0,0,0,3446,19842,0,0,19846,0,0,0,19850,0,0,0,0,0,0,0,19854,19858,0,19862,0,19866,0,0,0,0,0,0,2757,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19871,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19877,0,0,0,19881,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19886,0,0,0,19890,0,0,0,19895,0,0,0,0,0,0,0,0,19900,0,19905,0,0,0,0,0,0,0,0,3429,19910,0,0,19914,0,0,19918,19922,0,19926,0,0,0,0,0,19931,19935,0,19939,0,19943,0,0,0,0,0,0,19948,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19953,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3585,0,0,0,19960,0,0,0,19965,0,0,0,0,0,0,0,19970,0,0,19975,0,0,0,0,0,0,0,0,19980,0,0,0,19984,0,0,0,19989,0,0,0,0,0,0,0,19994,0,0,19999,0,20004,0,0,0,0,0,0,20010,0,0,0,20014,0,0,0,20019,0,0,0,0,0,0,0,20024,20029,0,20034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3432,20039,0,0,20043,0,0,0,20047,0,0,0,0,0,0,0,20051,20055,0,20059,0,20063,0,0,0,0,0,0,429,20068,0,0,12879,0,0,0,20072,0,0,0,0,20076,0,0,20081,20085,0,20089,0,20093,0,0,0,0,0,0,1700,20098,0,0,20103,0,0,0,20108,0,0,0,0,0,0,0,20113,20118,0,20123,20128,20134,0,0,0,0,0,0,20140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20150,20154,0,0,20159,0,0,0,20164,0,20169,0,0,0,0,0,20175,20180,0,20185,0,20190,0,0,0,0,0,0,1704,20196,0,0,13124,0,0,0,20200,0,0,0,0,0,0,0,20204,20208,0,20212,0,13383,0,0,0,0,0,0,20216,20221,0,0,20227,0,0,0,20233,0,0,0,0,0,0,0,20239,20245,0,20251,20257,20264,0,0,0,0,0,0,20271,0,0,0,20275,0,0,0,20280,0,0,0,0,0,0,0,0,20285,0,0,0,0,0,0,0,0,0,0,2515,20290,0,0,10817,0,0,0,20294,0,0,0,0,20298,0,0,20303,20307,0,20311,0,20315,0,0,0,16840,0,0,4219,20320,0,0,20325,0,0,0,20330,0,0,0,0,0,0,0,0,0,0,20335,0,20340,0,0,0,0,0,0,20346,20351,0,0,20357,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20363,0,20369,0,0,0,0,0,0,1589,20376,0,0,20381,0,0,0,20386,0,0,0,0,0,0,0,0,20391,0,20396,0,20401,0,0,0,0,0,0,20407,0,0,0,20411,0,0,0,20416,0,0,0,0,0,0,0,0,20421,0,20426,0,0,0,0,0,0,0,0,2501,20431,0,0,13015,0,0,0,20435,0,0,0,0,20439,0,0,20444,0,0,20448,0,20452,0,0,0,0,0,0,20457,0,0,0,20462,0,0,0,20468,0,0,0,0,0,0,0,20474,0,0,0,0,20480,0,0,0,0,0,0,4206,20487,0,0,888,20492,20496,20501,1597,20506,20511,20516,20520,20524,20529,20534,20539,20544,20549,20554,20559,20563,20567,20572,20576,20581,20586,20590,20594,16201,16209,20598,20602,20606,20611,20617,20623,20628,20634,20640,20645,20650,20656,20662,20668,20674,20680,20686,20692,20697,20702,20708,20713,20719,20725,20730,20735,20740,20745,20750,6603,20755,20760,20766,20772,20777,20783,20789,20794,20799,20805,20811,20817,20823,20829,20835,20841,20846,20851,20857,20862,20868,20874,20879,20884,20889,20894,20899,20904,20909,20915,20922,20929,20935,20942,20949,20955,20961,20968,20975,20982,20989,20996,21003,21010,21016,21022,21029,21035,21042,21049,21055,21061,21067,21073,21079,1114,21085,21090,21096,21102,21107,21113,21119,21124,21129,21135,21141,21147,21153,21159,21165,21171,21176,21181,21187,21192,21198,21204,21209,21214,21219,21224,21229,3214,21234,21238,21243,13187,21248,21253,21258,21262,21266,21271,21276,21281,21286,21291,21296,21301,21305,21309,21314,21318,21323,21328,21332,21336,16244,16252,21340,21344,21349,21355,21362,21369,21375,21382,21389,21395,21401,21408,21415,21422,21429,21436,21443,21450,21456,21462,21469,21475,21482,21489,21495,21501,21507,21513,21519,6625,21525,21530,21536,21542,21547,21553,21559,21564,21569,21575,21581,21587,21593,21599,21605,21611,21616,21621,21627,21632,21638,21644,21649,21654,21659,21664,21669,3217,21674,21678,21683,21688,21692,21697,21702,21706,21710,21715,21720,21725,21730,21735,21740,21745,21749,21753,21758,21762,21767,21772,21776,21780,16232,16240,21784,3220,21788,21793,21799,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,24,54,24,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21805,21810,21816,21822,21827,21832,21838,21844,21850,21856,21862,21868,21874,21879,21884,21890,21895,21901,21907,21912,21917,21922,21927,21932,21937,21942,21948,21955,21962,21968,21975,21982,21988,21994,22001,22008,22015,22022,22029,22036,22043,22049,22055,22062,22068,22075,22082,22088,22094,22100,22106,22112,22118,22122,22127,22133,22139,22144,22150,22156,22161,22166,22172,22178,22184,22190,22196,22202,22208,22213,22218,22224,22229,22235,22241,22246,22251,22256,22261,22266,6629,22271,22276,22282,22288,22293,22299,22305,22310,22315,22321,22327,22333,22339,22345,22351,22357,22362,22367,22373,22378,22384,22390,22395,22400,22405,22410,22415,3200,22420,22424,22429,22434,22438,22443,22448,22452,22456,22461,22466,22471,22476,22481,22486,22491,22495,22499,22504,22508,22513,22518,22522,22526,16256,16264,22530,22534,22539,22545,22552,22559,22565,22572,22579,22585,22591,22598,22605,22612,22619,22626,22633,22640,22646,22652,22659,22665,22672,22679,22685,22691,22697,22703,22709,3238,22715,22720,22726,22732,22737,22743,22749,22754,22759,22765,22771,22777,22783,22789,22795,22801,22806,22811,22817,22822,22828,22834,22839,22844,22849,22854,22859,3224,22864,22869,22875,22881,22886,22892,22898,22903,22908,22914,22920,22926,22932,22938,22944,22950,22955,22960,22966,22971,22977,22983,22988,22993,22998,23003,23008,6607,23013,23018,23024,23030,23035,23041,23047,23052,23057,23063,23069,23075,23081,23087,23093,23099,23104,23109,23115,23120,23126,23132,23137,23142,23147,23152,23157,23162,23166,23171,23177,23183,23188,23194,23200,23205,23210,23216,23222,23228,23234,23240,23246,23252,23257,23262,23268,23273,23279,23285,23290,23295,23300,23305,23310,6611,23315,23320,23326,23332,23337,23343,23349,23354,23359,23365,23371,23377,23383,23389,23395,23401,23406,23411,23417,23422,23428,23434,23439,23444,23449,23454,23459,3203,23464,23468,23473,23478,23482,23487,23492,23496,23500,23505,23510,23515,23520,23525,23530,23535,23539,23543,23548,23552,23557,23562,23566,23570,16170,16178,23574,1033,23578,23583,23589,23595,23600,23606,23612,23617,23622,23628,23634,23640,23646,23652,23658,23664,23669,23674,23680,23685,23691,23697,23702,23707,16401,16411,23712,23717,23722,23728,23735,23742,23748,23755,23762,23768,23774,23781,23788,23795,23802,23809,23816,23823,23829,23835,23842,23848,23855,23862,23868,23874,23880,23886,23892,23898,23903,23909,23916,23923,23929,23936,23943,23949,23955,23962,23969,23976,23983,23990,23997,24004,24010,24016,24023,24029,24036,24043,24049,24055,24061,24067,24073,24079,24085,24092,24100,24108,24115,24123,24131,24138,24145,24153,24161,24169,24177,24185,24193,24201,24208,24215,24223,24230,24238,24246,24253,24260,24267,24274,24281,24288,24293,24299,24306,24313,24319,24326,24333,24339,24345,24352,24359,24366,24373,24380,24387,24394,24400,24406,24413,24419,24426,24433,24439,24445,24451,24457,24463,3260,24469,24474,24480,24486,24491,24497,24503,24508,24513,24519,24525,24531,24537,24543,24549,24555,24560,24565,24571,24576,24582,24588,24593,24598,16454,16464,24603,24608,24614,24621,24629,24637,24644,24652,24660,24667,24674,24682,24690,24698,24706,24714,24722,24730,24737,24744,24752,24759,24767,24775,24782,24789,24796,24803,24810,24817,24822,24828,24835,24842,24848,24855,24862,24868,24874,24881,24888,24895,24902,24909,24916,24923,24929,24935,24942,24948,24955,24962,24968,24974,24980,24986,24992,3264,24998,25003,25009,25015,25020,25026,25032,25037,25042,25048,25054,25060,25066,25072,25078,25084,25089,25094,25100,25105,25111,25117,25122,25127,16439,16449,25132,6373,25137,25143,25150,25157,25163,25170,25177,25183,25189,25196,25203,25210,25217,25224,25231,25238,25244,25250,25257,25263,25270,25277,25283,25289,25295,25301,25307,25313,25319,25326,25334,25342,25349,25357,25365,25372,25379,25387,25395,25403,25411,25419,25427,25435,25442,25449,25457,25464,25472,25480,25487,25494,25501,25508,25515,25522,25527,25533,25540,25547,25553,25560,25567,25573,25579,25586,25593,25600,25607,25614,25621,25628,25634,25640,25647,25653,25660,25667,25673,25679,25685,25691,25697,25703,25708,25714,25721,25728,25734,25741,25748,25754,25760,25767,25774,25781,25788,25795,25802,25809,25815,25821,25828,25834,25841,25848,25854,25860,25866,25872,25878,3242,25884,25889,25895,25901,25906,25912,25918,25923,25928,25934,25940,25946,25952,25958,25964,25970,25975,25980,25986,25991,25997,26003,26008,26013,16469,16479,26018,26023,26029,26036,26044,26052,26059,26067,26075,26082,26089,26097,26105,26113,26121,26129,26137,26145,26152,26159,26167,26174,26182,26190,26197,26204,26211,26218,26225,6389,26232,26238,26245,26252,26258,26265,26272,26278,26284,26291,26298,26305,26312,26319,26326,26333,26339,26345,26352,26358,26365,26372,26378,26384,26390,26396,26402,6378,26408,26414,26421,26428,26434,26441,26448,26454,26460,26467,26474,26481,26488,26495,26502,26509,26515,26521,26528,26534,26541,26548,26554,26560,26566,26572,26578,26584,26589,26595,26602,26609,26615,26622,26629,26635,26641,26648,26655,26662,26669,26676,26683,26690,26696,26702,26709,26715,26722,26729,26735,26741,26747,26753,26759,26765,26770,26776,26783,26790,26796,26803,26810,26816,26822,26829,26836,26843,26850,26857,26864,26871,26877,26883,26890,26896,26903,26910,26916,26922,26928,26934,26940,26946,26951,26957,26964,26971,26977,26984,26991,26997,27003,27010,27017,27024,27031,27038,27045,27052,27058,27064,27071,27077,27084,27091,27097,27103,27109,27115,27121,3246,27127,27132,27138,27144,27149,27155,27161,27166,27171,27177,27183,27189,27195,27201,27207,27213,27218,27223,27229,27234,27240,27246,27251,27256,16374,27261,27266,815,27271,27275,27280,27285,27289,27294,27299,27303,27307,27312,27317,27322,27327,27332,27337,27342,27346,27350,27355,27359,27364,27369,27373,27377,27381,15831,3493,27385,27389,27394,27400,27406,27411,27417,27423,27428,27433,27439,27445,27451,27457,27463,27469,27475,27480,27485,27491,27496,27502,27508,27513,27518,27523,27528,27533,821,27538,27543,27549,27555,27560,27566,27572,27577,27582,27588,27594,27600,27606,27612,27618,27624,27629,27634,27640,27645,27651,27657,27662,27667,27672,27677,27682,27687,27692,27698,27705,27712,27718,27725,27732,27738,27744,27751,27758,27765,27772,27779,27786,27793,27799,27805,27812,27818,27825,27832,27838,27844,27850,27856,27862,27868,27872,27877,27883,27889,27894,27900,27906,27911,27916,27922,27928,27934,27940,27946,27952,27958,27963,27968,27974,27979,27985,27991,27996,28001,28006,28011,28016,2935,28021,28025,28030,28035,28039,28044,28049,28053,28057,28062,28067,28072,28077,28082,28087,28092,28096,28100,28105,28109,28114,28119,28123,28127,28131,15865,28135,28139,28144,28150,28157,28164,28170,28177,28184,28190,28196,28203,28210,28217,28224,28231,28238,28245,28251,28257,28264,28270,28277,28284,28290,28296,28302,28308,28314,2960,28320,28325,28331,28337,28342,28348,28354,28359,28364,28370,28376,28382,28388,28394,28400,28406,28411,28416,28422,28427,28433,28439,28444,28449,28454,28459,28464,1357,28469,28473,28478,28483,28487,28492,28497,28501,28505,28510,28515,28520,28525,28530,28535,28540,28544,28548,28553,28557,28562,28567,28571,28575,15849,15857,28579,2938,28583,28588,28594,28600,28605,28611,28617,28622,28627,28633,28639,28645,28651,28657,28663,28669,28674,28679,28685,28690,28696,28702,28707,28712,28717,28722,28727,28732,28737,28743,28750,28757,28763,28770,28777,28783,28789,28796,28803,28810,28817,28824,28831,28838,28844,28850,28857,28863,28870,28877,28883,28889,28895,28901,28907,28913,28917,28922,28928,28934,28939,28945,28951,28956,28961,28967,28973,28979,28985,28991,28997,29003,29008,29013,29019,29024,29030,29036,29041,29046,29051,29056,29061,2964,29066,29071,29077,29083,29088,29094,29100,29105,29110,29116,29122,29128,29134,29140,29146,29152,29157,29162,29168,29173,29179,29185,29190,29195,18789,18799,29200,2925,29205,29209,29214,29219,29223,29228,29233,29237,29241,29246,29251,29256,29261,29266,29271,13465,29276,29280,29285,29289,29294,29299,29303,29307,15869,15877,29311,29315,29320,29326,29333,29340,29346,29353,29360,29366,29372,29379,29386,29393,29400,29407,29414,29421,29427,29433,29440,29446,29453,29460,29466,29472,29478,29484,29490,3799,29496,29501,29507,29513,29518,29524,29530,29535,29540,29546,29552,29558,29564,29570,29576,29582,29587,29592,29598,29603,29609,29615,29620,29625,29630,29635,29640,29645,29649,29654,29660,29666,29671,29677,29683,29688,29693,29699,29705,29711,29717,29723,29729,29735,29740,29745,29751,29756,29762,29768,29773,29778,29783,29788,29793,2942,29798,29803,29809,29815,29820,29826,29832,29837,29842,29848,29854,29860,29866,29872,29878,29884,29889,29894,29900,29905,29911,29917,29922,29927,18804,18814,29932,29937,29941,29946,29952,29958,29963,29969,29975,29980,29985,29991,29997,30003,30009,30015,30021,30027,30032,30037,30043,30048,30054,30060,30065,30070,30075,30080,30085,2946,30090,30095,30101,30107,30112,30118,30124,30129,30134,30140,30146,30152,30158,30164,30170,30176,30181,30186,30192,30197,30203,30209,30214,30219,18734,18744,30224,2928,30229,30233,30238,30243,30247,30252,30257,30261,30265,30270,30275,30280,30285,30290,30295,30300,30304,30308,30313,30317,30322,30327,30331,30335,15801,15809,30339,789,30343,30347,30352,30357,30361,30366,30371,664,30375,30380,30385,30390,30395,30400,30405,30410,30414,30418,30423,30427,30432,30437,30441,30445,15344,15352,30449,30453,30457,30462,30468,30474,30479,30485,30491,30496,30501,30507,30513,30519,30525,30531,30537,30543,30548,30553,30559,30564,30570,30576,30581,30586,30591,30596,30601,30606,30610,30615,30621,30627,30632,30638,30644,30649,30654,30660,30666,30672,30678,30684,30690,30696,30701,30706,30712,30717,30723,30729,30734,30739,30744,30749,30754,30759,30764,30770,30777,30784,30790,30797,30804,30810,30816,30823,30830,30837,30844,30851,30858,30865,30871,30877,30884,30890,30897,30904,30910,30916,30922,30928,30934,30940,30944,30949,30955,30961,30966,30972,30978,30983,30988,30994,31000,31006,31012,31018,31024,31030,31035,31040,31046,31051,31057,31063,31068,31073,31078,31083,31088,432,82,31093,31098,31103,31107,31112,31117,31121,31125,31130,31135,31140,31145,31150,31155,31160,31164,31168,31173,31177,31182,31187,31191,31195,31199,15377,31203,31207,31212,31218,31225,31232,31238,31245,31252,31258,31264,31271,31278,31285,31292,31299,31306,31313,31319,31325,31332,31338,31345,31352,31358,31364,31370,31376,31382,31388,31392,31397,31403,31409,31414,31420,31426,31431,31436,31442,31448,31454,31460,31466,31472,31478,31483,31488,31494,31499,31505,31511,31516,31521,31526,31531,31536,3169,31541,31545,31550,1601,31555,31560,31565,31569,31573,31578,31583,31588,31593,31598,31603,31608,31612,31616,31621,31625,31630,31635,31639,31643,605,15369,31647,3172,31651,31656,31662,31668,31673,31679,31685,31690,31695,31701,31707,31713,31719,31725,31731,31737,31742,31747,31753,31758,31764,31770,31775,31780,31785,31790,31795,31800,31805,31811,31818}
diff --git a/nominatim/Makefile.in b/nominatim/Makefile.in
new file mode 100644 (file)
index 0000000..f6289d9
--- /dev/null
@@ -0,0 +1,89 @@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sysconfdir = @sysconfdir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+
+PACKAGE = @PACKAGE_NAME@
+VERSION = @PACKAGE_VERSION@
+SVN:=$(shell svnversion)
+DATADIR = $(datadir)/$(PACKAGE)
+
+
+CC = @CC@ 
+CXX = @CXX@
+
+CFLAGS += -g -O2 -Wall -Wextra
+CFLAGS += $(shell xml2-config --cflags)
+CFLAGS += $(shell geos-config --cflags)
+CFLAGS += -I$(shell pg_config --includedir)
+CFLAGS += -DVERSION=\"$(VERSION)-$(SVN)\"
+CFLAGS += -DHAVE_PTHREAD
+CFLAGS += -DNOMINATIM_DATADIR=\"$(DATADIR)\"
+
+LDFLAGS += $(shell xml2-config --libs) 
+LDFLAGS += $(shell geos-config --libs)
+LDFLAGS += -L$(shell pg_config --libdir) -lpq
+LDFLAGS += -lbz2 -lz
+LDFLAGS += -g -lproj
+LDFLAGS += -lstdc++
+LDFLAGS += -lpthread
+
+SRCS:=$(wildcard *.c) $(wildcard *.cpp)
+OBJS:=$(SRCS:.c=.o)
+OBJS:=$(OBJS:.cpp=.o)
+DEPS:=$(SRCS:.c=.d)
+DEPS:=$(DEPS:.cpp=.d)
+
+APPS:=nominatim
+DATA:=default.style
+
+.PHONY: all clean $(PACKAGE).spec
+
+all: $(APPS)
+
+clean: 
+       rm -f $(APPS) $(OBJS) $(DEPS)
+       rm -f $(PACKAGE)-*.tar.bz2
+       rm -f nominatim.spec
+
+clean-all: clean
+       rm -rf autom4te.cache
+       rm -f config.h
+       rm -f config.log
+       rm -f config.status
+       rm -f configure
+       rm -f Makefile
+
+install: $(APPS)
+       mkdir -p $(DESTDIR)$(bindir)
+       install -m 0755 $(APPS) $(DESTDIR)$(bindir)
+       mkdir -p $(DESTDIR)$(DATADIR)
+       install -m 0644 $(DATA) $(DESTDIR)$(DATADIR)
+
+%.d: %.c
+       @set -e; rm -f $@; \
+       $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
+       sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+       rm -f $@.$$$$
+
+-include $(DEPS)
+
+nominatim: $(OBJS)
+       $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+$(PACKAGE).spec: $(PACKAGE).spec.in
+       sed -e "s/@PACKAGE@/$(PACKAGE)/g; s/@VERSION@/$(VERSION)/g; s/@SVN@/$(SVN)/g;" $^ > $@
+
+$(PACKAGE)-$(VERSION).tar.bz2: $(PACKAGE).spec
+       rm -fR tmp
+       mkdir -p tmp/nominatim
+       cp -p Makefile *.[ch] *.cpp README.txt nominatim-svn.sh tmp/nominatim
+       cp -p nominatim.spec tmp/
+       tar cjf $@ -C tmp .
+       rm -fR tmp
+
+rpm: $(PACKAGE)-$(VERSION).tar.bz2
+       rpmbuild -ta $^
diff --git a/nominatim/README.txt b/nominatim/README.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nominatim/autogen.sh b/nominatim/autogen.sh
new file mode 100755 (executable)
index 0000000..4066e97
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+autoconf
diff --git a/nominatim/config.h.in b/nominatim/config.h.in
new file mode 100644 (file)
index 0000000..f80de9c
--- /dev/null
@@ -0,0 +1,19 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
diff --git a/nominatim/configure.ac b/nominatim/configure.ac
new file mode 100644 (file)
index 0000000..18e51e4
--- /dev/null
@@ -0,0 +1,15 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(nominatim, 0.1)
+
+dnl Generate configuration header file
+AC_CONFIG_HEADER(config.h)
+
+dnl Find C compiler
+AC_PROG_CC
+
+dnl Find C++ compiler
+AC_PROG_CXX
+
+dnl Generate Makefile
+AC_OUTPUT(Makefile)
+
diff --git a/nominatim/export.c b/nominatim/export.c
new file mode 100644 (file)
index 0000000..422b44a
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include <libpq-fe.h>
+
+#include "nominatim.h"
+#include "export.h"
+#include "postgresql.h"
+
+extern int verbose;
+
+void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile)
+{
+    xmlTextWriterPtr writer;
+
+       int rankTotalDone;
+
+       PGconn *conn;
+       PGresult * res;
+       PGresult * resSectors;
+       PGresult * resPlaces;
+
+       int rank;
+       int i;
+       int iSector;
+    int tuples;
+
+    const char *paramValues[2];
+    int         paramLengths[2];
+    int         paramFormats[2];
+    uint32_t    paramRank;
+    uint32_t    paramSector;
+    uint32_t    sector;
+
+    Oid pg_prepare_params[2];
+
+       conn = PQconnectdb(conninfo);
+    if (PQstatus(conn) != CONNECTION_OK) {
+        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
+        exit(EXIT_FAILURE);
+    }
+
+    pg_prepare_params[0] = PG_OID_INT4;
+    res = PQprepare(conn, "index_sectors",
+       "select geometry_sector,count(*) from placex where rank_search = $1 and indexed = true group by geometry_sector order by geometry_sector",
+       1, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    pg_prepare_params[0] = PG_OID_INT4;
+    pg_prepare_params[1] = PG_OID_INT4;
+    res = PQprepare(conn, "index_sector_places",
+       "select place_id from placex where rank_search = $1 and geometry_sector = $2",
+       2, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    nominatim_exportCreatePreparedQueries(conn);
+
+       // Create the output file
+       writer = nominatim_exportXMLStart(structuredoutputfile);
+
+    for (rank = rank_min; rank <= rank_max; rank++)
+    {
+       printf("Starting rank %d\n", rank);
+
+        paramRank = PGint32(rank);
+        paramValues[0] = (char *)&paramRank;
+        paramLengths[0] = sizeof(paramRank);
+        paramFormats[0] = 1;
+        resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
+        if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
+        {
+            fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+        }
+               if (PQftype(resSectors, 0) != PG_OID_INT4)
+               {
+            fprintf(stderr, "Sector value has unexpected type\n");
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+               }
+               if (PQftype(resSectors, 1) != PG_OID_INT8)
+               {
+            fprintf(stderr, "Sector value has unexpected type\n");
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+               }
+
+               rankTotalDone = 0;
+       for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
+       {
+                       sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
+
+                       // Get all the place_id's for this sector
+               paramRank = PGint32(rank);
+               paramValues[0] = (char *)&paramRank;
+               paramLengths[0] = sizeof(paramRank);
+               paramFormats[0] = 1;
+               paramSector = PGint32(sector);
+               paramValues[1] = (char *)&paramSector;
+               paramLengths[1] = sizeof(paramSector);
+               paramFormats[1] = 1;
+               resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
+               if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
+               {
+                   fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
+                   PQclear(resPlaces);
+                   exit(EXIT_FAILURE);
+               }
+                       if (PQftype(resPlaces, 0) != PG_OID_INT8)
+                       {
+                   fprintf(stderr, "Place_id value has unexpected type\n");
+                   PQclear(resPlaces);
+                   exit(EXIT_FAILURE);
+                       }
+
+                       tuples = PQntuples(resPlaces);
+                       for(i = 0; i < tuples; i++)
+                       {
+                               nominatim_exportPlace(PGint64(*((uint64_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL);
+                               rankTotalDone++;
+                               if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
+               }
+            PQclear(resPlaces);
+       }
+        PQclear(resSectors);
+    }
+
+    nominatim_exportXMLEnd(writer);
+
+    PQfinish(conn);
+}
+
+void nominatim_exportCreatePreparedQueries(PGconn * conn)
+{
+    Oid pg_prepare_params[2];
+       PGresult * res;
+
+    pg_prepare_params[0] = PG_OID_INT8;
+    res = PQprepare(conn, "placex_details",
+       "select osm_type, osm_id, class, type, name, housenumber, country_code, ST_AsText(geometry), admin_level, rank_address, rank_search from placex where place_id = $1",
+       1, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    pg_prepare_params[0] = PG_OID_INT8;
+    res = PQprepare(conn, "placex_address",
+       "select osm_type,osm_id,class,type,distance,cached_rank_address from place_addressline join placex on (address_place_id = placex.place_id) where isaddress and place_addressline.place_id = $1 and address_place_id != place_addressline.place_id order by cached_rank_address asc",
+       1, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    pg_prepare_params[0] = PG_OID_INT8;
+    res = PQprepare(conn, "placex_names",
+       "select (each(name)).key,(each(name)).value from (select keyvalueToHStore(name) as name from placex where place_id = $1) as x",
+       1, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+}
+
+xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile)
+{
+    xmlTextWriterPtr writer;
+
+    writer = xmlNewTextWriterFilename(structuredoutputfile, 0);
+       if (writer==NULL)
+       {
+               fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
+               exit(EXIT_FAILURE);
+       }
+       xmlTextWriterSetIndent(writer, 1);
+    if (xmlTextWriterStartDocument(writer, NULL, "UTF8", NULL) < 0)
+    {
+               fprintf(stderr, "xmlTextWriterStartDocument failed\n");
+               exit(EXIT_FAILURE);
+    }
+    if (xmlTextWriterStartElement(writer, BAD_CAST "osmStructured") < 0)
+    {
+               fprintf(stderr, "xmlTextWriterStartElement failed\n");
+               exit(EXIT_FAILURE);
+    }
+    if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "0.1") < 0)
+    {
+               fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
+               exit(EXIT_FAILURE);
+    }
+    if (xmlTextWriterWriteAttribute(writer, BAD_CAST "generator", BAD_CAST "Nominatim") < 0)
+    {
+               fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
+               exit(EXIT_FAILURE);
+    }
+    if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
+    {
+               fprintf(stderr, "xmlTextWriterStartElement failed\n");
+               exit(EXIT_FAILURE);
+    }
+
+    return writer;
+}
+
+void nominatim_exportXMLEnd(xmlTextWriterPtr writer)
+{
+       // End <add>
+    if (xmlTextWriterEndElement(writer) < 0)
+    {
+               fprintf(stderr, "xmlTextWriterEndElement failed\n");
+               exit(EXIT_FAILURE);
+    }
+       // End <osmStructured>
+    if (xmlTextWriterEndElement(writer) < 0)
+    {
+               fprintf(stderr, "xmlTextWriterEndElement failed\n");
+               exit(EXIT_FAILURE);
+    }
+    if (xmlTextWriterEndDocument(writer) < 0)
+    {
+               fprintf(stderr, "xmlTextWriterEndDocument failed\n");
+               exit(EXIT_FAILURE);
+    }
+    xmlFreeTextWriter(writer);
+}
+
+/*
+ * Requirements: the prepared queries must exist
+ */
+void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex)
+{
+       PGresult *              res;
+       PGresult *              resNames;
+       PGresult *              resAddress;
+
+       int                     i;
+
+    const char *       paramValues[1];
+    int                paramLengths[1];
+    int                paramFormats[1];
+    uint64_t           paramPlaceID;
+
+
+       paramPlaceID = PGint64(place_id);
+    paramValues[0] = (char *)&paramPlaceID;
+    paramLengths[0] = sizeof(paramPlaceID);
+    paramFormats[0] = 1;
+
+    res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
+       if (PQresultStatus(res) != PGRES_TUPLES_OK)
+       {
+               fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
+               PQclear(res);
+               exit(EXIT_FAILURE);
+       }
+
+       resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
+       if (PQresultStatus(resNames) != PGRES_TUPLES_OK)
+       {
+               fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
+               PQclear(resNames);
+               exit(EXIT_FAILURE);
+       }
+
+       resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
+       if (PQresultStatus(resAddress) != PGRES_TUPLES_OK)
+       {
+               fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
+               PQclear(resAddress);
+               exit(EXIT_FAILURE);
+       }
+
+       if (writer_mutex) pthread_mutex_lock( writer_mutex );
+
+       xmlTextWriterStartElement(writer, BAD_CAST "feature");
+       xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(res, 0, 0));
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(res, 0, 1));
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(res, 0, 2));
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(res, 0, 3));
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(res, 0, 9));
+       xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(res, 0, 10));
+
+       if (PQgetvalue(res, 0, 4) && strlen(PQgetvalue(res, 0, 4)))
+       {
+               xmlTextWriterStartElement(writer, BAD_CAST "names");
+
+               for(i = 0; i < PQntuples(resNames); i++)
+               {
+                       xmlTextWriterStartElement(writer, BAD_CAST "name");
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resNames, i, 0));
+                       xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resNames, i, 1));
+                       xmlTextWriterEndElement(writer);
+               }
+
+               xmlTextWriterEndElement(writer);
+       }
+
+       if (PQgetvalue(res, 0, 5) && strlen(PQgetvalue(res, 0, 5)))
+       {
+               xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
+               xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 5));
+               xmlTextWriterEndElement(writer);
+       }
+
+       if (PQgetvalue(res, 0, 8) && strlen(PQgetvalue(res, 0, 8)))
+       {
+               xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
+               xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 8));
+               xmlTextWriterEndElement(writer);
+       }
+
+       if (PQgetvalue(res, 0, 6) && strlen(PQgetvalue(res, 0, 6)))
+       {
+               xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
+               xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 6));
+               xmlTextWriterEndElement(writer);
+       }
+
+       if (PQntuples(resAddress)> 0)
+       {
+               xmlTextWriterStartElement(writer, BAD_CAST "address");
+               for(i = 0; i < PQntuples(resAddress); i++)
+               {
+                       xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(resAddress, i, 5))));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(resAddress, i, 5));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resAddress, i, 0));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(resAddress, i, 1));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(resAddress, i, 2));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(resAddress, i, 3));
+                       xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(resAddress, i, 4));
+                       xmlTextWriterEndElement(writer);
+               }
+               xmlTextWriterEndElement(writer);
+       }
+
+       xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
+       xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 7));
+       xmlTextWriterEndElement(writer);
+
+       xmlTextWriterEndElement(writer); // </feature>
+
+       if (writer_mutex) pthread_mutex_unlock( writer_mutex );
+
+       PQclear(res);
+       PQclear(resNames);
+       PQclear(resAddress);
+}
+
+const char * getRankLabel(int rank)
+{
+       switch(rank)
+       {
+       case 0:
+       case 1:
+               return "continent";
+       case 2:
+       case 3:
+               return "sea";
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+               return "country";
+       case 8:
+       case 9:
+       case 10:
+       case 11:
+               return "state";
+       case 12:
+       case 13:
+       case 14:
+       case 15:
+               return "county";
+       case 16:
+               return "city";
+       case 17:
+               return "town";
+       case 18:
+               return "village";
+       case 19:
+               return "unknown";
+       case 20:
+               return "suburb";
+       case 21:
+               return "postcode";
+       case 22:
+               return "neighborhood";
+       case 23:
+               return "postcode";
+       case 24:
+               return "unknown";
+       case 25:
+               return "postcode";
+       case 26:
+               return "street";
+       case 27:
+               return "access";
+       case 28:
+               return "building";
+       case 29:
+       default:
+               return "other";
+       }
+}
diff --git a/nominatim/export.h b/nominatim/export.h
new file mode 100644 (file)
index 0000000..7533db2
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef EXPORT_H
+#define EXPORT_H
+
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#include <stdint.h>
+
+void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile);
+void nominatim_exportCreatePreparedQueries(PGconn * conn);
+xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile);
+void nominatim_exportXMLEnd(xmlTextWriterPtr writer);
+void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex);
+const char * getRankLabel(int rank);
+
+#endif
diff --git a/nominatim/geometry.cpp b/nominatim/geometry.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nominatim/import.c b/nominatim/import.c
new file mode 100644 (file)
index 0000000..2a25839
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpq-fe.h>
+
+#include <libxml/xmlstring.h>
+#include <libxml/xmlreader.h>
+#include <libxml/hash.h>
+
+#include "nominatim.h"
+#include "import.h"
+#include "input.h"
+
+typedef enum { FILETYPE_NONE, FILETYPE_STRUCTUREDV0P1 } filetypes_t;
+typedef enum { FILEMODE_NONE, FILEMODE_ADD, FILEMODE_UPDATE, FILEMODE_DELETE } filemodes_t;
+
+#define MAX_FEATUREADDRESS 500
+#define MAX_FEATURENAMES 1000
+
+struct feature_address {
+       int                     place_id;
+       int                     rankAddress;
+       xmlChar *       type;
+       xmlChar *       id;
+       xmlChar *       key;
+       xmlChar *       value;
+       xmlChar *       distance;
+};
+
+struct feature_name {
+       xmlChar *       type;
+       xmlChar *       value;
+};
+
+struct feature {
+       int                     placeID;
+       xmlChar *       type;
+       xmlChar *       id;
+       xmlChar *       key;
+       xmlChar *       value;
+       xmlChar *       rankAddress;
+       xmlChar *       rankSearch;
+       xmlChar *       countryCode;
+       xmlChar *       adminLevel;
+       xmlChar *       houseNumber;
+       xmlChar *       geometry;
+} feature;
+
+int                                    fileType = FILETYPE_NONE;
+int                                    fileMode = FILEMODE_ADD;
+PGconn *                               conn;
+struct feature_address         featureAddress[MAX_FEATUREADDRESS];
+struct feature_name    featureName[MAX_FEATURENAMES];
+struct feature                         feature;
+int                                    featureAddressLines = 0;
+int                                    featureNameLines = 0;
+int                                    featureCount = 0;
+xmlHashTablePtr                partionTableTagsHash;
+
+
+
+void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
+{
+    char * value;
+    float version;
+    int isAddressLine;
+
+    if (fileType == FILETYPE_NONE)
+    {
+       // Potential to handle other file types in the future / versions
+        if (xmlStrEqual(name, BAD_CAST "osmStructured"))
+        {
+               value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version");
+               version = strtof(value, NULL);
+               xmlFree(value);
+
+               if (version == (float)0.1)
+               {
+                       fileType = FILETYPE_STRUCTUREDV0P1;
+                       fileMode = FILEMODE_ADD;
+               }
+               else
+               {
+                fprintf( stderr, "Unknown osmStructured version %f\n", version );
+                exit_nicely();
+               }
+        }
+        else
+        {
+            fprintf( stderr, "Unknown XML document type: %s\n", name );
+            exit_nicely();
+        }
+        return;
+    }
+
+    if (xmlStrEqual(name, BAD_CAST "add"))
+    {
+       fileMode = FILEMODE_ADD;
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "update"))
+    {
+       fileMode = FILEMODE_UPDATE;
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "delete"))
+    {
+       fileMode = FILEMODE_DELETE;
+       return;
+    }
+    if (fileMode == FILEMODE_NONE)
+    {
+        fprintf( stderr, "Unknown import mode in: %s\n", name );
+        exit_nicely();
+    }
+
+    if (xmlStrEqual(name, BAD_CAST "feature"))
+    {
+       feature.type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+       feature.id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
+       feature.key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
+       feature.value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
+       feature.rankAddress = xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
+       feature.rankSearch = xmlTextReaderGetAttribute(reader, BAD_CAST "importance");
+
+               feature.countryCode = NULL;
+               feature.adminLevel = NULL;
+               feature.houseNumber = NULL;
+               feature.geometry = NULL;
+               featureAddressLines = 0;
+               featureNameLines = 0;
+
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "names")) return;
+    if (xmlStrEqual(name, BAD_CAST "name"))
+    {
+       featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+       featureName[featureNameLines].value = xmlTextReaderReadString(reader);
+       featureNameLines++;
+       if (featureNameLines >= MAX_FEATURENAMES)
+       {
+            fprintf( stderr, "Too many name elements\n");
+            exit_nicely();
+       }
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "osmGeometry"))
+    {
+       feature.geometry = xmlTextReaderReadString(reader);
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "adminLevel"))
+    {
+       feature.adminLevel = xmlTextReaderReadString(reader);
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "countryCode"))
+    {
+       feature.countryCode = xmlTextReaderReadString(reader);
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "houseNumber"))
+    {
+       feature.houseNumber = xmlTextReaderReadString(reader);
+       return;
+    }
+    if (xmlStrEqual(name, BAD_CAST "address"))
+    {
+       featureAddressLines = 0;
+       return;
+    }
+    isAddressLine = 0;
+    if (xmlStrEqual(name, BAD_CAST "continent"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "sea"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "country"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "state"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "county"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "city"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "town"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "village"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "unknown"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "suburb"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "postcode"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "neighborhood"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "street"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "access"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "building"))
+    {
+        isAddressLine = 1;
+    }
+    else if (xmlStrEqual(name, BAD_CAST "other"))
+    {
+        isAddressLine = 1;
+    }
+    if (isAddressLine)
+    {
+       value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
+       if (!value)
+       {
+            fprintf( stderr, "Address element missing rank\n");
+            exit_nicely();
+       }
+       featureAddress[featureAddressLines].rankAddress =  atoi(value);
+       xmlFree(value);
+
+       featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
+       featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
+       featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
+       featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
+       featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
+
+       featureAddressLines++;
+       if (featureAddressLines >= MAX_FEATUREADDRESS)
+       {
+            fprintf( stderr, "Too many address elements\n");
+            exit_nicely();
+       }
+
+       return;
+    }
+    fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
+}
+
+void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
+{
+       PGresult *              res;
+       PGresult *              resPlaceID;
+    const char *       paramValues[11];
+    char *                     place_id;
+    char *                     partionQueryName;
+       int i;
+
+    if (xmlStrEqual(name, BAD_CAST "feature"))
+       {
+       featureCount++;
+       if (featureCount % 1000 == 0) printf("feature %i(k)\n", featureCount/1000);
+
+        if (fileMode == FILEMODE_ADD)
+        {
+               resPlaceID = PQexecPrepared(conn, "get_new_place_id", 0, NULL, NULL, NULL, 0);
+               if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
+                       {
+                               fprintf(stderr, "get_place_id: INSERT failed: %s", PQerrorMessage(conn));
+                               PQclear(resPlaceID);
+                               exit(EXIT_FAILURE);
+                       }
+        }
+        else
+        {
+            paramValues[0] = (const char *)feature.type;
+            paramValues[1] = (const char *)feature.id;
+            paramValues[2] = (const char *)feature.key;
+            paramValues[3] = (const char *)feature.value;
+            resPlaceID = PQexecPrepared(conn, "get_new_place_id", 4, paramValues, NULL, NULL, 0);
+            if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
+            {
+                fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
+                PQclear(resPlaceID);
+                exit(EXIT_FAILURE);
+            }
+        }
+               place_id = PQgetvalue(resPlaceID, 0, 0);
+
+        if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE)
+        {
+            paramValues[0] = (const char *)place_id;
+            res = PQexecPrepared(conn, "placex_delete", 1, paramValues, NULL, NULL, 0);
+            if (PQresultStatus(res) != PGRES_COMMAND_OK)
+            {
+                fprintf(stderr, "placex_delete: DELETE failed: %s", PQerrorMessage(conn));
+                PQclear(res);
+                exit(EXIT_FAILURE);
+            }
+            PQclear(res);
+
+            res = PQexecPrepared(conn, "search_name_delete", 1, paramValues, NULL, NULL, 0);
+            if (PQresultStatus(res) != PGRES_COMMAND_OK)
+            {
+                fprintf(stderr, "search_name_delete: DELETE failed: %s", PQerrorMessage(conn));
+                PQclear(res);
+                exit(EXIT_FAILURE);
+            }
+            PQclear(res);
+
+            res = PQexecPrepared(conn, "place_addressline_delete", 1, paramValues, NULL, NULL, 0);
+            if (PQresultStatus(res) != PGRES_COMMAND_OK)
+            {
+                fprintf(stderr, "place_addressline_delete: DELETE failed: %s", PQerrorMessage(conn));
+                PQclear(res);
+                exit(EXIT_FAILURE);
+            }
+            PQclear(res);
+        }
+
+        if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_ADD)
+        {
+                       // Insert into placex
+                       paramValues[0] = (const char *)place_id;
+                       paramValues[1] = (const char *)feature.type;
+                       paramValues[2] = (const char *)feature.id;
+                       paramValues[3] = (const char *)feature.key;
+                       paramValues[4] = (const char *)feature.value;
+//                     paramValues[5] = (const char *)feature.name;
+                       paramValues[6] = (const char *)feature.adminLevel;
+                       paramValues[7] = (const char *)feature.houseNumber;
+                       paramValues[8] = (const char *)feature.rankAddress;
+                       paramValues[9] = (const char *)feature.rankSearch;
+                       paramValues[10] = (const char *)feature.geometry;
+                       res = PQexecPrepared(conn, "placex_insert", 11, paramValues, NULL, NULL, 0);
+                       if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                       {
+                               fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
+                               PQclear(res);
+                               exit(EXIT_FAILURE);
+                       }
+                       PQclear(res);
+
+                       for(i = 0; i < featureAddressLines; i++)
+                       {
+                               // insert into place_address
+                               paramValues[0] = (const char *)place_id;
+                               paramValues[1] = (const char *)featureAddress[i].distance;
+                               paramValues[2] = (const char *)featureAddress[i].type;
+                               paramValues[3] = (const char *)featureAddress[i].id;
+                               paramValues[4] = (const char *)featureAddress[i].key;
+                               paramValues[5] = (const char *)featureAddress[i].value;
+                               res = PQexecPrepared(conn, "place_addressline_insert", 6, paramValues, NULL, NULL, 0);
+                               if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                               {
+                                       fprintf(stderr, "place_addressline_insert: INSERT failed: %s", PQerrorMessage(conn));
+                                       PQclear(res);
+                                       exit(EXIT_FAILURE);
+                               }
+                               PQclear(res);
+
+                               xmlFree(featureAddress[i].type);
+                               xmlFree(featureAddress[i].id);
+                               xmlFree(featureAddress[i].key);
+                               xmlFree(featureAddress[i].value);
+                               xmlFree(featureAddress[i].distance);
+                       }
+
+                       if (featureNameLines)
+                       {
+                               paramValues[0] = (const char *)place_id;
+                               res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
+                               if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                               {
+                                       fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
+                                       PQclear(res);
+                                       exit(EXIT_FAILURE);
+                               }
+                               PQclear(res);
+                       }
+
+                       partionQueryName = xmlHashLookup2(partionTableTagsHash, feature.key, feature.value);
+                       if (partionQueryName)
+                       {
+                               // insert into partition table
+                               paramValues[0] = (const char *)place_id;
+                               paramValues[1] = (const char *)feature.geometry;
+                               res = PQexecPrepared(conn, partionQueryName, 2, paramValues, NULL, NULL, 0);
+                               if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                               {
+                                       fprintf(stderr, "%s: INSERT failed: %s", partionQueryName, PQerrorMessage(conn));
+                                       PQclear(res);
+                                       exit(EXIT_FAILURE);
+                               }
+                               PQclear(res);
+
+                       }
+
+        }
+        else
+        {
+                       for(i = 0; i < featureAddressLines; i++)
+                       {
+                               xmlFree(featureAddress[i].type);
+                               xmlFree(featureAddress[i].id);
+                               xmlFree(featureAddress[i].key);
+                               xmlFree(featureAddress[i].value);
+                               xmlFree(featureAddress[i].distance);
+                       }
+        }
+
+               xmlFree(feature.type);
+               xmlFree(feature.id);
+               xmlFree(feature.key);
+               xmlFree(feature.value);
+               xmlFree(feature.rankAddress);
+               xmlFree(feature.rankSearch);
+//             if (feature.name) xmlFree(feature.name);
+               if (feature.countryCode) xmlFree(feature.countryCode);
+               if (feature.adminLevel) xmlFree(feature.adminLevel);
+               if (feature.houseNumber) xmlFree(feature.houseNumber);
+               if (feature.geometry) xmlFree(feature.geometry);
+
+               PQclear(resPlaceID);
+       }
+}
+
+static void processNode(xmlTextReaderPtr reader)
+{
+       xmlChar *name;
+    name = xmlTextReaderName(reader);
+    if (name == NULL)
+    {
+        name = xmlStrdup(BAD_CAST "--");
+    }
+
+    switch(xmlTextReaderNodeType(reader))
+    {
+        case XML_READER_TYPE_ELEMENT:
+            StartElement(reader, name);
+            if (xmlTextReaderIsEmptyElement(reader))
+                EndElement(reader, name); /* No end_element for self closing tags! */
+            break;
+        case XML_READER_TYPE_END_ELEMENT:
+            EndElement(reader, name);
+            break;
+        case XML_READER_TYPE_TEXT:
+        case XML_READER_TYPE_CDATA:
+        case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
+            /* Ignore */
+            break;
+        default:
+            fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
+            break;
+    }
+
+    xmlFree(name);
+}
+
+int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename)
+{
+    xmlTextReaderPtr   reader;
+    int                                ret = 0;
+       PGresult *                      res;
+       FILE *                          partionTagsFile;
+       char *                          partionQueryName;
+    char                               partionQuerySQL[1024];
+
+       conn = PQconnectdb(conninfo);
+    if (PQstatus(conn) != CONNECTION_OK)
+    {
+        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
+        exit(EXIT_FAILURE);
+    }
+
+       partionTableTagsHash = xmlHashCreate(200);
+
+       partionTagsFile = fopen(partionTagsFilename, "rt");
+       if (!partionTagsFile)
+    {
+        fprintf(stderr, "Unable to read partition tags file: %s\n", partionTagsFilename);
+        exit(EXIT_FAILURE);
+    }
+
+       char buffer[1024], osmkey[256], osmvalue[256];
+       int fields;
+       while(fgets(buffer, sizeof(buffer), partionTagsFile) != NULL)
+       {
+               fields = sscanf( buffer, "%23s %63s", osmkey, osmvalue );
+
+               if( fields <= 0 ) continue;
+
+           if( fields != 2  )
+           {
+             fprintf( stderr, "Error partition file\n");
+             exit_nicely();
+           }
+           partionQueryName = malloc(strlen("partition_insert_")+strlen(osmkey)+strlen(osmvalue)+2);
+               strcpy(partionQueryName, "partition_insert_");
+               strcat(partionQueryName, osmkey);
+               strcat(partionQueryName, "_");
+               strcat(partionQueryName, osmvalue);
+
+               strcpy(partionQuerySQL, "insert into place_classtype_");
+               strcat(partionQuerySQL, osmkey);
+               strcat(partionQuerySQL, "_");
+               strcat(partionQuerySQL, osmvalue);
+               strcat(partionQuerySQL, " (place_id, centroid) values ($1, ST_Centroid(st_setsrid($2, 4326)))");
+
+           res = PQprepare(conn, partionQueryName, partionQuerySQL, 2, NULL);
+           if (PQresultStatus(res) != PGRES_COMMAND_OK)
+               {
+               fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
+               exit(EXIT_FAILURE);
+               }
+
+               xmlHashAddEntry2(partionTableTagsHash, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
+       }
+
+    res = PQprepare(conn, "get_new_place_id",
+               "select nextval('seq_place')",
+       0, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare get_new_place_id: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "get_place_id",
+               "select place_id from placex where osm_type = $1 and osm_id = $2 and class = $3 and type = $4",
+       4, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare get_place_id: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "placex_insert",
+               "insert into placex (place_id,osm_type,osm_id,class,type,name,admin_level,housenumber,rank_address,rank_search,geometry) "
+               "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, st_setsrid($11, 4326))",
+       11, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "search_name_insert",
+               "insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
+               "select place_id, rank_address, rank_search, country_code, make_keywords(name), "
+               "(select uniq(sort(array_agg(name_vector))) from place_addressline join search_name on "
+               "(address_place_id = search_name.place_id) where place_addressline.place_id = $1 ), st_centroid(geometry) from placex "
+               "where place_id = $1",
+       1, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "place_addressline_insert",
+               "insert into place_addressline (place_id, address_place_id, fromarea, isaddress, distance, cached_rank_address) "
+               "select $1, place_id, false, true, $2, rank_address from placex where osm_type = $3 and osm_id = $4 and class = $5 and type = $6",
+       6, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare place_addressline_insert: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "placex_delete",
+               "delete from placex where place_id = $1",
+       1, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare placex_delete: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "search_name_delete",
+               "delete from search_name where place_id = $1",
+       1, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare search_name_delete: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    res = PQprepare(conn, "place_addressline_delete",
+               "delete from place_addressline where place_id = $1",
+       1, NULL);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+        fprintf(stderr, "Failed to prepare place_addressline_delete: %s\n", PQerrorMessage(conn));
+       exit(EXIT_FAILURE);
+       }
+
+    featureCount = 0;
+
+    reader = inputUTF8(filename);
+
+    if (reader == NULL)
+    {
+        fprintf(stderr, "Unable to open %s\n", filename);
+        return 1;
+    }
+
+    ret = xmlTextReaderRead(reader);
+    while (ret == 1)
+    {
+       processNode(reader);
+       ret = xmlTextReaderRead(reader);
+    }
+       if (ret != 0) {
+               fprintf(stderr, "%s : failed to parse\n", filename);
+               return ret;
+       }
+
+       xmlFreeTextReader(reader);
+       xmlHashFree(partionTableTagsHash, NULL);
+
+    return 0;
+}
diff --git a/nominatim/import.h b/nominatim/import.h
new file mode 100644 (file)
index 0000000..ae8c26c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef IMPORT_H
+#define IMPORT_H
+
+int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename);
+
+#endif
diff --git a/nominatim/index.c b/nominatim/index.c
new file mode 100644 (file)
index 0000000..e1c21a5
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdint.h>
+
+#include <libpq-fe.h>
+
+#include "nominatim.h"
+#include "index.h"
+#include "export.h"
+#include "postgresql.h"
+
+extern int verbose;
+
+void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
+{
+       struct index_thread_data * thread_data;
+       pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
+       int tuples, count, sleepcount;
+
+       time_t rankStartTime;
+       int rankTotalTuples;
+       int rankCountTuples;
+       float rankPerSecond;
+
+       PGconn *conn;
+       PGresult * res;
+       PGresult * resSectors;
+       PGresult * resPlaces;
+
+       int rank;
+       int i;
+       int iSector;
+
+    const char *paramValues[2];
+    int         paramLengths[2];
+    int         paramFormats[2];
+    uint32_t    paramRank;
+    uint32_t    paramSector;
+    uint32_t    sector;
+
+    xmlTextWriterPtr writer;
+       pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+    Oid pg_prepare_params[2];
+
+       conn = PQconnectdb(conninfo);
+    if (PQstatus(conn) != CONNECTION_OK) {
+        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
+        exit(EXIT_FAILURE);
+    }
+
+    pg_prepare_params[0] = PG_OID_INT4;
+    res = PQprepare(conn, "index_sectors",
+       "select geometry_sector,count(*) from placex where rank_search = $1 and indexed = false and name is not null group by geometry_sector order by geometry_sector",
+       1, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    pg_prepare_params[0] = PG_OID_INT4;
+    pg_prepare_params[1] = PG_OID_INT4;
+    res = PQprepare(conn, "index_sector_places",
+       "select place_id from placex where rank_search = $1 and geometry_index(geometry,indexed,name) = $2",
+       2, pg_prepare_params);
+    if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+    PQclear(res);
+
+    // Build the data for each thread
+    thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads);
+       for (i = 0; i < num_threads; i++)
+       {
+               thread_data[i].conn = PQconnectdb(conninfo);
+           if (PQstatus(thread_data[i].conn) != CONNECTION_OK) {
+               fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(thread_data[i].conn));
+               exit(EXIT_FAILURE);
+           }
+
+           pg_prepare_params[0] = PG_OID_INT8;
+           res = PQprepare(thread_data[i].conn, "index_placex",
+               "update placex set indexed = true where place_id = $1",
+               1, pg_prepare_params);
+           if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
+           PQclear(res);
+
+           nominatim_exportCreatePreparedQueries(thread_data[i].conn);
+       }
+
+       // Create the output file
+       writer = NULL;
+       if (structuredoutputfile)
+       {
+               writer = nominatim_exportXMLStart(structuredoutputfile);
+       }
+
+    fprintf(stderr, "Starting indexing rank (%i > %i ) using %i treads\n", rank_min, rank_max, num_threads);
+
+    for (rank = rank_min; rank <= rank_max; rank++)
+    {
+       printf("Starting rank %d\n", rank);
+       rankStartTime = time(0);
+       rankCountTuples = 0;
+       rankPerSecond = 0;
+
+        paramRank = PGint32(rank);
+        paramValues[0] = (char *)&paramRank;
+        paramLengths[0] = sizeof(paramRank);
+        paramFormats[0] = 1;
+        resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
+        if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
+        {
+            fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+        }
+               if (PQftype(resSectors, 0) != PG_OID_INT4)
+               {
+            fprintf(stderr, "Sector value has unexpected type\n");
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+               }
+               if (PQftype(resSectors, 1) != PG_OID_INT8)
+               {
+            fprintf(stderr, "Sector value has unexpected type\n");
+            PQclear(resSectors);
+            exit(EXIT_FAILURE);
+               }
+
+               rankTotalTuples = 0;
+       for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
+       {
+               rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
+       }
+
+       for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
+       {
+                       sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
+               //printf("\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
+
+                       // Get all the place_id's for this sector
+               paramRank = PGint32(rank);
+               paramValues[0] = (char *)&paramRank;
+               paramLengths[0] = sizeof(paramRank);
+               paramFormats[0] = 1;
+               paramSector = PGint32(sector);
+               paramValues[1] = (char *)&paramSector;
+               paramLengths[1] = sizeof(paramSector);
+               paramFormats[1] = 1;
+               resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
+               if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
+               {
+                   fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
+                   PQclear(resPlaces);
+                   exit(EXIT_FAILURE);
+               }
+                       if (PQftype(resPlaces, 0) != PG_OID_INT8)
+                       {
+                   fprintf(stderr, "Place_id value has unexpected type\n");
+                   PQclear(resPlaces);
+                   exit(EXIT_FAILURE);
+                       }
+
+                       count = 0;
+                       rankPerSecond = 0;
+                       tuples = PQntuples(resPlaces);
+
+                       if (tuples > 0)
+               {
+                               // Spawn threads
+                               for (i = 0; i < num_threads; i++)
+                               {
+                                       thread_data[i].res = resPlaces;
+                                       thread_data[i].tuples = tuples;
+                                       thread_data[i].count = &count;
+                                       thread_data[i].count_mutex = &count_mutex;
+                                       thread_data[i].writer = writer;
+                                       thread_data[i].writer_mutex = &writer_mutex;
+                                       pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
+                               }
+
+                               // Monitor threads to give user feedback
+                               sleepcount = 0;
+                               while(count < tuples)
+                               {
+                                       usleep(1000);
+
+                                       // Aim for one update per second
+                                       if (sleepcount++ > 500)
+                                       {
+                                               rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
+                                               printf("  Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
+                                               sleepcount = 0;
+                                       }
+                               }
+
+                               // Wait for everything to finish
+                               for (i = 0; i < num_threads; i++)
+                               {
+                                       pthread_join(thread_data[i].thread, NULL);
+                               }
+
+                               rankCountTuples += tuples;
+               }
+
+                       // Finished sector
+                       rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
+                       printf("  Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
+
+            PQclear(resPlaces);
+
+       }
+        // Finished rank
+               printf("\r  Done %i in %i @ %f per second - FINISHED                      \n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
+
+        PQclear(resSectors);
+    }
+
+    if (writer)
+    {
+       nominatim_exportXMLEnd(writer);
+    }
+}
+
+void *nominatim_indexThread(void * thread_data_in)
+{
+       struct index_thread_data * thread_data = (struct index_thread_data * )thread_data_in;
+
+       PGresult * res;
+
+    const char *paramValues[1];
+    int         paramLengths[1];
+    int         paramFormats[1];
+    uint64_t    paramPlaceID;
+    uint64_t place_id;
+
+       while(1)
+       {
+               pthread_mutex_lock( thread_data->count_mutex );
+               if (*(thread_data->count) >= thread_data->tuples)
+               {
+                       pthread_mutex_unlock( thread_data->count_mutex );
+                       break;
+               }
+
+               place_id = PGint64(*((uint64_t *)PQgetvalue(thread_data->res, *thread_data->count, 0)));
+               (*thread_data->count)++;
+
+               pthread_mutex_unlock( thread_data->count_mutex );
+
+               //printf("  Processing place_id %ld\n", place_id);
+               paramPlaceID = PGint64(place_id);
+        paramValues[0] = (char *)&paramPlaceID;
+        paramLengths[0] = sizeof(paramPlaceID);
+        paramFormats[0] = 1;
+        res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
+        if (PQresultStatus(res) != PGRES_COMMAND_OK)
+        {
+            fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
+            PQclear(res);
+            exit(EXIT_FAILURE);
+        }
+        PQclear(res);
+
+        if (thread_data->writer)
+        {
+               nominatim_exportPlace(place_id, thread_data->conn, thread_data->writer, thread_data->writer_mutex);
+        }
+       }
+
+       return NULL;
+}
diff --git a/nominatim/index.h b/nominatim/index.h
new file mode 100644 (file)
index 0000000..1e41553
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef INDEX_H
+#define INDEX_H
+
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+
+struct index_thread_data{
+   pthread_t thread;
+   PGconn * conn;
+   PGresult * res;
+   int tuples;
+   int * count;
+   pthread_mutex_t * count_mutex;
+   xmlTextWriterPtr writer;
+   pthread_mutex_t * writer_mutex;
+};
+void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile);
+void *nominatim_indexThread(void * thread_data_in);
+
+#endif
diff --git a/nominatim/input.c b/nominatim/input.c
new file mode 100644 (file)
index 0000000..5152f52
--- /dev/null
@@ -0,0 +1,220 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+
+#ifdef __MINGW_H
+# include <windows.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <zlib.h>
+#endif
+
+#include <libxml/xmlreader.h>
+#include <bzlib.h>
+
+#include "input.h"
+
+struct Input {
+  char *name;
+  enum { plainFile, gzipFile, bzip2File } type;
+  void *fileHandle;
+  // needed by bzip2 when decompressing from multiple streams. other
+  // decompressors must ignore it.
+  FILE *systemHandle; 
+  int eof;
+  char buf[4096];
+  int buf_ptr, buf_fill;
+};
+
+// tries to re-open the bz stream at the next stream start.
+// returns 0 on success, -1 on failure.
+int bzReOpen(struct Input *ctx, int *error) {
+  // for copying out the last unused part of the block which
+  // has an EOS token in it. needed for re-initialising the
+  // next stream.
+  unsigned char unused[BZ_MAX_UNUSED];
+  void *unused_tmp_ptr = NULL;
+  int nUnused, i;
+
+  BZ2_bzReadGetUnused(error, (BZFILE *)(ctx->fileHandle), &unused_tmp_ptr, &nUnused);
+  if (*error != BZ_OK) return -1;
+             
+  // when bzReadClose is called the unused buffer is deallocated, 
+  // so it needs to be copied somewhere safe first.
+  for (i = 0; i < nUnused; ++i)
+    unused[i] = ((unsigned char *)unused_tmp_ptr)[i];
+  
+  BZ2_bzReadClose(error, (BZFILE *)(ctx->fileHandle));
+  if (*error != BZ_OK) return -1;
+
+  // reassign the file handle
+  ctx->fileHandle = BZ2_bzReadOpen(error, ctx->systemHandle, 0, 0, unused, nUnused);
+  if (ctx->fileHandle == NULL || *error != BZ_OK) return -1;
+
+  return 0;
+}
+
+int readFile(void *context, char * buffer, int len)
+{
+    struct Input *ctx = context;
+    void *f = ctx->fileHandle;
+    int l = 0, error = 0;
+
+    if (ctx->eof || (len == 0))
+        return 0;
+    switch(ctx->type) {
+        case plainFile:
+            l = read(*(int *)f, buffer, len);
+           if (l <= 0) ctx->eof = 1;
+            break;
+        case gzipFile:
+            l = gzread((gzFile)f, buffer, len);
+           if (l <= 0) ctx->eof = 1;
+            break;
+        case bzip2File:
+         l = BZ2_bzRead(&error, (BZFILE *)f, buffer, len);
+
+         // error codes BZ_OK and BZ_STREAM_END are both "OK", but the stream 
+         // end means the reader needs to be reset from the original handle.
+         if (error != BZ_OK) {
+           // for stream errors, try re-opening the stream before admitting defeat.
+           if (error != BZ_STREAM_END || bzReOpen(ctx, &error) != 0) {
+             l = 0;
+             ctx->eof = 1;
+           }
+         }
+         break;
+        default:
+            fprintf(stderr, "Bad file type\n");
+            break;
+    }
+
+    if (l < 0) {
+      fprintf(stderr, "File reader received error %d (%d)\n", l, error);
+        l = 0;
+    }
+
+    return l;
+}
+
+char inputGetChar(void *context)
+{
+    struct Input *ctx = context;
+
+    if (ctx->buf_ptr == ctx->buf_fill) {
+        ctx->buf_fill = readFile(context, &ctx->buf[0], sizeof(ctx->buf));
+        ctx->buf_ptr = 0;
+        if (ctx->buf_fill == 0)
+            return 0;
+        if (ctx->buf_fill < 0) {
+            perror("Error while reading file");
+            exit(1);
+        }
+    }
+    //readFile(context, &c, 1);
+    return ctx->buf[ctx->buf_ptr++];
+}
+
+int inputEof(void *context)
+{
+    return ((struct Input *)context)->eof;
+}
+
+void *inputOpen(const char *name)
+{
+    const char *ext = strrchr(name, '.');
+    struct Input *ctx = malloc (sizeof(*ctx));
+
+    if (!ctx)
+        return NULL;
+
+    memset(ctx, 0, sizeof(*ctx));
+
+    ctx->name = strdup(name);
+
+    if (ext && !strcmp(ext, ".gz")) {
+        ctx->fileHandle = (void *)gzopen(name, "rb");
+        ctx->type = gzipFile;
+    } else if (ext && !strcmp(ext, ".bz2")) {
+      int error = 0;
+      ctx->systemHandle = fopen(name, "rb");
+      if (!ctx->systemHandle) {
+        fprintf(stderr, "error while opening file %s\n", name);
+        exit(10);
+      }
+
+      ctx->fileHandle = (void *)BZ2_bzReadOpen(&error, ctx->systemHandle, 0, 0, NULL, 0);
+      ctx->type = bzip2File;
+      
+    } else {
+        int *pfd = malloc(sizeof(pfd));
+        if (pfd) {
+            if (!strcmp(name, "-")) {
+                *pfd = STDIN_FILENO;
+            } else {
+                int flags = O_RDONLY;
+#ifdef O_LARGEFILE
+                flags |= O_LARGEFILE;
+#endif
+                *pfd = open(name, flags);
+                if (*pfd < 0) {
+                    free(pfd);
+                    pfd = NULL;
+                }
+            }
+        }
+        ctx->fileHandle = (void *)pfd;
+        ctx->type = plainFile;
+    }
+    if (!ctx->fileHandle) {
+        fprintf(stderr, "error while opening file %s\n", name);
+        exit(10);
+    }
+    ctx->buf_ptr = 0;
+    ctx->buf_fill = 0;
+    return (void *)ctx;
+}
+
+int inputClose(void *context)
+{
+    struct Input *ctx = context;
+    void *f = ctx->fileHandle;
+
+    switch(ctx->type) {
+        case plainFile:
+            close(*(int *)f);
+            free(f);
+            break;
+        case gzipFile:
+            gzclose((gzFile)f);
+            break;
+        case bzip2File:
+            BZ2_bzclose((BZFILE *)f);
+            break;
+        default:
+            fprintf(stderr, "Bad file type\n");
+            break;
+    }
+
+    free(ctx->name);
+    free(ctx);
+    return 0;
+}
+
+xmlTextReaderPtr inputUTF8(const char *name)
+{
+    void *ctx = inputOpen(name);
+
+    if (!ctx) {
+        fprintf(stderr, "Input reader create failed for: %s\n", name);
+        return NULL;
+    }
+
+    return xmlReaderForIO(readFile, inputClose, (void *)ctx, NULL, NULL, 0);
+}
diff --git a/nominatim/input.h b/nominatim/input.h
new file mode 100644 (file)
index 0000000..de5f802
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+int readFile(void *context, char * buffer, int len);
+int inputClose(void *context);
+void *inputOpen(const char *name);
+char inputGetChar(void *context);
+int inputEof(void *context);
+xmlTextReaderPtr inputUTF8(const char *name);
+
+#endif
diff --git a/nominatim/nominatim-svn.sh b/nominatim/nominatim-svn.sh
new file mode 100755 (executable)
index 0000000..f717b24
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+DATE=$(date +%Y%m%d)
+MODULE="$(basename $0 -svn.sh)"
+SVNROOT=http://svn.openstreetmap.org/applications/utils/nominatim/
+
+set -x
+rm -rf $MODULE
+
+svn export $SVNROOT $MODULE/
+
+## tar it up
+tar cjf $MODULE-${DATE}svn.tar.bz2 $MODULE
+
+## cleanup
+rm -rf $MODULE
+
diff --git a/nominatim/nominatim.c b/nominatim/nominatim.c
new file mode 100644 (file)
index 0000000..c994253
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+#-----------------------------------------------------------------------------
+# nominatim - [description]
+#-----------------------------------------------------------------------------
+# Copyright 2010, Brian Quinion
+# Based on osm2pgsql
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#-----------------------------------------------------------------------------
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <libpq-fe.h>
+
+#include "nominatim.h"
+#include "postgresql.h"
+#include "sprompt.h"
+#include "index.h"
+#include "export.h"
+#include "import.h"
+
+int verbose;
+
+void exit_nicely(void)
+{
+    fprintf(stderr, "Error occurred, cleaning up\n");
+    exit(1);
+}
+
+void short_usage(char *arg0)
+{
+    const char *name = basename(arg0);
+
+    fprintf(stderr, "Usage error. For further information see:\n");
+    fprintf(stderr, "\t%s -h|--help\n", name);
+}
+
+static void long_usage(char *arg0)
+{
+    const char *name = basename(arg0);
+
+    fprintf(stderr, "Usage:\n");
+    fprintf(stderr, "\t%s [options] planet.osms\n", name);
+    fprintf(stderr, "\nThis will import the structured osm data into a PostgreSQL database\n");
+    fprintf(stderr, "suitable for nominatim search engine\n");
+    fprintf(stderr, "\nOptions:\n");
+    fprintf(stderr, "   -d|--database\tThe name of the PostgreSQL database to connect\n");
+    fprintf(stderr, "                \tto (default: nominatim).\n");
+    fprintf(stderr, "   -U|--username\tPostgresql user name.\n");
+    fprintf(stderr, "   -W|--password\tForce password prompt.\n");
+    fprintf(stderr, "   -H|--host\t\tDatabase server hostname or socket location.\n");
+    fprintf(stderr, "   -P|--port\t\tDatabase server port.\n");
+    fprintf(stderr, "   -i|--index\t\tIndex the database.\n");
+    fprintf(stderr, "   -e|--export\t\tGenerate a structured file.\n");
+    fprintf(stderr, "   -I|--import\t\tImport a structured file.\n");
+    fprintf(stderr, "   -t|--threads\t\tNumber of threads to create for indexing.\n");
+    fprintf(stderr, "   -F|--file\t\tfile to use (either to import or export).\n");
+    fprintf(stderr, "   -T|--tagfile\t\tfile containing 'special' tag pairs\n");
+    fprintf(stderr, "                \t(default: partitionedtags.def).\n");
+    fprintf(stderr, "   -h|--help\t\tHelp information.\n");
+    fprintf(stderr, "   -v|--verbose\t\tVerbose output.\n");
+    fprintf(stderr, "\n");
+
+    if (sizeof(int*) == 4) {
+        fprintf(stderr, "\n\nYou are running this on 32bit system - this will not work\n");
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int long_usage_bool=0;
+    int pass_prompt=0;
+    const char *db = "nominatim";
+    const char *username=NULL;
+    const char *host=NULL;
+    const char *password=NULL;
+    const char *port = "5432";
+    const char *conninfo = NULL;
+    int index = 0;
+    int export = 0;
+    int import = 0;
+    int threads = 1;
+    const char *file = NULL;
+    const char *tagsfile = "partitionedtags.def";
+
+    //import = 1;
+    //structuredinputfile = "out.osms";
+
+    PGconn *conn;
+
+    fprintf(stderr, "nominatim SVN version %s\n\n", VERSION);
+
+    if (sizeof(int*) == 4) {
+        fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n");
+        fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n");
+        fprintf(stderr, "!! exceptions during import, you should try running in slim\n");
+        fprintf(stderr, "!! mode using parameter -s.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (1) {
+        int c, option_index = 0;
+        static struct option long_options[] = {
+            {"help",     0, 0, 'h'},
+
+            {"verbose",  0, 0, 'v'},
+
+            {"database", 1, 0, 'd'},
+            {"username", 1, 0, 'U'},
+            {"password", 0, 0, 'W'},
+            {"host",     1, 0, 'H'},
+            {"port",     1, 0, 'P'},
+
+            {"index",  0, 0, 'i'},
+            {"export",  0, 0, 'e'},
+            {"import",  1, 0, 'I'},
+            {"threads",  1, 0, 't'},
+            {"file",  1, 0, 'F'},
+            {"tagsfile",  1, 0, 'T'},
+
+
+            {0, 0, 0, 0}
+        };
+
+        c = getopt_long(argc, argv, "vhd:U:WH:P:ieIt:F:T:", long_options, &option_index);
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 'v': verbose=1;  break;
+            case 'd': db=optarg;  break;
+            case 'U': username=optarg; break;
+            case 'W': pass_prompt=1; break;
+            case 'H': host=optarg; break;
+            case 'P': port=optarg; break;
+            case 'h': long_usage_bool=1; break;
+            case 'i': index=1; break;
+            case 'e': export=1; break;
+            case 'I': import=1; break;
+            case 't': threads=atoi(optarg); break;
+            case 'F': file=optarg; break;
+            case 'T': tagsfile=optarg; break;
+            case '?':
+            default:
+                short_usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+    }
+
+    if (long_usage_bool) {
+        long_usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (threads < 1) threads = 1;
+
+/*
+    if (argc == optind) {  // No non-switch arguments
+        short_usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+*/
+    if (index && import) {
+        fprintf(stderr, "Error: --index and --import options can not be used on the same database!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    if (pass_prompt)
+        password = simple_prompt("Password:", 100, 0);
+    else {
+        password = getenv("PGPASS");
+    }
+
+    // Test the database connection
+    conninfo = build_conninfo(db, username, password, host, port);
+    conn = PQconnectdb(conninfo);
+    if (PQstatus(conn) != CONNECTION_OK) {
+        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
+        exit(EXIT_FAILURE);
+    }
+    PQfinish(conn);
+
+    if (index) nominatim_index(0, 30, threads, conninfo, file);
+    if (export) nominatim_export(0, 30, conninfo, file);
+    if (import) nominatim_import(conninfo, tagsfile, file);
+
+    return 0;
+}
diff --git a/nominatim/nominatim.h b/nominatim/nominatim.h
new file mode 100644 (file)
index 0000000..df0b1f6
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef NOMINATIM_H
+#define NOMINATIM_H
+
+#define MAX(x,y) (x > y?x:y)
+#define MIN(x,y) (x < y?x:y)
+
+struct output_options {
+  const char *conninfo;  /* Connection info string */
+  const char *prefix;    /* prefix for table names */
+  int scale;       /* scale for converting coordinates to fixed point */
+  int projection;  /* SRS of projection */
+  int append;      /* Append to existing data */
+  int slim;        /* In slim mode */
+  int cache;       /* Memory usable for cache in MB */
+  struct middle_t *mid;  /* Mid storage to use */
+  const char *tblsindex;     /* Pg Tablespace to store indexes */
+  const char *style;     /* style file to use */
+  int expire_tiles_zoom;        /* Zoom level for tile expiry list */
+  int expire_tiles_zoom_min;    /* Minimum zoom level for tile expiry list */
+  const char *expire_tiles_filename;    /* File name to output expired tiles list to */
+  int enable_hstore; /* add an additional hstore column with objects key/value pairs */
+  int enable_multi; /* Output multi-geometries intead of several simple geometries */
+  char** hstore_columns; /* list of columns that should be written into their own hstore column */
+  int n_hstore_columns; /* number of hstore columns */
+};
+
+void exit_nicely(void);
+void short_usage(char *arg0);
+
+#endif
diff --git a/nominatim/nominatim.spec.in b/nominatim/nominatim.spec.in
new file mode 100644 (file)
index 0000000..e7adf88
--- /dev/null
@@ -0,0 +1,55 @@
+
+%define svn @SVN@
+
+Summary: Nominatim OpenStreetMap geocoding database
+Name:   @PACKAGE@
+Group:  Applications/Text
+Version: @VERSION@
+Release: 1.%{svn}%{?dist}
+
+License: GPL
+URL:     http://svn.openstreetmap.org/applications/utils/nominatim
+Source0: %{name}-%{version}-%{svn}.tar.bz2
+Source1: nominatim-svn.sh
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 
+
+BuildRequires: geos-devel
+BuildRequires: libxml2-devel
+BuildRequires: postgresql-devel
+BuildRequires: bzip2-devel
+BuildRequires: proj-devel
+
+%description
+Processes data imported using osm2pgsql from the communtiy mapping project
+at http://www.openstreetmap.org.
+
+%prep
+%setup -q  -n %{name}
+
+
+%build
+
+export CFLAGS="$RPM_OPT_FLAGS"
+export CXXFLAGS="$RPM_OPT_FLAGS"
+
+make all
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -D -p nominatim $RPM_BUILD_ROOT/usr/bin/nominatim
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%defattr(-,root,root)
+%doc README.txt
+%{_bindir}/nominatim
+
+
+%changelog
+* Fri Sep 09 2010 Brian Quinion <nominatim@brian.quinion.co.uk> 0.1-1.20070316svn
+- Initial build
diff --git a/nominatim/partitionedtags.def b/nominatim/partitionedtags.def
new file mode 100644 (file)
index 0000000..51a2654
--- /dev/null
@@ -0,0 +1,2 @@
+amenity        pub
+amenity hotel
diff --git a/nominatim/postgresql.c b/nominatim/postgresql.c
new file mode 100644 (file)
index 0000000..f526dbf
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+*/
+#include <string.h>
+#include "postgresql.h"
+
+const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port)
+{
+    static char conninfo[1024];
+
+    conninfo[0]='\0';
+    strcat(conninfo, "dbname='");
+    strcat(conninfo, db);
+    strcat(conninfo, "'");
+
+    if (username) {
+        strcat(conninfo, " user='");
+        strcat(conninfo, username);
+        strcat(conninfo, "'");
+    }
+    if (password) {
+        strcat(conninfo, " password='");
+        strcat(conninfo, password);
+        strcat(conninfo, "'");
+    }
+    if (host) {
+        strcat(conninfo, " host='");
+        strcat(conninfo, host);
+        strcat(conninfo, "'");
+    }
+    if (port) {
+        strcat(conninfo, " port='");
+        strcat(conninfo, port);
+        strcat(conninfo, "'");
+    }
+
+    return conninfo;
+}
diff --git a/nominatim/postgresql.h b/nominatim/postgresql.h
new file mode 100644 (file)
index 0000000..ebece61
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+*/
+
+#ifndef POSTGRESQL_H
+#define POSTGRESQL_H
+
+#define PG_OID_INT8                    20
+#define PG_OID_INT4                    23
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define PGint16(x)     (x)
+#define PGint32(x)     (x)
+#define PGint64(x)     (x)
+#else
+#define PGint16(x)     __bswap_16 (x)
+#define PGint32(x)     __bswap_32 (x)
+#define PGint64(x)     __bswap_64 (x)
+#endif
+
+const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port);
+
+#endif
diff --git a/nominatim/sprompt.c b/nominatim/sprompt.c
new file mode 100644 (file)
index 0000000..f972366
--- /dev/null
@@ -0,0 +1,199 @@
+/*-------------------------------------------------------------------------
+ *
+ * sprompt.c
+ *       simple_prompt() routine
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $PostgreSQL: pgsql/src/port/sprompt.c,v 1.18 2006/10/04 00:30:14 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ * 
+ * PostgreSQL Database Management System
+ * (formerly known as Postgres, then as Postgres95)
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1994, The Regents of the University of California
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without a written agreement
+ * is hereby granted, provided that the above copyright notice and this
+ * paragraph and the following two paragraphs appear in all copies.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+ * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+ * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+
+/*
+ * simple_prompt
+ *
+ * Generalized function especially intended for reading in usernames and
+ * password interactively. Reads from /dev/tty or stdin/stderr.
+ *
+ * prompt:             The prompt to print
+ * maxlen:             How many characters to accept
+ * echo:               Set to false if you want to hide what is entered (for passwords)
+ *
+ * Returns a malloc()'ed string with the input (w/o trailing newline).
+ */
+
+#define DEVTTY "/dev/tty"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <libpq-fe.h>
+
+#ifdef __MINGW_H
+# include <windows.h>
+#else
+# define HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+/*
+extern char *simple_prompt(const char *prompt, int maxlen, int echo);
+*/
+
+char *
+simple_prompt(const char *prompt, int maxlen, int echo)
+{
+       int                     length;
+       char       *destination;
+       FILE       *termin,
+                          *termout;
+
+#ifdef HAVE_TERMIOS_H
+       struct termios t_orig,
+                               t;
+#else
+#ifdef WIN32
+       HANDLE          t = NULL;
+       LPDWORD         t_orig = NULL;
+#endif
+#endif
+
+       destination = (char *) malloc(maxlen + 1);
+       if (!destination)
+               return NULL;
+
+       /*
+        * Do not try to collapse these into one "w+" mode file. Doesn't work on
+        * some platforms (eg, HPUX 10.20).
+        */
+       termin = fopen(DEVTTY, "r");
+       termout = fopen(DEVTTY, "w");
+       if (!termin || !termout
+#ifdef WIN32
+       /* See DEVTTY comment for msys */
+               || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
+#endif
+               )
+       {
+               if (termin)
+                       fclose(termin);
+               if (termout)
+                       fclose(termout);
+               termin = stdin;
+               termout = stderr;
+       }
+
+#ifdef HAVE_TERMIOS_H
+       if (!echo)
+       {
+               tcgetattr(fileno(termin), &t);
+               t_orig = t;
+               t.c_lflag &= ~ECHO;
+               tcsetattr(fileno(termin), TCSAFLUSH, &t);
+       }
+#else
+#ifdef WIN32
+       if (!echo)
+       {
+               /* get a new handle to turn echo off */
+               t_orig = (LPDWORD) malloc(sizeof(DWORD));
+               t = GetStdHandle(STD_INPUT_HANDLE);
+
+               /* save the old configuration first */
+               GetConsoleMode(t, t_orig);
+
+               /* set to the new mode */
+               SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
+       }
+#endif
+#endif
+
+       if (prompt)
+       {
+               fputs(prompt, termout);
+               fflush(termout);
+       }
+
+       if (fgets(destination, maxlen + 1, termin) == NULL)
+               destination[0] = '\0';
+
+       length = strlen(destination);
+       if (length > 0 && destination[length - 1] != '\n')
+       {
+               /* eat rest of the line */
+               char            buf[128];
+               int                     buflen;
+
+               do
+               {
+                       if (fgets(buf, sizeof(buf), termin) == NULL)
+                               break;
+                       buflen = strlen(buf);
+               } while (buflen > 0 && buf[buflen - 1] != '\n');
+       }
+
+       if (length > 0 && destination[length - 1] == '\n')
+               /* remove trailing newline */
+               destination[length - 1] = '\0';
+
+#ifdef HAVE_TERMIOS_H
+       if (!echo)
+       {
+               tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
+               fputs("\n", termout);
+               fflush(termout);
+       }
+#else
+#ifdef WIN32
+       if (!echo)
+       {
+               /* reset to the original console mode */
+               SetConsoleMode(t, *t_orig);
+               fputs("\n", termout);
+               fflush(termout);
+               free(t_orig);
+       }
+#endif
+#endif
+
+       if (termin != stdin)
+       {
+               fclose(termin);
+               fclose(termout);
+       }
+
+       return destination;
+}
diff --git a/nominatim/sprompt.h b/nominatim/sprompt.h
new file mode 100644 (file)
index 0000000..5e68492
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef SPROMPT_H
+#define SPROMPT_H
+char *simple_prompt(const char *prompt, int maxlen, int echo);
+#endif
diff --git a/settings/settings.php b/settings/settings.php
new file mode 100644 (file)
index 0000000..84cfa3e
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+       // General settings
+       @define('CONST_Debug', false);
+       @define('CONST_Database_DSN', 'pgsql://@/nominatim');
+
+       // Website settings
+       @define('CONST_ClosedForIndexing', false);
+       @define('CONST_ClosedForIndexingExceptionIPs', '');
+       @define('CONST_BlockedIPs', '');
+
+       @define('CONST_Website_BaseURL', 'http://'.php_uname('n').'/');
+
+       @define('CONST_Default_Language', 'xx');
+       @define('CONST_Default_Lat', 20.0);
+       @define('CONST_Default_Lon', 0.0);
+       @define('CONST_Default_Zoom', 2);
+
+       @define('CONST_Search_AreaPolygons_Enabled', true);
+
+       @define('CONST_Suggestions_Enabled', false);
+
+
diff --git a/sql/functions.sql b/sql/functions.sql
new file mode 100644 (file)
index 0000000..75ab479
--- /dev/null
@@ -0,0 +1,2516 @@
+--DROP TRIGGER IF EXISTS place_before_insert on placex;
+--DROP TRIGGER IF EXISTS place_before_update on placex;
+--CREATE TYPE addresscalculationtype AS (
+--  word text,
+--  score integer
+--);
+
+
+CREATE OR REPLACE FUNCTION getclasstypekey(c text, t text) RETURNS TEXT
+  AS $$
+DECLARE
+BEGIN
+  RETURN c||'|'||t;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION isbrokengeometry(place geometry) RETURNS BOOLEAN
+  AS $$
+DECLARE
+  NEWgeometry geometry;
+BEGIN
+  NEWgeometry := place;
+  IF ST_IsEmpty(NEWgeometry) OR NOT ST_IsValid(NEWgeometry) OR ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+    RETURN true;
+  END IF;
+  RETURN false;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION clean_geometry(place geometry) RETURNS geometry
+  AS $$
+DECLARE
+  NEWgeometry geometry;
+BEGIN
+  NEWgeometry := place;
+  IF ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+    NEWgeometry := ST_buffer(NEWgeometry,0);
+    IF ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+      RETURN ST_SetSRID(ST_Point(0,0),4326);
+    END IF;
+  END IF;
+  RETURN NEWgeometry;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION geometry_sector(place geometry) RETURNS INTEGER
+  AS $$
+DECLARE
+  NEWgeometry geometry;
+BEGIN
+--  RAISE WARNING '%',place;
+  NEWgeometry := place;
+  IF ST_IsEmpty(NEWgeometry) OR NOT ST_IsValid(NEWgeometry) OR ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+    NEWgeometry := ST_buffer(NEWgeometry,0);
+    IF ST_IsEmpty(NEWgeometry) OR NOT ST_IsValid(NEWgeometry) OR ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+      RETURN 0;
+    END IF;
+  END IF;
+  RETURN (500-ST_X(ST_Centroid(NEWgeometry))::integer)*1000 + (500-ST_Y(ST_Centroid(NEWgeometry))::integer);
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION debug_geometry_sector(osmid integer, place geometry) RETURNS INTEGER
+  AS $$
+DECLARE
+  NEWgeometry geometry;
+BEGIN
+--  RAISE WARNING '%',osmid;
+  IF osmid = 61315 THEN
+    return null;
+  END IF;
+  NEWgeometry := place;
+  IF ST_IsEmpty(NEWgeometry) OR NOT ST_IsValid(NEWgeometry) OR ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+    NEWgeometry := ST_buffer(NEWgeometry,0);
+    IF ST_IsEmpty(NEWgeometry) OR NOT ST_IsValid(NEWgeometry) OR ST_X(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEWgeometry))::text in ('NaN','Infinity','-Infinity') THEN  
+      RETURN NULL;
+    END IF;
+  END IF;
+  RETURN (500-ST_X(ST_Centroid(NEWgeometry))::integer)*1000 + (500-ST_Y(ST_Centroid(NEWgeometry))::integer);
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION geometry_index(place geometry,indexed BOOLEAN,name keyvalue[]) RETURNS INTEGER
+  AS $$
+BEGIN
+IF indexed THEN RETURN NULL; END IF;
+IF name is null THEN RETURN NULL; END IF;
+RETURN geometry_sector(place);
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION geometry_index(sector integer, indexed BOOLEAN, name keyvalue[]) RETURNS INTEGER
+  AS $$
+BEGIN
+IF indexed THEN RETURN NULL; END IF;
+IF name is null THEN RETURN NULL; END IF;
+RETURN sector;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION transliteration(text) RETURNS text
+  AS '/home/brian/nominatim/live/osm2pgsql/gazetteer/gazetteer.so', 'transliteration'
+LANGUAGE c IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION gettokenstring(text) RETURNS text
+  AS '/home/brian/nominatim/live/osm2pgsql/gazetteer/gazetteer.so', 'gettokenstring'
+LANGUAGE c IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION make_standard_name(name TEXT) RETURNS TEXT
+  AS $$
+DECLARE
+  o TEXT;
+BEGIN
+  o := gettokenstring(transliteration(name));
+  RETURN trim(substr(o,1,length(o)));
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION getorcreate_word_id(lookup_word TEXT) 
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class is null and type is null into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, regexp_replace(lookup_token,E'([^0-9])\\1+',E'\\1','g'), null, null, null, null, 0, null);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_housenumber_id(lookup_word TEXT)
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class='place' and type='house' into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, null, null, 'place', 'house', null, 0, null);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_country(lookup_word TEXT, lookup_country_code varchar(2))
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and country_code=lookup_country_code into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, null, null, null, null, lookup_country_code, 0, null);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_amenity(lookup_word TEXT, lookup_class text, lookup_type text)
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class=lookup_class and type = lookup_type into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, null, null, lookup_class, lookup_type, null, 0, null);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_tagpair(lookup_class text, lookup_type text)
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := lookup_class||'='||lookup_type;
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, null, null, null, null, null, 0, null);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_tagpair(lookup_class text, lookup_type text)
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := lookup_class||'='||lookup_type;
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token into return_word_id;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_amenityoperator(lookup_word TEXT, lookup_class text, lookup_type text, op text)
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class=lookup_class and type = lookup_type and operator = op into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, null, null, lookup_class, lookup_type, null, 0, null, op);
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT, src_word TEXT) 
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  nospace_lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class is null and type is null into return_word_id;
+  IF return_word_id IS NULL THEN
+    return_word_id := nextval('seq_word');
+    INSERT INTO word VALUES (return_word_id, lookup_token, regexp_replace(lookup_token,E'([^0-9])\\1+',E'\\1','g'), src_word, null, null, null, 0, null);
+--    nospace_lookup_token := replace(replace(lookup_token, '-',''), ' ','');
+--    IF ' '||nospace_lookup_token != lookup_token THEN
+--      INSERT INTO word VALUES (return_word_id, '-'||nospace_lookup_token, null, src_word, null, null, null, 0, null);
+--    END IF;
+  END IF;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT) 
+  RETURNS INTEGER
+  AS $$
+DECLARE
+BEGIN
+  RETURN getorcreate_name_id(lookup_word, '');
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_word_id(lookup_word TEXT) 
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class is null and type is null into return_word_id;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_name_id(lookup_word TEXT) 
+  RETURNS INTEGER
+  AS $$
+DECLARE
+  lookup_token TEXT;
+  return_word_id INTEGER;
+BEGIN
+  lookup_token := ' '||trim(lookup_word);
+  SELECT min(word_id) FROM word WHERE word_token = lookup_token and class is null and type is null into return_word_id;
+  RETURN return_word_id;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION array_merge(a INTEGER[], b INTEGER[])
+  RETURNS INTEGER[]
+  AS $$
+DECLARE
+  i INTEGER;
+  r INTEGER[];
+BEGIN
+  IF array_upper(a, 1) IS NULL THEN
+    RETURN b;
+  END IF;
+  IF array_upper(b, 1) IS NULL THEN
+    RETURN a;
+  END IF;
+  r := a;
+  FOR i IN 1..array_upper(b, 1) LOOP  
+    IF NOT (ARRAY[b[i]] && r) THEN
+      r := r || b[i];
+    END IF;
+  END LOOP;
+  RETURN r;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION add_keywords(a keyvalue[], b keyvalue[]) RETURNS keyvalue[]
+  AS $$
+DECLARE
+  i INTEGER;
+  j INTEGER;
+  f BOOLEAN;
+  r keyvalue[];
+BEGIN
+  IF array_upper(a, 1) IS NULL THEN
+    RETURN b;
+  END IF;
+  IF array_upper(b, 1) IS NULL THEN
+    RETURN a;
+  END IF;
+  r := a;
+  FOR i IN 1..array_upper(b, 1) LOOP  
+    f := false;
+    FOR j IN 1..array_upper(a, 1) LOOP  
+      IF (a[j].key = b[i].key) THEN
+        f := true;
+      END IF; 
+    END LOOP;
+    IF NOT f THEN
+      r := r || b[i];
+    END IF;
+  END LOOP;
+  RETURN r;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION make_keywords(src HSTORE) RETURNS INTEGER[]
+  AS $$
+DECLARE
+  result INTEGER[];
+  s TEXT;
+  w INTEGER;
+  words TEXT[];
+  item RECORD;
+  j INTEGER;
+BEGIN
+  result := '{}'::INTEGER[];
+
+  FOR item IN SELECT (each(src)).* LOOP
+
+    s := make_standard_name(item.value);
+
+    w := getorcreate_name_id(s, item.value);
+    result := result | w;
+
+    words := string_to_array(s, ' ');
+    IF array_upper(words, 1) IS NOT NULL THEN
+      FOR j IN 1..array_upper(words, 1) LOOP
+        IF (words[j] != '') THEN
+          w = getorcreate_word_id(words[j]);
+          IF NOT (ARRAY[w] && result) THEN
+            result := result | w;
+          END IF;
+        END IF;
+      END LOOP;
+    END IF;
+
+    words := regexp_split_to_array(item.value, E'[,;()]');
+    IF array_upper(words, 1) != 1 THEN
+      FOR j IN 1..array_upper(words, 1) LOOP
+        s := make_standard_name(words[j]);
+        IF s != '' THEN
+          w := getorcreate_word_id(s);
+          IF NOT (ARRAY[w] && result) THEN
+            result := result | w;
+          END IF;
+        END IF;
+      END LOOP;
+    END IF;
+
+    s := regexp_replace(item.value, '市$', '');
+    IF s != item.value THEN
+      s := make_standard_name(s);
+      IF s != '' THEN
+        w := getorcreate_name_id(s, item.value);
+        IF NOT (ARRAY[w] && result) THEN
+          result := result | w;
+        END IF;
+      END IF;
+    END IF;
+
+  END LOOP;
+
+  RETURN result;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION make_keywords(src TEXT) RETURNS INTEGER[]
+  AS $$
+DECLARE
+  result INTEGER[];
+  s TEXT;
+  w INTEGER;
+  words TEXT[];
+  i INTEGER;
+  j INTEGER;
+BEGIN
+  result := '{}'::INTEGER[];
+
+  s := make_standard_name(src);
+  w := getorcreate_name_id(s);
+
+  IF NOT (ARRAY[w] && result) THEN
+    result := result || w;
+  END IF;
+
+  words := string_to_array(s, ' ');
+  IF array_upper(words, 1) IS NOT NULL THEN
+    FOR j IN 1..array_upper(words, 1) LOOP
+      IF (words[j] != '') THEN
+        w = getorcreate_word_id(words[j]);
+        IF NOT (ARRAY[w] && result) THEN
+          result := result || w;
+        END IF;
+      END IF;
+    END LOOP;
+  END IF;
+
+  RETURN result;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_word_score(wordscores wordscore[], words text[]) RETURNS integer
+  AS $$
+DECLARE
+  idxword integer;
+  idxscores integer;
+  result integer;
+BEGIN
+  IF (wordscores is null OR words is null) THEN
+    RETURN 0;
+  END IF;
+
+  result := 0;
+  FOR idxword in 1 .. array_upper(words, 1) LOOP
+    FOR idxscores in 1 .. array_upper(wordscores, 1) LOOP
+      IF wordscores[idxscores].word = words[idxword] THEN
+        result := result + wordscores[idxscores].score;
+      END IF;
+    END LOOP;
+  END LOOP;
+
+  RETURN result;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_country_code(place geometry) RETURNS TEXT
+  AS $$
+DECLARE
+  place_centre GEOMETRY;
+  nearcountry RECORD;
+BEGIN
+  place_centre := ST_Centroid(place);
+
+  -- Try for a OSM polygon first
+  FOR nearcountry IN select country_code from location_area where st_contains(area, place_centre) limit 1
+  LOOP
+    RETURN nearcountry.country_code;
+  END LOOP;
+
+  -- Try for an OSM polygon first, grid is faster
+  FOR nearcountry IN select country_code from country_osm_grid where st_contains(geometry, place_centre) limit 1
+  LOOP
+    RETURN nearcountry.country_code;
+  END LOOP;
+
+  -- Natural earth data (first fallback)
+--  FOR nearcountry IN select country_code from country_naturalearthdata where st_contains(geometry, place_centre) limit 1
+--  LOOP
+--    RETURN nearcountry.country_code;
+--  END LOOP;
+
+  -- WorldBoundaries data (second fallback - think there might be something broken in this data)
+  FOR nearcountry IN select country_code from country where st_contains(geometry, place_centre) limit 1
+  LOOP
+    RETURN nearcountry.country_code;
+  END LOOP;
+
+  -- Still not in a country - try nearest within ~12 miles of a country
+  FOR nearcountry IN select country_code from country where st_distance(geometry, place_centre) < 0.5 
+    order by st_distance(geometry, place) limit 1
+  LOOP
+    RETURN nearcountry.country_code;
+  END LOOP;
+
+  RETURN NULL;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_country_language_code(search_country_code VARCHAR(2)) RETURNS TEXT
+  AS $$
+DECLARE
+  nearcountry RECORD;
+BEGIN
+  FOR nearcountry IN select distinct country_default_language_code from country where country_code = search_country_code limit 1
+  LOOP
+    RETURN lower(nearcountry.country_default_language_code);
+  END LOOP;
+  RETURN NULL;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION delete_location(OLD_place_id BIGINT) RETURNS BOOLEAN
+  AS $$
+DECLARE
+BEGIN
+  DELETE FROM location_area where place_id = OLD_place_id;
+-- TODO:location_area
+  RETURN true;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION add_location(
+    place_id BIGINT,
+    place_country_code varchar(2),
+    name keyvalue[],
+    rank_search INTEGER,
+    rank_address INTEGER,
+    geometry GEOMETRY
+  ) 
+  RETURNS BOOLEAN
+  AS $$
+DECLARE
+  keywords INTEGER[];
+  country_code VARCHAR(2);
+  locationid INTEGER;
+  isarea BOOLEAN;
+  xmin INTEGER;
+  ymin INTEGER;
+  xmax INTEGER;
+  ymax INTEGER;
+  lon INTEGER;
+  lat INTEGER;
+  secgeo GEOMETRY;
+  diameter FLOAT;
+BEGIN
+
+  -- Allocate all tokens ids - prevents multi-processor race condition later on at cost of slowing down import
+  keywords := make_keywords(name);
+
+  -- 26 = street/highway
+  IF rank_search <= 26 THEN
+    IF place_country_code IS NULL THEN
+      country_code := get_country_code(geometry);
+    END IF;
+    country_code := lower(place_country_code);
+
+    isarea := false;
+    IF (ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_IsValid(geometry)) THEN
+
+      isArea := true;
+
+      xmin := floor(st_xmin(geometry));
+      xmax := ceil(st_xmax(geometry));
+      ymin := floor(st_ymin(geometry));
+      ymax := ceil(st_ymax(geometry));
+
+      IF xmin = xmax OR ymin = ymax OR (xmax-xmin < 2 AND ymax-ymin < 2) THEN
+        INSERT INTO location_area values (place_id, country_code, name, keywords,
+          rank_search, rank_address, false, ST_Centroid(geometry), geometry);
+      ELSE
+        FOR lon IN xmin..(xmax-1) LOOP
+          FOR lat IN ymin..(ymax-1) LOOP
+            secgeo := st_intersection(geometry, ST_SetSRID(ST_MakeBox2D(ST_Point(lon,lat),ST_Point(lon+1,lat+1)),4326));
+            IF NOT ST_IsEmpty(secgeo) AND ST_GeometryType(secgeo) in ('ST_Polygon','ST_MultiPolygon') THEN
+              INSERT INTO location_area values (place_id, country_code, name, keywords,
+                rank_search, rank_address, false, ST_Centroid(geometry),
+                st_intersection(geometry, ST_SetSRID(ST_MakeBox2D(ST_Point(lon,lat),ST_Point(lon+1,lat+1)),4326))
+                );
+            END IF;
+          END LOOP;
+        END LOOP;
+      END IF;
+
+    ELSE
+
+      diameter := 0.02;
+      IF rank_search = 14 THEN
+        diameter := 1;
+      ELSEIF rank_search = 15 THEN
+        diameter := 0.5;
+      ELSEIF rank_search = 16 THEN
+        diameter := 0.15;
+      ELSEIF rank_search = 17 THEN
+        diameter := 0.05;
+      ELSEIF rank_search = 25 THEN
+        diameter := 0.005;
+      ELSEIF rank_search = 26 THEN
+        diameter := 0.001;
+      END IF;
+
+      secgeo := ST_Buffer(geometry, diameter);
+      INSERT INTO location_area values (place_id, country_code, name, keywords,
+        rank_search, rank_address, true, ST_Centroid(geometry), secgeo);
+
+    END IF;
+
+    INSERT INTO location_point values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+
+    RETURN true;
+
+    IF not isarea THEN
+    IF rank_search < 26 THEN
+      INSERT INTO location_point_26 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 25 THEN
+      INSERT INTO location_point_25 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 24 THEN
+      INSERT INTO location_point_24 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 23 THEN
+      INSERT INTO location_point_23 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 22 THEN
+      INSERT INTO location_point_22 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 21 THEN
+      INSERT INTO location_point_21 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 20 THEN
+      INSERT INTO location_point_20 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 19 THEN
+      INSERT INTO location_point_19 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 18 THEN
+      INSERT INTO location_point_18 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 17 THEN
+      INSERT INTO location_point_17 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 16 THEN
+      INSERT INTO location_point_16 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 15 THEN
+      INSERT INTO location_point_15 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 14 THEN
+      INSERT INTO location_point_14 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 13 THEN
+      INSERT INTO location_point_13 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 12 THEN
+      INSERT INTO location_point_12 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 11 THEN
+      INSERT INTO location_point_11 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 10 THEN
+      INSERT INTO location_point_10 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 9 THEN
+      INSERT INTO location_point_9 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 8 THEN
+      INSERT INTO location_point_8 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 7 THEN
+      INSERT INTO location_point_7 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 6 THEN
+      INSERT INTO location_point_6 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 5 THEN
+      INSERT INTO location_point_5 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 4 THEN
+      INSERT INTO location_point_4 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 3 THEN
+      INSERT INTO location_point_3 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 2 THEN
+      INSERT INTO location_point_2 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    IF rank_search < 1 THEN
+      INSERT INTO location_point_1 values (place_id,country_code,name,keywords,rank_search,rank_address,isarea,ST_Centroid(geometry));
+    END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;
+    END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;END IF;
+    END IF;END IF;END IF;END IF;END IF;END IF;END IF;
+    RETURN true;
+  END IF;
+
+  RETURN false;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION update_location(
+    place_id BIGINT,
+    place_country_code varchar(2),
+    name keyvalue[],
+    rank_search INTEGER,
+    rank_address INTEGER,
+    geometry GEOMETRY
+  ) 
+  RETURNS BOOLEAN
+  AS $$
+DECLARE
+  b BOOLEAN;
+BEGIN
+  b := delete_location(place_id);
+  RETURN add_location(place_id, place_country_code, name, rank_search, rank_address, geometry);
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION search_name_add_words(parent_place_id BIGINT, to_add INTEGER[])
+  RETURNS BOOLEAN
+  AS $$
+DECLARE
+  childplace RECORD;
+BEGIN
+
+  IF #to_add = 0 THEN
+    RETURN true;
+  END IF;
+
+  -- this should just be an update, but it seems to do insane things to the index size (delete and insert doesn't)
+  FOR childplace IN select * from search_name,place_addressline 
+    where  address_place_id = parent_place_id
+      and search_name.place_id = place_addressline.place_id
+  LOOP
+    delete from search_name where place_id = childplace.place_id;
+    childplace.nameaddress_vector := uniq(sort_asc(childplace.nameaddress_vector + to_add));
+    IF childplace.place_id = parent_place_id THEN
+      childplace.name_vector := uniq(sort_asc(childplace.name_vector + to_add));
+    END IF;
+    insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) 
+      values (childplace.place_id, childplace.search_rank, childplace.address_rank, childplace.country_code, 
+        childplace.name_vector, childplace.nameaddress_vector, childplace.centroid);
+  END LOOP;
+
+  RETURN true;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION update_location_nameonly(OLD_place_id BIGINT, name keyvalue[]) RETURNS BOOLEAN
+  AS $$
+DECLARE
+  newkeywords INTEGER[];
+  addedkeywords INTEGER[];
+  removedkeywords INTEGER[];
+BEGIN
+
+  -- what has changed?
+  newkeywords := make_keywords(name);
+  select coalesce(newkeywords,'{}'::INTEGER[]) - coalesce(location_point.keywords,'{}'::INTEGER[]), 
+    coalesce(location_point.keywords,'{}'::INTEGER[]) - coalesce(newkeywords,'{}'::INTEGER[]) from location_point 
+    where place_id = OLD_place_id into addedkeywords, removedkeywords;
+
+--  RAISE WARNING 'update_location_nameonly for %: new:% added:% removed:%', OLD_place_id, newkeywords, addedkeywords, removedkeywords;
+
+  IF #removedkeywords > 0 THEN
+    -- abort due to tokens removed
+    RETURN false;
+  END IF;
+  
+  IF #addedkeywords > 0 THEN
+    -- short circuit - no changes
+    RETURN true;
+  END IF;
+
+  UPDATE location_area set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_0 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_1 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_2 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_3 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_4 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_5 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_6 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_7 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_8 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_9 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_10 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_11 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_12 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_13 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_14 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_15 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_16 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_17 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_18 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_19 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_20 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_21 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_22 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_23 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_24 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_25 set keywords = newkeywords where place_id = OLD_place_id;
+  UPDATE location_point_26 set keywords = newkeywords where place_id = OLD_place_id;
+
+  RETURN search_name_add_words(OLD_place_id, addedkeywords);
+END;
+$$
+LANGUAGE plpgsql;
+
+
+CREATE OR REPLACE FUNCTION create_interpolation(wayid BIGINT, interpolationtype TEXT) RETURNS INTEGER
+  AS $$
+DECLARE
+  
+  newpoints INTEGER;
+  waynodes integer[];
+  nodeid INTEGER;
+  prevnode RECORD;
+  nextnode RECORD;
+  startnumber INTEGER;
+  endnumber INTEGER;
+  stepsize INTEGER;
+  orginalstartnumber INTEGER;
+  originalnumberrange INTEGER;
+  housenum INTEGER;
+  linegeo GEOMETRY;
+  search_place_id INTEGER;
+
+  havefirstpoint BOOLEAN;
+  linestr TEXT;
+BEGIN
+  newpoints := 0;
+  IF interpolationtype = 'odd' OR interpolationtype = 'even' OR interpolationtype = 'all' THEN
+
+    select nodes from planet_osm_ways where id = wayid INTO waynodes;
+--RAISE WARNING 'interpolation % % %',wayid,interpolationtype,waynodes;
+    IF array_upper(waynodes, 1) IS NOT NULL THEN
+
+      havefirstpoint := false;
+
+      FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP
+
+        select min(place_id) from placex where osm_type = 'N' and osm_id = waynodes[nodeidpos]::bigint and type = 'house' INTO search_place_id;
+        IF search_place_id IS NULL THEN
+          -- null record of right type
+          select * from placex where osm_type = 'N' and osm_id = waynodes[nodeidpos]::bigint and type = 'house' limit 1 INTO nextnode;
+          select ST_SetSRID(ST_Point(lon::float/10000000,lat::float/10000000),4326) from planet_osm_nodes where id = waynodes[nodeidpos] INTO nextnode.geometry;
+        ELSE
+          select * from placex where place_id = search_place_id INTO nextnode;
+        END IF;
+
+--RAISE WARNING 'interpolation node % % % ',nextnode.housenumber,ST_X(nextnode.geometry),ST_Y(nextnode.geometry);
+      
+        IF havefirstpoint THEN
+
+          -- add point to the line string
+          linestr := linestr||','||ST_X(nextnode.geometry)||' '||ST_Y(nextnode.geometry);
+          endnumber := ('0'||substring(nextnode.housenumber,'[0-9]+'))::integer;
+
+          IF startnumber IS NOT NULL and startnumber > 0 AND endnumber IS NOT NULL and endnumber > 0 THEN
+
+--RAISE WARNING 'interpolation end % % ',nextnode.place_id,endnumber;
+
+            IF startnumber != endnumber THEN
+
+              linestr := linestr || ')';
+--RAISE WARNING 'linestr %',linestr;
+              linegeo := ST_GeomFromText(linestr,4326);
+              linestr := 'LINESTRING('||ST_X(nextnode.geometry)||' '||ST_Y(nextnode.geometry);
+              IF (startnumber > endnumber) THEN
+                housenum := endnumber;
+                endnumber := startnumber;
+                startnumber := housenum;
+                linegeo := ST_Reverse(linegeo);
+              END IF;
+              orginalstartnumber := startnumber;
+              originalnumberrange := endnumber - startnumber;
+
+-- Too much broken data worldwide for this test to be worth using
+--              IF originalnumberrange > 500 THEN
+--                RAISE WARNING 'Number block of % while processing % %', originalnumberrange, prevnode, nextnode;
+--              END IF;
+
+              IF (interpolationtype = 'odd' AND startnumber%2 = 0) OR (interpolationtype = 'even' AND startnumber%2 = 1) THEN
+                startnumber := startnumber + 1;
+                stepsize := 2;
+              ELSE
+                IF (interpolationtype = 'odd' OR interpolationtype = 'even') THEN
+                  startnumber := startnumber + 2;
+                  stepsize := 2;
+                ELSE -- everything else assumed to be 'all'
+                  startnumber := startnumber + 1;
+                  stepsize := 1;
+                END IF;
+              END IF;
+              endnumber := endnumber - 1;
+              delete from placex where osm_type = 'N' and osm_id = prevnode.osm_id and type = 'house' and place_id != prevnode.place_id;
+              FOR housenum IN startnumber..endnumber BY stepsize LOOP
+                -- this should really copy postcodes but it puts a huge burdon on the system for no big benefit
+                -- ideally postcodes should move up to the way
+                insert into placex values (null,'N',prevnode.osm_id,prevnode.class,prevnode.type,NULL,prevnode.admin_level,housenum,prevnode.street,prevnode.isin,null,prevnode.country_code,prevnode.street_place_id,prevnode.rank_address,prevnode.rank_search,false,ST_Line_Interpolate_Point(linegeo, (housenum::float-orginalstartnumber::float)/originalnumberrange::float));
+                newpoints := newpoints + 1;
+--RAISE WARNING 'interpolation number % % ',prevnode.place_id,housenum;
+              END LOOP;
+            END IF;
+            havefirstpoint := false;
+          END IF;
+        END IF;
+
+        IF NOT havefirstpoint THEN
+          startnumber := ('0'||substring(nextnode.housenumber,'[0-9]+'))::integer;
+          IF startnumber IS NOT NULL AND startnumber > 0 THEN
+            havefirstpoint := true;
+            linestr := 'LINESTRING('||ST_X(nextnode.geometry)||' '||ST_Y(nextnode.geometry);
+            prevnode := nextnode;
+          END IF;
+--RAISE WARNING 'interpolation start % % ',nextnode.place_id,startnumber;
+        END IF;
+      END LOOP;
+    END IF;
+  END IF;
+
+--RAISE WARNING 'interpolation points % ',newpoints;
+
+  RETURN newpoints;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION placex_insert() RETURNS TRIGGER
+  AS $$
+DECLARE
+  i INTEGER;
+  postcode TEXT;
+  result BOOLEAN;
+  country_code VARCHAR(2);
+  diameter FLOAT;
+BEGIN
+--  RAISE WARNING '%',NEW.osm_id;
+--  RAISE WARNING '%',NEW.osm_id;
+
+  -- just block these
+  IF NEW.class = 'highway' and NEW.type in ('turning_circle','traffic_signals','mini_roundabout','noexit','crossing') THEN
+    RETURN null;
+  END IF;
+  IF NEW.class in ('landuse','natural') and NEW.name is null THEN
+    RETURN null;
+  END IF;
+
+--  RAISE WARNING '%',NEW.osm_id;
+  IF ST_IsEmpty(NEW.geometry) OR NOT ST_IsValid(NEW.geometry) OR ST_X(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') THEN  
+    -- block all invalid geometary - just not worth the risk.  seg faults are causing serious problems.
+    RETURN NULL;
+
+    -- Dead code
+    IF NEW.osm_type = 'R' THEN
+      -- invalid multipolygons can crash postgis, don't even bother to try!
+      RETURN NULL;
+    END IF;
+    NEW.geometry := ST_buffer(NEW.geometry,0);
+    IF ST_IsEmpty(NEW.geometry) OR NOT ST_IsValid(NEW.geometry) OR ST_X(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') THEN  
+      RAISE WARNING 'Invalid geometary, rejecting: % %', NEW.osm_type, NEW.osm_id;
+      RETURN NULL;
+    END IF;
+  END IF;
+
+  NEW.place_id := nextval('seq_place');
+  NEW.indexed := false;
+  NEW.country_code := lower(NEW.country_code);
+  NEW.geometry_sector := geometry_sector(NEW.geometry);
+
+  IF NEW.admin_level > 15 THEN
+    NEW.admin_level := 15;
+  END IF;
+
+  IF NEW.housenumber IS NOT NULL THEN
+    i := getorcreate_housenumber_id(make_standard_name(NEW.housenumber));
+  END IF;
+
+  IF NEW.osm_type = 'X' THEN
+    -- E'X'ternal records should already be in the right format so do nothing
+  ELSE
+    NEW.rank_search := 30;
+    NEW.rank_address := NEW.rank_search;
+
+    -- By doing in postgres we have the country available to us - currently only used for postcode
+    IF NEW.class = 'place' THEN
+      IF NEW.type in ('continent') THEN
+        NEW.rank_search := 2;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('sea') THEN
+        NEW.rank_search := 2;
+        NEW.rank_address := 0;
+      ELSEIF NEW.type in ('country') THEN
+        NEW.rank_search := 4;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('state') THEN
+        NEW.rank_search := 8;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('region') THEN
+        NEW.rank_search := 10;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('county') THEN
+        NEW.rank_search := 12;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('city') THEN
+        NEW.rank_search := 16;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('island') THEN
+        NEW.rank_search := 17;
+        NEW.rank_address := 0;
+      ELSEIF NEW.type in ('town') THEN
+        NEW.rank_search := 17;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('village','hamlet','municipality','district','unincorporated_area','borough') THEN
+        NEW.rank_search := 18;
+        NEW.rank_address := 17;
+      ELSEIF NEW.type in ('airport') AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') THEN
+        NEW.rank_search := 18;
+        NEW.rank_address := 17;
+      ELSEIF NEW.type in ('moor') AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') THEN
+        NEW.rank_search := 17;
+        NEW.rank_address := 18;
+      ELSEIF NEW.type in ('moor') THEN
+        NEW.rank_search := 17;
+        NEW.rank_address := 0;
+      ELSEIF NEW.type in ('national_park') THEN
+        NEW.rank_search := 18;
+        NEW.rank_address := 18;
+      ELSEIF NEW.type in ('suburb','croft','subdivision') THEN
+        NEW.rank_search := 20;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('farm','locality','islet') THEN
+        NEW.rank_search := 20;
+        NEW.rank_address := 0;
+      ELSEIF NEW.type in ('hall_of_residence','neighbourhood','housing_estate','nature_reserve') THEN
+        NEW.rank_search := 22;
+        NEW.rank_address := 22;
+      ELSEIF NEW.type in ('postcode') THEN
+
+        -- Postcode processing is very country dependant
+        IF NEW.country_code IS NULL THEN
+          NEW.country_code := get_country_code(NEW.geometry);
+        END IF;
+
+        NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+
+        IF NEW.country_code = 'gb' THEN
+
+          IF NEW.postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9][A-Z][A-Z])$' THEN
+            NEW.rank_search := 25;
+            NEW.rank_address := 5;
+            NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+          ELSEIF NEW.postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])$' THEN
+            NEW.rank_search := 23;
+            NEW.rank_address := 5;
+            NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+          ELSEIF NEW.postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z])$' THEN
+            NEW.rank_search := 21;
+            NEW.rank_address := 5;
+            NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+          END IF;
+
+        ELSEIF NEW.country_code = 'de' THEN
+
+          IF NEW.postcode ~ '^([0-9]{5})$' THEN
+            NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+            NEW.rank_search := 21;
+            NEW.rank_address := 11;
+          END IF;
+
+        ELSE
+          -- Guess at the postcode format and coverage (!)
+          IF upper(NEW.postcode) ~ '^[A-Z0-9]{1,5}$' THEN -- Probably too short to be very local
+            NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+            NEW.rank_search := 21;
+            NEW.rank_address := 11;
+          ELSE
+            -- Does it look splitable into and area and local code?
+            postcode := substring(upper(NEW.postcode) from '^([- :A-Z0-9]+)([- :][A-Z0-9]+)$');
+
+            IF postcode IS NOT NULL THEN
+
+              -- TODO: insert new line into location instead
+              --result := add_location(NEW.place_id,NEW.country_code,ARRAY[ROW('ref',postcode)::keyvalue],21,11,NEW.geometry);
+
+              NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+              NEW.rank_search := 25;
+              NEW.rank_address := 11;
+            ELSEIF NEW.postcode ~ '^[- :A-Z0-9]{6,}$' THEN
+              NEW.name := ARRAY[ROW('ref',NEW.postcode)::keyvalue];
+              NEW.rank_search := 21;
+              NEW.rank_address := 11;
+            END IF;
+          END IF;
+        END IF;
+
+      ELSEIF NEW.type in ('airport','street') THEN
+        NEW.rank_search := 26;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('house','building') THEN
+        NEW.rank_search := 28;
+        NEW.rank_address := NEW.rank_search;
+      ELSEIF NEW.type in ('houses') THEN
+        -- can't guarantee all required nodes loaded yet due to caching in osm2pgsql
+        -- insert new point into place for each derived building
+        --i := create_interpolation(NEW.osm_id, NEW.housenumber);
+      END IF;
+
+    ELSEIF NEW.class = 'boundary' THEN
+      IF NEW.country_code is null THEN
+        NEW.country_code := get_country_code(NEW.geometry);
+      END IF;
+      NEW.rank_search := NEW.admin_level * 2;
+      NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'landuse' AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') THEN
+      NEW.rank_search := 22;
+      NEW.rank_address := NEW.rank_search;
+    -- any feature more than 5 square miles is probably worth indexing
+    ELSEIF ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_Area(NEW.geometry) > 0.1 THEN
+      NEW.rank_search := 22;
+      NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'highway' AND NEW.name is NULL AND 
+           NEW.type in ('service','cycleway','path','footway','steps','bridleway','track','byway','motorway_link','primary_link','trunk_link','secondary_link','tertiary_link') THEN
+      RETURN NULL;
+    ELSEIF NEW.class = 'railway' AND NEW.type in ('rail') THEN
+      RETURN NULL;
+    ELSEIF NEW.class = 'waterway' AND NEW.name is NULL THEN
+      RETURN NULL;
+    ELSEIF NEW.class = 'waterway' THEN
+      NEW.rank_address := 17;
+    ELSEIF NEW.class = 'highway' AND NEW.osm_type != 'N' AND NEW.type in ('service','cycleway','path','footway','steps','bridleway','motorway_link','primary_link','trunk_link','secondary_link','tertiary_link') THEN
+      NEW.rank_search := 27;
+      NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'highway' AND NEW.osm_type != 'N' THEN
+      NEW.rank_search := 26;
+      NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'natural' and NEW.type = 'sea' THEN
+      NEW.rank_search := 4;
+      NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'natural' and NEW.type in ('coastline') THEN
+      RETURN NULL;
+    ELSEIF NEW.class = 'natural' and NEW.type in ('peak','volcano') THEN
+      NEW.rank_search := 18;
+      NEW.rank_address := 0;
+    END IF;
+
+  END IF;
+
+  IF NEW.rank_search > 30 THEN
+    NEW.rank_search := 30;
+  END IF;
+
+  IF NEW.rank_address > 30 THEN
+    NEW.rank_address := 30;
+  END IF;
+
+-- Block import below rank 22
+--  IF NEW.rank_search > 22 THEN
+--    RETURN NULL;
+--  END IF;
+
+  IF array_upper(NEW.name, 1) is not null THEN
+    result := add_location(NEW.place_id,NEW.country_code,NEW.name,NEW.rank_search,NEW.rank_address,NEW.geometry);
+  END IF;
+
+  --RETURN NEW;
+  -- The following is not needed until doing diff updates, and slows the main index process down
+
+  IF (ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_IsValid(NEW.geometry)) THEN
+    -- Performance: We just can't handle re-indexing for country level changes
+    IF st_area(NEW.geometry) < 1 THEN
+      -- mark items within the geometry for re-indexing
+--    RAISE WARNING 'placex poly insert: % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+-- work around bug in postgis
+      update placex set indexed = false where indexed and (ST_Contains(NEW.geometry, placex.geometry) OR ST_Intersects(NEW.geometry, placex.geometry)) 
+       AND rank_search > NEW.rank_search and ST_geometrytype(placex.geometry) = 'ST_Point';
+      update placex set indexed = false where indexed and (ST_Contains(NEW.geometry, placex.geometry) OR ST_Intersects(NEW.geometry, placex.geometry)) 
+       AND rank_search > NEW.rank_search and ST_geometrytype(placex.geometry) != 'ST_Point';
+    END IF;
+  ELSE
+    -- mark nearby items for re-indexing, where 'nearby' depends on the features rank_search and is a complete guess :(
+    diameter := 0;
+    -- 16 = city, anything higher than city is effectively ignored (polygon required!)
+    IF NEW.type='postcode' THEN
+      diameter := 0.001;
+    ELSEIF NEW.rank_search < 16 THEN
+      diameter := 0;
+    ELSEIF NEW.rank_search < 18 THEN
+      diameter := 0.1;
+    ELSEIF NEW.rank_search < 20 THEN
+      diameter := 0.05;
+    ELSEIF NEW.rank_search = 21 THEN
+      diameter := 0.001;
+    ELSEIF NEW.rank_search < 24 THEN
+      diameter := 0.02;
+    ELSEIF NEW.rank_search < 26 THEN
+      diameter := 0.002; -- 100 to 200 meters
+    ELSEIF NEW.rank_search < 28 THEN
+      diameter := 0.001; -- 50 to 100 meters
+    END IF;
+    IF diameter > 0 THEN
+--      RAISE WARNING 'placex point insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,diameter;
+      update placex set indexed = false where indexed and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter);
+    END IF;
+
+  END IF;
+
+--  IF NEW.rank_search < 26 THEN
+--    RAISE WARNING 'placex insert: % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+--  END IF;
+
+  RETURN NEW;
+
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION placex_update() RETURNS 
+TRIGGER
+  AS $$
+DECLARE
+
+  place_centroid GEOMETRY;
+  place_geometry_text TEXT;
+
+  search_maxdistance FLOAT[];
+  search_mindistance FLOAT[];
+  address_havelevel BOOLEAN[];
+--  search_scores wordscore[];
+--  search_scores_pos INTEGER;
+  search_country_code_conflict BOOLEAN;
+
+  i INTEGER;
+  iMax FLOAT;
+  location RECORD;
+  relation RECORD;
+  search_diameter FLOAT;
+  search_prevdiameter FLOAT;
+  search_maxrank INTEGER;
+  address_maxrank INTEGER;
+  address_street_word_id INTEGER;
+  street_place_id_count INTEGER;
+  isin TEXT[];
+  tagpairid INTEGER;
+
+  bPointCountryCode BOOLEAN;
+
+  name_vector INTEGER[];
+  nameaddress_vector INTEGER[];
+
+  result BOOLEAN;
+
+BEGIN
+
+--  RAISE WARNING '%',NEW.place_id;
+--RAISE WARNING '%', NEW;
+
+  IF NEW.class = 'place' AND NEW.type = 'postcodearea' THEN
+    -- Silently do nothing
+    RETURN NEW;
+  END IF;
+
+  NEW.country_code := lower(NEW.country_code);
+
+  IF NEW.indexed and NOT OLD.indexed THEN
+
+    IF NEW.class = 'place' AND NEW.type = 'houses' THEN
+      i := create_interpolation(NEW.osm_id, NEW.housenumber);
+      RETURN NEW;
+    END IF;
+
+--RAISE WARNING 'PROCESSING: % %', NEW.place_id, NEW.name;
+
+    search_country_code_conflict := false;
+
+    DELETE FROM search_name WHERE place_id = NEW.place_id;
+--RAISE WARNING 'x1';
+    DELETE FROM place_addressline WHERE place_id = NEW.place_id;
+--RAISE WARNING 'x2';
+    DELETE FROM place_boundingbox where place_id = NEW.place_id;
+
+    -- Adding ourselves to the list simplifies address calculations later
+    INSERT INTO place_addressline VALUES (NEW.place_id, NEW.place_id, true, true, 0, NEW.rank_address); 
+--RAISE WARNING 'x3';
+
+    -- What level are we searching from
+    search_maxrank := NEW.rank_search;
+
+    -- Default max/min distances to look for a location
+    FOR i IN 1..28 LOOP
+      search_maxdistance[i] := 1;
+      search_mindistance[i] := 0.0;
+      address_havelevel[i] := false;
+    END LOOP;
+    -- Minimum size to search, can be larger but don't let it shink below this
+    search_mindistance[14] := 0.2;
+    search_mindistance[15] := 0.1;
+    search_mindistance[16] := 0.05;
+    search_mindistance[17] := 0.03;
+    search_mindistance[18] := 0.015;
+    search_mindistance[19] := 0.008;
+    search_mindistance[20] := 0.006;
+    search_mindistance[21] := 0.004;
+    search_mindistance[22] := 0.003;
+    search_mindistance[23] := 0.002;
+    search_mindistance[24] := 0.002;
+    search_mindistance[25] := 0.001;
+    search_mindistance[26] := 0.001;
+
+    search_maxdistance[14] := 1;
+    search_maxdistance[15] := 0.5;
+    search_maxdistance[16] := 0.15;
+    search_maxdistance[17] := 0.05;
+    search_maxdistance[18] := 0.02;
+    search_maxdistance[19] := 0.02;
+    search_maxdistance[20] := 0.02;
+    search_maxdistance[21] := 0.02;
+    search_maxdistance[22] := 0.02;
+    search_maxdistance[23] := 0.02;
+    search_maxdistance[24] := 0.02;
+    search_maxdistance[25] := 0.02;
+    search_maxdistance[26] := 0.02;
+
+    -- Speed up searches - just use the centroid of the feature
+    -- cheaper but less acurate
+    place_centroid := ST_Centroid(NEW.geometry);
+    place_geometry_text := 'ST_GeomFromText('''||ST_AsText(NEW.geometry)||''','||ST_SRID(NEW.geometry)||')';
+
+    -- copy the building number to the name
+    -- done here rather than on insert to avoid initial indexing
+    -- TODO: This might be a silly thing to do
+    --IF (NEW.name IS NULL OR array_upper(NEW.name,1) IS NULL) AND NEW.housenumber IS NOT NULL THEN
+    --  NEW.name := ARRAY[ROW('ref',NEW.housenumber)::keyvalue];
+    --END IF;
+
+    --Temp hack to prevent need to re-index
+    IF NEW.name::text = '{"(ref,'||NEW.housenumber||')"}' THEN
+      NEW.name := NULL;
+    END IF;
+
+    --IF (NEW.name IS NULL OR array_upper(NEW.name,1) IS NULL) AND NEW.type IS NOT NULL THEN
+    --  NEW.name := ARRAY[ROW('type',NEW.type)::keyvalue];
+    --END IF;
+
+    -- Initialise the name and address vectors using our name
+    name_vector := make_keywords(NEW.name);
+    nameaddress_vector := name_vector;
+
+    -- some tag combinations add a special id for search
+    tagpairid := get_tagpair(NEW.class,NEW.type);
+    IF tagpairid IS NOT NULL THEN
+      name_vector := name_vector + tagpairid;
+    END IF;
+
+--RAISE WARNING '% %', NEW.place_id, NEW.rank_search;
+
+    -- For low level elements we inherit from our parent road
+    IF (NEW.rank_search > 27 OR (NEW.type = 'postcode' AND NEW.rank_search = 25)) THEN
+
+--RAISE WARNING 'finding street for %', NEW;
+
+      NEW.street_place_id := null;
+
+      -- to do that we have to find our parent road
+      -- Copy data from linked items (points on ways, addr:street links, relations)
+      -- Note that addr:street links can only be indexed once the street itself is indexed
+      IF NEW.street_place_id IS NULL AND NEW.osm_type = 'N' THEN
+
+        -- Is this node part of a relation?
+        FOR relation IN select * from planet_osm_rels where parts @> ARRAY[NEW.osm_id::integer] and members @> ARRAY['n'||NEW.osm_id]
+        LOOP
+          -- At the moment we only process one type of relation - associatedStreet
+          IF relation.tags @> ARRAY['associatedStreet'] AND array_upper(relation.members, 1) IS NOT NULL THEN
+            FOR i IN 1..array_upper(relation.members, 1) BY 2 LOOP
+              IF NEW.street_place_id IS NULL AND relation.members[i+1] = 'street' THEN
+--RAISE WARNING 'node in relation %',relation;
+                SELECT place_id from placex where osm_type='W' and osm_id = substring(relation.members[i],2,200)::integer 
+                  and rank_search = 26 INTO NEW.street_place_id;
+              END IF;
+            END LOOP;
+          END IF;
+        END LOOP;      
+
+--RAISE WARNING 'x1';
+        -- Is this node part of a way?
+        FOR location IN select * from placex where osm_type = 'W' 
+          and osm_id in (select id from planet_osm_ways where nodes && ARRAY[NEW.osm_id::integer])
+        LOOP
+--RAISE WARNING '%', location;
+          -- Way IS a road then we are on it - that must be our road
+          IF location.rank_search = 26 AND NEW.street_place_id IS NULL THEN
+--RAISE WARNING 'node in way that is a street %',location;
+            NEW.street_place_id := location.place_id;
+          END IF;
+
+          -- Is the WAY part of a relation
+          FOR relation IN select * from planet_osm_rels where parts @> ARRAY[location.osm_id::integer] and members @> ARRAY['w'||location.osm_id]
+          LOOP
+            -- At the moment we only process one type of relation - associatedStreet
+            IF relation.tags @> ARRAY['associatedStreet'] AND array_upper(relation.members, 1) IS NOT NULL THEN
+              FOR i IN 1..array_upper(relation.members, 1) BY 2 LOOP
+                IF NEW.street_place_id IS NULL AND relation.members[i+1] = 'street' THEN
+--RAISE WARNING 'node in way that is in a relation %',relation;
+                  SELECT place_id from placex where osm_type='W' and osm_id = substring(relation.members[i],2,200)::integer 
+                    and rank_search = 26 INTO NEW.street_place_id;
+                END IF;
+              END LOOP;
+            END IF;
+          END LOOP;
+          
+          -- If the way contains an explicit name of a street copy it
+          IF NEW.street IS NULL AND location.street IS NOT NULL THEN
+--RAISE WARNING 'node in way that has a streetname %',location;
+            NEW.street := location.street;
+          END IF;
+
+          -- If this way is a street interpolation line then it is probably as good as we are going to get
+          IF NEW.street_place_id IS NULL AND NEW.street IS NULL AND location.class = 'place' and location.type='houses' THEN
+            -- Try and find a way that is close roughly parellel to this line
+            FOR relation IN SELECT place_id FROM placex
+              WHERE ST_DWithin(location.geometry, placex.geometry, 0.001) and placex.rank_search = 26
+              ORDER BY (ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,0))+
+                        ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,0.5))+
+                        ST_distance(placex.geometry, ST_Line_Interpolate_Point(location.geometry,1))) ASC limit 1
+            LOOP
+--RAISE WARNING 'using nearest street to address interpolation line,0.001 %',relation;
+              NEW.street_place_id := relation.place_id;
+            END LOOP;
+          END IF;
+
+        END LOOP;
+                
+      END IF;
+
+--RAISE WARNING 'x2';
+
+      IF NEW.street_place_id IS NULL AND NEW.osm_type = 'W' THEN
+        -- Is this way part of a relation?
+        FOR relation IN select * from planet_osm_rels where parts @> ARRAY[NEW.osm_id::integer] and members @> ARRAY['w'||NEW.osm_id]
+        LOOP
+          -- At the moment we only process one type of relation - associatedStreet
+          IF relation.tags @> ARRAY['associatedStreet'] AND array_upper(relation.members, 1) IS NOT NULL THEN
+            FOR i IN 1..array_upper(relation.members, 1) BY 2 LOOP
+              IF NEW.street_place_id IS NULL AND relation.members[i+1] = 'street' THEN
+--RAISE WARNING 'way that is in a relation %',relation;
+                SELECT place_id from placex where osm_type='W' and osm_id = substring(relation.members[i],2,200)::integer
+                  and rank_search = 26 INTO NEW.street_place_id;
+              END IF;
+            END LOOP;
+          END IF;
+        END LOOP;
+      END IF;
+      
+--RAISE WARNING 'x3';
+
+      IF NEW.street_place_id IS NULL AND NEW.street IS NOT NULL THEN
+       address_street_word_id := get_name_id(make_standard_name(NEW.street));
+--RAISE WARNING 'street: % %', NEW.street, address_street_word_id;
+        IF address_street_word_id IS NOT NULL THEN
+          FOR location IN SELECT place_id,ST_distance(NEW.geometry, search_name.centroid) as distance 
+            FROM search_name WHERE search_name.name_vector @> ARRAY[address_street_word_id]
+            AND ST_DWithin(NEW.geometry, search_name.centroid, 0.01) and search_rank between 22 and 27
+            ORDER BY ST_distance(NEW.geometry, search_name.centroid) ASC limit 1
+          LOOP
+--RAISE WARNING 'streetname found nearby %',location;
+            NEW.street_place_id := location.place_id;
+          END LOOP;
+        END IF;
+        -- Failed, fall back to nearest - don't just stop
+        IF NEW.street_place_id IS NULL THEN
+--RAISE WARNING 'unable to find streetname nearby % %',NEW.street,address_street_word_id;
+--          RETURN null;
+        END IF;
+      END IF;
+
+--RAISE WARNING 'x4';
+
+<<<<<<< .mine
+      IF NEW.street_place_id IS NULL THEN
+        FOR location IN SELECT place_id
+          FROM location_area
+          WHERE ST_Contains(area, place_centroid) and location_area.rank_search = 26
+          ORDER BY ST_Distance(place_centroid, centroid) ASC limit 1
+=======
+      search_diameter := 0.00005;
+      WHILE NEW.street_place_id IS NULL AND search_diameter < 0.1 LOOP
+--RAISE WARNING '% %', search_diameter,ST_AsText(ST_Centroid(NEW.geometry));
+        FOR location IN SELECT place_id FROM placex
+          WHERE ST_DWithin(place_centroid, placex.geometry, search_diameter) and rank_search between 22 and 27
+          ORDER BY ST_distance(NEW.geometry, placex.geometry) ASC limit 1
+>>>>>>> .r23726
+        LOOP
+--RAISE WARNING 'using nearest street,% % %',search_diameter,NEW.street,location;
+          NEW.street_place_id := location.place_id;
+        END LOOP;
+      END IF;
+
+--RAISE WARNING 'x6 %',NEW.street_place_id;
+
+      -- If we didn't find any road fallback to standard method
+      IF NEW.street_place_id IS NOT NULL THEN
+
+        -- Some unnamed roads won't have been indexed, index now if needed
+        select count(*) from place_addressline where place_id = NEW.street_place_id INTO street_place_id_count;
+        IF street_place_id_count = 0 THEN
+          UPDATE placex set indexed = true where indexed = false and place_id = NEW.street_place_id;
+        END IF;
+
+        -- Add the street to the address as zero distance to force to front of list
+        INSERT INTO place_addressline VALUES (NEW.place_id, NEW.street_place_id, true, true, 0, 26);
+        address_havelevel[26] := true;
+
+        -- Import address details from parent, reclculating distance in process
+        INSERT INTO place_addressline select NEW.place_id, x.address_place_id, x.fromarea, x.isaddress, ST_distance(NEW.geometry, placex.geometry), placex.rank_address
+          from place_addressline as x join placex on (address_place_id = placex.place_id)
+          where x.place_id = NEW.street_place_id and x.address_place_id != NEW.street_place_id;
+
+        -- Get the details of the parent road
+        select * from search_name where place_id = NEW.street_place_id INTO location;
+        NEW.country_code := location.country_code;
+
+--RAISE WARNING '%', NEW.name;
+        -- If there is no name it isn't searchable, don't bother to create a search record
+        IF NEW.name is NULL THEN
+          return NEW;
+        END IF;
+
+        -- Merge address from parent
+        nameaddress_vector := array_merge(nameaddress_vector, location.nameaddress_vector);
+
+        -- Performance, it would be more acurate to do all the rest of the import process but it takes too long
+        -- Just be happy with inheriting from parent road only
+        INSERT INTO search_name values (NEW.place_id, NEW.rank_search, NEW.rank_address, NEW.country_code,
+          name_vector, nameaddress_vector, place_centroid);
+
+        return NEW;
+      END IF;
+
+    END IF;
+
+--RAISE WARNING '  INDEXING: %',NEW;
+
+    -- Process area matches (tend to be better quality)
+    FOR location IN SELECT
+      place_id,
+      name,
+      keywords,
+      country_code,
+      rank_address,
+      rank_search,
+      ST_Distance(place_centroid, centroid) as distance
+      FROM location_area
+      WHERE ST_Contains(area, place_centroid) and location_area.rank_search < search_maxrank
+      ORDER BY ST_Distance(place_centroid, centroid) ASC
+    LOOP
+
+--RAISE WARNING '  AREA: % % %',location.keywords,NEW.country_code,location.country_code;
+
+      IF NEW.country_code IS NULL THEN
+        NEW.country_code := location.country_code;
+      ELSEIF NEW.country_code != location.country_code and location.rank_search > 3 THEN
+        search_country_code_conflict := true;
+      END IF;
+
+      -- Add it to the list of search terms
+      nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+      INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, true, NOT address_havelevel[location.rank_address], location.distance, location.rank_address); 
+      address_havelevel[location.rank_address] := true;
+
+    END LOOP;
+
+    -- try using the isin value to find parent places
+    address_maxrank := search_maxrank;
+    IF NEW.isin IS NOT NULL THEN
+      -- Doing isin without a country code seems to be dangerous
+      IF NEW.country_code is null THEN
+        NEW.country_code := get_country_code(place_centroid);
+      END IF;
+      isin := regexp_split_to_array(NEW.isin, E'[;,]');
+      FOR i IN 1..array_upper(isin, 1) LOOP
+        address_street_word_id := get_name_id(make_standard_name(isin[i]));
+        IF address_street_word_id IS NOT NULL THEN
+--RAISE WARNING '  search: %',address_street_word_id;
+          FOR location IN SELECT place_id,keywords,rank_search,location_point.country_code,rank_address,
+            ST_Distance(place_centroid, search_name.centroid) as distance
+            FROM search_name join location_point using (place_id)
+            WHERE search_name.name_vector @> ARRAY[address_street_word_id]
+            AND rank_search < NEW.rank_search
+            AND (NEW.country_code IS NULL OR search_name.country_code = NEW.country_code OR search_name.address_rank < 4)
+            ORDER BY ST_distance(NEW.geometry, search_name.centroid) ASC limit 1
+          LOOP
+
+            IF NEW.country_code IS NULL THEN
+              NEW.country_code := location.country_code;
+            ELSEIF NEW.country_code != location.country_code and location.rank_search > 3 THEN
+              search_country_code_conflict := true;
+            END IF;
+
+--RAISE WARNING '  found: %',location.place_id;
+            nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+            INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, false, NOT address_havelevel[location.rank_address], location.distance, location.rank_address);
+
+            IF address_maxrank > location.rank_address THEN
+              address_maxrank := location.rank_address;
+            END IF;
+          END LOOP;
+        END IF;
+      END LOOP;
+      FOR i IN address_maxrank..28 LOOP
+        address_havelevel[i] := true;
+      END LOOP;
+    END IF;
+
+    -- If we have got a consistent country code from the areas and/or isin then we don't care about points (too inacurate)
+    bPointCountryCode := NEW.country_code IS NULL;
+
+    IF true THEN
+    -- full search using absolute position
+
+    search_diameter := 0;
+    -- 16 = city, anything larger tends to be an area so don't continue
+    WHILE FALSE AND search_diameter < 1 AND search_maxrank > 16 LOOP
+
+--      RAISE WARNING 'Nearest: % %', search_diameter, search_maxrank;
+
+      search_prevdiameter := search_diameter;
+      IF search_diameter = 0 THEN
+        search_diameter := 0.001;
+      ELSE
+        search_diameter := search_diameter * 2;
+      END IF;
+
+--RAISE WARNING '%', 'SELECT place_id, name, keywords, country_code, rank_address, rank_search,'||
+--        'ST_Distance('||place_geometry_text||', centroid) as distance,'||
+--        'ST_Distance('||place_geometry_text||', centroid) as maxdistance'|| -- this version of postgis doesnt have maxdistance !
+--        ' FROM location_point_'||(case when search_maxrank > 26 THEN 26 ELSE search_maxrank end)||
+--        ' WHERE ST_DWithin('||place_geometry_text||', centroid, '||search_diameter||') '||
+--        '  AND ST_Distance('||place_geometry_text||', centroid) > '||search_prevdiameter||
+--        ' ORDER BY ST_Distance('||place_geometry_text||', centroid) ASC';
+
+      -- Try nearest
+      FOR location IN EXECUTE 'SELECT place_id, name, keywords, country_code, rank_address, rank_search,'||
+        'ST_Distance('||place_geometry_text||', centroid) as distance,'||
+        'ST_Distance('||place_geometry_text||', centroid) as maxdistance'|| -- this version of postgis doesnt have maxdistance !
+        ' FROM location_point_'||(case when search_maxrank > 26 THEN 26 ELSE search_maxrank end)||
+        ' WHERE ST_DWithin('||place_geometry_text||', centroid, '||search_diameter||') '||
+        '  AND ST_Distance('||place_geometry_text||', centroid) >= '||search_prevdiameter||
+        ' ORDER BY ST_Distance('||place_geometry_text||', centroid) ASC'
+      LOOP
+
+        IF bPointCountryCode THEN      
+          IF NEW.country_code IS NULL THEN
+            NEW.country_code := location.country_code;
+          ELSEIF NEW.country_code != location.country_code THEN
+            search_country_code_conflict := true;
+          END IF;
+        END IF;
+    
+        -- Find search words
+--RAISE WARNING 'IF % % % %', location.name, location.distance, location.rank_search, search_maxdistance;
+--RAISE WARNING '  POINT: % % % % %', location.name, location.rank_search, location.place_id, location.distance, search_maxdistance[location.rank_search];
+        IF (location.distance < search_maxdistance[location.rank_search]) THEN
+--RAISE WARNING '  adding';     
+          -- Add it to the list of search terms, de-duplicate
+          nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+    
+          iMax := (location.maxdistance*1.5)::float;
+          FOR i IN location.rank_search..28 LOOP
+            IF iMax < search_maxdistance[i] THEN
+--RAISE WARNING '  setting % to %',i,iMax;     
+              IF iMax > search_mindistance[i] THEN
+                search_maxdistance[i] := iMax;
+              ELSE
+                search_maxdistance[i] := search_mindistance[i];
+              END IF;
+            END IF;
+          END LOOP;
+
+          INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, false, NOT address_havelevel[location.rank_address], location.distance, location.rank_address); 
+          address_havelevel[location.rank_address] := true;
+  
+        ELSE
+--RAISE WARNING '  Stopped: % % % %', location.rank_search, location.distance, search_maxdistance[location.rank_search], location.name;
+          IF search_maxrank > location.rank_search THEN
+            search_maxrank := location.rank_search;
+          END IF;
+        END IF;
+    
+      END LOOP;
+  
+--RAISE WARNING '  POINT LOCATIONS, % %', search_maxrank, search_diameter;
+  
+    END LOOP; --WHILE
+
+    ELSE
+      -- Cascading search using nearest parent
+    END IF;
+
+    IF search_country_code_conflict OR NEW.country_code IS NULL THEN
+      NEW.country_code := get_country_code(place_centroid);
+    END IF;
+
+    INSERT INTO search_name values (NEW.place_id, NEW.rank_search, NEW.rank_search, NEW.country_code, 
+      name_vector, nameaddress_vector, place_centroid);
+
+    IF NEW.country_code IS NOT NULL THEN
+      DELETE FROM place_addressline WHERE place_id = NEW.place_id and address_place_id in (
+        select address_place_id from place_addressline join placex on (address_place_id = placex.place_id)
+          where place_addressline.place_id = NEW.place_id and placex.country_code != NEW.country_code and cached_rank_address >= 4);
+    END IF;
+
+  END IF;
+
+  return NEW;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION placex_delete() RETURNS TRIGGER
+  AS $$
+DECLARE
+BEGIN
+
+--IF OLD.rank_search < 26 THEN
+--RAISE WARNING 'delete % % % % %',OLD.place_id,OLD.osm_type,OLD.osm_id,OLD.class,OLD.type;
+--END IF;
+
+  -- mark everything linked to this place for re-indexing
+  UPDATE placex set indexed = false from place_addressline where address_place_id = OLD.place_id and placex.place_id = place_addressline.place_id and indexed;
+
+  -- do the actual delete
+  DELETE FROM location_area where place_id = OLD.place_id;
+  DELETE FROM location_point where place_id = OLD.place_id;
+  DELETE FROM location_point_0 where place_id = OLD.place_id;
+  DELETE FROM location_point_1 where place_id = OLD.place_id;
+  DELETE FROM location_point_2 where place_id = OLD.place_id;
+  DELETE FROM location_point_3 where place_id = OLD.place_id;
+  DELETE FROM location_point_4 where place_id = OLD.place_id;
+  DELETE FROM location_point_5 where place_id = OLD.place_id;
+  DELETE FROM location_point_6 where place_id = OLD.place_id;
+  DELETE FROM location_point_7 where place_id = OLD.place_id;
+  DELETE FROM location_point_8 where place_id = OLD.place_id;
+  DELETE FROM location_point_9 where place_id = OLD.place_id;
+  DELETE FROM location_point_10 where place_id = OLD.place_id;
+  DELETE FROM location_point_11 where place_id = OLD.place_id;
+  DELETE FROM location_point_12 where place_id = OLD.place_id;
+  DELETE FROM location_point_13 where place_id = OLD.place_id;
+  DELETE FROM location_point_14 where place_id = OLD.place_id;
+  DELETE FROM location_point_15 where place_id = OLD.place_id;
+  DELETE FROM location_point_16 where place_id = OLD.place_id;
+  DELETE FROM location_point_17 where place_id = OLD.place_id;
+  DELETE FROM location_point_18 where place_id = OLD.place_id;
+  DELETE FROM location_point_19 where place_id = OLD.place_id;
+  DELETE FROM location_point_20 where place_id = OLD.place_id;
+  DELETE FROM location_point_21 where place_id = OLD.place_id;
+  DELETE FROM location_point_22 where place_id = OLD.place_id;
+  DELETE FROM location_point_23 where place_id = OLD.place_id;
+  DELETE FROM location_point_24 where place_id = OLD.place_id;
+  DELETE FROM location_point_25 where place_id = OLD.place_id;
+  DELETE FROM location_point_26 where place_id = OLD.place_id;
+  DELETE FROM search_name where place_id = OLD.place_id;
+  DELETE FROM place_addressline where place_id = OLD.place_id;
+  DELETE FROM place_addressline where address_place_id = OLD.place_id;
+
+  RETURN OLD;
+
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION place_delete() RETURNS TRIGGER
+  AS $$
+DECLARE
+  placeid INTEGER;
+BEGIN
+
+--  RAISE WARNING 'delete: % % % %',OLD.osm_type,OLD.osm_id,OLD.class,OLD.type;
+  delete from placex where osm_type = OLD.osm_type and osm_id = OLD.osm_id and class = OLD.class and type = OLD.type;
+  RETURN OLD;
+
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION place_insert() RETURNS TRIGGER
+  AS $$
+DECLARE
+  i INTEGER;
+  existing RECORD;
+  existingplacex RECORD;
+  existinggeometry GEOMETRY;
+  existingplace_id bigint;
+  result BOOLEAN;
+BEGIN
+
+  IF FALSE AND NEW.osm_type = 'R' THEN
+    RAISE WARNING '-----------------------------------------------------------------------------------';
+    RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
+    select * from placex where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type INTO existingplacex;
+    RAISE WARNING '%', existingplacex;
+  END IF;
+
+  -- Just block these - lots and pointless
+  IF NEW.class = 'highway' and NEW.type in ('turning_circle','traffic_signals','mini_roundabout','noexit','crossing') THEN
+    RETURN null;
+  END IF;
+  IF NEW.class in ('landuse','natural') and NEW.name is null THEN
+    RETURN null;
+  END IF;
+
+  IF ST_IsEmpty(NEW.geometry) OR NOT ST_IsValid(NEW.geometry) OR ST_X(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') OR ST_Y(ST_Centroid(NEW.geometry))::text in ('NaN','Infinity','-Infinity') THEN  
+--    RAISE WARNING 'Invalid Geometry: % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+    RETURN null;
+  END IF;
+
+  -- Patch in additional country names
+  -- adminitrative (with typo) is unfortunately hard codes - this probably won't get fixed until v2
+  IF NEW.admin_level = 2 AND NEW.type = 'adminitrative' AND NEW.country_code is not null THEN
+    select add_keywords(NEW.name, country_name.name) from country_name where country_name.country_code = lower(NEW.country_code) INTO NEW.name;
+  END IF;
+    
+  -- Have we already done this place?
+  select * from place where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type INTO existing;
+
+  -- Get the existing place_id
+  select * from placex where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type INTO existingplacex;
+
+  -- Handle a place changing type by removing the old data
+  -- My generated 'place' types are causing havok because they overlap with real tags
+  -- TODO: move them to their own special purpose tag to avoid collisions
+  IF existing.osm_type IS NULL AND (NEW.type not in ('postcode','house','houses')) THEN
+    DELETE FROM place where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type not in ('postcode','house','houses');
+  END IF;
+
+--  RAISE WARNING 'Existing: %',existing.place_id;
+
+  -- To paraphrase, if there isn't an existing item, OR if the admin level has changed, OR if it is a major change in geometry
+  IF existing.osm_type IS NULL 
+     OR existingplacex.osm_type IS NULL
+     OR coalesce(existing.admin_level, 100) != coalesce(NEW.admin_level, 100) 
+--     OR coalesce(existing.country_code, '') != coalesce(NEW.country_code, '')
+     OR (existing.geometry != NEW.geometry AND ST_Distance(ST_Centroid(existing.geometry),ST_Centroid(NEW.geometry)) > 0.01 AND NOT
+     (ST_GeometryType(existing.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon')))
+     THEN
+
+--  IF existing.osm_type IS NULL THEN
+--    RAISE WARNING 'no existing place';
+--  END IF;
+--  IF existingplacex.osm_type IS NULL THEN
+--    RAISE WARNING 'no existing placex %', existingplacex;
+--  END IF;
+
+
+--    RAISE WARNING 'delete and replace';
+
+    IF existing.osm_type IS NOT NULL THEN
+--      RAISE WARNING 'insert delete % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,ST_Distance(ST_Centroid(existing.geometry),ST_Centroid(NEW.geometry)),existing;
+      IF existing.rank_search < 26 THEN
+--        RAISE WARNING 'replace placex % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+      END IF;
+      DELETE FROM place where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type;
+    END IF;   
+
+--    RAISE WARNING 'delete and replace2';
+
+    -- No - process it as a new insertion (hopefully of low rank or it will be slow)
+    insert into placex values (NEW.place_id
+        ,NEW.osm_type
+        ,NEW.osm_id
+        ,NEW.class
+        ,NEW.type
+        ,NEW.name
+        ,NEW.admin_level
+        ,NEW.housenumber
+        ,NEW.street
+        ,NEW.isin
+        ,NEW.postcode
+        ,NEW.country_code
+        ,NEW.street_place_id
+        ,NEW.rank_address
+        ,NEW.rank_search
+        ,NEW.indexed
+        ,NEW.geometry
+        );
+
+--    RAISE WARNING 'insert done % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+
+    RETURN NEW;
+  END IF;
+
+  -- Various ways to do the update
+
+  -- Debug, what's changed?
+  IF FALSE AND existing.rank_search < 26 THEN
+    IF coalesce(existing.name::text, '') != coalesce(NEW.name::text, '') THEN
+      RAISE WARNING 'update details, name: % % % %',NEW.osm_type,NEW.osm_id,existing.name::text,NEW.name::text;
+    END IF;
+    IF coalesce(existing.housenumber, '') != coalesce(NEW.housenumber, '') THEN
+      RAISE WARNING 'update details, housenumber: % % % %',NEW.osm_type,NEW.osm_id,existing.housenumber,NEW.housenumber;
+    END IF;
+    IF coalesce(existing.street, '') != coalesce(NEW.street, '') THEN
+      RAISE WARNING 'update details, street: % % % %',NEW.osm_type,NEW.osm_id,existing.street,NEW.street;
+    END IF;
+    IF coalesce(existing.isin, '') != coalesce(NEW.isin, '') THEN
+      RAISE WARNING 'update details, isin: % % % %',NEW.osm_type,NEW.osm_id,existing.isin,NEW.isin;
+    END IF;
+    IF coalesce(existing.postcode, '') != coalesce(NEW.postcode, '') THEN
+      RAISE WARNING 'update details, postcode: % % % %',NEW.osm_type,NEW.osm_id,existing.postcode,NEW.postcode;
+    END IF;
+    IF coalesce(existing.country_code, '') != coalesce(NEW.country_code, '') THEN
+      RAISE WARNING 'update details, country_code: % % % %',NEW.osm_type,NEW.osm_id,existing.country_code,NEW.country_code;
+    END IF;
+  END IF;
+
+  -- Special case for polygon shape changes because they tend to be large and we can be a bit clever about how we handle them
+  IF existing.geometry != NEW.geometry 
+     AND ST_GeometryType(existing.geometry) in ('ST_Polygon','ST_MultiPolygon')
+     AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') 
+     THEN 
+
+--    IF existing.rank_search < 26 THEN
+--      RAISE WARNING 'existing polygon change % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+--    END IF;
+
+    -- Get the version of the geometry actually used (in placex table)
+    select geometry from placex where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type into existinggeometry;
+
+    -- Performance limit
+    IF st_area(NEW.geometry) < 1 AND st_area(existinggeometry) < 1 THEN
+
+      -- re-index points that have moved in / out of the polygon, could be done as a single query but postgres gets the index usage wrong
+      update placex set indexed = false where indexed and 
+          (ST_Contains(NEW.geometry, placex.geometry) OR ST_Intersects(NEW.geometry, placex.geometry))
+          AND NOT (ST_Contains(existinggeometry, placex.geometry) OR ST_Intersects(existinggeometry, placex.geometry))
+          AND rank_search > NEW.rank_search;
+
+      update placex set indexed = false where indexed and 
+          (ST_Contains(existinggeometry, placex.geometry) OR ST_Intersects(existinggeometry, placex.geometry))
+          AND NOT (ST_Contains(NEW.geometry, placex.geometry) OR ST_Intersects(NEW.geometry, placex.geometry))
+          AND rank_search > NEW.rank_search;
+
+    END IF;
+
+  END IF;
+
+  -- Special case - if we are just adding extra words we hack them into the search_name table rather than reindexing
+  IF existingplacex.rank_search < 26
+     AND coalesce(existing.housenumber, '') = coalesce(NEW.housenumber, '')
+     AND coalesce(existing.street, '') = coalesce(NEW.street, '')
+     AND coalesce(existing.isin, '') = coalesce(NEW.isin, '')
+     AND coalesce(existing.postcode, '') = coalesce(NEW.postcode, '')
+     AND coalesce(existing.country_code, '') = coalesce(NEW.country_code, '')
+     AND coalesce(existing.name::text, '') != coalesce(NEW.name::text, '') 
+     THEN
+
+--    IF existing.rank_search < 26 THEN
+--      RAISE WARNING 'name change only % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+--    END IF;
+
+    IF NOT update_location_nameonly(existingplacex.place_id, NEW.name) THEN
+
+      IF st_area(NEW.geometry) < 0.5 THEN
+        UPDATE placex set indexed = false from place_addressline where address_place_id = existingplacex.place_id 
+          and placex.place_id = place_addressline.place_id and indexed;
+      END IF;
+
+    END IF;
+  
+  ELSE
+
+    -- Anything else has changed - reindex the lot
+    IF coalesce(existing.name::text, '') != coalesce(NEW.name::text, '')
+        OR coalesce(existing.housenumber, '') != coalesce(NEW.housenumber, '')
+        OR coalesce(existing.street, '') != coalesce(NEW.street, '')
+        OR coalesce(existing.isin, '') != coalesce(NEW.isin, '')
+        OR coalesce(existing.postcode, '') != coalesce(NEW.postcode, '')
+        OR coalesce(existing.country_code, '') != coalesce(NEW.country_code, '') THEN
+
+--      IF existing.rank_search < 26 THEN
+--        RAISE WARNING 'other change % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
+--      END IF;
+
+      -- performance, can't take the load of re-indexing a whole country / huge area
+      IF st_area(NEW.geometry) < 0.5 THEN
+        UPDATE placex set indexed = false from place_addressline where address_place_id = existingplacex.place_id 
+          and placex.place_id = place_addressline.place_id and indexed;
+      END IF;
+
+    END IF;
+
+  END IF;
+
+  IF coalesce(existing.name::text, '') != coalesce(NEW.name::text, '')
+     OR coalesce(existing.housenumber, '') != coalesce(NEW.housenumber, '')
+     OR coalesce(existing.street, '') != coalesce(NEW.street, '')
+     OR coalesce(existing.isin, '') != coalesce(NEW.isin, '')
+     OR coalesce(existing.postcode, '') != coalesce(NEW.postcode, '')
+     OR coalesce(existing.country_code, '') != coalesce(NEW.country_code, '')
+     OR existing.geometry != NEW.geometry
+     THEN
+
+    update place set 
+      name = NEW.name,
+      housenumber  = NEW.housenumber,
+      street = NEW.street,
+      isin = NEW.isin,
+      postcode = NEW.postcode,
+      country_code = NEW.country_code,
+      street_place_id = null,
+      geometry = NEW.geometry
+      where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class and type = NEW.type;
+
+    update placex set 
+      name = NEW.name,
+      housenumber = NEW.housenumber,
+      street = NEW.street,
+      isin = NEW.isin,
+      postcode = NEW.postcode,
+      country_code = NEW.country_code,
+      street_place_id = null,
+      indexed = false,
+      geometry = NEW.geometry
+      where place_id = existingplacex.place_id;
+
+    result := update_location(existingplacex.place_id, existingplacex.country_code, NEW.name, existingplacex.rank_search, existingplacex.rank_address, NEW.geometry);
+
+  END IF;
+
+  -- Abort the add (we modified the existing place instead)
+  RETURN NULL;
+
+END; 
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_name_by_language(name keyvalue[], languagepref TEXT[]) RETURNS TEXT
+  AS $$
+DECLARE
+  search TEXT[];
+  found BOOLEAN;
+BEGIN
+
+  IF (array_upper(name, 1) is null) THEN
+    return null;
+  END IF;
+
+  search := languagepref;
+
+  FOR j IN 1..array_upper(search, 1) LOOP
+    FOR k IN 1..array_upper(name, 1) LOOP
+      IF (name[k].key = search[j] AND trim(name[k].value) != '') THEN
+        return trim(name[k].value);
+      END IF;
+    END LOOP;
+  END LOOP;
+
+  RETURN null;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_connected_ways(way_ids INTEGER[]) RETURNS SETOF planet_osm_ways
+  AS $$
+DECLARE
+  searchnodes INTEGER[];
+  location RECORD;
+  j INTEGER;
+BEGIN
+
+  searchnodes := '{}';
+  FOR j IN 1..array_upper(way_ids, 1) LOOP
+    FOR location IN 
+      select nodes from planet_osm_ways where id = way_ids[j] LIMIT 1
+    LOOP
+      searchnodes := searchnodes | location.nodes;
+    END LOOP;
+  END LOOP;
+
+  RETURN QUERY select * from planet_osm_ways where nodes && searchnodes and NOT ARRAY[id] <@ way_ids;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_address_postcode(for_place_id BIGINT) RETURNS TEXT
+  AS $$
+DECLARE
+  result TEXT[];
+  search TEXT[];
+  for_postcode TEXT;
+  found INTEGER;
+  location RECORD;
+BEGIN
+
+  found := 1000;
+  search := ARRAY['ref'];
+  result := '{}';
+
+  UPDATE placex set indexed = true where indexed = false and place_id = for_place_id;
+
+  select postcode from placex where place_id = for_place_id limit 1 into for_postcode;
+
+  FOR location IN 
+    select rank_address,name,distance,length(name::text) as namelength 
+      from place_addressline join placex on (address_place_id = placex.place_id) 
+      where place_addressline.place_id = for_place_id and rank_address in (5,11)
+      order by rank_address desc,rank_search desc,fromarea desc,distance asc,namelength desc
+  LOOP
+    IF array_upper(search, 1) IS NOT NULL AND array_upper(location.name, 1) IS NOT NULL THEN
+      FOR j IN 1..array_upper(search, 1) LOOP
+        FOR k IN 1..array_upper(location.name, 1) LOOP
+          IF (found > location.rank_address AND location.name[k].key = search[j] AND location.name[k].value != '') AND NOT result && ARRAY[trim(location.name[k].value)] AND (for_postcode IS NULL OR location.name[k].value ilike for_postcode||'%') THEN
+            result[(100 - location.rank_address)] := trim(location.name[k].value);
+            found := location.rank_address;
+          END IF;
+        END LOOP;
+      END LOOP;
+    END IF;
+  END LOOP;
+
+  RETURN array_to_string(result,', ');
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_address_by_language(for_place_id BIGINT, languagepref TEXT[]) RETURNS TEXT
+  AS $$
+DECLARE
+  result TEXT[];
+  search TEXT[];
+  found INTEGER;
+  location RECORD;
+  searchcountrycode varchar(2);
+  searchhousenumber TEXT;
+  searchrankaddress INTEGER;
+BEGIN
+
+  found := 1000;
+  search := languagepref;
+  result := '{}';
+
+--  UPDATE placex set indexed = false where indexed = true and place_id = for_place_id;
+  UPDATE placex set indexed = true where indexed = false and place_id = for_place_id;
+
+  select country_code,housenumber,rank_address from placex where place_id = for_place_id into searchcountrycode,searchhousenumber,searchrankaddress;
+
+  FOR location IN 
+    select CASE WHEN address_place_id = for_place_id AND rank_address = 0 THEN 100 ELSE rank_address END as rank_address,
+      CASE WHEN type = 'postcode' THEN ARRAY[ROW('name',postcode)::keyvalue] ELSE name END as name,
+      distance,length(name::text) as namelength 
+      from place_addressline join placex on (address_place_id = placex.place_id) 
+      where place_addressline.place_id = for_place_id and ((rank_address > 0 AND rank_address < searchrankaddress) OR address_place_id = for_place_id)
+      and (placex.country_code IS NULL OR searchcountrycode IS NULL OR placex.country_code = searchcountrycode OR rank_address < 4)
+      order by rank_address desc,fromarea desc,distance asc,rank_search desc,namelength desc
+  LOOP
+    IF array_upper(search, 1) IS NOT NULL AND array_upper(location.name, 1) IS NOT NULL THEN
+      FOR j IN 1..array_upper(search, 1) LOOP
+        FOR k IN 1..array_upper(location.name, 1) LOOP
+          IF (found > location.rank_address AND location.name[k].key = search[j] AND location.name[k].value != '') AND NOT result && ARRAY[trim(location.name[k].value)] THEN
+            result[(100 - location.rank_address)] := trim(location.name[k].value);
+            found := location.rank_address;
+          END IF;
+        END LOOP;
+      END LOOP;
+    END IF;
+  END LOOP;
+
+  IF searchhousenumber IS NOT NULL AND COALESCE(result[(100 - 28)],'') != searchhousenumber THEN
+    IF result[(100 - 28)] IS NOT NULL THEN
+      result[(100 - 29)] := result[(100 - 28)];
+    END IF;
+    result[(100 - 28)] := searchhousenumber;
+  END IF;
+
+  -- No country polygon - add it from the country_code
+  IF found > 4 THEN
+    select get_name_by_language(country_name.name,languagepref) as name from placex join country_name using (country_code) 
+      where place_id = for_place_id limit 1 INTO location;
+    IF location IS NOT NULL THEN
+      result[(100 - 4)] := trim(location.name);
+    END IF;
+  END IF;
+
+  RETURN array_to_string(result,', ');
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_addressdata_by_language(for_place_id BIGINT, languagepref TEXT[]) RETURNS TEXT[]
+  AS $$
+DECLARE
+  result TEXT[];
+  search TEXT[];
+  found INTEGER;
+  location RECORD;
+  searchcountrycode varchar(2);
+  searchhousenumber TEXT;
+BEGIN
+
+  found := 1000;
+  search := languagepref;
+  result := '{}';
+
+--  UPDATE placex set indexed = false where indexed = true and place_id = for_place_id;
+  UPDATE placex set indexed = true where indexed = false and place_id = for_place_id;
+
+  select country_code,housenumber from placex where place_id = for_place_id into searchcountrycode,searchhousenumber;
+
+  FOR location IN 
+    select CASE WHEN address_place_id = for_place_id AND rank_address = 0 THEN 100 ELSE rank_address END as rank_address,
+      name,distance,length(name::text) as namelength 
+      from place_addressline join placex on (address_place_id = placex.place_id) 
+      where place_addressline.place_id = for_place_id and (rank_address > 0 OR address_place_id = for_place_id)
+      and (placex.country_code IS NULL OR searchcountrycode IS NULL OR placex.country_code = searchcountrycode OR rank_address < 4)
+      order by rank_address desc,fromarea desc,distance asc,rank_search desc,namelength desc
+  LOOP
+    IF array_upper(search, 1) IS NOT NULL AND array_upper(location.name, 1) IS NOT NULL THEN
+      FOR j IN 1..array_upper(search, 1) LOOP
+        FOR k IN 1..array_upper(location.name, 1) LOOP
+          IF (found > location.rank_address AND location.name[k].key = search[j] AND location.name[k].value != '') AND NOT result && ARRAY[trim(location.name[k].value)] THEN
+            result[(100 - location.rank_address)] := trim(location.name[k].value);
+            found := location.rank_address;
+          END IF;
+        END LOOP;
+      END LOOP;
+    END IF;
+  END LOOP;
+
+  IF searchhousenumber IS NOT NULL AND result[(100 - 28)] IS NULL THEN
+    result[(100 - 28)] := searchhousenumber;
+  END IF;
+
+  -- No country polygon - add it from the country_code
+  IF found > 4 THEN
+    select get_name_by_language(country_name.name,languagepref) as name from placex join country_name using (country_code) 
+      where place_id = for_place_id limit 1 INTO location;
+    IF location IS NOT NULL THEN
+      result[(100 - 4)] := trim(location.name);
+    END IF;
+  END IF;
+
+  RETURN result;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_place_boundingbox(search_place_id INTEGER) RETURNS place_boundingbox
+  AS $$
+DECLARE
+  result place_boundingbox;
+  numfeatures integer;
+BEGIN
+  select * from place_boundingbox into result where place_id = search_place_id;
+  IF result.place_id IS NULL THEN
+-- remove  isaddress = true because if there is a matching polygon it always wins
+    select count(*) from place_addressline where address_place_id = search_place_id into numfeatures;
+    insert into place_boundingbox select place_id,
+             ST_Y(ST_PointN(ExteriorRing(ST_Box2D(area)),4)),ST_Y(ST_PointN(ExteriorRing(ST_Box2D(area)),2)),
+             ST_X(ST_PointN(ExteriorRing(ST_Box2D(area)),1)),ST_X(ST_PointN(ExteriorRing(ST_Box2D(area)),3)),
+             numfeatures, ST_Area(area),
+             area from location_area where place_id = search_place_id;
+    select * from place_boundingbox into result where place_id = search_place_id;
+  END IF;
+  IF result.place_id IS NULL THEN
+-- TODO 0.0001
+    insert into place_boundingbox select address_place_id,
+             min(ST_Y(ST_Centroid(geometry))) as minlon,max(ST_Y(ST_Centroid(geometry))) as maxlon,
+             min(ST_X(ST_Centroid(geometry))) as minlat,max(ST_X(ST_Centroid(geometry))) as maxlat,
+             count(*), ST_Area(ST_Buffer(ST_Convexhull(ST_Collect(geometry)),0.0001)) as area,
+             ST_Buffer(ST_Convexhull(ST_Collect(geometry)),0.0001) as boundary 
+             from (select * from place_addressline where address_place_id = search_place_id order by cached_rank_address limit 4000) as place_addressline join placex using (place_id) 
+             where address_place_id = search_place_id
+--               and (isaddress = true OR place_id = search_place_id)
+               and (st_length(geometry) < 0.01 or place_id = search_place_id)
+             group by address_place_id limit 1;
+    select * from place_boundingbox into result where place_id = search_place_id;
+  END IF;
+  return result;
+END;
+$$
+LANGUAGE plpgsql;
+
+-- don't do the operation if it would be slow
+CREATE OR REPLACE FUNCTION get_place_boundingbox_quick(search_place_id INTEGER) RETURNS place_boundingbox
+  AS $$
+DECLARE
+  result place_boundingbox;
+  numfeatures integer;
+  rank integer;
+BEGIN
+  select * from place_boundingbox into result where place_id = search_place_id;
+  IF result IS NULL AND rank > 14 THEN
+    select count(*) from place_addressline where address_place_id = search_place_id and isaddress = true into numfeatures;
+    insert into place_boundingbox select place_id,
+             ST_Y(ST_PointN(ExteriorRing(ST_Box2D(area)),4)),ST_Y(ST_PointN(ExteriorRing(ST_Box2D(area)),2)),
+             ST_X(ST_PointN(ExteriorRing(ST_Box2D(area)),1)),ST_X(ST_PointN(ExteriorRing(ST_Box2D(area)),3)),
+             numfeatures, ST_Area(area),
+             area from location_area where place_id = search_place_id;
+    select * from place_boundingbox into result where place_id = search_place_id;
+  END IF;
+  IF result IS NULL THEN
+    select rank_search from placex where place_id = search_place_id into rank;
+    IF rank > 20 THEN
+-- TODO 0.0001
+      insert into place_boundingbox select address_place_id,
+             min(ST_Y(ST_Centroid(geometry))) as minlon,max(ST_Y(ST_Centroid(geometry))) as maxlon,
+             min(ST_X(ST_Centroid(geometry))) as minlat,max(ST_X(ST_Centroid(geometry))) as maxlat,
+             count(*), ST_Area(ST_Buffer(ST_Convexhull(ST_Collect(geometry)),0.0001)) as area,
+             ST_Buffer(ST_Convexhull(ST_Collect(geometry)),0.0001) as boundary 
+             from place_addressline join placex using (place_id) 
+             where address_place_id = search_place_id 
+               and (isaddress = true OR place_id = search_place_id)
+               and (st_length(geometry) < 0.01 or place_id = search_place_id)
+             group by address_place_id limit 1;
+      select * from place_boundingbox into result where place_id = search_place_id;
+    END IF;
+  END IF;
+  return result;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION update_place(search_place_id INTEGER) RETURNS BOOLEAN
+  AS $$
+DECLARE
+  result place_boundingbox;
+  numfeatures integer;
+BEGIN
+  update placex set 
+      name = place.name,
+      housenumber = place.housenumber,
+      street = place.street,
+      isin = place.isin,
+      postcode = place.postcode,
+      country_code = place.country_code,
+      street_place_id = null,
+      indexed = false      
+      from place
+      where placex.place_id = search_place_id 
+        and place.osm_type = placex.osm_type and place.osm_id = placex.osm_id
+        and place.class = placex.class and place.type = placex.type;
+  update placex set indexed = true where place_id = search_place_id and indexed = false;
+  return true;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION update_place(search_place_id INTEGER) RETURNS BOOLEAN
+  AS $$
+DECLARE
+  result place_boundingbox;
+  numfeatures integer;
+BEGIN
+  update placex set 
+      name = place.name,
+      housenumber = place.housenumber,
+      street = place.street,
+      isin = place.isin,
+      postcode = place.postcode,
+      country_code = place.country_code,
+      street_place_id = null,
+      indexed = false      
+      from place
+      where placex.place_id = search_place_id 
+        and place.osm_type = placex.osm_type and place.osm_id = placex.osm_id
+        and place.class = placex.class and place.type = placex.type;
+  update placex set indexed = true where place_id = search_place_id and indexed = false;
+  return true;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_searchrank_label(rank INTEGER) RETURNS TEXT
+  AS $$
+DECLARE
+BEGIN
+  IF rank < 2 THEN
+    RETURN 'Continent';
+  ELSEIF rank < 4 THEN
+    RETURN 'Sea';
+  ELSEIF rank < 8 THEN
+    RETURN 'Country';
+  ELSEIF rank < 12 THEN
+    RETURN 'State';
+  ELSEIF rank < 16 THEN
+    RETURN 'County';
+  ELSEIF rank = 16 THEN
+    RETURN 'City';
+  ELSEIF rank = 17 THEN
+    RETURN 'Town / Island';
+  ELSEIF rank = 18 THEN
+    RETURN 'Village / Hamlet';
+  ELSEIF rank = 20 THEN
+    RETURN 'Suburb';
+  ELSEIF rank = 21 THEN
+    RETURN 'Postcode Area';
+  ELSEIF rank = 22 THEN
+    RETURN 'Croft / Farm / Locality / Islet';
+  ELSEIF rank = 23 THEN
+    RETURN 'Postcode Area';
+  ELSEIF rank = 25 THEN
+    RETURN 'Postcode Point';
+  ELSEIF rank = 26 THEN
+    RETURN 'Street / Major Landmark';
+  ELSEIF rank = 27 THEN
+    RETURN 'Minory Street / Path';
+  ELSEIF rank = 28 THEN
+    RETURN 'House / Building';
+  ELSE
+    RETURN 'Other: '||rank;
+  END IF;
+  
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_addressrank_label(rank INTEGER) RETURNS TEXT
+  AS $$
+DECLARE
+BEGIN
+  IF rank = 0 THEN
+    RETURN 'None';
+  ELSEIF rank < 2 THEN
+    RETURN 'Continent';
+  ELSEIF rank < 4 THEN
+    RETURN 'Sea';
+  ELSEIF rank = 5 THEN
+    RETURN 'Postcode';
+  ELSEIF rank < 8 THEN
+    RETURN 'Country';
+  ELSEIF rank < 12 THEN
+    RETURN 'State';
+  ELSEIF rank < 16 THEN
+    RETURN 'County';
+  ELSEIF rank = 16 THEN
+    RETURN 'City';
+  ELSEIF rank = 17 THEN
+    RETURN 'Town / Village / Hamlet';
+  ELSEIF rank = 20 THEN
+    RETURN 'Suburb';
+  ELSEIF rank = 21 THEN
+    RETURN 'Postcode Area';
+  ELSEIF rank = 22 THEN
+    RETURN 'Croft / Farm / Locality / Islet';
+  ELSEIF rank = 23 THEN
+    RETURN 'Postcode Area';
+  ELSEIF rank = 25 THEN
+    RETURN 'Postcode Point';
+  ELSEIF rank = 26 THEN
+    RETURN 'Street / Major Landmark';
+  ELSEIF rank = 27 THEN
+    RETURN 'Minory Street / Path';
+  ELSEIF rank = 28 THEN
+    RETURN 'House / Building';
+  ELSE
+    RETURN 'Other: '||rank;
+  END IF;
+  
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_word_suggestion(srcword TEXT) RETURNS TEXT
+  AS $$
+DECLARE
+  trigramtoken TEXT;
+  result TEXT;
+BEGIN
+
+  trigramtoken := regexp_replace(make_standard_name(srcword),E'([^0-9])\\1+',E'\\1','g');
+  SELECT word FROM word WHERE word_trigram like ' %' and word_trigram % trigramtoken ORDER BY similarity(word_trigram, trigramtoken) DESC, word limit 1 into result;
+
+  return result;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION get_word_suggestions(srcword TEXT) RETURNS TEXT[]
+  AS $$
+DECLARE
+  trigramtoken TEXT;
+  result TEXT[];
+  r RECORD;
+BEGIN
+
+  trigramtoken := regexp_replace(make_standard_name(srcword),E'([^0-9])\\1+',E'\\1','g');
+
+  FOR r IN SELECT word,similarity(word_trigram, trigramtoken) as score FROM word 
+    WHERE word_trigram like ' %' and word_trigram % trigramtoken ORDER BY similarity(word_trigram, trigramtoken) DESC, word limit 4
+  LOOP
+    result[coalesce(array_upper(result,1)+1,1)] := r.word;
+  END LOOP;
+
+  return result;
+END;
+$$
+LANGUAGE plpgsql;
+
+CREATE AGGREGATE array_agg(INT[])
+(
+    sfunc = array_cat,
+    stype = INT[],
+    initcond = '{}'
+);
+
+
diff --git a/sql/loaddata.sql b/sql/loaddata.sql
new file mode 100644 (file)
index 0000000..45df1e3
--- /dev/null
@@ -0,0 +1,13 @@
+TRUNCATE placex;
+TRUNCATE search_name;
+TRUNCATE place_addressline;
+TRUNCATE location_area;
+
+DROP SEQUENCE seq_place;
+CREATE SEQUENCE seq_place start 100000;
+
+insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, geometry) select * from place where osm_type = 'N';
+insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, geometry) select * from place where osm_type = 'W';
+insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, geometry) select * from place where osm_type = 'R';
+
+--select count(*) from (select create_interpolation(osm_id, housenumber) from placex where indexed=false and class='place' and type='houses') as x;
diff --git a/sql/partitions.src.sql b/sql/partitions.src.sql
new file mode 100644 (file)
index 0000000..1241982
--- /dev/null
@@ -0,0 +1,149 @@
+create type nearplace as (
+  place_id bigint
+);
+
+create type nearfeature as (
+  place_id bigint,
+  keywords int[],
+  rank_address integer,
+  rank_search integer,
+  distance float
+);
+
+-- start
+CREATE TABLE location_area_large_-partition- () INHERITS (location_area_large);
+CREATE INDEX idx_location_area_large_-partition-_geometry ON location_area_large_-partition- USING GIST (geometry);
+
+CREATE TABLE location_area_roadnear_-partition- () INHERITS (location_area_roadnear);
+CREATE INDEX idx_location_area_roadnear_-partition-_geometry ON location_area_roadnear_-partition- USING GIST (geometry);
+
+CREATE TABLE location_area_roadfar_-partition- () INHERITS (location_area_roadfar);
+CREATE INDEX idx_location_area_roadfar_-partition-_geometry ON location_area_roadfar_-partition- USING GIST (geometry);
+-- end
+
+create or replace function getNearRoads(in_partition TEXT, point GEOMETRY) RETURNS setof nearplace AS $$
+DECLARE
+  r nearplace%rowtype;
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    FOR r IN SELECT place_id FROM location_area_large WHERE partition = '-partition-' and ST_Contains(geometry, point) LOOP
+      RETURN NEXT r;
+    END LOOP;
+    RETURN;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+END
+$$
+LANGUAGE plpgsql;
+
+create or replace function getNearFeatures(in_partition TEXT, point GEOMETRY, maxrank INTEGER) RETURNS setof nearfeature AS $$
+DECLARE
+  r nearfeature%rowtype;
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    FOR r IN SELECT
+      place_id,
+      keywords,
+      rank_address,
+      rank_search,
+      ST_Distance(place_centroid, centroid) as distance
+      FROM location_area_large
+      WHERE ST_Contains(area, point) and location_area_large.rank_search < maxrank
+      ORDER BY ST_Distance(place_centroid, centroid) ASC
+    LOOP
+      RETURN NEXT r;
+    END LOOP;
+    RETURN;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+END
+$$
+LANGUAGE plpgsql;
+
+create or replace function deleteLocationArea(in_partition TEXT, in_place_id bigint) RETURNS BOOLEAN AS $$
+DECLARE
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    DELETE from location_area_large_-partition- WHERE place_id = in_place_id;
+    DELETE from location_area_roadnear_-partition- WHERE place_id = in_place_id;
+    DELETE from location_area_roadfar_-partition- WHERE place_id = in_place_id;
+    RETURN TRUE;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+
+  RETURN FALSE;
+END
+$$
+LANGUAGE plpgsql;
+
+create or replace function insertLocationAreaLarge(
+  in_partition TEXT, in_place_id bigint, in_keywords INTEGER[], 
+  in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN, 
+  in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
+DECLARE
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    INSERT INTO location_area_large_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
+    RETURN TRUE;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+  RETURN FALSE;
+END
+$$
+LANGUAGE plpgsql;
+
+create or replace function insertLocationAreaRoadNear(
+  in_partition TEXT, in_place_id bigint, in_keywords INTEGER[], 
+  in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN, 
+  in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
+DECLARE
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    INSERT INTO location_area_roadnear_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
+    RETURN TRUE;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+  RETURN FALSE;
+END
+$$
+LANGUAGE plpgsql;
+
+create or replace function insertLocationAreaRoadFar(
+  in_partition TEXT, in_place_id bigint, in_keywords INTEGER[], 
+  in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN, 
+  in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
+DECLARE
+BEGIN
+
+-- start
+  IF in_partition = '-partition-' THEN
+    INSERT INTO location_area_roadfar_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
+    RETURN TRUE;
+  END IF;
+-- end
+
+  RAISE EXCEPTION 'Unknown partition %', in_partition;
+  RETURN FALSE;
+END
+$$
+LANGUAGE plpgsql;
diff --git a/sql/tables.sql b/sql/tables.sql
new file mode 100644 (file)
index 0000000..5945ee7
--- /dev/null
@@ -0,0 +1,269 @@
+drop table import_status;
+CREATE TABLE import_status (
+  lastimportdate timestamp NOT NULL
+  );
+GRANT SELECT ON import_status TO "www-data" ;
+
+drop table import_osmosis_log;
+CREATE TABLE import_osmosis_log (
+  batchend timestamp,
+  batchsize integer,
+  starttime timestamp,
+  endtime timestamp,
+  event text
+  );
+
+--drop table IF EXISTS query_log;
+CREATE TABLE query_log (
+  starttime timestamp,
+  query text,
+  ipaddress text,
+  endtime timestamp,
+  results integer
+  );
+CREATE INDEX idx_query_log ON query_log USING BTREE (starttime);
+GRANT INSERT ON query_log TO "www-data" ;
+
+CREATE TABLE new_query_log (
+  type text,
+  starttime timestamp,
+  ipaddress text,
+  useragent text,
+  language text,
+  query text,
+  endtime timestamp,
+  results integer,
+  format text,
+  secret text
+  );
+CREATE INDEX idx_new_query_log_starttime ON new_query_log USING BTREE (starttime);
+GRANT INSERT ON new_query_log TO "www-data" ;
+GRANT UPDATE ON new_query_log TO "www-data" ;
+GRANT SELECT ON new_query_log TO "www-data" ;
+
+create view vw_search_query_log as SELECT substr(query, 1, 50) AS query, starttime, endtime - starttime AS duration, substr(useragent, 1, 20) as 
+useragent, language, results, ipaddress FROM new_query_log WHERE type = 'search' ORDER BY starttime DESC;
+
+--drop table IF EXISTS report_log;
+CREATE TABLE report_log (
+  starttime timestamp,
+  ipaddress text,
+  query text,
+  description text,
+  email text
+  );
+GRANT INSERT ON report_log TO "www-data" ;
+
+drop table IF EXISTS word;
+CREATE TABLE word (
+  word_id INTEGER,
+  word_token text,
+  word_trigram text,
+  word text,
+  class text,
+  type text,
+  country_code varchar(2),
+  search_name_count INTEGER
+  );
+SELECT AddGeometryColumn('word', 'location', 4326, 'GEOMETRY', 2);
+CREATE INDEX idx_word_word_id on word USING BTREE (word_id);
+CREATE INDEX idx_word_word_token on word USING BTREE (word_token);
+CREATE INDEX idx_word_trigram ON word USING gin(word_trigram gin_trgm_ops);
+GRANT SELECT ON word TO "www-data" ;
+DROP SEQUENCE seq_word;
+CREATE SEQUENCE seq_word start 1;
+
+drop table IF EXISTS location_area CASCADE;
+CREATE TABLE location_area (
+  partition varchar(10),
+  place_id bigint,
+  keywords INTEGER[],
+  rank_search INTEGER NOT NULL,
+  rank_address INTEGER NOT NULL,
+  isguess BOOL
+  );
+SELECT AddGeometryColumn('location_area', 'centroid', 4326, 'POINT', 2);
+SELECT AddGeometryColumn('location_area', 'geometry', 4326, 'GEOMETRY', 2);
+
+CREATE TABLE location_area_large () INHERITS (location_area);
+CREATE TABLE location_area_roadnear () INHERITS (location_area);
+CREATE TABLE location_area_roadfar () INHERITS (location_area);
+
+drop table IF EXISTS search_name;
+CREATE TABLE search_name (
+  place_id bigint,
+  search_rank integer,
+  address_rank integer,
+  country_code varchar(2),
+  name_vector integer[],
+  nameaddress_vector integer[]
+  );
+CREATE INDEX search_name_name_vector_idx ON search_name USING GIN (name_vector gin__int_ops);
+CREATE INDEX searchnameplacesearch_search_nameaddress_vector_idx ON search_name USING GIN (nameaddress_vector gin__int_ops);
+SELECT AddGeometryColumn('search_name', 'centroid', 4326, 'GEOMETRY', 2);
+CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid);
+CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id);
+
+drop table IF EXISTS place_addressline;
+CREATE TABLE place_addressline (
+  place_id bigint,
+  address_place_id bigint,
+  fromarea boolean,
+  isaddress boolean,
+  distance float,
+  cached_rank_address integer
+  );
+CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id);
+CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id);
+
+drop table IF EXISTS place_boundingbox CASCADE;
+CREATE TABLE place_boundingbox (
+  place_id bigint,
+  minlat float,
+  maxlat float,
+  minlon float,
+  maxlon float,
+  numfeatures integer,
+  area float
+  );
+CREATE INDEX idx_place_boundingbox_place_id on place_boundingbox USING BTREE (place_id);
+SELECT AddGeometryColumn('place_boundingbox', 'outline', 4326, 'GEOMETRY', 2);
+CREATE INDEX idx_place_boundingbox_outline ON place_boundingbox USING GIST (outline);
+GRANT SELECT on place_boundingbox to "www-data" ;
+GRANT INSERT on place_boundingbox to "www-data" ;
+
+drop table IF EXISTS reverse_cache;
+CREATE TABLE reverse_cache (
+  latlonzoomid integer,
+  country_code varchar(2),
+  place_id bigint
+  );
+GRANT SELECT on reverse_cache to "www-data" ;
+GRANT INSERT on reverse_cache to "www-data" ;
+CREATE INDEX idx_reverse_cache_latlonzoomid ON reverse_cache USING BTREE (latlonzoomid);
+
+drop table country;
+CREATE TABLE country (
+  country_code varchar(2),
+  country_name hstore,
+  country_default_language_code varchar(2)
+  );
+SELECT AddGeometryColumn('country', 'geometry', 4326, 'POLYGON', 2);
+insert into country select iso3166::varchar(2), ARRAY[ROW('name:en',cntry_name)::keyvalue], null, 
+  ST_Transform(geometryn(the_geom, generate_series(1, numgeometries(the_geom))), 4326) from worldboundaries;
+CREATE INDEX idx_country_country_code ON country USING BTREE (country_code);
+CREATE INDEX idx_country_geometry ON country USING GIST (geometry);
+
+drop table placex;
+CREATE TABLE placex (
+  place_id bigint NOT NULL,
+  partition varchar(10),
+  osm_type char(1),
+  osm_id bigint,
+  class TEXT NOT NULL,
+  type TEXT NOT NULL,
+  name HSTORE,
+  admin_level integer,
+  housenumber TEXT,
+  street TEXT,
+  isin TEXT,
+  postcode TEXT,
+  country_code varchar(2),
+  street_place_id bigint,
+  rank_address INTEGER,
+  rank_search INTEGER,
+  indexed_status INTEGER,
+  indexed_date TIMESTAMP,
+  geometry_sector INTEGER
+  );
+SELECT AddGeometryColumn('placex', 'geometry', 4326, 'GEOMETRY', 2);
+CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id);
+CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id);
+CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search);
+CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address);
+CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry);
+CREATE INDEX idx_placex_indexed ON placex USING BTREE (indexed);
+CREATE INDEX idx_placex_pending ON placex USING BTREE (rank_search) where name IS NOT NULL and indexed = false;
+CREATE INDEX idx_placex_pendingbylatlon ON placex USING BTREE (geometry_index(geometry_sector,indexed,name),rank_search) 
+  where geometry_index(geometry_sector,indexed,name) IS NOT NULL;
+CREATE INDEX idx_placex_street_place_id ON placex USING BTREE (street_place_id) where street_place_id IS NOT NULL;
+CREATE INDEX idx_placex_gb_postcodesector ON placex USING BTREE (substring(upper(postcode) from '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$'))
+  where country_code = 'gb' and substring(upper(postcode) from '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$') is not null;
+CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) where indexed = false and class='place' and type='houses';
+CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id);
+CLUSTER placex USING idx_placex_sector;
+
+DROP SEQUENCE seq_place;
+CREATE SEQUENCE seq_place start 1;
+GRANT SELECT on placex to "www-data" ;
+GRANT UPDATE ON placex to "www-data" ;
+GRANT SELECT ON search_name to "www-data" ;
+GRANT DELETE on search_name to "www-data" ;
+GRANT INSERT on search_name to "www-data" ;
+GRANT SELECT on place_addressline to "www-data" ;
+GRANT INSERT ON place_addressline to "www-data" ;
+GRANT DELETE on place_addressline to "www-data" ;
+GRANT SELECT on location_point to "www-data" ;
+GRANT SELECT ON seq_word to "www-data" ;
+GRANT UPDATE ON seq_word to "www-data" ;
+GRANT INSERT ON word to "www-data" ;
+GRANT SELECT ON planet_osm_ways to "www-data" ;
+GRANT SELECT ON planet_osm_rels to "www-data" ;
+GRANT SELECT on location_point to "www-data" ;
+GRANT SELECT on location_area to "www-data" ;
+GRANT SELECT on location_point_26 to "www-data" ;
+GRANT SELECT on location_point_25 to "www-data" ;
+GRANT SELECT on location_point_24 to "www-data" ;
+GRANT SELECT on location_point_23 to "www-data" ;
+GRANT SELECT on location_point_22 to "www-data" ;
+GRANT SELECT on location_point_21 to "www-data" ;
+GRANT SELECT on location_point_20 to "www-data" ;
+GRANT SELECT on location_point_19 to "www-data" ;
+GRANT SELECT on location_point_18 to "www-data" ;
+GRANT SELECT on location_point_17 to "www-data" ;
+GRANT SELECT on location_point_16 to "www-data" ;
+GRANT SELECT on location_point_15 to "www-data" ;
+GRANT SELECT on location_point_14 to "www-data" ;
+GRANT SELECT on location_point_13 to "www-data" ;
+GRANT SELECT on location_point_12 to "www-data" ;
+GRANT SELECT on location_point_11 to "www-data" ;
+GRANT SELECT on location_point_10 to "www-data" ;
+GRANT SELECT on location_point_9 to "www-data" ;
+GRANT SELECT on location_point_8 to "www-data" ;
+GRANT SELECT on location_point_7 to "www-data" ;
+GRANT SELECT on location_point_6 to "www-data" ;
+GRANT SELECT on location_point_5 to "www-data" ;
+GRANT SELECT on location_point_4 to "www-data" ;
+GRANT SELECT on location_point_3 to "www-data" ;
+GRANT SELECT on location_point_2 to "www-data" ;
+GRANT SELECT on location_point_1 to "www-data" ;
+GRANT SELECT on country to "www-data" ;
+
+-- insert creates the location tagbles, creates location indexes if indexed == true
+CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex
+    FOR EACH ROW EXECUTE PROCEDURE placex_insert();
+
+-- update insert creates the location tables
+CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex
+    FOR EACH ROW EXECUTE PROCEDURE placex_update();
+
+-- diff update triggers
+CREATE TRIGGER placex_before_delete AFTER DELETE ON placex
+    FOR EACH ROW EXECUTE PROCEDURE placex_delete();
+CREATE TRIGGER place_before_delete BEFORE DELETE ON place
+    FOR EACH ROW EXECUTE PROCEDURE place_delete();
+CREATE TRIGGER place_before_insert BEFORE INSERT ON place
+    FOR EACH ROW EXECUTE PROCEDURE place_insert();
+
+alter table placex add column geometry_sector INTEGER;
+alter table placex add column indexed_status INTEGER;
+alter table placex add column indexed_date TIMESTAMP;
+
+update placex set geometry_sector = geometry_sector(geometry);
+drop index idx_placex_pendingbylatlon;
+drop index idx_placex_interpolation;
+drop index idx_placex_sector;
+CREATE INDEX idx_placex_pendingbylatlon ON placex USING BTREE (geometry_index(geometry_sector,indexed,name),rank_search) 
+  where geometry_index(geometry_sector,indexed,name) IS NOT NULL;
+CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) where indexed = false and class='place' and type='houses';
+CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id);
diff --git a/utils/setup.php b/utils/setup.php
new file mode 100755 (executable)
index 0000000..397eaa1
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/php -Cq
+<?php
+
+       require_once('../lib/init-cmd.php');
+       ini_set('memory_limit', '800M');
+
+       $aCMDOptions = array(
+               "Create and setup nominatim search system",
+               array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
+               array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
+               array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
+
+               array('create-partitions', '', 0, 1, 0, 0, 'bool', 'Create required partition tables and triggers'),
+       );
+       getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
+
+       if ($aCMDResult['create-partitions'])
+       {
+               $sSQL = 'select distinct country_code from country_name order by country_code';
+               $aPartitions = $oDB->getCol($sSQL);
+               $aPartitions[] = 'none';
+
+               $sTemplate = file_get_contents(CONST_BasePath.'/sql/partitions.src.sql');
+               preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
+               foreach($aMatches as $aMatch)
+               {
+                       $sResult = '';
+                       foreach($aPartitions as $sPartitionName)
+                       {
+                               $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
+                       }
+                       $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
+               }
+               echo $sTemplate;
+       }
+
+       showUsage($aCMDOptions, true);