to-braille/src/main.rs
2025-04-21 00:21:49 -05:00

482 lines
34 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use clap::{Parser, ValueEnum};
use crossterm::terminal::size;
use image::{imageops::FilterType::Lanczos3, DynamicImage, ImageReader};
use itertools::Itertools;
use rand::Rng;
const BRAILLE: [&str; 64] = [
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "",
];
struct ThresholdMatrix {
n_rows: u32,
n_cols: u32,
matrix: Vec<u16>,
}
impl ThresholdMatrix {
fn bayer(power: u32) -> Self {
let length = 2_u32.pow(power);
let size = length * length;
let norm_factor = 65535. / size as f32;
let matrix = (0..length)
.cartesian_product(0..length)
.map(|(x, y)| {
let xc = x ^ y;
let yc = y;
let mut v = 0;
for p in (0..power).rev() {
let bit_idx = 2 * (power - p - 1);
v |= ((yc >> p) & 1) << bit_idx;
v |= ((xc >> p) & 1) << (bit_idx + 1);
}
(v as f32 * norm_factor) as u16
})
.collect();
Self {
n_rows: length,
n_cols: length,
matrix,
}
}
fn blue_noise() -> Self {
let matrix = Vec::from(BLUE_NOISE);
Self {
n_rows: 64,
n_cols: 64,
matrix,
}
}
fn white_noise(n_rows: u32, n_cols: u32) -> Self {
let size = n_rows * n_cols;
let mut matrix: Vec<u16> = Vec::new();
matrix.reserve_exact(size as usize);
let mut rng = rand::rng();
for _ in 0..size {
matrix.push(rng.random())
}
Self {
n_rows,
n_cols,
matrix,
}
}
fn look_up(&self, row: u32, col: u32) -> u16 {
let i = row % self.n_rows;
let j = col % self.n_cols;
self.matrix[(i * self.n_rows + j) as usize]
}
}
fn make_braille_pic(picture: DynamicImage, maybe_thresholds: Option<ThresholdMatrix>) {
let num_cells = get_cells_size(picture.width(), picture.height());
let braille_size = (num_cells.0 * 2, num_cells.1 * 3);
let resized_image = picture.resize_exact(braille_size.0, braille_size.1, Lanczos3);
let bw_image = resized_image.into_luma16();
let mut buf: Vec<Vec<u8>> = vec![vec![0; num_cells.0 as usize]; num_cells.1 as usize];
if let Some(thresholds) = maybe_thresholds {
for (x, y, pixel) in bw_image.enumerate_pixels() {
let pixel_value = pixel.0[0];
let pixel_on = pixel_value > thresholds.look_up(x, y);
if pixel_on {
let row = y / 3;
let col = x / 2;
let braille_row = y % 3;
let braille_col = x % 2;
buf[row as usize][col as usize] += 1 << (3 * braille_col + braille_row);
}
}
} else {
for (x, y, pixel) in bw_image.enumerate_pixels() {
let pixel_value = pixel.0[0];
let pixel_on = pixel_value > 32768;
if pixel_on {
let row = y / 3;
let col = x / 2;
let braille_row = y % 3;
let braille_col = x % 2;
buf[row as usize][col as usize] += 1 << (3 * braille_col + braille_row);
}
}
}
for row in buf {
for braille_index in row {
print!("{}", BRAILLE[braille_index as usize]);
}
println!()
}
}
fn get_cells_size(width: u32, height: u32) -> (u32, u32) {
let pic_size = (width as f32, height as f32);
let term_size = size().unwrap();
let bounded_term_size = ((term_size.0) as f32 / 2.0, (term_size.1 - 1) as f32);
let scale_factors = (
pic_size.0 / bounded_term_size.0,
pic_size.1 / bounded_term_size.1,
);
let scale_factor = f32::max(scale_factors.0, scale_factors.1);
(
2 * (pic_size.0 / scale_factor).floor() as u32,
(pic_size.1 / scale_factor).floor() as u32,
)
}
fn main() {
let cli = Cli::parse();
let my_image = ImageReader::open(cli.image).unwrap().decode().unwrap();
let my_thresholds = if let Some(dither_type) = cli.dithering {
match dither_type {
DitherType::Bayer => Some(ThresholdMatrix::bayer(2)),
DitherType::Blue => Some(ThresholdMatrix::blue_noise()),
DitherType::White => Some(ThresholdMatrix::white_noise(
my_image.width(),
my_image.height(),
)),
}
} else {
None
};
make_braille_pic(my_image, my_thresholds);
}
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
/// Choose dithering type
#[arg(long, short, value_enum)]
dithering: Option<DitherType>,
/// Path to image
image: String,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum DitherType {
/// Bayer matrix (size 4)
Bayer,
/// Blue noise
Blue,
/// White noise
White,
}
const BLUE_NOISE: [u16; 4096] = [
16672, 63280, 52112, 45440, 14000, 38144, 24640, 34672, 31296, 15936, 27984, 52736, 7040,
55776, 38912, 26384, 64160, 20112, 31440, 58608, 816, 21328, 59744, 41184, 11680, 62032, 27888,
10352, 32144, 23984, 51616, 9152, 59152, 48096, 65232, 53056, 37776, 3488, 22272, 34368, 63008,
50592, 45392, 57376, 15184, 23616, 33840, 43440, 12640, 46880, 35920, 880, 14880, 42256, 6992,
52336, 3136, 21312, 50256, 1264, 40896, 47008, 23760, 50464, 43744, 36080, 6192, 32656, 28128,
65504, 9200, 53872, 20304, 49472, 45664, 36144, 43200, 2864, 17904, 33488, 46608, 6912, 37856,
12160, 49040, 43728, 17136, 3472, 47952, 19600, 80, 50528, 41408, 17040, 37408, 44192, 26640,
34512, 14944, 24832, 46688, 59408, 41632, 29472, 8864, 18912, 544, 60992, 41664, 48160, 1776,
62288, 55824, 8048, 17760, 49552, 62560, 22352, 37488, 33440, 63680, 44224, 57680, 26688,
60336, 5440, 55888, 30000, 60624, 12576, 22448, 39696, 58576, 17824, 3968, 42736, 60304, 6336,
12320, 22112, 30480, 61040, 50000, 23264, 1744, 56704, 42384, 26928, 5344, 65520, 30832, 37424,
54096, 33200, 22640, 60592, 5616, 13360, 62768, 4576, 18896, 40464, 6352, 1952, 32400, 11072,
16576, 48672, 56048, 24416, 32784, 6128, 53216, 11888, 29056, 37248, 21840, 26208, 58720,
30704, 10448, 27280, 56944, 17072, 12736, 38960, 8096, 32384, 12016, 37120, 14768, 2672, 49120,
26784, 54768, 944, 10928, 50448, 46640, 26704, 37648, 304, 57232, 64640, 15360, 8752, 41280,
11600, 62688, 15712, 53440, 34064, 22816, 51168, 9600, 14432, 62960, 7424, 44736, 38928, 29424,
48640, 54352, 32576, 46064, 61072, 55296, 49952, 63200, 27952, 6672, 61584, 43760, 13296,
39760, 27680, 20816, 63888, 7168, 50032, 15472, 44848, 39312, 4960, 53360, 45344, 4016, 47872,
29376, 54080, 24000, 18592, 45712, 52096, 20992, 41552, 7264, 18464, 46048, 61968, 41168,
21424, 30880, 14128, 54848, 32976, 39936, 25728, 46224, 34864, 54784, 27344, 37104, 30048,
7872, 59232, 18304, 39680, 45552, 27360, 24272, 57520, 12192, 17840, 58864, 25344, 21392, 1104,
11696, 29216, 22416, 36208, 18576, 40112, 52016, 20448, 35664, 3456, 59504, 46416, 35200,
17344, 40800, 54416, 2656, 33392, 65040, 19776, 13472, 41040, 60256, 20528, 1440, 61872, 49392,
4784, 65120, 28608, 58224, 33552, 63520, 37872, 29680, 15296, 34288, 53232, 6704, 63616, 23376,
17376, 7952, 51840, 3360, 20016, 58848, 4144, 51552, 21040, 47088, 13392, 61632, 4640, 56592,
1984, 35632, 41840, 51952, 3216, 34336, 8256, 42176, 57344, 50880, 16176, 8576, 43536, 13200,
57424, 25856, 5024, 29920, 54112, 15792, 50800, 9248, 58000, 31216, 24016, 60560, 9808, 51376,
24912, 36240, 31600, 8544, 26272, 35648, 42480, 14960, 34240, 40304, 1056, 24688, 10496, 50976,
3408, 56272, 25264, 4320, 58208, 36880, 10224, 48592, 44208, 60736, 29008, 13648, 48464, 32256,
17152, 44400, 40048, 1040, 25952, 36288, 29328, 52544, 16304, 48976, 20352, 30336, 61760,
47504, 14656, 36736, 63568, 26352, 39504, 58752, 31056, 224, 45744, 9936, 38416, 47808, 65072,
22848, 1120, 26080, 44304, 4400, 47616, 14032, 28800, 42912, 112, 55232, 63328, 16128, 52064,
58304, 10976, 22000, 56320, 8768, 53040, 16608, 44288, 20512, 13184, 47696, 9488, 43952, 18832,
28240, 41456, 2528, 56384, 20800, 35856, 41984, 61856, 6624, 24432, 64848, 9920, 55216, 49712,
43648, 11248, 21936, 32240, 64096, 5584, 10288, 38336, 27744, 53248, 19568, 5392, 33328, 3264,
47024, 64672, 24160, 53824, 61776, 33264, 17536, 11472, 42320, 32592, 62192, 12256, 38976,
21152, 36512, 57120, 18224, 7392, 45936, 22208, 48560, 38464, 6160, 45152, 31280, 26816, 47232,
36336, 61184, 30768, 57760, 34688, 22832, 64944, 32096, 49520, 62224, 15584, 24992, 31680,
11440, 1296, 54368, 26848, 38048, 12912, 57248, 34592, 30736, 19184, 63488, 7536, 58624, 40688,
13664, 45360, 54864, 22576, 1376, 43184, 10944, 49168, 23200, 54688, 18960, 7408, 34720, 15248,
21472, 2352, 57808, 28224, 6976, 37184, 55248, 18000, 52528, 64288, 5632, 49872, 39712, 62256,
34128, 11856, 2160, 29664, 18768, 63872, 3792, 59776, 19728, 12240, 5952, 39536, 27200, 42336,
52624, 512, 39136, 12560, 6384, 52960, 59632, 38624, 46960, 64448, 16960, 8928, 52208, 47488,
5152, 22224, 14608, 2752, 38640, 24768, 47792, 768, 35168, 60032, 26192, 16368, 65184, 56800,
30608, 59440, 44544, 13760, 37952, 51760, 41536, 29456, 50016, 44336, 39424, 52160, 60224,
20400, 48432, 29232, 1616, 33712, 27024, 11120, 23488, 30400, 15216, 57968, 41696, 24384,
54720, 34912, 14224, 49664, 41952, 24192, 54288, 2560, 61616, 7200, 16448, 59536, 26752, 21712,
45584, 35152, 19024, 4544, 50864, 22864, 33680, 43920, 19872, 28976, 41136, 60496, 51120,
57744, 32800, 16848, 53744, 27856, 19312, 8896, 39888, 50368, 33824, 7520, 40384, 17168, 28736,
9296, 61440, 26944, 4928, 11904, 56496, 8384, 23872, 13600, 2800, 45728, 14848, 8688, 58080,
43488, 16336, 46720, 60288, 52880, 4816, 27392, 50768, 60608, 10048, 40256, 52480, 368, 32560,
64592, 45504, 18512, 49056, 31456, 10768, 36624, 50944, 3248, 55968, 30688, 9040, 27712, 13888,
40816, 5984, 61552, 56208, 16, 36704, 25616, 45488, 9456, 42560, 62400, 3984, 44480, 57552,
31696, 5072, 46944, 12784, 21200, 4032, 62640, 36272, 848, 55744, 20896, 47456, 64048, 36384,
18864, 27376, 62976, 31792, 35184, 25376, 39984, 61488, 22240, 51744, 2736, 34736, 8992, 43632,
36784, 17664, 46624, 7152, 22496, 28144, 17120, 37760, 7824, 29648, 13792, 38544, 44624, 56672,
19552, 42000, 61728, 14800, 40032, 63696, 44352, 58064, 54832, 25392, 30928, 15456, 11104,
63312, 17216, 4272, 28288, 13280, 36976, 22912, 51248, 14560, 62992, 24112, 53424, 37616,
27040, 45856, 52560, 24208, 48848, 32896, 16752, 43584, 1936, 31360, 58768, 5680, 49616, 41648,
55904, 4064, 50176, 11936, 31520, 7664, 40720, 18784, 55632, 21696, 65296, 3392, 13728, 33456,
62656, 44576, 59040, 11040, 56528, 51712, 22048, 62784, 5792, 24032, 33696, 8480, 29248, 24512,
48864, 752, 21552, 35984, 10320, 2448, 37600, 45824, 49824, 33376, 53904, 20656, 48896, 56064,
6544, 30512, 10672, 35712, 41920, 2880, 18048, 61200, 56240, 31888, 14640, 41600, 11264, 58592,
39088, 24928, 14528, 53664, 40096, 46304, 16992, 10912, 21984, 64976, 18336, 36832, 26432,
57440, 63728, 29072, 45792, 11344, 31952, 57360, 26720, 38576, 55344, 5936, 20752, 47360,
25888, 35248, 1568, 28624, 53952, 13312, 58816, 46112, 4416, 54528, 11584, 33648, 60448, 16240,
48128, 52896, 20944, 59472, 23952, 7344, 41888, 31152, 64928, 39104, 18128, 60896, 48048,
20576, 55152, 29824, 11168, 43296, 1584, 8736, 19904, 64816, 3168, 29152, 7584, 61216, 51008,
9968, 21248, 33760, 800, 59616, 28672, 6944, 42960, 54944, 400, 48144, 13776, 24672, 38000,
1216, 50352, 41392, 19248, 48480, 1792, 30560, 14864, 40832, 4592, 60096, 17392, 47584, 40528,
2944, 49632, 16736, 63232, 37008, 18608, 52400, 6880, 31312, 26880, 65424, 40448, 13344, 3200,
57328, 36224, 10304, 1632, 23712, 53104, 44080, 416, 8032, 26320, 64624, 36528, 49024, 23360,
60016, 50512, 34784, 46800, 22336, 54208, 35456, 4160, 29792, 63584, 25248, 54432, 37504,
51680, 46656, 15152, 33536, 21072, 39232, 4352, 53184, 61888, 16256, 23328, 60960, 8240, 52576,
24624, 37072, 64240, 50832, 32448, 43424, 10176, 65200, 25168, 35776, 31024, 22160, 43520,
27552, 41008, 23792, 46864, 43248, 3920, 17920, 8464, 30144, 44560, 27296, 15952, 59792, 46928,
14144, 33984, 27440, 40672, 59120, 50816, 15232, 6112, 32928, 16384, 28528, 38816, 5472, 56848,
13712, 42720, 19152, 45456, 48944, 16048, 7728, 44112, 13424, 31184, 23600, 60944, 9856, 63088,
43968, 17712, 8832, 32768, 47152, 6080, 30112, 12656, 43168, 17312, 56912, 8816, 22720, 13072,
54896, 20144, 7472, 14736, 52912, 59712, 10464, 5568, 56816, 1968, 64080, 13824, 58432, 38992,
50704, 34048, 55136, 62848, 19408, 52304, 43472, 25936, 5664, 62480, 11456, 16944, 31936,
22688, 46192, 57888, 40416, 54304, 44976, 12080, 26224, 17440, 32624, 63056, 27248, 12000,
58096, 40656, 34832, 61984, 19744, 2544, 39920, 4880, 27008, 50720, 30368, 57776, 36464, 26896,
58784, 39392, 55168, 35344, 63040, 4496, 33504, 45248, 58832, 832, 29840, 38064, 33152, 44320,
1680, 19328, 39168, 51152, 15344, 30080, 8880, 35424, 20688, 11088, 62016, 22464, 5232, 47664,
38208, 2400, 32864, 20912, 56432, 49728, 36016, 54592, 4224, 37920, 12752, 2112, 20768, 8304,
63776, 32, 59248, 52512, 39840, 6928, 1168, 37744, 22608, 3120, 28064, 56160, 10560, 47632,
58480, 53264, 35440, 12608, 5456, 48816, 21904, 42864, 3616, 14352, 20624, 25920, 47936, 10992,
28496, 18976, 40144, 26528, 61648, 50160, 23248, 57840, 28448, 62576, 45760, 32672, 61008,
48688, 53920, 25776, 55984, 656, 28688, 42464, 14400, 25088, 9088, 12464, 63904, 40176, 29200,
8784, 45376, 20208, 64032, 42656, 28384, 61712, 25488, 51024, 31488, 36848, 22736, 44032,
10144, 49904, 55552, 32048, 65360, 52272, 6368, 49776, 24736, 32832, 15696, 42144, 19920,
60048, 24848, 15328, 54400, 10800, 62384, 51488, 44896, 48, 59072, 38496, 53840, 49280, 6448,
15808, 46144, 4096, 17728, 9056, 37056, 12960, 25472, 7312, 22656, 18160, 38736, 44464, 32016,
16864, 46560, 35904, 51328, 59568, 30592, 54800, 49136, 4704, 17632, 60432, 1904, 25072, 51312,
10032, 56128, 47264, 35520, 14176, 18640, 47920, 4112, 29520, 20272, 60640, 25424, 16896,
46544, 20432, 14720, 42544, 38096, 64416, 7936, 29184, 1920, 45280, 38240, 64992, 2304, 34160,
18240, 29312, 8112, 32432, 16512, 22592, 3088, 63296, 36416, 56544, 11552, 53312, 63952, 40608,
48400, 55504, 3888, 35312, 42032, 12224, 2592, 5824, 49568, 60352, 8000, 56976, 3744, 18032,
41872, 36432, 15504, 23504, 43232, 37552, 31136, 14592, 34224, 5040, 16832, 30640, 3376, 58880,
41216, 54576, 61920, 14992, 35232, 45536, 13088, 41104, 8496, 34528, 61536, 30288, 288, 18272,
55408, 23040, 48512, 56656, 8400, 31200, 41504, 47248, 24080, 57872, 40368, 64656, 52240,
42576, 13696, 25200, 31392, 21120, 42048, 34480, 30240, 240, 21232, 16192, 51904, 64800, 47408,
58384, 28048, 63152, 23408, 37376, 12528, 26448, 32992, 21680, 62112, 448, 27824, 58352, 51520,
11648, 55328, 47968, 61120, 39648, 23280, 53152, 44608, 11360, 6592, 24400, 9344, 39408, 57216,
1712, 30624, 53792, 4176, 56960, 23664, 44880, 12832, 50544, 35760, 62208, 11616, 33600, 17984,
27312, 52352, 5872, 36912, 49920, 12032, 27264, 5744, 35072, 55616, 9184, 44496, 59264, 7216,
24464, 60528, 45040, 57536, 32192, 26560, 10128, 19584, 55088, 33808, 14816, 51600, 19936,
40944, 64864, 53584, 7376, 44960, 48304, 9520, 33856, 65168, 6864, 21920, 27504, 42224, 7776,
63344, 19472, 37664, 27408, 64688, 34032, 51728, 28000, 5808, 63984, 22624, 49424, 38288,
27600, 10240, 59360, 54144, 6000, 27120, 39600, 4688, 42704, 60784, 13168, 21056, 63024, 15824,
1600, 22144, 45840, 19760, 61520, 28752, 47376, 17472, 2640, 49648, 14208, 27728, 11024, 6032,
42816, 37968, 2224, 30320, 39440, 7008, 43120, 9792, 30992, 45808, 1552, 15904, 39456, 24560,
57296, 13904, 19616, 39296, 45168, 1088, 18144, 56928, 13232, 32944, 48720, 704, 55808, 20928,
43280, 16768, 47280, 19200, 42672, 11760, 59648, 18384, 47776, 3008, 40592, 19696, 31776,
46368, 16064, 21536, 49504, 624, 55040, 44944, 9280, 56080, 33424, 60704, 38304, 10432, 49184,
976, 33664, 63824, 39344, 52640, 36672, 54640, 18688, 50688, 62416, 21968, 58944, 45904, 16704,
24656, 53648, 61504, 4864, 56096, 28656, 49968, 11008, 34768, 29952, 53296, 3072, 25968, 31744,
59760, 36176, 51648, 3872, 26064, 59376, 15424, 30192, 50048, 12384, 3104, 32000, 52944, 25904,
35808, 6480, 32704, 62928, 13968, 36256, 25312, 63376, 9072, 58288, 53344, 24720, 30256, 35104,
39184, 25648, 29392, 42432, 53120, 3904, 57264, 15408, 41264, 23136, 12064, 26800, 20320, 4608,
65312, 39968, 34656, 14704, 8160, 52448, 12336, 63712, 480, 48112, 34896, 17872, 23056, 36800,
59728, 20384, 63552, 5504, 42192, 62352, 47136, 15264, 49808, 8912, 29296, 44144, 38800, 10416,
46272, 6064, 40160, 60368, 57408, 37456, 62544, 9136, 56480, 16032, 44592, 22016, 29584, 52816,
49104, 1392, 43376, 13328, 36544, 64368, 7552, 16464, 59680, 2512, 48704, 12592, 17696, 31408,
26160, 36496, 51280, 60320, 7632, 57728, 32304, 46096, 23824, 1200, 30864, 25056, 48000, 28464,
35264, 41680, 20128, 26832, 57920, 11872, 42352, 7808, 46912, 2608, 51968, 17024, 37232, 21408,
55728, 11392, 40768, 23888, 64528, 16688, 53280, 21856, 62320, 35936, 25520, 7904, 22992,
14688, 384, 40992, 29024, 50992, 1872, 55024, 41808, 5136, 17088, 56720, 33248, 28864, 3024,
41056, 46240, 11312, 50912, 19488, 65456, 23696, 7056, 44800, 62912, 21264, 4976, 29712, 43056,
48176, 15680, 9424, 42288, 12816, 57168, 44384, 3152, 55936, 5376, 59808, 32112, 38752, 3600,
50960, 64432, 14752, 26336, 32208, 43808, 12512, 28160, 8144, 34416, 4256, 60976, 20048, 2080,
33968, 58048, 5088, 31824, 18544, 52704, 43888, 29488, 49008, 20496, 46176, 23808, 64464,
38720, 9536, 60544, 11968, 24128, 38128, 20224, 60864, 51664, 18208, 23184, 56576, 32272, 4800,
40320, 34928, 59184, 47904, 9568, 54000, 13840, 18320, 55520, 2384, 37792, 59200, 17744, 49600,
61664, 19632, 37680, 15440, 23152, 49408, 9632, 14240, 45424, 29408, 33776, 54960, 40224,
57504, 23680, 61248, 50240, 58688, 25216, 52784, 30576, 45472, 55280, 12704, 24576, 42496,
50480, 1424, 65440, 11424, 34576, 61296, 55472, 5920, 33744, 12800, 26544, 19792, 31664, 45632,
65248, 6656, 48016, 10208, 26496, 5296, 62144, 37824, 27088, 43904, 53632, 15040, 28560, 2896,
41520, 31904, 38592, 64576, 34384, 25504, 52864, 28912, 36112, 4384, 8512, 53008, 32752, 64544,
43408, 18480, 54464, 62736, 23744, 6800, 21008, 960, 18288, 10016, 4768, 38560, 46352, 272,
42880, 17888, 36656, 6288, 39856, 48272, 9024, 37392, 14256, 27968, 56352, 16656, 4912, 39008,
10112, 17936, 59856, 48544, 3952, 58336, 35056, 50192, 28080, 41232, 55264, 15312, 43664,
33952, 48384, 13984, 8624, 21104, 58192, 10336, 37216, 19088, 50080, 24048, 208, 45776, 10880,
21488, 6640, 63104, 32128, 22800, 27616, 40432, 11568, 25696, 7488, 31168, 1360, 40576, 52080,
60160, 37152, 48320, 62608, 53328, 29696, 20176, 15616, 33120, 11952, 63808, 49344, 14832,
27056, 63168, 29904, 60176, 45600, 21168, 40496, 47552, 25232, 51936, 31472, 44448, 37200,
15632, 42608, 52496, 7232, 14096, 144, 21952, 31008, 36064, 59216, 53776, 992, 30352, 63920,
51360, 2096, 25104, 63216, 55056, 12848, 60128, 56448, 27632, 51040, 40512, 14384, 44832,
10544, 54480, 60192, 45520, 2016, 51264, 58256, 47392, 27328, 34544, 16640, 11504, 42896,
27696, 14064, 44992, 35888, 65344, 6016, 56560, 23168, 28992, 9328, 59168, 21376, 720, 18064,
51424, 4080, 8176, 32288, 59024, 2368, 21520, 64128, 27520, 2720, 54704, 29552, 23088, 40016,
18496, 57136, 62080, 3808, 8224, 19424, 11744, 22288, 40560, 45216, 17456, 34272, 48800, 43136,
29776, 5280, 33872, 8640, 16400, 61696, 3552, 57856, 48336, 640, 37984, 15648, 21024, 34992,
61392, 13632, 38176, 21216, 56464, 4368, 25456, 57936, 8080, 32368, 2128, 49456, 25680, 41200,
52224, 47472, 4128, 38080, 53600, 32640, 44128, 56144, 34944, 23856, 62048, 36688, 13504,
54912, 42112, 12208, 50496, 8288, 20192, 63392, 10624, 60400, 37040, 26112, 44528, 52608,
47056, 39120, 25584, 61152, 55376, 4528, 27776, 38848, 7248, 22128, 15776, 46464, 39632, 20032,
43776, 36768, 29936, 24528, 19392, 42752, 56608, 49248, 5328, 29632, 17552, 42304, 3344, 10272,
64960, 45120, 50384, 19456, 39568, 60800, 22304, 11280, 59104, 7760, 34960, 19680, 61376,
42096, 24448, 12272, 5776, 40208, 15744, 11184, 52768, 46432, 18368, 30208, 6608, 35968, 24176,
57584, 46016, 33920, 1808, 47328, 51344, 32496, 12368, 16592, 63744, 28768, 50096, 6784, 32544,
14512, 59984, 10896, 56256, 61424, 1504, 53168, 64176, 23424, 48608, 7088, 54240, 34320, 64912,
26592, 31104, 12432, 63664, 46592, 24544, 55760, 33184, 49152, 15088, 30176, 35504, 5712,
51856, 15392, 43344, 55536, 17600, 27904, 13536, 31264, 1280, 16560, 50128, 58176, 46976,
26144, 64064, 29136, 42848, 1536, 26576, 62496, 49200, 16480, 60688, 38432, 14016, 41616,
24960, 17200, 5200, 8720, 41792, 23216, 34400, 1696, 43216, 17856, 36560, 46736, 51696, 20064,
31968, 41712, 36480, 26736, 10064, 31584, 3184, 59872, 12672, 16976, 8432, 36928, 3696, 23232,
41024, 9312, 52672, 6240, 28016, 59600, 23568, 40912, 160, 62720, 28640, 24064, 33520, 4240,
47040, 39264, 63248, 45232, 56880, 36128, 8016, 19040, 34112, 2784, 54272, 7360, 37808, 20848,
56992, 9952, 44784, 31984, 576, 28576, 5424, 53728, 31040, 56736, 64896, 28320, 54992, 4512,
58736, 13568, 56336, 9648, 65088, 23904, 336, 43872, 25712, 12944, 18176, 49376, 57104, 14576,
51808, 28032, 41584, 46832, 50928, 60928, 53616, 58128, 16496, 36032, 62432, 39248, 19056,
44064, 8448, 54512, 12720, 45888, 56304, 9776, 64224, 36960, 52688, 2432, 21664, 54032, 11408,
27232, 65024, 30224, 59888, 22176, 48960, 17360, 60464, 50624, 34192, 3936, 40080, 22032,
55792, 19168, 62864, 49760, 11296, 21584, 43792, 36608, 48368, 19712, 38512, 30096, 51984,
20832, 40880, 30784, 7856, 54336, 63456, 3648, 59552, 6752, 34448, 43104, 37904, 18992, 62752,
2208, 21280, 13616, 6896, 43696, 32336, 912, 21616, 13040, 51536, 2416, 61936, 33792, 21776,
17776, 38384, 6432, 49072, 19824, 29968, 9008, 41968, 24704, 5184, 38448, 46384, 14336, 42976,
10480, 39744, 31232, 12304, 24320, 15072, 65136, 52144, 11840, 47536, 42832, 8976, 35088,
39616, 2624, 14416, 60240, 25440, 10400, 63120, 45696, 26240, 3504, 48448, 58528, 15376, 34640,
47648, 39488, 29088, 45408, 21344, 1664, 58416, 10608, 23968, 39664, 33408, 46256, 18880,
25280, 50224, 28416, 58992, 47312, 31728, 16080, 37440, 27168, 48208, 59312, 31552, 42448,
13952, 26512, 57312, 16272, 62000, 33056, 50784, 20256, 2176, 52176, 6416, 35472, 56752, 96,
46528, 42064, 6256, 29360, 25744, 36944, 59920, 15760, 27216, 23440, 58016, 46576, 18560,
33568, 496, 53856, 15536, 5760, 35328, 61456, 12112, 27568, 38016, 19296, 9904, 22976, 53504,
15984, 65376, 25568, 30800, 55008, 5216, 52800, 29344, 9584, 57152, 37712, 65216, 11216, 5008,
42624, 25040, 57024, 5312, 53136, 10640, 2688, 25008, 54064, 3584, 60512, 44048, 35872, 48624,
13376, 58976, 40976, 55584, 23728, 28304, 61232, 18800, 26400, 63472, 54976, 36096, 58800,
18448, 2272, 7280, 33312, 52992, 3520, 64016, 28880, 50896, 7888, 41472, 30976, 49840, 23520,
40064, 17424, 55184, 2496, 51408, 60752, 5104, 57616, 32720, 11808, 50848, 8320, 47712, 35024,
44368, 16208, 63536, 41152, 48752, 2976, 15008, 34560, 55696, 38672, 8656, 63632, 20464, 44720,
40272, 65056, 16720, 50208, 33344, 10960, 22512, 6832, 352, 28112, 17792, 7696, 31632, 63184,
15600, 44176, 50432, 33616, 5168, 16544, 9120, 48192, 43600, 55312, 39776, 61840, 20288, 44096,
6688, 12992, 38608, 57008, 62176, 20608, 44000, 57984, 8704, 33088, 42160, 22528, 45024, 31648,
25984, 43088, 672, 36352, 41248, 61280, 18096, 12976, 60144, 26864, 176, 23584, 30944, 20416,
44640, 51072, 22880, 18016, 30272, 48912, 34880, 14304, 29504, 7792, 36192, 20736, 62800,
39808, 47344, 30912, 53760, 64608, 45328, 36640, 11920, 47568, 38368, 4208, 9744, 22960, 40704,
52592, 21136, 32224, 11488, 22784, 30160, 13856, 49488, 37520, 31840, 54384, 22320, 26368,
11376, 36320, 4432, 13248, 64720, 28784, 47984, 7120, 63648, 10848, 17264, 49936, 62336, 20560,
27792, 3632, 38768, 22400, 7504, 50416, 35840, 11792, 54128, 59488, 6496, 27184, 62832, 3440,
12624, 59520, 1328, 24224, 51472, 56864, 46400, 1136, 27536, 55680, 18528, 59696, 38272, 10080,
21792, 26096, 58272, 1232, 20880, 54224, 58704, 13584, 45952, 28704, 60880, 4624, 50672, 64208,
45872, 784, 25136, 10160, 60832, 16288, 43008, 1728, 47600, 17648, 53552, 25600, 51232, 736,
20160, 57056, 14192, 35696, 39872, 55600, 7968, 14896, 45264, 52656, 55872, 32416, 42272,
57712, 17504, 4832, 62368, 39904, 32816, 9712, 53568, 46896, 39520, 54448, 43264, 18928, 61104,
11664, 31376, 41776, 14112, 8848, 4464, 24944, 15200, 42400, 49264, 5840, 52368, 34464, 42128,
27152, 31072, 36720, 62624, 1072, 39280, 25328, 35824, 17104, 8192, 57472, 52464, 18848, 48080,
35392, 6096, 63856, 28336, 58496, 33472, 39024, 44752, 16160, 37088, 30464, 52416, 2064, 28544,
46992, 23552, 31088, 59088, 5888, 25152, 1648, 64736, 28592, 46752, 37264, 25536, 13488, 18432,
43040, 35680, 15568, 26032, 32912, 7184, 28272, 38192, 5120, 22944, 58960, 49584, 37296, 44928,
52128, 33136, 2912, 56016, 29888, 60912, 13936, 17584, 65392, 7296, 48832, 19120, 10384, 55648,
14496, 58560, 41936, 28928, 34208, 40864, 27584, 2848, 56192, 30816, 51632, 39952, 9360, 3296,
22384, 59328, 11152, 62240, 41072, 23024, 60064, 19072, 6320, 64480, 38224, 10576, 34816,
49216, 19968, 14368, 9760, 52432, 43856, 1760, 49744, 57184, 28960, 528, 58320, 20672, 10736,
64256, 47840, 15104, 44160, 53808, 17616, 33936, 63440, 20592, 28256, 61328, 12128, 19216,
40352, 23344, 9392, 51184, 45088, 2960, 56832, 24256, 43328, 33216, 47200, 2992, 20080, 61568,
4992, 14288, 65104, 44672, 23392, 12896, 19664, 45568, 14912, 62512, 31248, 6176, 49360, 26176,
8960, 4752, 48416, 43824, 34000, 13216, 51456, 42784, 16528, 62448, 46128, 40192, 33360, 21184,
7328, 30128, 64560, 22544, 45680, 5904, 62064, 41312, 51216, 2928, 56368, 34608, 61952, 1856,
26480, 10864, 6736, 56400, 896, 47072, 35488, 63936, 44704, 3728, 32736, 38160, 25792, 12048,
35216, 15968, 53472, 6208, 26992, 51584, 11712, 45056, 54320, 21888, 9440, 37888, 59056, 6768,
34016, 24800, 55664, 48032, 18400, 54160, 34704, 43024, 55856, 32176, 16432, 53984, 25296,
3824, 57664, 21728, 27104, 8592, 30496, 2832, 61264, 55424, 59392, 34432, 15168, 8800, 36992,
52752, 24368, 30960, 17280, 37328, 21440, 25360, 8944, 40128, 51872, 29984, 42944, 16096,
39728, 23936, 7840, 16624, 27456, 54752, 47760, 61904, 20976, 59296, 40960, 30672, 64384,
21824, 59824, 37168, 31808, 24752, 39152, 50144, 29808, 16912, 53200, 41440, 61024, 688, 36576,
42016, 11776, 28208, 2288, 20000, 13520, 64144, 37472, 10096, 61680, 41120, 29872, 1152, 53888,
58672, 36048, 50272, 24288, 17056, 11136, 47296, 41488, 55072, 19808, 12880, 48768, 8272,
59952, 46288, 12480, 32032, 48576, 19840, 65472, 36160, 22672, 60480, 53968, 31328, 51104,
38480, 57696, 6304, 14544, 320, 52928, 28480, 6816, 50288, 1488, 39040, 9504, 17408, 56416,
192, 7568, 62304, 35360, 2240, 47744, 10688, 27488, 50656, 7744, 22752, 65488, 38784, 46080,
58912, 24240, 50576, 1312, 27872, 19536, 47520, 15024, 37344, 44272, 18656, 5856, 13136, 42240,
27424, 37728, 51392, 2256, 25840, 62880, 32608, 39552, 2480, 27920, 42592, 5728, 55568, 59424,
3664, 14320, 46512, 4896, 48880, 13120, 3536, 59136, 10816, 21360, 30896, 36368, 18112, 43504,
9840, 46704, 19856, 13920, 45312, 29264, 49312, 63840, 15120, 46848, 19344, 57648, 25808,
32352, 21296, 63504, 14160, 30416, 57600, 4736, 16016, 51824, 8128, 30304, 40240, 45184, 56688,
35584, 7616, 50112, 65008, 11056, 23472, 47216, 63424, 53072, 3760, 32064, 18352, 60816, 29536,
5520, 44688, 15488, 56640, 64768, 22768, 51088, 16928, 28816, 44512, 33008, 57392, 9376, 28400,
20096, 34496, 45136, 26304, 48656, 41904, 64752, 24480, 56224, 32688, 62896, 35792, 55104,
60672, 23536, 4304, 42640, 33904, 27840, 40400, 12928, 4288, 55488, 43360, 38880, 18720, 45072,
53024, 33168, 26048, 61472, 35136, 17568, 5536, 21568, 12416, 60416, 24304, 31568, 4480, 55440,
33888, 39376, 29280, 20864, 57488, 7024, 23776, 38832, 11536, 57632, 49792, 35376, 19264,
10000, 33232, 40336, 1184, 37024, 11232, 24352, 18624, 61408, 37568, 42416, 64352, 15872, 1520,
60720, 8336, 51776, 12400, 39328, 2320, 15888, 25408, 3568, 41360, 32880, 12352, 20704, 54672,
9216, 59584, 45104, 51296, 16144, 6400, 58512, 1840, 35296, 9408, 20960, 43456, 64, 11520,
47424, 63408, 54176, 33024, 2576, 52032, 17488, 42528, 26624, 59280, 432, 15920, 9696, 45968,
65408, 14480, 53696, 43152, 22080, 864, 26000, 54256, 46816, 14048, 60208, 26288, 62944, 54880,
49984, 40624, 0, 51920, 24784, 7104, 54608, 39584, 19008, 34080, 4336, 27664, 48256, 22432,
58112, 50736, 28192, 8352, 52192, 58544, 38112, 48736, 2032, 23648, 29600, 64880, 37280, 24896,
49536, 28096, 47184, 63072, 13056, 55920, 49328, 38032, 58464, 26672, 42208, 15856, 38864,
44912, 62816, 12864, 20240, 7984, 48528, 61360, 35728, 41328, 1824, 49232, 33280, 8608, 17296,
63792, 31344, 3840, 37936, 6576, 52848, 20336, 8368, 43392, 5360, 30720, 16320, 56112, 11632,
32464, 49696, 29040, 23072, 57072, 45616, 17248, 60080, 7136, 44416, 38256, 13152, 65264,
18416, 5264, 26256, 62672, 16800, 35744, 6848, 20544, 9680, 33584, 12176, 61088, 3776, 23920,
40736, 28848, 19136, 31536, 23008, 8560, 4000, 29616, 58160, 9472, 28176, 36752, 53392, 40480,
31120, 22480, 54816, 26768, 58400, 28832, 45200, 59936, 36448, 41568, 50752, 58896, 23312,
44256, 30016, 48288, 34096, 13008, 22368, 63968, 35616, 44656, 21648, 61808, 2816, 13552,
43616, 9872, 63136, 36816, 30032, 52832, 10656, 31712, 21504, 42800, 35568, 46768, 30848,
10832, 43712, 50608, 40000, 60576, 53712, 41760, 17968, 54656, 37536, 15520, 58928, 6512, 3040,
53936, 14448, 45984, 52976, 19360, 49088, 22704, 1456, 46784, 57568, 14784, 3056, 51136, 11728,
18816, 38320, 21088, 4656, 24864, 12768, 7072, 28432, 15056, 10592, 63264, 17680, 2768, 56512,
38656, 27472, 51200, 3312, 9104, 27136, 46480, 58032, 37840, 53088, 31920, 592, 13872, 41296,
19648, 3328, 60768, 48496, 57040, 608, 14928, 53376, 22096, 57456, 32320, 13456, 464, 46496,
30064, 5488, 21760, 44240, 31856, 51568, 34848, 64832, 42928, 59968, 33728, 37632, 64192,
12096, 35008, 60656, 5248, 32848, 24144, 64320, 43936, 34176, 6560, 52048, 14080, 56000, 48240,
61792, 19376, 46160, 56784, 40640, 36000, 24976, 61344, 15840, 46208, 58368, 19280, 60000,
39824, 15280, 34352, 18672, 5056, 26016, 47824, 21808, 54560, 24880, 64112, 35040, 16112, 6464,
24592, 29120, 61824, 39056, 7680, 3712, 63760, 24096, 17184, 26656, 57904, 50064, 64000, 8416,
26416, 11200, 48064, 16880, 25632, 10784, 1008, 21872, 5968, 41088, 25760, 50640, 18704, 43072,
10192, 28944, 17008, 47120, 60272, 42080, 29744, 128, 32480, 38896, 53536, 4848, 21744, 31504,
928, 49856, 41728, 4720, 32160, 10704, 6144, 47856, 30432, 53488, 64784, 8064, 41744, 61168,
16784, 59008, 5696, 49888, 46000, 27760, 55120, 40848, 51792, 9664, 45008, 34256, 18736, 47440,
28512, 55712, 42992, 4672, 35536, 14464, 39360, 1024, 57280, 19984, 41344, 7600, 38400, 51056,
30544, 47168, 56896, 16000, 54496, 30656, 7648, 62704, 37312, 56032, 4448, 25824, 9168, 35552,
64704, 17808, 43984, 10368, 26464, 34752, 64512, 8528, 54928, 12496, 28896, 52384, 23840,
37136, 42768, 25024, 12288, 1472, 49440, 23632, 29760, 11824, 35952, 39792, 9552, 33072, 12688,
1344, 37584, 19104, 32528, 13408, 23120, 59344, 54192, 41424, 11328, 37696, 51504, 59456,
10528, 23456, 33104, 46032, 52720, 62464, 29856, 22928, 56176, 62128, 18256, 26960, 61056,
9232, 45296, 39200, 13744, 52320, 19952, 48992, 40288, 62160, 22256, 55200, 6048, 49296, 23104,
58448, 3280, 51888, 43680, 18080, 46672, 60384, 20720, 7920, 65152, 54736, 16816, 62272, 56624,
36304, 19888, 44016, 55952, 50560, 2000, 26976, 43840, 57952, 22896, 61744, 8672, 58656, 46320,
63600, 5408, 26912, 1248, 15552, 21632, 33296, 8208, 19504, 47680, 61136, 28352, 17520, 13024,
35600, 6272, 44768, 2192, 34624, 13680, 43312, 3424, 34304, 22560, 256, 58640, 27072, 33632,
2048, 13104, 31760, 15728, 45920, 27648, 12448, 36896, 62528, 16416, 29568, 13264, 37360,
25872, 33040, 39472, 14672, 44816, 560, 21600, 32960, 40784, 27936, 4192, 14624, 62592, 32512,
20640, 64496, 52000, 17952, 30448, 42368, 48928, 26128, 3856, 17232, 42512, 50320, 36592,
62096, 48784, 2704, 64400, 30752, 40544, 2336, 55456, 42688, 3680, 25120, 60112, 15664, 48352,
9824, 53520, 38704, 50336, 29168, 65280, 17328, 47728, 6224, 23296, 44432, 58144, 51440, 3232,
59904, 40752, 54048, 31424, 7712, 41856, 22192, 50304, 56288, 5648, 2464, 57824, 48224, 34976,
29440, 50400, 4944, 9264, 60848, 47104, 39072, 10256, 6960, 46336, 15136, 4048, 38528, 6528,
14272, 20480, 35280, 53680, 39216, 56768, 31872, 9888, 29104, 57792, 25664, 44864, 16224,
53456, 21456, 7456, 65328, 49680, 38944, 52288, 31616, 20784, 64304, 24336, 5600, 19520, 12144,
55840, 36864, 41824, 61600, 54016, 10720, 28368, 38688, 20368, 9984, 25184, 2144, 19440, 57088,
47888, 1408, 61312, 10752, 41376, 63360, 18944, 24496, 10512, 59664, 13440, 43552, 52256,
16352, 24608, 54624, 34800, 28720, 53408, 24816, 35408, 57200, 45648, 55392, 64272, 1888,
29728, 12544, 22064, 6720, 19232, 43568, 13808, 54544, 5552, 38352, 11984, 26608, 36400, 30528,
9616, 18752, 58240, 4560, 27808, 40928, 55360, 32080, 59840, 46448, 25552, 9728, 30384, 14976,
35120, 18192, 64336, 7440, 34144,
];