├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── demo-sdl2 │ ├── main.rs │ └── renderer │ └── mod.rs ├── res └── microui.png ├── rustfmt.toml └── src ├── atlas.rs ├── fixed_collections.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | *.vscode/ 2 | *.idea/ 3 | *target/ 4 | *.lock 5 | SDL2.* -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "microui" 3 | authors = ["Wael El Oraiby"] 4 | version = "0.2.5" 5 | edition = "2021" 6 | readme = "README.md" 7 | license = "BSD-3-Clause" 8 | description = "MicroUI (immediate mode GUI) library in pure rust" 9 | repository = "https://github.com/NeoCogi/microui-rs" 10 | categories = ["no-std", "gui", "rendering"] 11 | 12 | [lib] 13 | name = "microui" 14 | 15 | [dependencies] 16 | bitflags = "2.4.1" 17 | 18 | [dev-dependencies] 19 | glow = "0.13.0" 20 | sdl2 = "0.36.0" 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022-Present (c) Raja Lehtihet & Wael El Oraiby 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rxi's Microui Port to Rust 2 | [![Crate](https://img.shields.io/crates/v/microui.svg)](https://crates.io/crates/microui) 3 | 4 | This a port of Rxi's MicroUI to Rust language. 5 | We tried to keep the usage pattern as close to the original as possible, but also as idiomatic to Rust as possible. By no mean this library should be considered complete. 6 | 7 | We used C2Rust to create the initial code and iterated > 60 times to get it to where it is now. Few bugs are lingering (Lost to translation!), be advised! 8 | 9 | ## Approach taken 10 | This is a relatively small project. And to be honest, it did not start with c2rust. 11 | 12 | #### First Step 13 | Rather, we forked microui and made few changes to the C code to make the generated more understandable. The fork can be found [here](https://github.com/eloraiby/microui/commits/jump_int). The C code modification mainly convert the pointer jumping to index jumping. 14 | 15 | #### C2Rust 16 | Otherwise, we have done the following: 17 | 1. Use stable rust: 18 | 1. By default, c2rust generates code that builds with nightly. Our aim is to build using stable rust, that was our first milestone. 19 | 2. C2Rust generates a fake main, so we removed the boiler-plate 20 | 2. Start porting C Enums (constants when translated to rust) to rust enums 21 | 3. Use containers (if the aim is to use `std`, then use the rust standard library collections/containers). For us, to be faithful to the original design of microui, our objective is to provide a zero allocation microui. We created our own non-alloc containers for that. 22 | 4. Move from C strings to rust strings 23 | 5. Finally, change all C types to rust compatible types. 24 | 25 | ## Demo 26 | Clone and build the demo (SDL2 & glow) / Tested on linux: 27 | ``` 28 | $ cargo run --example demo-sdl2 29 | ``` 30 | 31 | ![random](https://github.com/NeoCogi/microui-rs/raw/master/res/microui.png) 32 | 33 | ## Caveats 34 | We opt to use our own implementations for parsing/serializing decimals (not general purpose floats). The decimal representation is stored as float. This is not a general purpose floating point parser/serializer and the algorithm is rather naive. Keep that in mind! 35 | -------------------------------------------------------------------------------- /examples/demo-sdl2/main.rs: -------------------------------------------------------------------------------- 1 | extern crate sdl2; 2 | mod renderer; 3 | 4 | use sdl2::event::{Event, WindowEvent}; 5 | use sdl2::keyboard::Keycode; 6 | use sdl2::video::GLProfile; 7 | use crate::renderer::Renderer; 8 | use microui::*; 9 | 10 | pub fn r_get_char_width(_font: FontId, c: char) -> usize { 11 | ATLAS[ATLAS_FONT as usize + c as usize].w as usize 12 | } 13 | 14 | pub fn r_get_font_height(_font: FontId) -> usize { 15 | 18 16 | } 17 | 18 | struct State<'a> { 19 | label_colors: [LabelColor<'a>; 15], 20 | bg: [Real; 3], 21 | logbuf: FixedString<65536>, 22 | logbuf_updated: bool, 23 | submit_buf: FixedString<128>, 24 | ctx: microui::Context, 25 | checks: [bool; 3], 26 | } 27 | 28 | #[derive(Copy, Clone)] 29 | #[repr(C)] 30 | pub struct LabelColor<'a> { 31 | pub label: &'a str, 32 | pub idx: ControlColor, 33 | } 34 | 35 | impl<'a> State<'a> { 36 | pub fn new() -> Self { 37 | let mut ctx = microui::Context::new(); 38 | 39 | ctx.char_width = Some(r_get_char_width); 40 | ctx.font_height = Some(r_get_font_height); 41 | 42 | Self { 43 | label_colors: [ 44 | LabelColor { label: "text", idx: ControlColor::Text }, 45 | LabelColor { 46 | label: "border:", 47 | idx: ControlColor::Border, 48 | }, 49 | LabelColor { 50 | label: "windowbg:", 51 | idx: ControlColor::WindowBG, 52 | }, 53 | LabelColor { 54 | label: "titlebg:", 55 | idx: ControlColor::TitleBG, 56 | }, 57 | LabelColor { 58 | label: "titletext:", 59 | idx: ControlColor::TitleText, 60 | }, 61 | LabelColor { 62 | label: "panelbg:", 63 | idx: ControlColor::PanelBG, 64 | }, 65 | LabelColor { 66 | label: "button:", 67 | idx: ControlColor::Button, 68 | }, 69 | LabelColor { 70 | label: "buttonhover:", 71 | idx: ControlColor::ButtonHover, 72 | }, 73 | LabelColor { 74 | label: "buttonfocus:", 75 | idx: ControlColor::ButtonFocus, 76 | }, 77 | LabelColor { label: "base:", idx: ControlColor::Base }, 78 | LabelColor { 79 | label: "basehover:", 80 | idx: ControlColor::BaseHover, 81 | }, 82 | LabelColor { 83 | label: "basefocus:", 84 | idx: ControlColor::BaseFocus, 85 | }, 86 | LabelColor { 87 | label: "scrollbase:", 88 | idx: ControlColor::ScrollBase, 89 | }, 90 | LabelColor { 91 | label: "scrollthumb:", 92 | idx: ControlColor::ScrollThumb, 93 | }, 94 | LabelColor { label: "", idx: ControlColor::Text }, 95 | ], 96 | bg: [90.0, 95.0, 100.0], 97 | logbuf: FixedString::new(), 98 | logbuf_updated: false, 99 | submit_buf: FixedString::new(), 100 | ctx, 101 | checks: [false, true, false], 102 | } 103 | } 104 | 105 | fn write_log(&mut self, text: &str) { 106 | if self.logbuf.len() != 0 { 107 | self.logbuf.push('\n'); 108 | } 109 | for c in text.chars() { 110 | self.logbuf.push(c); 111 | } 112 | self.logbuf_updated = true; 113 | } 114 | 115 | fn test_window(&mut self) { 116 | if !self.ctx.begin_window_ex("Demo Window", rect(40, 40, 300, 450), WidgetOption::NONE).is_none() { 117 | let mut win = self.ctx.get_current_container_rect(); 118 | win.w = if win.w > 240 { win.w } else { 240 }; 119 | win.h = if win.h > 300 { win.h } else { 300 }; 120 | 121 | self.ctx.set_current_container_rect(&win); 122 | 123 | let mut buff = FixedString::<128>::new(); 124 | 125 | if !self.ctx.header_ex("Window Info", WidgetOption::NONE).is_none() { 126 | let win_0 = self.ctx.get_current_container_rect(); 127 | self.ctx.layout_row(&[54, -1], 0); 128 | self.ctx.label("Position:"); 129 | 130 | buff.clear(); 131 | buff.append_int(10, 0, win_0.x); 132 | buff.add_str(", "); 133 | buff.append_int(10, 0, win_0.y); 134 | 135 | self.ctx.label(buff.as_str()); 136 | buff.clear(); 137 | self.ctx.label("Size:"); 138 | 139 | buff.append_int(10, 0, win_0.w); 140 | buff.add_str(", "); 141 | buff.append_int(10, 0, win_0.h); 142 | 143 | self.ctx.label(buff.as_str()); 144 | } 145 | if !self.ctx.header_ex("Test Buttons", WidgetOption::EXPANDED).is_none() { 146 | self.ctx.layout_row(&[86, -110, -1], 0); 147 | self.ctx.label("Test buttons 1:"); 148 | if !self.ctx.button_ex("Button 1", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 149 | self.write_log("Pressed button 1"); 150 | } 151 | if !self.ctx.button_ex("Button 2", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 152 | self.write_log("Pressed button 2"); 153 | } 154 | self.ctx.label("Test buttons 2:"); 155 | if !self.ctx.button_ex("Button 3", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 156 | self.write_log("Pressed button 3"); 157 | } 158 | if !self.ctx.button_ex("Popup", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 159 | self.ctx.open_popup("Test Popup"); 160 | } 161 | if !self.ctx.begin_popup("Test Popup").is_none() { 162 | if !self.ctx.button_ex("Hello", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 163 | self.write_log("Hello") 164 | } 165 | if !self.ctx.button_ex("World", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 166 | self.write_log("World") 167 | } 168 | self.ctx.end_popup(); 169 | } 170 | } 171 | if !self.ctx.header_ex("Tree and Text", WidgetOption::EXPANDED).is_none() { 172 | self.ctx.layout_row(&[140, -1], 0); 173 | self.ctx.layout_begin_column(); 174 | if !self.ctx.begin_treenode_ex("Test 1", WidgetOption::NONE).is_none() { 175 | if !self.ctx.begin_treenode_ex("Test 1a", WidgetOption::NONE).is_none() { 176 | self.ctx.label("Hello"); 177 | self.ctx.label("world"); 178 | self.ctx.end_treenode(); 179 | } 180 | if !self.ctx.begin_treenode_ex("Test 1b", WidgetOption::NONE).is_none() { 181 | if !self.ctx.button_ex("Button 1", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 182 | self.write_log("Pressed button 1"); 183 | } 184 | if !self.ctx.button_ex("Button 2", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 185 | self.write_log("Pressed button 2"); 186 | } 187 | self.ctx.end_treenode(); 188 | } 189 | self.ctx.end_treenode(); 190 | } 191 | if !self.ctx.begin_treenode_ex("Test 2", WidgetOption::NONE).is_none() { 192 | self.ctx.layout_row(&[54, 54], 0); 193 | if !self.ctx.button_ex("Button 3", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 194 | self.write_log("Pressed button 3"); 195 | } 196 | if !self.ctx.button_ex("Button 4", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 197 | self.write_log("Pressed button 4"); 198 | } 199 | if !self.ctx.button_ex("Button 5", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 200 | self.write_log("Pressed button 5"); 201 | } 202 | if !self.ctx.button_ex("Button 6", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 203 | self.write_log("Pressed button 6"); 204 | } 205 | self.ctx.end_treenode(); 206 | } 207 | if !self.ctx.begin_treenode_ex("Test 3", WidgetOption::NONE).is_none() { 208 | self.ctx.checkbox("Checkbox 1", &mut self.checks[0]); 209 | self.ctx.checkbox("Checkbox 2", &mut self.checks[1]); 210 | self.ctx.checkbox("Checkbox 3", &mut self.checks[2]); 211 | self.ctx.end_treenode(); 212 | } 213 | self.ctx.layout_end_column(); 214 | self.ctx.layout_begin_column(); 215 | self.ctx.layout_row(&[-1], 0); 216 | self.ctx.text( 217 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas lacinia, sem eu lacinia molestie, mi risus faucibus ipsum, eu varius magna felis a nulla." 218 | , 219 | ); 220 | self.ctx.layout_end_column(); 221 | } 222 | if !self.ctx.header_ex("Background Color", WidgetOption::EXPANDED).is_none() { 223 | self.ctx.layout_row(&[-78, -1], 74); 224 | self.ctx.layout_begin_column(); 225 | self.ctx.layout_row(&[46, -1], 0); 226 | self.ctx.label("Red:"); 227 | self.ctx 228 | .slider_ex(&mut self.bg[0], 0 as Real, 255 as Real, 0 as Real, 0, WidgetOption::ALIGN_CENTER); 229 | self.ctx.label("Green:"); 230 | self.ctx 231 | .slider_ex(&mut self.bg[1], 0 as Real, 255 as Real, 0 as Real, 0, WidgetOption::ALIGN_CENTER); 232 | self.ctx.label("Blue:"); 233 | self.ctx 234 | .slider_ex(&mut self.bg[2], 0 as Real, 255 as Real, 0 as Real, 0, WidgetOption::ALIGN_CENTER); 235 | self.ctx.layout_end_column(); 236 | let r: Rect = self.ctx.layout_next(); 237 | self.ctx.draw_rect(r, color(self.bg[0] as u8, self.bg[1] as u8, self.bg[2] as u8, 255)); 238 | let mut buff = FixedString::<128>::new(); 239 | buff.add_str("#"); 240 | buff.append_int(16, 2, self.bg[0] as _); 241 | buff.append_int(16, 2, self.bg[1] as _); 242 | buff.append_int(16, 2, self.bg[2] as _); 243 | self.ctx.draw_control_text(buff.as_str(), r, ControlColor::Text, WidgetOption::ALIGN_CENTER); 244 | } 245 | self.ctx.end_window(); 246 | } 247 | } 248 | 249 | fn log_window(&mut self) { 250 | if !self.ctx.begin_window_ex("Log Window", rect(350, 40, 300, 200), WidgetOption::NONE).is_none() { 251 | self.ctx.layout_row(&[-1], -25); 252 | self.ctx.begin_panel_ex("Log Output", WidgetOption::NONE); 253 | let mut scroll = self.ctx.get_current_container_scroll(); 254 | let content_size = self.ctx.get_current_container_content_size(); 255 | self.ctx.layout_row(&[-1], -1); 256 | self.ctx.text(self.logbuf.as_str()); 257 | if self.logbuf_updated { 258 | scroll.y = content_size.y; 259 | self.ctx.set_current_container_scroll(&scroll); 260 | self.logbuf_updated = false; 261 | } 262 | self.ctx.end_panel(); 263 | 264 | let mut submitted = false; 265 | self.ctx.layout_row(&[-70, -1], 0); 266 | if self.ctx.textbox_ex(&mut self.submit_buf, WidgetOption::NONE).is_submitted() { 267 | self.ctx.set_focus(self.ctx.last_id); 268 | submitted = true; 269 | } 270 | if !self.ctx.button_ex("Submit", Icon::None, WidgetOption::ALIGN_CENTER).is_none() { 271 | submitted = true; 272 | } 273 | if submitted { 274 | let mut buf = FixedString::<128>::new(); 275 | buf.add_str(self.submit_buf.as_str()); 276 | self.write_log(buf.as_str()); 277 | self.submit_buf.clear(); 278 | } 279 | self.ctx.end_window(); 280 | } 281 | } 282 | fn uint8_slider(&mut self, value: &mut u8, low: i32, high: i32) -> ResourceState { 283 | let mut tmp = *value as f32; 284 | self.ctx.push_id_from_ptr(value); 285 | let res = self 286 | .ctx 287 | .slider_ex(&mut tmp, low as Real, high as Real, 0 as Real, 0, WidgetOption::ALIGN_CENTER); 288 | *value = tmp as u8; 289 | self.ctx.pop_id(); 290 | return res; 291 | } 292 | fn style_window(&mut self) { 293 | if !self.ctx.begin_window_ex("Style Editor", rect(350, 250, 300, 240), WidgetOption::NONE).is_none() { 294 | let sw = (self.ctx.get_current_container_body().w as f64 * 0.14) as i32; 295 | self.ctx.layout_row(&[80, sw, sw, sw, sw, -1], 0); 296 | let mut i = 0; 297 | while self.label_colors[i].label.len() > 0 { 298 | self.ctx.label(self.label_colors[i].label); 299 | unsafe { 300 | let color = self.ctx.style.colors.as_mut_ptr().offset(i as isize); 301 | self.uint8_slider(&mut (*color).r, 0, 255); 302 | self.uint8_slider(&mut (*color).g, 0, 255); 303 | self.uint8_slider(&mut (*color).b, 0, 255); 304 | self.uint8_slider(&mut (*color).a, 0, 255); 305 | } 306 | let next_layout = self.ctx.layout_next(); 307 | self.ctx.draw_rect(next_layout, self.ctx.style.colors[i]); 308 | i += 1; 309 | } 310 | self.ctx.end_window(); 311 | } 312 | } 313 | 314 | fn process_frame(&mut self) { 315 | self.ctx.begin(); 316 | self.style_window(); 317 | self.log_window(); 318 | self.test_window(); 319 | self.ctx.end(); 320 | } 321 | } 322 | 323 | fn main() { 324 | let sdl_context = sdl2::init().unwrap(); 325 | let video_subsystem = sdl_context.video().unwrap(); 326 | 327 | let gl_attr = video_subsystem.gl_attr(); 328 | gl_attr.set_context_profile(GLProfile::GLES); 329 | gl_attr.set_context_version(3, 0); 330 | 331 | let window = video_subsystem.window("Window", 800, 600).opengl().build().unwrap(); 332 | 333 | // Unlike the other example above, nobody created a context for your window, so you need to create one. 334 | 335 | // TODO: the rust compiler optimizes this out 336 | let _x_ = window.gl_create_context().unwrap(); 337 | let gl = unsafe { glow::Context::from_loader_function(|s| video_subsystem.gl_get_proc_address(s) as *const _) }; 338 | 339 | debug_assert_eq!(gl_attr.context_profile(), GLProfile::GLES); 340 | debug_assert_eq!(gl_attr.context_version(), (3, 0)); 341 | 342 | let mut event_pump = sdl_context.event_pump().unwrap(); 343 | let (width, height) = window.size(); 344 | let mut rd = Renderer::new(&gl, µui::ATLAS_TEXTURE, width, height); 345 | 346 | let mut state = State::new(); 347 | 348 | 'running: loop { 349 | let (width, height) = window.size(); 350 | 351 | rd.clear( 352 | &gl, 353 | width as i32, 354 | height as i32, 355 | color(state.bg[0] as u8, state.bg[1] as u8, state.bg[2] as u8, 255), 356 | ); 357 | 358 | fn map_mouse_button(sdl_mb: sdl2::mouse::MouseButton) -> microui::MouseButton { 359 | match sdl_mb { 360 | sdl2::mouse::MouseButton::Left => microui::MouseButton::LEFT, 361 | sdl2::mouse::MouseButton::Right => microui::MouseButton::RIGHT, 362 | sdl2::mouse::MouseButton::Middle => microui::MouseButton::MIDDLE, 363 | _ => microui::MouseButton::NONE, 364 | } 365 | } 366 | 367 | fn map_keymode(sdl_km: sdl2::keyboard::Mod, sdl_kc: Option) -> microui::KeyMode { 368 | match (sdl_km, sdl_kc) { 369 | (sdl2::keyboard::Mod::LALTMOD, _) | (sdl2::keyboard::Mod::RALTMOD, _) => microui::KeyMode::ALT, 370 | (sdl2::keyboard::Mod::LCTRLMOD, _) | (sdl2::keyboard::Mod::RCTRLMOD, _) => microui::KeyMode::CTRL, 371 | (sdl2::keyboard::Mod::LSHIFTMOD, _) | (sdl2::keyboard::Mod::RSHIFTMOD, _) => microui::KeyMode::SHIFT, 372 | (_, Some(sdl2::keyboard::Keycode::Backspace)) => microui::KeyMode::BACKSPACE, 373 | (_, Some(sdl2::keyboard::Keycode::Return)) => microui::KeyMode::RETURN, 374 | _ => microui::KeyMode::NONE, 375 | } 376 | } 377 | 378 | for event in event_pump.poll_iter() { 379 | match event { 380 | Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running, 381 | Event::Window { win_event: WindowEvent::Close, .. } => break 'running, 382 | Event::MouseMotion { x, y, .. } => state.ctx.input_mousemove(x, y), 383 | Event::MouseWheel { y, .. } => state.ctx.input_scroll(0, y * -30), 384 | Event::MouseButtonDown { x, y, mouse_btn, .. } => { 385 | let mb = map_mouse_button(mouse_btn); 386 | state.ctx.input_mousedown(x, y, mb); 387 | } 388 | Event::MouseButtonUp { x, y, mouse_btn, .. } => { 389 | let mb = map_mouse_button(mouse_btn); 390 | state.ctx.input_mouseup(x, y, mb); 391 | } 392 | Event::KeyDown { keymod, keycode, .. } => { 393 | let km = map_keymode(keymod, keycode); 394 | state.ctx.input_keydown(km); 395 | } 396 | Event::KeyUp { keymod, keycode, .. } => { 397 | let km = map_keymode(keymod, keycode); 398 | state.ctx.input_keyup(km); 399 | } 400 | Event::TextInput { text, .. } => { 401 | state.ctx.input_text(text.as_str()); 402 | } 403 | 404 | _ => {} 405 | } 406 | } 407 | 408 | state.process_frame(); 409 | 410 | let mut cmd_id = 0; 411 | loop { 412 | match state.ctx.mu_next_command(cmd_id) { 413 | Some((command, id)) => { 414 | match command { 415 | Command::Text { str_start, str_len, pos, color, .. } => { 416 | let str = &state.ctx.text_stack[str_start..str_start + str_len]; 417 | rd.draw_text(&gl, str, pos, color); 418 | } 419 | Command::Rect { rect, color } => { 420 | rd.draw_rect(&gl, rect, color); 421 | } 422 | Command::Icon { id, rect, color } => { 423 | rd.draw_icon(&gl, id, rect, color); 424 | } 425 | Command::Clip { rect } => { 426 | rd.set_clip_rect(&gl, 800, 600, rect); 427 | } 428 | _ => {} 429 | } 430 | cmd_id = id; 431 | } 432 | None => break, 433 | } 434 | } 435 | 436 | rd.flush(&gl); 437 | window.gl_swap_window(); 438 | 439 | ::std::thread::sleep(::std::time::Duration::new(0, 1_000_000_000u32 / 60)); 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /examples/demo-sdl2/renderer/mod.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022-Present (c) Raja Lehtihet & Wael El Oraiby 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its contributors 15 | // may be used to endorse or promote products derived from this software without 16 | // specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | // POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // ----------------------------------------------------------------------------- 31 | // Ported to rust from https://github.com/rxi/microui/ and the original license 32 | // 33 | // Copyright (c) 2020 rxi 34 | // 35 | // Permission is hereby granted, free of charge, to any person obtaining a copy 36 | // of this software and associated documentation files (the "Software"), to 37 | // deal in the Software without restriction, including without limitation the 38 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 39 | // sell copies of the Software, and to permit persons to whom the Software is 40 | // furnished to do so, subject to the following conditions: 41 | // 42 | // The above copyright notice and this permission notice shall be included in 43 | // all copies or substantial portions of the Software. 44 | // 45 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 50 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 51 | // IN THE SOFTWARE. 52 | // 53 | use microui::*; 54 | use glow::*; 55 | 56 | const VERTEX_SHADER: &str = "#version 100 57 | uniform highp mat4 uTransform; 58 | attribute highp vec2 vertexPosition; 59 | attribute highp vec2 vertexTexCoord; 60 | attribute lowp vec4 vertexColor; 61 | varying highp vec2 vTexCoord; 62 | varying lowp vec4 vVertexColor; 63 | void main() 64 | { 65 | vVertexColor = vertexColor; 66 | vTexCoord = vertexTexCoord; 67 | highp vec4 pos = vec4(vertexPosition.x, vertexPosition.y, 0.0, 1.0); 68 | gl_Position = uTransform * pos; 69 | }"; 70 | 71 | const FRAGMENT_SHADER: &str = "#version 100 72 | varying highp vec2 vTexCoord; 73 | varying lowp vec4 vVertexColor; 74 | uniform sampler2D uTexture; 75 | void main() 76 | { 77 | lowp vec4 col = texture2D(uTexture, vTexCoord).aaaa; 78 | gl_FragColor = vec4(vVertexColor.rgb, col.a * vVertexColor.a); 79 | }"; 80 | 81 | #[derive(Default, Copy, Clone)] 82 | #[repr(C)] 83 | pub struct Vec2f { 84 | x: f32, 85 | y: f32, 86 | } 87 | 88 | #[derive(Default, Copy, Clone)] 89 | #[repr(C)] 90 | struct Vertex { 91 | pos: Vec2f, 92 | tex: Vec2f, 93 | color: Color, 94 | } 95 | 96 | pub fn ortho4(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> [f32; 16] { 97 | let width = right - left; 98 | let height = top - bottom; 99 | let depth = far - near; 100 | let r00 = 2.0 / width; 101 | let r11 = 2.0 / height; 102 | let r22 = -2.0 / depth; 103 | let r03 = -(right + left) / width; 104 | let r13 = -(top + bottom) / height; 105 | let r23 = -(far + near) / depth; 106 | [r00, 0.0, 0.0, 0.0, 0.0, r11, 0.0, 0.0, 0.0, 0.0, r22, 0.0, r03, r13, r23, 1.0] 107 | } 108 | 109 | pub struct Renderer { 110 | verts: Vec, 111 | indices: Vec, 112 | 113 | vbo: NativeBuffer, 114 | ibo: NativeBuffer, 115 | tex_o: NativeTexture, 116 | 117 | program: NativeProgram, 118 | 119 | width: u32, 120 | height: u32, 121 | } 122 | 123 | impl Renderer { 124 | fn create_program(gl: &glow::Context, vertex_shader_source: &str, fragment_shader_source: &str) -> NativeProgram { 125 | unsafe { 126 | let program = gl.create_program().expect("Cannot create program"); 127 | 128 | let shader_sources = [(glow::VERTEX_SHADER, vertex_shader_source), (glow::FRAGMENT_SHADER, fragment_shader_source)]; 129 | 130 | let mut shaders = Vec::with_capacity(shader_sources.len()); 131 | 132 | for (shader_type, shader_source) in shader_sources.iter() { 133 | let shader = gl.create_shader(*shader_type).expect("Cannot create shader"); 134 | gl.shader_source(shader, shader_source); 135 | gl.compile_shader(shader); 136 | if !gl.get_shader_compile_status(shader) { 137 | panic!("{}", gl.get_shader_info_log(shader)); 138 | } 139 | gl.attach_shader(program, shader); 140 | shaders.push(shader); 141 | } 142 | 143 | gl.link_program(program); 144 | if !gl.get_program_link_status(program) { 145 | panic!("{}", gl.get_program_info_log(program)); 146 | } 147 | 148 | for shader in shaders { 149 | gl.detach_shader(program, shader); 150 | gl.delete_shader(shader); 151 | } 152 | 153 | program 154 | } 155 | } 156 | 157 | pub fn new(gl: &glow::Context, atlas_texture: &[u8], width: u32, height: u32) -> Self { 158 | assert_eq!(core::mem::size_of::(), 20); 159 | unsafe { 160 | // init texture 161 | let tex_o = gl.create_texture().unwrap(); 162 | debug_assert!(gl.get_error() == 0); 163 | gl.bind_texture(glow::TEXTURE_2D, Some(tex_o)); 164 | debug_assert!(gl.get_error() == 0); 165 | gl.tex_image_2d( 166 | glow::TEXTURE_2D, 167 | 0, 168 | glow::ALPHA as i32, 169 | ATLAS_WIDTH as i32, 170 | ATLAS_HEIGHT as i32, 171 | 0, 172 | glow::ALPHA, 173 | glow::UNSIGNED_BYTE, 174 | Some(&atlas_texture), 175 | ); 176 | debug_assert!(gl.get_error() == 0); 177 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); 178 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); 179 | debug_assert!(gl.get_error() == 0); 180 | 181 | let vbo = gl.create_buffer().unwrap(); 182 | let ibo = gl.create_buffer().unwrap(); 183 | 184 | let program = Self::create_program(gl, VERTEX_SHADER, FRAGMENT_SHADER); 185 | 186 | Self { 187 | verts: Vec::new(), 188 | indices: Vec::new(), 189 | 190 | vbo, 191 | ibo, 192 | tex_o, 193 | program, 194 | 195 | width, 196 | height, 197 | } 198 | } 199 | } 200 | 201 | pub fn flush(&mut self, gl: &glow::Context) { 202 | if self.verts.len() == 0 || self.indices.len() == 0 { 203 | return; 204 | } 205 | 206 | unsafe { 207 | // opengl rendering states 208 | gl.viewport(0, 0, self.width as i32, self.height as i32); 209 | 210 | gl.enable(glow::BLEND); 211 | debug_assert!(gl.get_error() == 0); 212 | gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); 213 | debug_assert!(gl.get_error() == 0); 214 | gl.disable(glow::CULL_FACE); 215 | debug_assert!(gl.get_error() == 0); 216 | gl.disable(glow::DEPTH_TEST); 217 | debug_assert!(gl.get_error() == 0); 218 | gl.enable(glow::SCISSOR_TEST); 219 | debug_assert!(gl.get_error() == 0); 220 | 221 | // set the program 222 | gl.use_program(Some(self.program)); 223 | debug_assert!(gl.get_error() == 0); 224 | 225 | // set the texture 226 | gl.bind_texture(glow::TEXTURE_2D, Some(self.tex_o)); 227 | gl.active_texture(glow::TEXTURE0 + 0); 228 | let tex_uniform_id = gl.get_uniform_location(self.program, "uTexture").unwrap(); 229 | gl.uniform_1_i32(Some(&tex_uniform_id), 0); 230 | debug_assert_eq!(gl.get_error(), 0); 231 | 232 | // set the viewport 233 | let viewport = gl.get_uniform_location(self.program, "uTransform").unwrap(); 234 | let tm = ortho4(0.0, self.width as f32, self.height as f32, 0.0, -1.0, 1.0); 235 | gl.uniform_matrix_4_f32_slice(Some(&viewport), false, &tm); 236 | debug_assert_eq!(gl.get_error(), 0); 237 | 238 | // set the vertex buffer 239 | let pos_attrib_id = gl.get_attrib_location(self.program, "vertexPosition").unwrap(); 240 | let tex_attrib_id = gl.get_attrib_location(self.program, "vertexTexCoord").unwrap(); 241 | let col_attrib_id = gl.get_attrib_location(self.program, "vertexColor").unwrap(); 242 | gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo)); 243 | gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.ibo)); 244 | debug_assert!(gl.get_error() == 0); 245 | 246 | // update the vertex buffer 247 | let vertices_u8: &[u8] = core::slice::from_raw_parts(self.verts.as_ptr() as *const u8, self.verts.len() * core::mem::size_of::()); 248 | gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, vertices_u8, glow::DYNAMIC_DRAW); 249 | debug_assert!(gl.get_error() == 0); 250 | 251 | // update the index buffer 252 | let indices_u8: &[u8] = core::slice::from_raw_parts(self.indices.as_ptr() as *const u8, self.indices.len() * core::mem::size_of::()); 253 | gl.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, indices_u8, glow::DYNAMIC_DRAW); 254 | debug_assert!(gl.get_error() == 0); 255 | 256 | gl.enable_vertex_attrib_array(pos_attrib_id); 257 | gl.enable_vertex_attrib_array(tex_attrib_id); 258 | gl.enable_vertex_attrib_array(col_attrib_id); 259 | debug_assert!(gl.get_error() == 0); 260 | 261 | gl.vertex_attrib_pointer_f32(pos_attrib_id, 2, glow::FLOAT, false, 20, 0); 262 | gl.vertex_attrib_pointer_f32(tex_attrib_id, 2, glow::FLOAT, false, 20, 8); 263 | gl.vertex_attrib_pointer_f32(col_attrib_id, 4, glow::UNSIGNED_BYTE, true, 20, 16); 264 | debug_assert!(gl.get_error() == 0); 265 | 266 | gl.draw_elements(glow::TRIANGLES, self.indices.len() as i32, glow::UNSIGNED_SHORT, 0); 267 | debug_assert!(gl.get_error() == 0); 268 | 269 | gl.disable_vertex_attrib_array(pos_attrib_id); 270 | gl.disable_vertex_attrib_array(tex_attrib_id); 271 | gl.disable_vertex_attrib_array(col_attrib_id); 272 | debug_assert!(gl.get_error() == 0); 273 | gl.use_program(None); 274 | debug_assert!(gl.get_error() == 0); 275 | 276 | self.verts.clear(); 277 | self.indices.clear(); 278 | } 279 | } 280 | 281 | fn push_quad_vertices(&mut self, gl: &glow::Context, v0: &Vertex, v1: &Vertex, v2: &Vertex, v3: &Vertex) { 282 | if self.verts.len() + 4 >= 65536 || self.indices.len() + 6 >= 65536 { 283 | self.flush(gl); 284 | } 285 | 286 | let is = self.verts.len() as u16; 287 | self.indices.push(is + 0); 288 | self.indices.push(is + 1); 289 | self.indices.push(is + 2); 290 | self.indices.push(is + 2); 291 | self.indices.push(is + 3); 292 | self.indices.push(is + 0); 293 | 294 | self.verts.push(v0.clone()); 295 | self.verts.push(v1.clone()); 296 | self.verts.push(v2.clone()); 297 | self.verts.push(v3.clone()); 298 | } 299 | 300 | pub fn push_rect(&mut self, gl: &glow::Context, dst: Rect, src: Rect, color: Color) { 301 | let x = src.x as f32 / ATLAS_WIDTH as f32; 302 | let y = src.y as f32 / ATLAS_HEIGHT as f32; 303 | let w = src.w as f32 / ATLAS_WIDTH as f32; 304 | let h = src.h as f32 / ATLAS_HEIGHT as f32; 305 | 306 | let mut v0 = Vertex::default(); 307 | let mut v1 = Vertex::default(); 308 | let mut v2 = Vertex::default(); 309 | let mut v3 = Vertex::default(); 310 | 311 | // tex coordinates 312 | v0.tex.x = x; 313 | v0.tex.y = y; 314 | v1.tex.x = x + w; 315 | v1.tex.y = y; 316 | v2.tex.x = x + w; 317 | v2.tex.y = y + h; 318 | v3.tex.x = x; 319 | v3.tex.y = y + h; 320 | 321 | // position 322 | v0.pos.x = dst.x as f32; 323 | v0.pos.y = dst.y as f32; 324 | v1.pos.x = dst.x as f32 + dst.w as f32; 325 | v1.pos.y = dst.y as f32; 326 | v2.pos.x = dst.x as f32 + dst.w as f32; 327 | v2.pos.y = dst.y as f32 + dst.h as f32; 328 | v3.pos.x = dst.x as f32; 329 | v3.pos.y = dst.y as f32 + dst.h as f32; 330 | 331 | // color 332 | v0.color = microui::color(color.r, color.g, color.b, color.a); 333 | v1.color = v0.color; 334 | v2.color = v0.color; 335 | v3.color = v0.color; 336 | 337 | self.push_quad_vertices(gl, &v0, &v1, &v2, &v3); 338 | } 339 | 340 | pub fn draw_rect(&mut self, gl: &glow::Context, rect: Rect, color: Color) { 341 | self.push_rect(gl, rect, ATLAS[ATLAS_WHITE as usize], color); 342 | } 343 | 344 | pub fn draw_text(&mut self, gl: &glow::Context, text: &str, pos: Vec2i, color: Color) { 345 | let mut dst = Rect { x: pos.x, y: pos.y, w: 0, h: 0 }; 346 | for p in text.chars() { 347 | if (p as usize) < 127 { 348 | let chr = usize::min(p as usize, 127); 349 | let src = ATLAS[ATLAS_FONT as usize + chr]; 350 | dst.w = src.w; 351 | dst.h = src.h; 352 | self.push_rect(gl, dst, src, color); 353 | dst.x += dst.w; 354 | } 355 | } 356 | } 357 | 358 | pub fn draw_icon(&mut self, gl: &glow::Context, id: Icon, r: Rect, color: Color) { 359 | let src = ATLAS[id as usize]; 360 | let x = r.x + (r.w - src.w) / 2; 361 | let y = r.y + (r.h - src.h) / 2; 362 | self.push_rect(gl, rect(x, y, src.w, src.h), src, color); 363 | } 364 | 365 | pub fn get_char_width(&self, _font: FontId, c: char) -> usize { 366 | ATLAS[ATLAS_FONT as usize + c as usize].w as usize 367 | } 368 | 369 | pub fn get_font_height(&self, _font: FontId) -> usize { 370 | 18 371 | } 372 | 373 | pub fn set_clip_rect(&mut self, gl: &glow::Context, width: i32, height: i32, rect: Rect) { 374 | unsafe { 375 | self.width = width as u32; 376 | self.height = height as u32; 377 | self.flush(gl); 378 | gl.scissor(rect.x, height - (rect.y + rect.h), rect.w, rect.h); 379 | } 380 | } 381 | 382 | pub fn clear(&mut self, gl: &glow::Context, width: i32, height: i32, clr: Color) { 383 | unsafe { 384 | self.width = width as u32; 385 | self.height = height as u32; 386 | self.flush(gl); 387 | gl.clear_color(clr.r as f32 / 255.0, clr.g as f32 / 255.0, clr.b as f32 / 255.0, clr.a as f32 / 255.0); 388 | gl.clear(glow::COLOR_BUFFER_BIT); 389 | } 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /res/microui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeoCogi/microui-rs/5b323cef5f63f479a56127f299377f2be5c34103/res/microui.png -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | indent_style = "Block" 2 | reorder_imports = false 3 | max_width = 160 4 | struct_lit_width = 40 5 | fn_single_line = true -------------------------------------------------------------------------------- /src/atlas.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | pub const ATLAS_HEIGHT: u32 = 128; 3 | pub const ATLAS_WIDTH: u32 = 128; 4 | pub const ATLAS_WHITE: u32 = 5; 5 | pub const ATLAS_FONT: u32 = 6; 6 | 7 | pub const ATLAS_TEXTURE: [u8; 16384] = [ 8 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | 0, 0, 0, 0, 0, 0x20, 0xc0, 0x20, 0, 0, 0, 0, 0, 0, 0x9, 0x32, 0xb, 0, 0, 0, 0, 0x31, 0x35, 0x1, 0, 0, 0, 0x15, 0x35, 0x1d, 0x30, 0x19, 0, 0, 0xf, 0x35, 19 | 0x6, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb, 0x2d, 0, 0, 0, 0x14, 0x26, 0, 0, 0x31, 0x2a, 0, 0, 0, 0x10, 0x31, 0, 0, 0, 0, 0x6, 0x3e, 0x8, 0, 0, 20 | 0, 0, 0, 0, 0x6, 0x3e, 0x8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc, 0x40, 0xd, 0, 0, 0, 0, 0x31, 0x35, 0x2f, 0x2, 0, 0, 0, 0, 0, 0, 0x18, 0x41, 21 | 0x37, 0x8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x21, 0xe0, 0xea, 0x2c, 0, 0, 0, 0, 0x36, 0xc4, 0xdb, 0xb2, 0xd9, 0xc1, 0x1a, 0, 0, 0xea, 0xff, 0x39, 22 | 0, 0, 0, 0x9e, 0xff, 0x88, 0xbe, 0x9c, 0, 0, 0x72, 0xff, 0x48, 0, 0, 0xbb, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c, 0xe4, 0xce, 0x8d, 0, 0, 0xb5, 0x60, 0, 0, 23 | 0xea, 0xfa, 0x2c, 0, 0, 0x4e, 0xeb, 0, 0, 0x1c, 0x8f, 0xea, 0xea, 0xee, 0x92, 0x1f, 0, 0, 0x1c, 0x8f, 0xea, 0xea, 0xee, 0x92, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 24 | 0, 0, 0, 0x42, 0xf3, 0xcd, 0xf5, 0x3a, 0, 0, 0, 0xea, 0xf2, 0xef, 0xe5, 0x8f, 0x2f, 0, 0, 0xf, 0xa0, 0xfe, 0xf2, 0xf1, 0xfa, 0x33, 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0x21, 0xe0, 0xea, 0x2d, 0, 0, 0, 0, 0x35, 0xdc, 0x33, 0, 0x6, 0, 0x5a, 0xd7, 0x13, 0, 0xea, 0xd8, 0x92, 0, 0, 0x9, 0xf0, 0xd9, 0x88, 0x7b, 26 | 0xda, 0, 0, 0xb9, 0xe9, 0x91, 0, 0x5, 0xf4, 0x3, 0x35, 0x2, 0x32, 0x1f, 0, 0x4, 0x37, 0x24, 0, 0x5b, 0xa9, 0x1b, 0xe7, 0x1, 0x44, 0xd0, 0x2, 0, 0, 0xea, 27 | 0xe4, 0xc3, 0x1, 0, 0x4e, 0xeb, 0, 0, 0x8f, 0xd8, 0x42, 0x1, 0x3a, 0xd0, 0x9b, 0, 0, 0x8f, 0xd8, 0x42, 0x1, 0x3a, 0xd0, 0x9b, 0, 0x2e, 0x1a, 0, 0x3, 0x36, 28 | 0x19, 0, 0x4, 0x36, 0, 0xa3, 0xa0, 0, 0xb5, 0x8d, 0, 0, 0, 0xea, 0x6d, 0x1, 0x3d, 0xac, 0xe5, 0x3, 0, 0xa1, 0xeb, 0x63, 0xc, 0x3, 0x2e, 0x1, 0, 0, 0, 0, 0, 29 | 0, 0, 0, 0, 0, 0, 0x21, 0xe1, 0xeb, 0x2d, 0, 0, 0, 0, 0, 0xd6, 0x38, 0x37, 0xb4, 0xd6, 0xe9, 0x35, 0x9e, 0x5c, 0, 0xea, 0x87, 0xe8, 0x3, 0, 0x56, 0xcc, 30 | 0xba, 0x88, 0x38, 0xff, 0x1a, 0x9, 0xf7, 0x84, 0xd9, 0, 0x39, 0xfe, 0xe, 0xff, 0xb7, 0xe1, 0xf3, 0x94, 0xbc, 0xde, 0xfb, 0x97, 0x73, 0x9b, 0xb, 0xfb, 0xb, 31 | 0xcf, 0x44, 0x1, 0, 0, 0xea, 0x65, 0xf7, 0x63, 0, 0x4e, 0xeb, 0, 0x1, 0xe0, 0x79, 0, 0, 0, 0x6b, 0xea, 0x3, 0x1, 0xe0, 0x79, 0, 0, 0, 0x6b, 0xea, 0x3, 32 | 0xb0, 0xa4, 0, 0x39, 0xfe, 0xa0, 0, 0x3d, 0xfd, 0, 0x6e, 0xe0, 0x5b, 0xef, 0x41, 0, 0, 0, 0xea, 0x6d, 0, 0, 0x17, 0xfd, 0x47, 0x18, 0xff, 0x8f, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0xe, 0, 0, 0, 0, 0, 0x21, 0xe1, 0xeb, 0x2d, 0, 0, 0, 0, 0, 0x16, 0xe3, 0, 0xc5, 0x51, 0, 0xd4, 0x37, 0x61, 0x99, 0, 0xea, 0x4d, 0xe9, 0x45, 34 | 0, 0xb2, 0x70, 0xbf, 0x88, 0x4, 0xf0, 0x59, 0x48, 0xe9, 0x18, 0xfd, 0x23, 0x77, 0xd4, 0xe, 0xff, 0x9f, 0x2, 0x54, 0xff, 0x86, 0, 0x69, 0xf0, 0x39, 0xd1, 35 | 0x61, 0xca, 0x60, 0xb6, 0x6f, 0xe3, 0x98, 0, 0xea, 0x4a, 0x7f, 0xec, 0x15, 0x4e, 0xeb, 0, 0x32, 0xff, 0x36, 0, 0, 0, 0x29, 0xff, 0x3e, 0x32, 0xff, 0x36, 0, 36 | 0, 0, 0x29, 0xff, 0x3f, 0x68, 0xe6, 0, 0x83, 0xaf, 0xe7, 0x1, 0x80, 0xc9, 0, 0x18, 0xf4, 0xff, 0x53, 0, 0x15, 0x3b, 0, 0xea, 0x6d, 0, 0, 0, 0xc5, 0xa2, 37 | 0x41, 0xff, 0x39, 0, 0x40, 0x73, 0x73, 0x35, 0, 0, 0, 0x3d, 0xed, 0x45, 0, 0, 0, 0x22, 0xe1, 0xeb, 0x2d, 0, 0, 0, 0, 0, 0, 0x4f, 0xb3, 0x12, 0xf9, 0x4, 38 | 0x3, 0xef, 0x2c, 0x6a, 0x94, 0, 0xea, 0x4d, 0x95, 0x9e, 0x14, 0xf6, 0x18, 0xc1, 0x88, 0, 0xb2, 0x96, 0x8e, 0xa4, 0, 0xcb, 0x6a, 0xb5, 0x92, 0xe, 0xff, 39 | 0x59, 0, 0x27, 0xff, 0x3d, 0, 0x3a, 0xff, 0x4, 0x71, 0xae, 0x40, 0xe0, 0x2e, 0xee, 0x1e, 0xd5, 0, 0xea, 0x4d, 0x8, 0xd9, 0xa0, 0x4b, 0xeb, 0, 0x20, 0xfe, 40 | 0x45, 0, 0, 0, 0x37, 0xff, 0x2c, 0x20, 0xfe, 0x45, 0, 0, 0, 0x37, 0xff, 0x3b, 0x21, 0xff, 0x29, 0xcc, 0x4a, 0xe9, 0x30, 0xc3, 0x81, 0x14, 0xdf, 0xab, 0xbd, 41 | 0xcd, 0x14, 0x9c, 0xb5, 0, 0xea, 0x6d, 0, 0, 0, 0xdc, 0xa6, 0x20, 0xfe, 0x42, 0, 0x63, 0xb2, 0xf4, 0x76, 0, 0, 0, 0x13, 0xd0, 0xf6, 0x45, 0, 0x22, 0xe1, 42 | 0xeb, 0x2e, 0, 0, 0, 0, 0, 0, 0, 0x3f, 0xe7, 0x3, 0xd7, 0x5e, 0x75, 0xf7, 0x8d, 0xc7, 0x4a, 0, 0xea, 0x4d, 0x3c, 0xf0, 0x71, 0xb7, 0, 0xc1, 0x88, 0, 0x70, 43 | 0xc9, 0xcb, 0x5d, 0, 0x83, 0xa2, 0xe9, 0x4f, 0xe, 0xff, 0x43, 0, 0x26, 0xff, 0x2d, 0, 0x39, 0xff, 0, 0, 0, 0x7c, 0x9a, 0x1f, 0xf1, 0, 0xaf, 0, 0xea, 0x4d, 44 | 0, 0x44, 0xfe, 0x83, 0xeb, 0, 0, 0xcd, 0x89, 0, 0, 0, 0x7b, 0xd9, 0, 0, 0xcd, 0x89, 0, 0, 0, 0x7b, 0xf8, 0x8, 0, 0xd8, 0x75, 0xf8, 0xd, 0xa7, 0x79, 0xf7, 45 | 0x39, 0x5b, 0xfc, 0xa, 0x9, 0xba, 0xd4, 0xf6, 0x39, 0, 0xea, 0x6d, 0, 0, 0x31, 0xff, 0x75, 0, 0xcc, 0x8f, 0, 0, 0, 0xdb, 0x76, 0, 0, 0, 0, 0x13, 0xd0, 46 | 0xf6, 0x63, 0xe1, 0xeb, 0x2e, 0, 0, 0, 0, 0, 0, 0, 0, 0x11, 0xf3, 0x44, 0x2c, 0x96, 0x87, 0x29, 0xa3, 0x64, 0, 0, 0xea, 0x4d, 0x1, 0xe1, 0xf3, 0x5b, 0, 47 | 0xc1, 0x88, 0, 0x2e, 0xf7, 0xf5, 0x17, 0, 0x3a, 0xec, 0xfc, 0x10, 0xe, 0xff, 0x43, 0, 0x26, 0xff, 0x2d, 0, 0x39, 0xff, 0, 0, 0x17, 0xe6, 0x19, 0x2, 0xee, 48 | 0x13, 0xd0, 0, 0xea, 0x4d, 0, 0, 0xa5, 0xf6, 0xeb, 0, 0, 0x7d, 0xec, 0x7a, 0x24, 0x73, 0xe7, 0x87, 0, 0, 0x7d, 0xec, 0x7a, 0x24, 0x73, 0xe7, 0x9c, 0, 0, 49 | 0x91, 0xda, 0xbd, 0, 0x61, 0xd9, 0xed, 0x3, 0x2b, 0xfe, 0x67, 0x1d, 0x70, 0xfc, 0xf0, 0x1a, 0, 0xea, 0x7f, 0x31, 0x81, 0xdc, 0xdc, 0xa, 0, 0x79, 0xef, 50 | 0x83, 0x23, 0x1c, 0xe1, 0x76, 0, 0, 0, 0, 0, 0x13, 0xd0, 0xff, 0xec, 0x2e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6b, 0xdc, 0x78, 0x20, 0xd, 0x3c, 0x3b, 0, 0, 0, 51 | 0xea, 0x4d, 0, 0x8a, 0xf3, 0xb, 0, 0xc1, 0x88, 0, 0x1, 0xea, 0xce, 0, 0, 0x3, 0xed, 0xc9, 0, 0xe, 0xff, 0x43, 0, 0x26, 0xff, 0x2d, 0, 0x39, 0xff, 0, 0, 52 | 0x98, 0x7e, 0, 0, 0x78, 0xe7, 0xb0, 0, 0xea, 0x4d, 0, 0, 0x18, 0xef, 0xeb, 0, 0, 0x6, 0x54, 0xb6, 0xfb, 0xbb, 0x57, 0x7, 0, 0, 0x6, 0x54, 0xb6, 0xfc, 0xff, 53 | 0x8d, 0x1, 0, 0, 0x49, 0xff, 0x74, 0, 0x1b, 0xfe, 0xa8, 0, 0, 0x7f, 0xde, 0xff, 0xe7, 0x72, 0xb1, 0xdb, 0, 0xea, 0xff, 0xf8, 0xd6, 0x92, 0x13, 0, 0, 0x6, 54 | 0x52, 0xb4, 0xfb, 0xff, 0xe5, 0x55, 0, 0, 0, 0, 0, 0, 0x13, 0xbc, 0x2e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x44, 0xb7, 0xde, 0xdb, 0xad, 0x50, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0x8, 0, 0, 0, 0, 0, 0, 0, 0, 0x1b, 0xda, 0xbb, 0x7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf, 0xc, 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x26, 0xe6, 0xa0, 0x2, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x31, 0x17, 0, 0, 0, 0x2a, 0x1e, 0, 0x35, 75 | 0x13, 0, 0, 0, 0x2c, 0x1c, 0, 0, 0xc, 0x27, 0, 0x29, 0x9, 0, 0, 0, 0x3c, 0x24, 0, 0, 0, 0x31, 0x35, 0x30, 0x8, 0, 0, 0, 0, 0, 0x11, 0x44, 0x1f, 0, 0, 0x31, 76 | 0x17, 0, 0, 0x13, 0x35, 0, 0x31, 0x35, 0x2b, 0x2, 0, 0, 0, 0x31, 0x35, 0x2a, 0x2, 0, 0, 0x33, 0x16, 0, 0, 0, 0xf, 0x35, 0x27, 0x28, 0, 0, 0, 0x1f, 0x2e, 77 | 0xb, 0xbc, 0x31, 0, 0, 0, 0, 0, 0, 0, 0, 0x13, 0xbc, 0x2a, 0xb, 0xbc, 0x31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78 | 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0xc9, 0x8e, 0, 0xfc, 0x5b, 0, 0, 0, 0xd2, 0x84, 0, 0, 0x59, 0xa9, 0, 0xea, 0xf, 0, 0, 0x34, 0xfe, 0xce, 0, 0, 0, 79 | 0xea, 0xf2, 0xed, 0xfa, 0xce, 0x1a, 0, 0x9, 0xb5, 0xfd, 0xe7, 0xf5, 0xaf, 0, 0xea, 0x6d, 0, 0xc, 0xcf, 0xa7, 0, 0xea, 0xf2, 0xf3, 0xea, 0x94, 0, 0, 0xea, 80 | 0xf4, 0xf6, 0xec, 0x9d, 0, 0xc0, 0x9e, 0, 0, 0, 0x7a, 0xe5, 0x58, 0xf8, 0x26, 0, 0xd, 0xe4, 0x7a, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a, 0xff, 81 | 0x39, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0xc9, 0x8e, 82 | 0, 0xfc, 0x5b, 0, 0, 0, 0xd2, 0x84, 0, 0, 0x89, 0x79, 0x1c, 0xdd, 0, 0, 0, 0x93, 0xad, 0xf9, 0x2e, 0, 0, 0xea, 0x6d, 0, 0x19, 0xe3, 0x8c, 0, 0xab, 0xe1, 83 | 0x4f, 0x2, 0x7, 0x1f, 0, 0xea, 0x6d, 0x3, 0xb2, 0xc6, 0x8, 0, 0xea, 0x6d, 0x3, 0x4d, 0xff, 0x33, 0, 0xea, 0x6d, 0x3, 0x49, 0xff, 0x3a, 0x67, 0xee, 0x6, 0, 84 | 0, 0xd0, 0x8e, 0, 0xb3, 0xbb, 0, 0x8e, 0xcf, 0x5, 0xe, 0xff, 0x41, 0x12, 0x25, 0, 0, 0, 0, 0x18, 0x20, 0x18, 0xff, 0x39, 0xe, 0xff, 0x41, 0x2e, 0x33, 0x1, 85 | 0, 0x3, 0x35, 0x1, 0x2e, 0x34, 0x1, 0, 0, 0, 0, 0, 0, 0x4, 0x39, 0x5, 0, 0, 0x3, 0x36, 0x2, 0x11, 0x25, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0xc9, 86 | 0x8e, 0, 0xfc, 0x5b, 0, 0, 0, 0xd2, 0x84, 0x41, 0xd3, 0xf0, 0xe3, 0xdd, 0xf4, 0xd3, 0, 0x6, 0xec, 0x52, 0xb4, 0x8d, 0, 0, 0xea, 0x6d, 0, 0x6, 0xdd, 0x86, 87 | 0xb, 0xfc, 0x81, 0, 0, 0, 0, 0, 0xea, 0x6d, 0x8d, 0xdd, 0x15, 0, 0, 0xea, 0x6d, 0, 0x7, 0xf3, 0x64, 0, 0xea, 0x6d, 0, 0xa, 0xf4, 0x69, 0x13, 0xfa, 0x4a, 0, 88 | 0x27, 0xff, 0x34, 0, 0x1c, 0xf1, 0x86, 0xf7, 0x33, 0, 0xe, 0xff, 0xaa, 0xd3, 0xf8, 0xab, 0x1, 0, 0x87, 0xf6, 0xda, 0xa5, 0xff, 0x39, 0xe, 0xff, 0xc0, 0xe5, 89 | 0xf2, 0xd5, 0x3, 0xe, 0xff, 0xb4, 0xe5, 0xf2, 0xd6, 0x4, 0, 0, 0, 0, 0x6d, 0xe7, 0xdd, 0xe7, 0x6d, 0, 0xe, 0xff, 0x98, 0xd2, 0xf8, 0xab, 0x1, 0, 0, 0, 0, 90 | 0, 0xea, 0xe9, 0xd9, 0xd9, 0xd9, 0xf7, 0x8e, 0, 0xfc, 0x5b, 0, 0, 0, 0xd2, 0x84, 0x9, 0x1d, 0xec, 0x2e, 0x93, 0x87, 0x1d, 0, 0x52, 0xf1, 0x9, 0x5d, 0xe8, 91 | 0x4, 0, 0xea, 0xe4, 0xd3, 0xf6, 0xb1, 0xd, 0x3c, 0xff, 0x37, 0, 0, 0, 0, 0, 0xea, 0xc9, 0xff, 0x60, 0, 0, 0, 0xea, 0x8a, 0x49, 0x9e, 0xf1, 0xd, 0, 0xea, 92 | 0xa6, 0x71, 0xbb, 0xe1, 0x1a, 0, 0xb4, 0xa0, 0, 0x7d, 0xda, 0, 0, 0, 0x74, 0xff, 0x93, 0, 0, 0xe, 0xff, 0x9c, 0x2, 0x2a, 0xff, 0x32, 0xe, 0xfa, 0x5a, 0, 93 | 0x6f, 0xff, 0x39, 0xe, 0xff, 0xa6, 0x4, 0x1e, 0xff, 0x42, 0xe, 0xff, 0xa5, 0x4, 0x1e, 0xff, 0x42, 0, 0, 0, 0x7, 0xf1, 0x59, 0, 0x55, 0xf2, 0x9, 0xe, 0xff, 94 | 0x99, 0x1, 0x2d, 0xff, 0x32, 0, 0, 0, 0, 0, 0xea, 0x98, 0x4c, 0x4c, 0x4c, 0xd9, 0x8e, 0, 0xfc, 0x5b, 0, 0, 0, 0xd2, 0x84, 0x37, 0x58, 0xef, 0x4a, 0xc6, 95 | 0x83, 0x38, 0, 0xb1, 0xd5, 0x6f, 0x7d, 0xff, 0x4c, 0, 0xea, 0x94, 0x47, 0x70, 0xe7, 0x83, 0x22, 0xff, 0x42, 0, 0, 0, 0, 0, 0xea, 0xd2, 0xaf, 0xe2, 0x10, 0, 96 | 0, 0xea, 0xf5, 0xda, 0x94, 0x3e, 0, 0, 0xea, 0xd6, 0xc4, 0xfd, 0x27, 0, 0, 0x5b, 0xef, 0x6, 0xd3, 0x81, 0, 0, 0x1, 0xbc, 0xeb, 0xd2, 0x6, 0, 0xe, 0xff, 97 | 0x56, 0, 0, 0xdd, 0x77, 0x50, 0xfb, 0xc, 0, 0x23, 0xff, 0x39, 0xe, 0xff, 0x5c, 0, 0, 0xeb, 0x68, 0xe, 0xff, 0x5c, 0, 0, 0xeb, 0x68, 0, 0, 0, 0x4c, 0xfb, 98 | 0xb, 0, 0x8, 0xf8, 0x51, 0xe, 0xff, 0x52, 0, 0, 0xde, 0x77, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0xc9, 0x8e, 0, 0xd3, 0x85, 0, 0, 0x9, 0xf4, 0x6b, 0x7b, 99 | 0xc7, 0xdf, 0xa7, 0xfd, 0xa9, 0x7f, 0x16, 0xfa, 0xc4, 0xb8, 0xb8, 0xe2, 0xab, 0, 0xea, 0x6d, 0, 0, 0x8e, 0xdf, 0, 0xd2, 0x89, 0, 0, 0, 0, 0, 0xea, 0x6d, 100 | 0xf, 0xe0, 0xa1, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0, 0xea, 0x6d, 0x1, 0xc6, 0xa5, 0, 0, 0xc, 0xf5, 0x69, 0xff, 0x28, 0, 0, 0x60, 0xec, 0x21, 0xe4, 0x80, 0, 101 | 0xe, 0xff, 0x65, 0, 0x1, 0xea, 0x67, 0x43, 0xfe, 0x12, 0, 0x25, 0xff, 0x39, 0xe, 0xff, 0x43, 0, 0, 0xea, 0x68, 0xe, 0xff, 0x43, 0, 0, 0xea, 0x68, 0, 0, 0, 102 | 0x4c, 0xfe, 0x16, 0, 0x11, 0xfd, 0x40, 0xe, 0xff, 0x65, 0, 0x1, 0xeb, 0x67, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0xc9, 0x8e, 0, 0x72, 0xdf, 0x4b, 0x23, 103 | 0x8c, 0xfa, 0x28, 0, 0x7c, 0x81, 0x1a, 0xe5, 0, 0, 0x70, 0xeb, 0x5, 0, 0, 0x5c, 0xf8, 0, 0xea, 0x7f, 0x22, 0x4a, 0xdd, 0x95, 0, 0x84, 0xed, 0x7c, 0x1d, 104 | 0x24, 0x32, 0, 0xea, 0x6d, 0, 0x40, 0xfd, 0x52, 0, 0xea, 0x6d, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0x31, 0xfc, 0x49, 0, 0, 0xa8, 0xe3, 0xcd, 0, 0, 0x17, 0xed, 105 | 0x62, 0, 0x54, 0xf9, 0x2d, 0xe, 0xff, 0xbc, 0x1d, 0x5f, 0xff, 0x21, 0x7, 0xf5, 0x7e, 0x11, 0x8d, 0xff, 0x39, 0xe, 0xff, 0x43, 0, 0, 0xea, 0x68, 0xe, 0xff, 106 | 0x43, 0, 0, 0xea, 0x68, 0, 0, 0, 0x14, 0xf2, 0x88, 0x15, 0x82, 0xe8, 0x3, 0xe, 0xff, 0xbc, 0x1e, 0x61, 0xff, 0x20, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 107 | 0xc9, 0x8e, 0, 0x10, 0x85, 0xdc, 0xfe, 0xd9, 0x4c, 0, 0, 0xaa, 0x50, 0x4b, 0xb4, 0, 0, 0xcf, 0x97, 0, 0, 0, 0xc, 0xf4, 0, 0xea, 0xff, 0xff, 0xdd, 0x93, 108 | 0x1c, 0, 0x8, 0x5c, 0xc0, 0xfe, 0xed, 0x7b, 0, 0xea, 0x6d, 0, 0, 0x8d, 0xea, 0, 0xea, 0x6d, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0x95, 0xe0, 0, 0, 0x4f, 0xff, 109 | 0x74, 0, 0, 0xa8, 0xc3, 0x1, 0, 0, 0xb7, 0xca, 0xe, 0xfd, 0x6f, 0xd4, 0xe5, 0x72, 0, 0, 0x5c, 0xd9, 0xdb, 0x63, 0xef, 0x39, 0xe, 0xff, 0x43, 0, 0, 0xea, 110 | 0x68, 0xe, 0xff, 0x43, 0, 0, 0xea, 0x68, 0, 0, 0, 0, 0x43, 0xdb, 0xfc, 0xb7, 0x46, 0, 0xe, 0xff, 0x8c, 0xd4, 0xe4, 0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 | 0, 0, 0, 0, 0, 0, 0xc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0x6, 0, 0, 0, 0, 0x2, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 | 0, 0, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0xe, 0xff, 0x43, 0x1, 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 116 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb, 0xc2, 0x33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131 | 0, 0, 0, 0, 0, 0, 0x11, 0x79, 0, 0, 0, 0, 0x58, 0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xa, 0x2f, 0, 0, 0, 0, 0, 0x2e, 0x14, 0, 0, 0x4, 0x32, 0x3b, 0x3, 0, 0, 132 | 0, 0x21, 0x38, 0x4, 0, 0, 0, 0, 0x7, 0x3b, 0xf, 0, 0x2e, 0x35, 0x35, 0x35, 0x16, 0, 0, 0x3, 0x26, 0x49, 0x1f, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0, 0, 133 | 0x18, 0x3a, 0x5, 0, 0, 0, 0x14, 0x37, 0x3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f, 0, 0x31, 0x35, 0x35, 0x35, 0x27, 0, 134 | 0x31, 0x35, 0x35, 0x35, 0x26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3c, 0xa6, 0xea, 0x9e, 0x53, 0xf, 0x3, 0x5f, 0xa3, 0, 0x13, 0, 0, 0, 0, 135 | 0, 0, 0, 0x6d, 0xe9, 0xea, 0xb4, 0x23, 0, 0x7, 0x98, 0xff, 0x61, 0, 0x27, 0xd4, 0xee, 0xe8, 0xe8, 0x2f, 0x32, 0xcf, 0xdd, 0xe5, 0xef, 0x33, 0, 0, 0, 0x89, 136 | 0xff, 0x41, 0, 0xea, 0xf9, 0xf6, 0xf6, 0x64, 0, 0x25, 0xcf, 0xfe, 0xd1, 0x6c, 0x90, 0xf6, 0xf6, 0xf6, 0xf9, 0xff, 0, 0xa0, 0xea, 0xca, 0xee, 0x3e, 0, 0x9e, 137 | 0xf3, 0xe2, 0xe3, 0x1c, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1f, 0xfc, 0, 0xea, 0xf4, 0xec, 0xec, 0xac, 0, 0xea, 0xf4, 0xec, 138 | 0xec, 0xa9, 0, 0, 0, 0, 0x17, 0x3a, 0x5, 0x30, 0xc, 0x6, 0x36, 0xc, 0, 0, 0x34, 0x13, 0x16, 0xf6, 0x91, 0xc3, 0x79, 0x5b, 0x80, 0xed, 0xc9, 0xd9, 0xdb, 139 | 0xcb, 0, 0, 0x31, 0xa9, 0, 0, 0x6, 0xf7, 0x57, 0xc, 0xbd, 0x88, 0x5, 0xc6, 0xb6, 0xed, 0x61, 0, 0x8, 0x64, 0x5, 0x2, 0xbf, 0x9d, 0x4, 0x3a, 0, 0x1, 0xbe, 140 | 0xa2, 0, 0, 0x3d, 0xd1, 0xfc, 0x41, 0x2, 0xfc, 0x41, 0, 0, 0, 0, 0xc9, 0xa9, 0x1f, 0, 0, 0, 0, 0, 0, 0x90, 0xbf, 0x23, 0xfe, 0x27, 0, 0x9b, 0xaf, 0x2b, 141 | 0xfc, 0x21, 0, 0xa9, 0xb1, 0, 0, 0, 0x1, 0x50, 0xce, 0, 0, 0, 0, 0, 0, 0x6f, 0x98, 0x1e, 0, 0, 0, 0, 0, 0x7c, 0xc1, 0, 0xea, 0x6d, 0, 0, 0, 0, 0xea, 0x6a, 142 | 0, 0, 0, 0, 0, 0, 0x85, 0xf6, 0xdf, 0xbf, 0xf9, 0x39, 0x1d, 0xff, 0x38, 0, 0, 0xf6, 0x5c, 0x30, 0xff, 0x55, 0xa7, 0, 0, 0x6, 0x21, 0xdd, 0xeb, 0x45, 0xc, 143 | 0, 0, 0x3a, 0xc8, 0, 0, 0x35, 0xfd, 0x9, 0, 0x77, 0xc1, 0, 0x44, 0x3, 0xee, 0x61, 0, 0, 0, 0, 0, 0xa6, 0xa9, 0, 0, 0, 0x9, 0xdb, 0x79, 0, 0xd, 0xdc, 0x43, 144 | 0xff, 0x41, 0x13, 0xff, 0x38, 0xf, 0, 0, 0x36, 0xff, 0x34, 0x26, 0x5, 0, 0, 0, 0, 0x12, 0xf3, 0x4e, 0xa, 0xf1, 0x6b, 0x16, 0xce, 0x80, 0x6e, 0xda, 0, 0, 145 | 0x58, 0xe9, 0, 0x1, 0x50, 0xce, 0xbc, 0x44, 0x49, 0xab, 0xab, 0xab, 0xab, 0xa8, 0xf, 0x78, 0xe1, 0x98, 0x1f, 0, 0, 0x1, 0xdb, 0x62, 0, 0xea, 0x6d, 0, 0, 0, 146 | 0, 0xea, 0x6a, 0, 0, 0, 0, 0, 0xe, 0xfa, 0x58, 0, 0x6f, 0xff, 0x39, 0x1d, 0xff, 0x38, 0, 0, 0xf6, 0x5c, 0, 0x90, 0xfc, 0xdd, 0x46, 0, 0, 0x8b, 0xbb, 0x75, 147 | 0xce, 0x6, 0x41, 0x8d, 0xa7, 0xe7, 0x8d, 0x8d, 0x6b, 0xe3, 0, 0, 0x52, 0xf5, 0, 0, 0, 0xf0, 0x61, 0, 0, 0, 0, 0x31, 0xf8, 0x3f, 0, 0x33, 0xcb, 0xf8, 0x85, 148 | 0x5, 0, 0x9c, 0x8e, 0x8, 0xff, 0x41, 0x1f, 0xfd, 0xfe, 0xfa, 0xb8, 0x2d, 0x5b, 0xf2, 0xc9, 0xe6, 0xe7, 0x5a, 0, 0, 0, 0x7c, 0xd9, 0x2, 0, 0x37, 0xfb, 0xf8, 149 | 0xa4, 0x2, 0x2e, 0xfd, 0x49, 0x26, 0xbd, 0xfe, 0x35, 0xce, 0xac, 0x34, 0, 0, 0x24, 0x55, 0x55, 0x55, 0x55, 0x53, 0, 0, 0x8, 0x68, 0xd8, 0x98, 0, 0x3b, 150 | 0xf4, 0xd, 0, 0xea, 0xe8, 0xd6, 0xd6, 0x6f, 0, 0xea, 0xb6, 0x82, 0x82, 0x42, 0, 0, 0x4f, 0xfb, 0xc, 0, 0x23, 0xff, 0x39, 0x1d, 0xff, 0x38, 0, 0, 0xf6, 151 | 0x5c, 0, 0, 0x3a, 0xe4, 0xf4, 0x89, 0, 0x24, 0x30, 0xc, 0x48, 0, 0x34, 0x72, 0x92, 0xe1, 0x72, 0x72, 0x5e, 0xea, 0, 0, 0x59, 0xee, 0, 0, 0, 0xf0, 0x61, 0, 152 | 0, 0, 0x22, 0xe6, 0x76, 0, 0, 0x15, 0x57, 0x82, 0xe7, 0x79, 0x4d, 0xd5, 0x9, 0x8, 0xff, 0x41, 0, 0x13, 0x3, 0x2c, 0xcd, 0xa5, 0x6f, 0xfc, 0x30, 0x1, 0x81, 153 | 0xd3, 0, 0, 0x9, 0xe9, 0x6a, 0, 0xf, 0xc5, 0xb2, 0x78, 0xed, 0x63, 0, 0x7f, 0xe4, 0xe4, 0xa5, 0xeb, 0x34, 0xc4, 0xcd, 0x64, 0xa, 0, 0x2e, 0x6c, 0x6c, 0x6c, 154 | 0x6c, 0x6a, 0, 0, 0x29, 0x92, 0xe4, 0x93, 0, 0x9a, 0xa3, 0, 0, 0xea, 0x96, 0x48, 0x48, 0x25, 0, 0xea, 0xc8, 0xa1, 0xa1, 0x52, 0, 0, 0x43, 0xfe, 0x12, 0, 155 | 0x23, 0xff, 0x39, 0x1c, 0xff, 0x3d, 0, 0x1c, 0xff, 0x5c, 0x6, 0, 0x17, 0xa7, 0x8a, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0xc8, 0, 0, 0x25, 0xff, 0xf, 0, 156 | 0x7f, 0xb8, 0, 0, 0, 0xf0, 0x61, 0, 0, 0x20, 0xe0, 0x7d, 0, 0, 0, 0, 0, 0, 0x84, 0xe4, 0xc4, 0xf0, 0xe2, 0xe3, 0xff, 0xe9, 0, 0, 0, 0, 0x7b, 0xdd, 0x4b, 157 | 0xf3, 0x7, 0, 0x47, 0xf8, 0, 0, 0x68, 0xed, 0xb, 0, 0x5f, 0xe3, 0x2, 0, 0x5d, 0xeb, 0, 0, 0x1, 0, 0xaa, 0xbd, 0, 0, 0x35, 0xa5, 0xea, 0x90, 0x3f, 0x92, 158 | 0x92, 0x92, 0x92, 0x90, 0x34, 0xbe, 0xe0, 0x74, 0x10, 0, 0x9, 0xf0, 0x44, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0xea, 0x6a, 0, 0, 0, 0, 0, 0x7, 0xf5, 0x7b, 0x10, 159 | 0x8b, 0xff, 0x39, 0x2, 0xe4, 0x8c, 0x10, 0x86, 0xff, 0x5c, 0x60, 0xd2, 0xa9, 0xea, 0xfd, 0x77, 0, 0, 0, 0, 0, 0, 0, 0, 0x2a, 0x91, 0, 0, 0x1, 0xea, 0x87, 160 | 0x2f, 0xd5, 0x81, 0, 0, 0, 0xf0, 0x61, 0, 0x1f, 0xdf, 0x9f, 0x29, 0x29, 0x29, 0x36, 0x28, 0x4, 0x29, 0xcd, 0x9c, 0x2a, 0x35, 0x35, 0x3b, 0xff, 0x69, 0x28, 161 | 0x37, 0x9, 0x32, 0xd3, 0x81, 0x16, 0xef, 0x7f, 0x18, 0xa7, 0xaf, 0, 0x3, 0xdb, 0x87, 0, 0, 0x3e, 0xf5, 0x26, 0x5, 0x88, 0xc7, 0, 0x6, 0x1b, 0x75, 0xf4, 162 | 0x48, 0, 0, 0, 0, 0x1b, 0x87, 0, 0, 0, 0, 0, 0, 0x4d, 0x56, 0x4, 0, 0, 0, 0x5a, 0xe2, 0x2, 0, 0, 0xea, 0x81, 0x24, 0x24, 0x1a, 0, 0xea, 0x6a, 0, 0, 0, 0, 163 | 0, 0, 0x5c, 0xda, 0xda, 0x71, 0xff, 0x39, 0, 0x68, 0xe4, 0xfa, 0xa6, 0xd0, 0x5c, 0x9, 0x38, 0x74, 0xc9, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164 | 0x32, 0xb5, 0xef, 0x82, 0x10, 0, 0, 0, 0xf0, 0x61, 0, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f, 0xdc, 0xfc, 0xe9, 0xa6, 0x22, 0, 0, 0, 0x8, 0xff, 0x41, 165 | 0x3e, 0xd7, 0xfd, 0xe4, 0x95, 0x17, 0, 0x47, 0xdc, 0xfb, 0xb2, 0x30, 0, 0x55, 0xfa, 0x1b, 0, 0, 0, 0x90, 0xe3, 0xf2, 0xbf, 0x3c, 0, 0xec, 0xfc, 0xde, 0x57, 166 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb9, 0x85, 0, 0, 0, 0xea, 0xff, 0xff, 0xff, 0xba, 0, 0xea, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0x3, 0x4, 167 | 0x1a, 0xff, 0x39, 0, 0, 0x2, 0xa, 0, 0, 0, 0, 0, 0x10, 0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168 | 0, 0, 0, 0xd, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc, 0x1, 0, 0, 0, 0, 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb, 0, 0, 0, 0xf, 0xd, 0, 0, 0, 0, 0, 0, 169 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a, 0xff, 0x39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0xc2, 0x2b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x31, 187 | 0x17, 0, 0, 0, 0, 0, 0x15, 0x43, 0x14, 0, 0x2d, 0x35, 0x35, 0x35, 0x35, 0x35, 0x32, 0x1b, 0, 0, 0, 0x26, 0x1c, 0x35, 0x35, 0x35, 0x35, 0x35, 0, 0, 0x1d, 188 | 0x17, 0, 0, 0, 0, 0x8c, 0xa9, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb, 0xbc, 0x2f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 189 | 0, 0, 0, 0, 0, 0, 0, 0, 0x3f, 0x7a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x31, 0x35, 0x35, 0x35, 0x2b, 0xd, 0x35, 0x4, 0x35, 0xe, 0, 0x12, 0x41, 0xe, 0, 0x2f, 0x14, 190 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0xa1, 0xf9, 0xe4, 0xfe, 0x7c, 0xc9, 0xf0, 0xf6, 0xfe, 0xf0, 0xf0, 0x9e, 0xd1, 0x2, 0, 191 | 0x14, 0xf1, 0x7c, 0xf0, 0xf0, 0xf0, 0xf8, 0xff, 0, 0, 0xbd, 0xae, 0, 0, 0, 0, 0xb, 0xb2, 0x74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192 | 0xe, 0xff, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xb5, 0x60, 0x60, 0x60, 0xaa, 193 | 0x33, 0xfc, 0x2, 0xf9, 0x36, 0x9f, 0xeb, 0xd6, 0xf7, 0x5d, 0xa5, 0x99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0x2b, 0xfe, 0x2d, 194 | 0, 0x1a, 0x15, 0, 0, 0x6c, 0xea, 0, 0, 0x1d, 0xf7, 0x58, 0, 0x8a, 0xda, 0, 0, 0, 0x8, 0xd5, 0x9c, 0, 0x35, 0xc9, 0xd2, 0x34, 0, 0, 0, 0, 0x1, 0x6, 0, 0, 195 | 0x3, 0x35, 0x42, 0x9, 0, 0, 0, 0x7, 0x38, 0x3, 0, 0, 0, 0x28, 0x48, 0x36, 0x36, 0xe, 0xff, 0x40, 0, 0xe, 0x36, 0x34, 0x17, 0, 0, 0xf, 0x36, 0x25, 0x2c, 0, 196 | 0, 0x1a, 0x35, 0x33, 0x1a, 0, 0, 0x10, 0x36, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x95, 0, 0, 0, 0x95, 0x1f, 0xea, 0, 0xe6, 0x22, 0x1c, 0x4, 0, 197 | 0x7a, 0xcf, 0x46, 0xef, 0x9, 0, 0, 0, 0x4, 0x3e, 0x21, 0, 0x4, 0x36, 0x34, 0x6, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0x24, 0xff, 0x4c, 0, 0, 0, 0, 0, 0x6c, 0xea, 198 | 0, 0, 0, 0x8b, 0xd9, 0x1d, 0xf5, 0x54, 0, 0, 0, 0x8b, 0xe0, 0xe, 0, 0xac, 0x58, 0x54, 0xb7, 0, 0, 0, 0, 0, 0, 0, 0, 0xa7, 0xd5, 0xc6, 0xf3, 0x42, 0, 0x6d, 199 | 0xe1, 0xc7, 0xe1, 0x49, 0x2, 0xca, 0xbd, 0xb6, 0xff, 0xb2, 0xe, 0xff, 0x40, 0xc, 0xc7, 0xae, 0xba, 0xa4, 0, 0, 0x7f, 0xdf, 0x46, 0xfb, 0x38, 0x8, 0xd8, 200 | 0x97, 0xb6, 0xb1, 0, 0, 0x81, 0xe2, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x95, 0, 0, 0, 0x95, 0xa, 0xa3, 0, 0xa1, 0xd, 0, 0, 0x2, 0xa9, 0xb9, 0x3, 201 | 0xe3, 0x58, 0, 0, 0x70, 0xe7, 0xdd, 0xf7, 0x11, 0xe9, 0xe3, 0xd8, 0xcf, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0x84, 0xfb, 0xb6, 0x33, 0, 0, 0, 0x6c, 0xea, 0, 0, 202 | 0, 0x12, 0xef, 0xd9, 0xc8, 0x1, 0, 0, 0x3b, 0xfb, 0x42, 0, 0x26, 0xdf, 0x4, 0x2, 0xd1, 0x3d, 0, 0, 0, 0, 0, 0, 0, 0xa, 0, 0, 0xa7, 0xa5, 0x7, 0xf1, 0x3f, 203 | 0, 0x77, 0xba, 0x45, 0xf4, 0x6, 0x1, 0xe9, 0x66, 0xe, 0xff, 0x45, 0xbc, 0xbb, 0x7, 0x59, 0xf3, 0xa, 0, 0xd8, 0x80, 0, 0x95, 0xd5, 0x8f, 0xdb, 0xb, 0x50, 204 | 0xf9, 0x13, 0, 0xd8, 0x85, 0, 0, 0x58, 0xaa, 0, 0, 0x2c, 0xb1, 0xcf, 0x88, 0x4c, 0x89, 0, 0x95, 0, 0, 0, 0x95, 0, 0, 0, 0, 0, 0, 0x1, 0x9a, 0xd6, 0x1d, 0, 205 | 0x86, 0xb7, 0, 0x7, 0xf1, 0x62, 0, 0x6, 0x58, 0xf8, 0x20, 0, 0x8, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0, 0x33, 0xbe, 0xfe, 0x5a, 0, 0, 0x6c, 0xea, 0, 0, 0, 0, 206 | 0x79, 0xff, 0x40, 0, 0, 0xa, 0xda, 0x92, 0, 0, 0x9a, 0x75, 0, 0, 0x53, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0x44, 0x8b, 0xbf, 0xe6, 0xc5, 0x49, 0xfe, 0xc3, 0xc2, 207 | 0xd2, 0xfc, 0x36, 0xfe, 0x39, 0x2b, 0xf8, 0x29, 0xe, 0xff, 0xc7, 0xf9, 0x18, 0, 0x9, 0xef, 0x57, 0x32, 0xfd, 0x20, 0, 0xb, 0xe0, 0xff, 0x3d, 0, 0x4, 0xe5, 208 | 0x69, 0x31, 0xfe, 0x25, 0, 0, 0x58, 0xaa, 0, 0, 0x49, 0x3a, 0x47, 0x91, 0xbd, 0x67, 0, 0x95, 0, 0, 0, 0x95, 0, 0, 0, 0, 0, 0, 0x43, 0xe6, 0x15, 0, 0, 0x28, 209 | 0xfb, 0x1a, 0x4a, 0xfb, 0xd, 0, 0, 0x11, 0xc2, 0xf4, 0x90, 0x19, 0, 0, 0, 0xea, 0x6d, 0, 0, 0, 0, 0, 0, 0, 0xaf, 0xbe, 0, 0, 0x6c, 0xea, 0, 0, 0, 0, 0x47, 210 | 0xff, 0x12, 0, 0, 0x91, 0xda, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x27, 0xfc, 0x6a, 0x1e, 0x9a, 0xc5, 0x3b, 0xfd, 0x42, 0x31, 0x31, 0x31, 0, 211 | 0x9f, 0xe5, 0xb3, 0x5d, 0, 0xe, 0xff, 0xac, 0xd2, 0xa4, 0, 0, 0x97, 0xac, 0x88, 0xbc, 0, 0, 0x2b, 0xf7, 0xee, 0x75, 0, 0, 0x82, 0xbf, 0x86, 0xc3, 0, 0, 0, 212 | 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x95, 0, 0, 0, 0x95, 0, 0, 0, 0, 0, 0, 0x34, 0x5b, 0, 0, 0, 0, 0xc7, 0x76, 0x40, 0xfe, 0x15, 0, 0, 0, 0x1, 0x4f, 213 | 0xd1, 0xdf, 0, 0, 0, 0xea, 0x83, 0x27, 0x27, 0x23, 0x39, 0x44, 0x14, 0x2b, 0xd1, 0x7b, 0, 0, 0x6c, 0xea, 0, 0, 0, 0, 0x47, 0xff, 0x12, 0, 0x40, 0xfd, 0x60, 214 | 0x27, 0x27, 0x27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5f, 0xf6, 0xf, 0x1f, 0xe4, 0xc5, 0x1, 0xe0, 0x89, 0xe, 0x7, 0x31, 0x8, 0xfa, 0x4e, 0x24, 0xa, 0, 215 | 0xe, 0xff, 0x40, 0x2b, 0xf5, 0x65, 0, 0x36, 0xef, 0xd1, 0x5b, 0, 0x5, 0xcd, 0x9e, 0x4b, 0xf8, 0x2d, 0, 0x1e, 0xf6, 0xda, 0x63, 0, 0, 0, 0x58, 0xaa, 0, 0, 216 | 0, 0, 0, 0, 0, 0, 0, 0x95, 0, 0, 0, 0x95, 0, 0, 0, 0, 0, 0, 0x10, 0x5f, 0, 0, 0, 0, 0x68, 0xd4, 0x4, 0xec, 0x8a, 0x14, 0x3f, 0x27, 0x2c, 0x1, 0x54, 0xee, 217 | 0, 0, 0, 0xea, 0xff, 0xff, 0xff, 0xe6, 0x51, 0xdb, 0xfd, 0xea, 0xa3, 0x11, 0, 0, 0x6c, 0xea, 0, 0, 0, 0, 0x47, 0xff, 0x12, 0, 0xa0, 0xff, 0xff, 0xff, 0xff, 218 | 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf, 0xc8, 0xf7, 0xdf, 0x83, 0xc5, 0, 0x3f, 0xae, 0xf4, 0xfc, 0x9f, 0xa, 0xd2, 0xfc, 0xfb, 0xf7, 0x90, 0xe, 0xff, 219 | 0x40, 0, 0x65, 0xf6, 0, 0, 0xd4, 0xf0, 0x9, 0, 0x83, 0xe5, 0x10, 0, 0xa2, 0xd0, 0, 0, 0xb4, 0xf4, 0xd, 0, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220 | 0xc6, 0x95, 0x95, 0x95, 0xb6, 0, 0, 0, 0, 0, 0, 0x82, 0xe8, 0, 0, 0, 0, 0x11, 0xf7, 0, 0x4f, 0xbf, 0xfe, 0xf1, 0x57, 0xe9, 0xf3, 0xde, 0x67, 0, 0, 0, 0, 0, 221 | 0, 0, 0, 0, 0, 0xc, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe, 0, 0, 0, 0, 0, 0, 0xd, 222 | 0xa, 0, 0xaa, 0x94, 0x8, 0x2, 0x4e, 0xf8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6, 0xbf, 0xa0, 0, 0, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 223 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0x5, 0, 0, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xa0, 0xae, 0x37, 0x49, 0xae, 225 | 0x9e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x42, 0xc3, 0xf1, 0x1e, 0, 0, 0, 0, 0x58, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x18, 0x79, 0xb0, 0x96, 0x5c, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228 | 0, 0, 0, 0, 0x89, 0x9f, 0x3a, 0, 0, 0, 0, 0, 0x3d, 0x77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5a, 0xff, 0x5a, 0xff, 0x8f, 0, 0, 0, 0xff, 0x8f, 0, 0, 0, 0x8f, 0xff, 0xff, 234 | 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3c, 0xaa, 0x3c, 0x8f, 0xff, 0x8f, 0, 0, 0x8f, 0xff, 0x8f, 0, 0x8f, 0xff, 0x8f, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239 | 0, 0x8f, 0xff, 0x8f, 0, 0, 0x8f, 0xff, 0x8f, 0xff, 0x8f, 0, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0x5c, 0, 0, 0, 0, 0, 0, 0x5c, 0x14, 0, 0, 0, 0, 0, 0, 0x6e, 0xaa, 0, 0x3c, 0xaa, 0x3c, 0, 0, 0x8f, 0xff, 0x8f, 242 | 0, 0, 0x8f, 0xff, 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x18, 0x86, 0xbd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 243 | 0x17, 0, 0, 0, 0xa, 0x35, 0x13, 0, 0, 0x30, 0x20, 0x1d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x31, 0x17, 0, 0x33, 0x15, 0x7, 0x35, 0x35, 244 | 0x26, 0x35, 0x31, 0x3, 0x7f, 0x18, 0x3, 0x7f, 0x18, 0xb, 0xbc, 0x31, 0, 0, 0xd, 0x35, 0, 0, 0, 0x5e, 0xff, 0x70, 0, 0, 0, 0, 0x70, 0xff, 0x5e, 0, 0, 0, 0, 245 | 0, 0, 0xa5, 0xff, 0, 0x5a, 0xff, 0x5a, 0, 0x8f, 0xff, 0x8f, 0, 0, 0, 0, 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246 | 0x81, 0xd8, 0x56, 0, 0, 0, 0, 0, 0x4f, 0x3b, 0, 0, 0, 0xb5, 0xf5, 0xb0, 0xe7, 0x28, 0, 0x26, 0xff, 0x55, 0, 0x3e, 0xe7, 0x4c, 0xdc, 0x6, 0, 0, 0, 0, 0, 0, 247 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 0xff, 0xcb, 0x8e, 0xd6, 0xeb, 0xb, 0xc5, 0x2f, 0xb, 0xc5, 0x2f, 0xe, 0xff, 0x43, 0, 0, 0x33, 248 | 0xfc, 0, 0, 0, 0, 0x70, 0xff, 0x70, 0, 0, 0x70, 0xff, 0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x8f, 0xff, 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x17, 0x36, 0x36, 0x36, 0x36, 0, 0, 0, 0, 0x7, 0xcd, 0xa8, 0x36, 0x3, 0x35, 0, 0x24, 0xb, 0xcf, 0x85, 0x36, 0, 0x32, 0xfd, 0x1b, 250 | 0x1, 0xbb, 0x85, 0, 0x19, 0xff, 0x48, 0x1, 0xca, 0x70, 0x1, 0xca, 0x6f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2c, 0x9, 0, 0x2c, 0x8, 0, 0xea, 0x6d, 0, 0xf4, 251 | 0x64, 0x22, 0xff, 0x12, 0, 0x46, 0xeb, 0x3, 0x36, 0xe, 0x3, 0x36, 0xe, 0xe, 0xff, 0x43, 0, 0, 0x1f, 0xea, 0, 0, 0, 0, 0, 0x70, 0xff, 0x70, 0x70, 0xff, 252 | 0x70, 0, 0, 0, 0, 0, 0x55, 0x37, 0, 0x37, 0x55, 0, 0x1e, 0x55, 0x1e, 0xff, 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x57, 253 | 0xcc, 0xcc, 0xe8, 0xf8, 0, 0, 0, 0, 0x98, 0xf3, 0xe6, 0xc9, 0xe, 0xff, 0x85, 0xfc, 0x93, 0xfb, 0xde, 0xc9, 0, 0x41, 0xf6, 0, 0, 0x9e, 0x99, 0, 0xc, 0xff, 254 | 0x3c, 0x2c, 0xff, 0xf, 0, 0x69, 0xd0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1e, 0xf8, 0x54, 0x20, 0xf8, 0x51, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 0xff, 0x12, 0, 255 | 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0, 0, 0xa, 0xa3, 0, 0, 0, 0, 0, 0, 0x70, 0xff, 0xff, 0x70, 0, 0, 0, 0, 0, 0, 0xff, 0xa5, 0, 256 | 0xa5, 0xff, 0, 0x5a, 0xff, 0x5a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0xe6, 0x6f, 0, 0, 0, 0, 0, 0xc7, 257 | 0x8b, 0, 0xe, 0xff, 0xc7, 0x1f, 0, 0xee, 0x64, 0, 0, 0x64, 0xe7, 0, 0, 0x8f, 0xba, 0, 0x1, 0xfd, 0x2f, 0x54, 0xe5, 0, 0, 0x41, 0xf6, 0, 0, 0, 0, 0, 0, 0, 258 | 0, 0, 0x2, 0x45, 0x9, 0x3, 0x46, 0x9, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 0xff, 0x12, 0, 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0, 259 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70, 0xff, 0xff, 0x70, 0, 0, 0, 0, 0, 0, 0x55, 0x37, 0, 0x37, 0x55, 0, 0x1e, 0x55, 0x1e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1, 0xb1, 0xb6, 0x1, 0, 0, 0, 0, 0, 0xc7, 0x8b, 0, 0xe, 0xff, 0x5d, 0, 0, 0xee, 0x64, 0, 0x9b, 0xe8, 0x53, 0, 0, 261 | 0x23, 0xc4, 0xd7, 0, 0xf1, 0x22, 0x7b, 0xbe, 0, 0, 0x1a, 0xff, 0, 0, 0, 0x62, 0xa4, 0xa4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 262 | 0xff, 0x12, 0, 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x70, 0xff, 0x70, 0x70, 0xff, 0x70, 0, 0, 0, 0, 0, 263 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x69, 0xe8, 0x17, 0, 0, 0, 0, 0, 0, 0xc7, 0x8b, 0, 264 | 0xe, 0xff, 0x43, 0, 0, 0xee, 0x64, 0, 0x52, 0xcc, 0xa7, 0, 0, 0x4e, 0xea, 0x76, 0, 0x75, 0xc, 0x6f, 0xca, 0, 0, 0x26, 0xff, 0, 0, 0, 0x49, 0x7a, 0x7a, 0, 265 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 0xff, 0x12, 0, 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 266 | 0, 0, 0x70, 0xff, 0x70, 0, 0, 0x70, 0xff, 0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267 | 0, 0, 0x2a, 0xf5, 0x4c, 0x3, 0x3, 0, 0, 0, 0, 0, 0xc7, 0x8b, 0, 0xe, 0xff, 0x43, 0, 0, 0xd0, 0x8f, 0x5, 0, 0x4a, 0xf5, 0, 0, 0x99, 0xa2, 0, 0x8, 0x75, 268 | 0x17, 0x47, 0xf2, 0x1, 0, 0x4e, 0xeb, 0x9, 0x56, 0x17, 0, 0, 0, 0x8, 0x75, 0x17, 0x8, 0x75, 0x17, 0x9, 0x56, 0x17, 0, 0xea, 0x6d, 0, 0xf4, 0x64, 0x22, 269 | 0xff, 0x12, 0, 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 0, 0x5e, 0xff, 0x70, 0, 0, 0, 0, 0x70, 0xff, 0x5e, 0, 0, 0, 270 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x9a, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0xc7, 271 | 0x8b, 0, 0xe, 0xff, 0x43, 0, 0, 0x62, 0xee, 0xfc, 0, 0x41, 0xf7, 0, 0, 0x9f, 0x99, 0, 0x27, 0xfe, 0x4f, 0x1a, 0xfc, 0x27, 0, 0x82, 0xba, 0x3d, 0xf9, 0x14, 272 | 0, 0, 0, 0x27, 0xfe, 0x4f, 0x27, 0xfe, 0x4f, 0x3d, 0xf9, 0x14, 0, 0xea, 0x6d, 0, 0xf6, 0x60, 0x22, 0xff, 0x12, 0, 0x46, 0xeb, 0xe, 0xff, 0x43, 0xe, 0xff, 273 | 0x43, 0xe, 0xff, 0x43, 0, 0, 0, 0, 0, 0, 0, 0x14, 0x5c, 0, 0, 0, 0, 0, 0, 0x5c, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x6, 0xe, 0, 0x13, 0xf7, 0x74, 0x3a, 0xe1, 0x6d, 0, 0, 275 | 0x12, 0, 0, 0x97, 0x9e, 0xd, 0xeb, 0x3d, 0x71, 0xaf, 0, 0, 0, 0, 0, 0x12, 0, 0, 0x12, 0, 0x71, 0xaf, 0, 0, 0, 0, 0x33, 0xff, 0x25, 0x22, 0xff, 0x3c, 0x20, 276 | 0x67, 0xeb, 0, 0, 0, 0x17, 0xff, 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc1, 0xc1, 0xc1, 0xc1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x58, 0xa8, 0x8b, 278 | 0x86, 0xd, 0, 0, 0, 0, 0, 0x16, 0xc8, 0x5c, 0x97, 0, 0x49, 0x33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x49, 0x33, 0, 0, 0, 0, 0xf9, 0xad, 0, 0x1c, 0xd1, 0xd1, 279 | 0x95, 0xd1, 0xc0, 0, 0, 0, 0xba, 0xf7, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 282 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 283 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 285 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 287 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 293 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 294 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 295 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 296 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 298 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 299 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 302 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 304 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 305 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 306 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 307 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 310 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 313 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 314 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 315 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 316 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 317 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 321 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 322 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 323 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 325 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 326 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 327 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 328 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 329 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 331 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 332 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 334 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 335 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 337 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 338 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 339 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 340 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 341 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 342 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 347 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 349 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 353 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 354 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 355 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 356 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 357 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 358 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 359 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 362 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 366 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 372 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 373 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 374 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 375 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 376 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 378 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 379 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 380 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 381 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 382 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 383 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 387 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391 | ]; 392 | pub const ATLAS: [Rect; 134] = [ 393 | Rect { x: 0, y: 0, w: 0, h: 0 }, 394 | Rect { x: 88, y: 68, w: 16, h: 16 }, 395 | Rect { x: 0, y: 0, w: 18, h: 18 }, 396 | Rect { x: 113, y: 68, w: 5, h: 7 }, 397 | Rect { x: 118, y: 68, w: 7, h: 5 }, 398 | Rect { x: 125, y: 68, w: 3, h: 3 }, 399 | Rect { x: 0, y: 0, w: 0, h: 0 }, 400 | Rect { x: 0, y: 0, w: 0, h: 0 }, 401 | Rect { x: 0, y: 0, w: 0, h: 0 }, 402 | Rect { x: 0, y: 0, w: 0, h: 0 }, 403 | Rect { x: 0, y: 0, w: 0, h: 0 }, 404 | Rect { x: 0, y: 0, w: 0, h: 0 }, 405 | Rect { x: 0, y: 0, w: 0, h: 0 }, 406 | Rect { x: 0, y: 0, w: 0, h: 0 }, 407 | Rect { x: 0, y: 0, w: 0, h: 0 }, 408 | Rect { x: 0, y: 0, w: 0, h: 0 }, 409 | Rect { x: 0, y: 0, w: 0, h: 0 }, 410 | Rect { x: 0, y: 0, w: 0, h: 0 }, 411 | Rect { x: 0, y: 0, w: 0, h: 0 }, 412 | Rect { x: 0, y: 0, w: 0, h: 0 }, 413 | Rect { x: 0, y: 0, w: 0, h: 0 }, 414 | Rect { x: 0, y: 0, w: 0, h: 0 }, 415 | Rect { x: 0, y: 0, w: 0, h: 0 }, 416 | Rect { x: 0, y: 0, w: 0, h: 0 }, 417 | Rect { x: 0, y: 0, w: 0, h: 0 }, 418 | Rect { x: 0, y: 0, w: 0, h: 0 }, 419 | Rect { x: 0, y: 0, w: 0, h: 0 }, 420 | Rect { x: 0, y: 0, w: 0, h: 0 }, 421 | Rect { x: 0, y: 0, w: 0, h: 0 }, 422 | Rect { x: 0, y: 0, w: 0, h: 0 }, 423 | Rect { x: 0, y: 0, w: 0, h: 0 }, 424 | Rect { x: 0, y: 0, w: 0, h: 0 }, 425 | Rect { x: 0, y: 0, w: 0, h: 0 }, 426 | Rect { x: 0, y: 0, w: 0, h: 0 }, 427 | Rect { x: 0, y: 0, w: 0, h: 0 }, 428 | Rect { x: 0, y: 0, w: 0, h: 0 }, 429 | Rect { x: 0, y: 0, w: 0, h: 0 }, 430 | Rect { x: 0, y: 0, w: 0, h: 0 }, 431 | Rect { x: 84, y: 68, w: 2, h: 17 }, 432 | Rect { x: 39, y: 68, w: 3, h: 17 }, 433 | Rect { x: 114, y: 51, w: 5, h: 17 }, 434 | Rect { x: 34, y: 17, w: 7, h: 17 }, 435 | Rect { x: 28, y: 34, w: 6, h: 17 }, 436 | Rect { x: 58, y: 0, w: 9, h: 17 }, 437 | Rect { x: 103, y: 0, w: 8, h: 17 }, 438 | Rect { x: 86, y: 68, w: 2, h: 17 }, 439 | Rect { x: 42, y: 68, w: 3, h: 17 }, 440 | Rect { x: 45, y: 68, w: 3, h: 17 }, 441 | Rect { x: 34, y: 34, w: 6, h: 17 }, 442 | Rect { x: 40, y: 34, w: 6, h: 17 }, 443 | Rect { x: 48, y: 68, w: 3, h: 17 }, 444 | Rect { x: 51, y: 68, w: 3, h: 17 }, 445 | Rect { x: 54, y: 68, w: 3, h: 17 }, 446 | Rect { x: 124, y: 34, w: 4, h: 17 }, 447 | Rect { x: 46, y: 34, w: 6, h: 17 }, 448 | Rect { x: 52, y: 34, w: 6, h: 17 }, 449 | Rect { x: 58, y: 34, w: 6, h: 17 }, 450 | Rect { x: 64, y: 34, w: 6, h: 17 }, 451 | Rect { x: 70, y: 34, w: 6, h: 17 }, 452 | Rect { x: 76, y: 34, w: 6, h: 17 }, 453 | Rect { x: 82, y: 34, w: 6, h: 17 }, 454 | Rect { x: 88, y: 34, w: 6, h: 17 }, 455 | Rect { x: 94, y: 34, w: 6, h: 17 }, 456 | Rect { x: 100, y: 34, w: 6, h: 17 }, 457 | Rect { x: 57, y: 68, w: 3, h: 17 }, 458 | Rect { x: 60, y: 68, w: 3, h: 17 }, 459 | Rect { x: 106, y: 34, w: 6, h: 17 }, 460 | Rect { x: 112, y: 34, w: 6, h: 17 }, 461 | Rect { x: 118, y: 34, w: 6, h: 17 }, 462 | Rect { x: 119, y: 51, w: 5, h: 17 }, 463 | Rect { x: 18, y: 0, w: 10, h: 17 }, 464 | Rect { x: 41, y: 17, w: 7, h: 17 }, 465 | Rect { x: 48, y: 17, w: 7, h: 17 }, 466 | Rect { x: 55, y: 17, w: 7, h: 17 }, 467 | Rect { x: 111, y: 0, w: 8, h: 17 }, 468 | Rect { x: 0, y: 35, w: 6, h: 17 }, 469 | Rect { x: 6, y: 35, w: 6, h: 17 }, 470 | Rect { x: 119, y: 0, w: 8, h: 17 }, 471 | Rect { x: 18, y: 17, w: 8, h: 17 }, 472 | Rect { x: 63, y: 68, w: 3, h: 17 }, 473 | Rect { x: 66, y: 68, w: 3, h: 17 }, 474 | Rect { x: 62, y: 17, w: 7, h: 17 }, 475 | Rect { x: 12, y: 51, w: 6, h: 17 }, 476 | Rect { x: 28, y: 0, w: 10, h: 17 }, 477 | Rect { x: 67, y: 0, w: 9, h: 17 }, 478 | Rect { x: 76, y: 0, w: 9, h: 17 }, 479 | Rect { x: 69, y: 17, w: 7, h: 17 }, 480 | Rect { x: 85, y: 0, w: 9, h: 17 }, 481 | Rect { x: 76, y: 17, w: 7, h: 17 }, 482 | Rect { x: 18, y: 51, w: 6, h: 17 }, 483 | Rect { x: 24, y: 51, w: 6, h: 17 }, 484 | Rect { x: 26, y: 17, w: 8, h: 17 }, 485 | Rect { x: 83, y: 17, w: 7, h: 17 }, 486 | Rect { x: 38, y: 0, w: 10, h: 17 }, 487 | Rect { x: 90, y: 17, w: 7, h: 17 }, 488 | Rect { x: 30, y: 51, w: 6, h: 17 }, 489 | Rect { x: 36, y: 51, w: 6, h: 17 }, 490 | Rect { x: 69, y: 68, w: 3, h: 17 }, 491 | Rect { x: 124, y: 51, w: 4, h: 17 }, 492 | Rect { x: 72, y: 68, w: 3, h: 17 }, 493 | Rect { x: 42, y: 51, w: 6, h: 17 }, 494 | Rect { x: 15, y: 68, w: 4, h: 17 }, 495 | Rect { x: 48, y: 51, w: 6, h: 17 }, 496 | Rect { x: 54, y: 51, w: 6, h: 17 }, 497 | Rect { x: 97, y: 17, w: 7, h: 17 }, 498 | Rect { x: 0, y: 52, w: 5, h: 17 }, 499 | Rect { x: 104, y: 17, w: 7, h: 17 }, 500 | Rect { x: 60, y: 51, w: 6, h: 17 }, 501 | Rect { x: 19, y: 68, w: 4, h: 17 }, 502 | Rect { x: 66, y: 51, w: 6, h: 17 }, 503 | Rect { x: 111, y: 17, w: 7, h: 17 }, 504 | Rect { x: 75, y: 68, w: 3, h: 17 }, 505 | Rect { x: 78, y: 68, w: 3, h: 17 }, 506 | Rect { x: 72, y: 51, w: 6, h: 17 }, 507 | Rect { x: 81, y: 68, w: 3, h: 17 }, 508 | Rect { x: 48, y: 0, w: 10, h: 17 }, 509 | Rect { x: 118, y: 17, w: 7, h: 17 }, 510 | Rect { x: 0, y: 18, w: 7, h: 17 }, 511 | Rect { x: 7, y: 18, w: 7, h: 17 }, 512 | Rect { x: 14, y: 34, w: 7, h: 17 }, 513 | Rect { x: 23, y: 68, w: 4, h: 17 }, 514 | Rect { x: 5, y: 52, w: 5, h: 17 }, 515 | Rect { x: 27, y: 68, w: 4, h: 17 }, 516 | Rect { x: 21, y: 34, w: 7, h: 17 }, 517 | Rect { x: 78, y: 51, w: 6, h: 17 }, 518 | Rect { x: 94, y: 0, w: 9, h: 17 }, 519 | Rect { x: 84, y: 51, w: 6, h: 17 }, 520 | Rect { x: 90, y: 51, w: 6, h: 17 }, 521 | Rect { x: 10, y: 68, w: 5, h: 17 }, 522 | Rect { x: 31, y: 68, w: 4, h: 17 }, 523 | Rect { x: 96, y: 51, w: 6, h: 17 }, 524 | Rect { x: 35, y: 68, w: 4, h: 17 }, 525 | Rect { x: 102, y: 51, w: 6, h: 17 }, 526 | Rect { x: 108, y: 51, w: 6, h: 17 }, 527 | ]; 528 | -------------------------------------------------------------------------------- /src/fixed_collections.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022-Present (c) Raja Lehtihet & Wael El Oraiby 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its contributors 15 | // may be used to endorse or promote products derived from this software without 16 | // specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | // POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | use core::ops::{IndexMut, Index, AddAssign}; 31 | use core::str::Chars; 32 | use core::cmp::Ordering; 33 | 34 | pub trait IVec { 35 | fn push(&mut self, t: T) -> (&mut T, usize); 36 | fn pop(&mut self); 37 | 38 | fn top(&self) -> Option<&T>; 39 | 40 | fn top_mut(&mut self) -> Option<&mut T>; 41 | 42 | fn capacity(&self) -> usize; 43 | fn len(&self) -> usize; 44 | fn clear(&mut self); 45 | 46 | fn as_slice(&self) -> &[T]; 47 | fn as_slice_mut(&mut self) -> &mut [T]; 48 | 49 | fn get(&self, index: usize) -> &T; 50 | fn get_mut(&mut self, index: usize) -> &mut T; 51 | 52 | fn append(&mut self, other: &[T]) { 53 | for e in other { 54 | self.push(e.clone()); 55 | } 56 | } 57 | 58 | fn reverse(&mut self); 59 | } 60 | 61 | pub fn quick_sort_by Ordering>(arr: &mut [T], f: F) { 62 | let len = arr.len(); 63 | if len == 0 { 64 | return; 65 | } 66 | _quick_sort(arr, 0, (len - 1) as isize, &f); 67 | } 68 | 69 | fn _quick_sort Ordering>(arr: &mut [T], low: isize, high: isize, f: &F) { 70 | if low < high { 71 | let p = partition(arr, low, high, f); 72 | _quick_sort(arr, low, p - 1, f); 73 | _quick_sort(arr, p + 1, high, f); 74 | } 75 | } 76 | 77 | fn partition Ordering>(arr: &mut [T], low: isize, high: isize, f: &F) -> isize { 78 | let pivot = high as usize; 79 | let mut store_index = low - 1; 80 | let mut last_index = high; 81 | 82 | loop { 83 | store_index += 1; 84 | while f(&arr[store_index as usize], &arr[pivot]).is_lt() { 85 | store_index += 1; 86 | } 87 | last_index -= 1; 88 | while last_index >= 0 && f(&arr[last_index as usize], &arr[pivot]).is_gt() { 89 | last_index -= 1; 90 | } 91 | if store_index >= last_index { 92 | break; 93 | } else { 94 | arr.swap(store_index as usize, last_index as usize); 95 | } 96 | } 97 | arr.swap(store_index as usize, pivot as usize); 98 | store_index 99 | } 100 | 101 | #[derive(Clone)] 102 | pub struct FixedVec { 103 | idx: usize, 104 | items: [T; N], 105 | } 106 | 107 | impl IVec for FixedVec { 108 | fn push(&mut self, t: T) -> (&mut T, usize) { 109 | assert!(self.idx < N - 1); 110 | self.items[self.idx] = t; 111 | self.idx += 1; 112 | (&mut self.items[self.idx - 1], self.idx - 1) 113 | } 114 | 115 | fn pop(&mut self) { 116 | assert!(self.idx > 0); 117 | self.idx -= 1; 118 | self.items[self.idx] = T::default(); 119 | } 120 | 121 | fn top(&self) -> Option<&T> { 122 | if self.idx != 0 { 123 | Some(&self.items[self.idx - 1]) 124 | } else { 125 | None 126 | } 127 | } 128 | 129 | fn top_mut(&mut self) -> Option<&mut T> { 130 | if self.idx != 0 { 131 | Some(&mut self.items[self.idx - 1]) 132 | } else { 133 | None 134 | } 135 | } 136 | 137 | fn capacity(&self) -> usize { 138 | N 139 | } 140 | fn len(&self) -> usize { 141 | self.idx 142 | } 143 | fn clear(&mut self) { 144 | for i in 0..self.idx { 145 | self.items[i] = T::default(); 146 | } 147 | self.idx = 0; 148 | } 149 | 150 | fn as_slice(&self) -> &[T] { 151 | &self.items[0..self.idx] 152 | } 153 | 154 | fn as_slice_mut(&mut self) -> &mut [T] { 155 | &mut self.items[0..self.idx] 156 | } 157 | 158 | fn get(&self, index: usize) -> &T { 159 | assert!((index as usize) < self.idx); 160 | assert!((index as usize) < N); 161 | &self.items[index as usize] 162 | } 163 | 164 | fn get_mut(&mut self, index: usize) -> &mut T { 165 | assert!((index as usize) < self.idx); 166 | assert!((index as usize) < N); 167 | &mut self.items[index as usize] 168 | } 169 | 170 | fn reverse(&mut self) { 171 | let len = self.len(); 172 | for i in 0..len / 2 { 173 | let tmp = self.items[i]; 174 | self.items[i] = self.items[len - 1 - i]; 175 | self.items[len - 1 - i] = tmp; 176 | } 177 | } 178 | } 179 | 180 | impl Index for FixedVec { 181 | type Output = T; 182 | fn index(&self, index: usize) -> &Self::Output { 183 | self.get(index as usize) 184 | } 185 | } 186 | 187 | impl IndexMut for FixedVec { 188 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { 189 | self.get_mut(index as usize) 190 | } 191 | } 192 | 193 | impl Default for FixedVec { 194 | fn default() -> Self { 195 | Self { idx: 0, items: [T::default(); N] } 196 | } 197 | } 198 | 199 | impl Index for dyn IVec { 200 | type Output = T; 201 | fn index(&self, index: usize) -> &Self::Output { 202 | self.get(index as usize) 203 | } 204 | } 205 | 206 | impl IndexMut for dyn IVec { 207 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { 208 | self.get_mut(index as usize) 209 | } 210 | } 211 | 212 | impl core::fmt::Write for FixedVec { 213 | fn write_str(&mut self, s: &str) -> core::fmt::Result { 214 | for c in s.chars() { 215 | if self.idx < N - 1 { 216 | self.push(c); 217 | } else { 218 | return Err(core::fmt::Error); 219 | } 220 | } 221 | Ok(()) 222 | } 223 | } 224 | 225 | const DIGITS: [char; 32] = [ 226 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 227 | 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 228 | ]; 229 | 230 | pub trait IString { 231 | fn push(&mut self, c: char); 232 | fn pop(&mut self); 233 | fn as_str(&self) -> &str; 234 | fn chars(&self) -> Chars<'_>; 235 | fn char_count(&self) -> usize; 236 | fn clear(&mut self); 237 | fn len(&self) -> usize; 238 | fn as_u8_slice(&self) -> &[u8]; 239 | fn capacity(&self) -> usize; 240 | fn add_str(&mut self, s: &str); 241 | 242 | fn append_real(&mut self, precision: usize, f: f64) { 243 | assert!(self.capacity() - self.len() >= 32); 244 | let mut int_str = FixedVec::::default(); 245 | let mut i = (f.signum() * f) as usize; 246 | while i != 0 { 247 | int_str.push(DIGITS[i % 10]); 248 | i /= 10; 249 | } 250 | 251 | if int_str.len() == 0 { 252 | int_str.push('0'); 253 | } 254 | 255 | if f < 0.0 { 256 | int_str.push('-'); 257 | } 258 | 259 | int_str.reverse(); 260 | 261 | let mut pow_10 = 1; 262 | for _ in 0..precision { 263 | pow_10 *= 10; 264 | } 265 | 266 | // i2 = i * 10^p 267 | // d2 = f * 10^p 268 | // i = 10^p + (d2 - i2) <- needed so we can get the number of leading 0 right 269 | let int2_part = ((f.signum() * f) as usize) * pow_10; 270 | let mut dec2_part = pow_10 + ((f.signum() * f) * (pow_10 as f64)) as usize - int2_part; 271 | 272 | if dec2_part == pow_10 || precision == 0 { 273 | for i in 0..int_str.len() { 274 | self.push(int_str[i]); 275 | } 276 | return; 277 | } 278 | 279 | int_str.push('.'); 280 | 281 | let mut dec_str = FixedVec::::default(); 282 | for _ in 0..precision { 283 | dec_str.push(DIGITS[dec2_part % 10]); 284 | dec2_part /= 10; 285 | } 286 | 287 | dec_str.reverse(); 288 | 289 | for i in 0..int_str.len() { 290 | self.push(int_str[i]); 291 | } 292 | 293 | for i in 0..dec_str.len() { 294 | self.push(dec_str[i]); 295 | } 296 | } 297 | 298 | // base should be <= 32 299 | fn append_int(&mut self, base: usize, leading_zeros: usize, v: i32) { 300 | assert!(self.capacity() - self.len() >= 32); 301 | assert!(base <= 32); 302 | let mut int_str = FixedVec::::default(); 303 | let mut v2 = (v.signum() * v) as usize; 304 | while v2 != 0 { 305 | int_str.push(DIGITS[v2 % base]); 306 | v2 /= base; 307 | } 308 | 309 | for _ in int_str.len()..leading_zeros { 310 | int_str.push('0'); 311 | } 312 | 313 | if v < 0 { 314 | int_str.push('-'); 315 | } 316 | 317 | int_str.reverse(); 318 | for i in 0..int_str.len() { 319 | self.push(int_str[i]); 320 | } 321 | } 322 | } 323 | 324 | #[derive(Default, Clone)] 325 | pub struct FixedString { 326 | char_count: usize, 327 | vec: FixedVec, 328 | } 329 | 330 | impl FixedString { 331 | pub fn new() -> Self { 332 | Self { char_count: 0, vec: FixedVec::default() } 333 | } 334 | } 335 | 336 | impl IString for FixedString { 337 | fn push(&mut self, c: char) { 338 | let mut encoding = [0; 4]; 339 | let bytes = c.encode_utf8(&mut encoding).bytes(); 340 | for b in bytes { 341 | self.vec.push(b); 342 | } 343 | self.char_count += 1; 344 | } 345 | 346 | fn pop(&mut self) { 347 | let ch = self.chars().rev().next().unwrap(); 348 | 349 | let bc = ch.len_utf8(); 350 | for _ in 0..bc { 351 | self.vec.pop(); 352 | } 353 | self.char_count -= 1; 354 | } 355 | 356 | fn as_str(&self) -> &str { 357 | unsafe { core::str::from_utf8_unchecked(self.vec.as_slice()) } 358 | } 359 | 360 | fn chars(&self) -> Chars<'_> { 361 | self.as_str().chars() 362 | } 363 | 364 | fn char_count(&self) -> usize { 365 | self.char_count 366 | } 367 | 368 | fn clear(&mut self) { 369 | self.char_count = 0; 370 | self.vec.clear(); 371 | } 372 | 373 | fn len(&self) -> usize { 374 | self.vec.len() 375 | } 376 | 377 | fn as_u8_slice(&self) -> &[u8] { 378 | self.vec.as_slice() 379 | } 380 | 381 | fn capacity(&self) -> usize { 382 | N 383 | } 384 | 385 | fn add_str(&mut self, s: &str) { 386 | for c in s.chars() { 387 | self.push(c) 388 | } 389 | } 390 | } 391 | 392 | impl AddAssign<&str> for FixedString { 393 | fn add_assign(&mut self, rhs: &str) { 394 | for c in rhs.chars() { 395 | self.push(c); 396 | } 397 | } 398 | } 399 | 400 | impl AddAssign<&str> for dyn IString { 401 | fn add_assign(&mut self, rhs: &str) { 402 | for c in rhs.chars() { 403 | self.push(c); 404 | } 405 | } 406 | } 407 | 408 | // impl core::fmt::Write for FixedString { 409 | // fn write_str(&mut self, s: &str) -> core::fmt::Result { 410 | // for c in s.chars() { 411 | // if self.vec.len() < N - 1 { 412 | // self.push(c); 413 | // } else { 414 | // return Err(core::fmt::Error); 415 | // } 416 | // } 417 | // Ok(()) 418 | // } 419 | // } 420 | 421 | impl Index for FixedString { 422 | type Output = u8; 423 | fn index(&self, index: usize) -> &Self::Output { 424 | self.vec.get(index as usize) 425 | } 426 | } 427 | 428 | impl Index> for FixedString { 429 | type Output = str; 430 | fn index(&self, index: core::ops::Range) -> &Self::Output { 431 | unsafe { core::str::from_utf8_unchecked(&self.vec.as_slice()[index.start..index.end]) } 432 | } 433 | } 434 | 435 | fn is_digit(ch: char) -> bool { 436 | let c = ch as usize; 437 | c >= '0' as usize && c <= '9' as usize 438 | } 439 | 440 | fn digit_to_num(ch: char) -> i32 { 441 | ch as i32 - '0' as i32 442 | } 443 | 444 | pub fn parse_decimal(s: &str) -> Result { 445 | let mut sign = 1.0; 446 | let mut p = s.chars().peekable(); 447 | match p.peek() { 448 | Some('+') => { 449 | p.next(); 450 | } 451 | Some('-') => { 452 | p.next(); 453 | sign = -1.0 454 | } 455 | Some(c) if is_digit(*c) => (), 456 | _ => return Err(()), 457 | } 458 | 459 | // consume the leading zeros 460 | 'zeros: loop { 461 | match p.peek() { 462 | Some('0') => { 463 | p.next(); 464 | } 465 | _ => break 'zeros, 466 | } 467 | } 468 | 469 | let mut int_part = 0; 470 | 471 | 'int_part: loop { 472 | match p.next() { 473 | Some(c) if is_digit(c) => int_part = int_part * 10 + digit_to_num(c), 474 | Some('.') => break 'int_part, 475 | None => return Ok((int_part as f64) * sign), 476 | _ => return Err(()), 477 | } 478 | } 479 | 480 | let mut decimal_part = 0.0; 481 | let mut power = 10.0; 482 | loop { 483 | match p.next() { 484 | Some(c) if is_digit(c) => { 485 | decimal_part += digit_to_num(c) as f64 / power; 486 | power *= 10.0; 487 | } 488 | 489 | None => return Ok((int_part as f64) * sign + decimal_part), 490 | _ => return Err(()), 491 | } 492 | } 493 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2022-Present (c) Raja Lehtihet & Wael El Oraiby 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its contributors 15 | // may be used to endorse or promote products derived from this software without 16 | // specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | // POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // ----------------------------------------------------------------------------- 31 | // Ported to rust from https://github.com/rxi/microui/ and the original license 32 | // 33 | // Copyright (c) 2020 rxi 34 | // 35 | // Permission is hereby granted, free of charge, to any person obtaining a copy 36 | // of this software and associated documentation files (the "Software"), to 37 | // deal in the Software without restriction, including without limitation the 38 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 39 | // sell copies of the Software, and to permit persons to whom the Software is 40 | // furnished to do so, subject to the following conditions: 41 | // 42 | // The above copyright notice and this permission notice shall be included in 43 | // all copies or substantial portions of the Software. 44 | // 45 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 50 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 51 | // IN THE SOFTWARE. 52 | // 53 | #![no_std] 54 | 55 | extern crate std; 56 | use std::f32; 57 | use std::f64; 58 | 59 | mod fixed_collections; 60 | pub use crate::fixed_collections::*; 61 | 62 | mod atlas; 63 | pub use atlas::*; 64 | 65 | use bitflags::*; 66 | 67 | #[derive(Copy, Clone)] 68 | pub struct Pool { 69 | vec: [PoolItem; N], 70 | } 71 | 72 | impl Pool { 73 | pub fn alloc(&mut self, id: Id, frame: usize) -> usize { 74 | let mut res = None; 75 | let mut latest_update = frame; 76 | for i in 0..N { 77 | if self.vec[i].last_update < latest_update { 78 | latest_update = self.vec[i].last_update; 79 | res = Some(i); 80 | } 81 | } 82 | 83 | assert!(res.is_some()); 84 | self.vec[res.unwrap()].id = id; 85 | self.update(res.unwrap(), frame); 86 | return res.unwrap(); 87 | } 88 | 89 | pub fn get(&self, id: Id) -> Option { 90 | for i in 0..N { 91 | if self.vec[i].id == id { 92 | return Some(i); 93 | } 94 | } 95 | None 96 | } 97 | 98 | pub fn update(&mut self, idx: usize, frame: usize) { 99 | self.vec[idx].last_update = frame; 100 | } 101 | 102 | pub fn reset(&mut self, idx: usize) { 103 | self.vec[idx] = PoolItem::default(); 104 | } 105 | } 106 | 107 | impl Default for Pool { 108 | fn default() -> Self { 109 | Self { vec: [PoolItem::default(); N] } 110 | } 111 | } 112 | 113 | #[derive(PartialEq, Copy, Clone)] 114 | #[repr(u32)] 115 | pub enum Clip { 116 | None = 0, 117 | Part = 1, 118 | All = 2, 119 | } 120 | 121 | #[derive(PartialEq, Copy, Clone)] 122 | #[repr(u32)] 123 | pub enum ControlColor { 124 | Max = 14, 125 | ScrollThumb = 13, 126 | ScrollBase = 12, 127 | BaseFocus = 11, 128 | BaseHover = 10, 129 | Base = 9, 130 | ButtonFocus = 8, 131 | ButtonHover = 7, 132 | Button = 6, 133 | PanelBG = 5, 134 | TitleText = 4, 135 | TitleBG = 3, 136 | WindowBG = 2, 137 | Border = 1, 138 | Text = 0, 139 | } 140 | 141 | impl ControlColor { 142 | pub fn hover(&mut self) { 143 | *self = match self { 144 | Self::Base => Self::BaseHover, 145 | Self::Button => Self::ButtonHover, 146 | _ => *self, 147 | } 148 | } 149 | 150 | pub fn focus(&mut self) { 151 | *self = match self { 152 | Self::Base => Self::BaseFocus, 153 | Self::Button => Self::ButtonFocus, 154 | Self::BaseHover => Self::BaseFocus, 155 | Self::ButtonHover => Self::ButtonFocus, 156 | _ => *self, 157 | } 158 | } 159 | } 160 | 161 | #[derive(PartialEq, Copy, Clone)] 162 | #[repr(u32)] 163 | pub enum Icon { 164 | Max = 5, 165 | Expanded = 4, 166 | Collapsed = 3, 167 | Check = 2, 168 | Close = 1, 169 | None = 0, 170 | } 171 | 172 | bitflags! { 173 | pub struct ResourceState : u32 { 174 | const CHANGE = 4; 175 | const SUBMIT = 2; 176 | const ACTIVE = 1; 177 | const NONE = 0; 178 | } 179 | } 180 | 181 | impl ResourceState { 182 | pub fn is_changed(&self) -> bool { 183 | self.intersects(Self::CHANGE) 184 | } 185 | pub fn is_submitted(&self) -> bool { 186 | self.intersects(Self::SUBMIT) 187 | } 188 | pub fn is_active(&self) -> bool { 189 | self.intersects(Self::ACTIVE) 190 | } 191 | pub fn is_none(&self) -> bool { 192 | self.bits() == 0 193 | } 194 | } 195 | 196 | bitflags! { 197 | #[derive(Copy, Clone)] 198 | pub struct WidgetOption : u32 { 199 | const EXPANDED = 4096; 200 | const CLOSED = 2048; 201 | const POPUP= 1024; 202 | const AUTO_SIZE = 512; 203 | const HOLD_FOCUS = 256; 204 | const NO_TITLE = 128; 205 | const NO_CLOSE = 64; 206 | const NO_SCROLL = 32; 207 | const NO_RESIZE = 16; 208 | const NO_FRAME = 8; 209 | const NO_INTERACT = 4; 210 | const ALIGN_RIGHT = 2; 211 | const ALIGN_CENTER = 1; 212 | const NONE = 0; 213 | } 214 | } 215 | 216 | impl WidgetOption { 217 | pub fn is_expanded(&self) -> bool { 218 | self.intersects(WidgetOption::EXPANDED) 219 | } 220 | pub fn is_closed(&self) -> bool { 221 | self.intersects(WidgetOption::CLOSED) 222 | } 223 | pub fn is_popup(&self) -> bool { 224 | self.intersects(WidgetOption::POPUP) 225 | } 226 | pub fn is_auto_sizing(&self) -> bool { 227 | self.intersects(WidgetOption::AUTO_SIZE) 228 | } 229 | pub fn is_holding_focus(&self) -> bool { 230 | self.intersects(WidgetOption::HOLD_FOCUS) 231 | } 232 | pub fn has_no_title(&self) -> bool { 233 | self.intersects(WidgetOption::NO_TITLE) 234 | } 235 | pub fn has_no_close(&self) -> bool { 236 | self.intersects(WidgetOption::NO_CLOSE) 237 | } 238 | pub fn has_no_scroll(&self) -> bool { 239 | self.intersects(WidgetOption::NO_SCROLL) 240 | } 241 | pub fn is_fixed(&self) -> bool { 242 | self.intersects(WidgetOption::NO_RESIZE) 243 | } 244 | pub fn has_no_frame(&self) -> bool { 245 | self.intersects(WidgetOption::NO_FRAME) 246 | } 247 | pub fn is_not_interactive(&self) -> bool { 248 | self.intersects(WidgetOption::NO_INTERACT) 249 | } 250 | pub fn is_aligned_right(&self) -> bool { 251 | self.intersects(WidgetOption::ALIGN_RIGHT) 252 | } 253 | pub fn is_aligned_center(&self) -> bool { 254 | self.intersects(WidgetOption::ALIGN_CENTER) 255 | } 256 | pub fn is_none(&self) -> bool { 257 | self.bits() == 0 258 | } 259 | } 260 | 261 | bitflags! { 262 | #[derive(Copy, Clone)] 263 | pub struct MouseButton : u32 { 264 | const MIDDLE = 4; 265 | const RIGHT = 2; 266 | const LEFT = 1; 267 | const NONE = 0; 268 | } 269 | } 270 | 271 | impl MouseButton { 272 | pub fn is_middle(&self) -> bool { 273 | self.intersects(Self::MIDDLE) 274 | } 275 | pub fn is_right(&self) -> bool { 276 | self.intersects(Self::RIGHT) 277 | } 278 | pub fn is_left(&self) -> bool { 279 | self.intersects(Self::LEFT) 280 | } 281 | pub fn is_none(&self) -> bool { 282 | self.bits() == 0 283 | } 284 | } 285 | 286 | bitflags! { 287 | #[derive(Copy, Clone)] 288 | pub struct KeyMode : u32 { 289 | const RETURN = 16; 290 | const BACKSPACE = 8; 291 | const ALT = 4; 292 | const CTRL = 2; 293 | const SHIFT = 1; 294 | const NONE = 0; 295 | } 296 | } 297 | 298 | impl KeyMode { 299 | pub fn is_none(&self) -> bool { 300 | self.bits() == 0 301 | } 302 | pub fn is_return(&self) -> bool { 303 | self.intersects(Self::RETURN) 304 | } 305 | pub fn is_backspace(&self) -> bool { 306 | self.intersects(Self::BACKSPACE) 307 | } 308 | pub fn is_alt(&self) -> bool { 309 | self.intersects(Self::ALT) 310 | } 311 | pub fn is_ctrl(&self) -> bool { 312 | self.intersects(Self::CTRL) 313 | } 314 | pub fn is_shift(&self) -> bool { 315 | self.intersects(Self::SHIFT) 316 | } 317 | } 318 | 319 | #[repr(C)] 320 | pub struct Context { 321 | pub char_width: Option usize>, 322 | pub font_height: Option usize>, 323 | pub draw_frame: Option ()>, 324 | pub style: Style, 325 | pub hover: Option, 326 | pub focus: Option, 327 | pub last_id: Option, 328 | pub last_rect: Rect, 329 | pub last_zindex: i32, 330 | pub updated_focus: bool, 331 | pub frame: usize, 332 | pub hover_root: Option, 333 | pub next_hover_root: Option, 334 | pub scroll_target: Option, 335 | pub number_edit_buf: FixedString<127>, 336 | pub number_edit: Option, 337 | pub command_list: FixedVec, 338 | pub root_list: FixedVec, 339 | pub container_stack: FixedVec, 340 | pub clip_stack: FixedVec, 341 | pub id_stack: FixedVec, 342 | pub layout_stack: FixedVec, 343 | pub text_stack: FixedString<65536>, 344 | pub container_pool: Pool<48>, 345 | pub containers: [Container; 48], 346 | pub treenode_pool: Pool<48>, 347 | pub mouse_pos: Vec2i, 348 | pub last_mouse_pos: Vec2i, 349 | pub mouse_delta: Vec2i, 350 | pub scroll_delta: Vec2i, 351 | pub mouse_down: MouseButton, 352 | pub mouse_pressed: MouseButton, 353 | pub key_down: KeyMode, 354 | pub key_pressed: KeyMode, 355 | pub input_text: FixedString<32>, 356 | } 357 | 358 | impl Default for Context { 359 | fn default() -> Self { 360 | Self { 361 | char_width: None, 362 | font_height: None, 363 | draw_frame: None, 364 | style: Style::default(), 365 | hover: None, 366 | focus: None, 367 | last_id: None, 368 | last_rect: Rect::default(), 369 | last_zindex: 0, 370 | updated_focus: false, 371 | frame: 0, 372 | hover_root: None, 373 | next_hover_root: None, 374 | scroll_target: None, 375 | number_edit_buf: FixedString::default(), 376 | number_edit: None, 377 | command_list: FixedVec::default(), 378 | root_list: FixedVec::default(), 379 | container_stack: FixedVec::default(), 380 | clip_stack: FixedVec::default(), 381 | id_stack: FixedVec::default(), 382 | layout_stack: FixedVec::default(), 383 | text_stack: FixedString::default(), 384 | container_pool: Pool::default(), 385 | containers: [Container::default(); 48], 386 | treenode_pool: Pool::default(), 387 | mouse_pos: Vec2i::default(), 388 | last_mouse_pos: Vec2i::default(), 389 | mouse_delta: Vec2i::default(), 390 | scroll_delta: Vec2i::default(), 391 | mouse_down: MouseButton::NONE, 392 | mouse_pressed: MouseButton::NONE, 393 | key_down: KeyMode::NONE, 394 | key_pressed: KeyMode::NONE, 395 | input_text: FixedString::default(), 396 | } 397 | } 398 | } 399 | 400 | #[derive(Default, Copy, Clone)] 401 | pub struct Vec2i { 402 | pub x: i32, 403 | pub y: i32, 404 | } 405 | 406 | #[derive(Default, Copy, Clone)] 407 | struct PoolItem { 408 | pub id: Id, 409 | pub last_update: usize, 410 | } 411 | 412 | #[derive(Default, Copy, Clone, Eq, PartialEq)] 413 | pub struct Id(u32); 414 | 415 | #[derive(Default, Copy, Clone)] 416 | pub struct Container { 417 | pub head_idx: Option, 418 | pub tail_idx: Option, 419 | pub rect: Rect, 420 | pub body: Rect, 421 | pub content_size: Vec2i, 422 | pub scroll: Vec2i, 423 | pub zindex: i32, 424 | pub open: bool, 425 | } 426 | 427 | #[derive(Default, Copy, Clone)] 428 | pub struct Rect { 429 | pub x: i32, 430 | pub y: i32, 431 | pub w: i32, 432 | pub h: i32, 433 | } 434 | 435 | #[derive(Default, Copy, Clone)] 436 | pub struct Layout { 437 | pub body: Rect, 438 | pub next: Rect, 439 | pub position: Vec2i, 440 | pub size: Vec2i, 441 | pub max: Vec2i, 442 | pub widths: [i32; 16], 443 | pub items: usize, 444 | pub item_index: usize, 445 | pub next_row: i32, 446 | pub next_type: LayoutPosition, 447 | pub indent: i32, 448 | } 449 | 450 | #[derive(Copy, Clone)] 451 | pub enum Command { 452 | Jump { 453 | dst_idx: Option, 454 | }, 455 | Clip { 456 | rect: Rect, 457 | }, 458 | Rect { 459 | rect: Rect, 460 | color: Color, 461 | }, 462 | Text { 463 | font: FontId, 464 | pos: Vec2i, 465 | color: Color, 466 | str_start: usize, 467 | str_len: usize, 468 | }, 469 | Icon { 470 | rect: Rect, 471 | id: Icon, 472 | color: Color, 473 | }, 474 | None, 475 | } 476 | 477 | impl Default for Command { 478 | fn default() -> Self { 479 | Command::None 480 | } 481 | } 482 | 483 | #[derive(Default, Copy, Clone)] 484 | #[repr(C)] 485 | pub struct Color { 486 | pub r: u8, 487 | pub g: u8, 488 | pub b: u8, 489 | pub a: u8, 490 | } 491 | 492 | pub trait Font { 493 | fn name(&self) -> &str; 494 | fn get_size(&self) -> usize; 495 | fn get_char_size(&self, c: char) -> (usize, usize); 496 | } 497 | 498 | #[derive(Copy, Clone)] 499 | pub struct FontId(pub usize); 500 | 501 | #[derive(Copy, Clone)] 502 | pub struct Style { 503 | pub font: FontId, 504 | pub size: Vec2i, 505 | pub padding: i32, 506 | pub spacing: i32, 507 | pub indent: i32, 508 | pub title_height: i32, 509 | pub scrollbar_size: i32, 510 | pub thumb_size: i32, 511 | pub colors: [Color; 14], 512 | } 513 | 514 | pub type Real = f32; 515 | 516 | #[derive(PartialEq, Copy, Clone)] 517 | #[repr(u32)] 518 | pub enum LayoutPosition { 519 | Absolute = 2, 520 | Relative = 1, 521 | None = 0, 522 | } 523 | 524 | impl Default for LayoutPosition { 525 | fn default() -> Self { 526 | LayoutPosition::None 527 | } 528 | } 529 | 530 | static UNCLIPPED_RECT: Rect = Rect { x: 0, y: 0, w: 0x1000000, h: 0x1000000 }; 531 | 532 | impl Default for Style { 533 | fn default() -> Self { 534 | Self { 535 | font: FontId(0), 536 | size: Vec2i { x: 68, y: 10 }, 537 | padding: 5, 538 | spacing: 4, 539 | indent: 24, 540 | title_height: 24, 541 | scrollbar_size: 12, 542 | thumb_size: 8, 543 | colors: [ 544 | Color { r: 230, g: 230, b: 230, a: 255 }, 545 | Color { r: 25, g: 25, b: 25, a: 255 }, 546 | Color { r: 50, g: 50, b: 50, a: 255 }, 547 | Color { r: 25, g: 25, b: 25, a: 255 }, 548 | Color { r: 240, g: 240, b: 240, a: 255 }, 549 | Color { r: 0, g: 0, b: 0, a: 0 }, 550 | Color { r: 75, g: 75, b: 75, a: 255 }, 551 | Color { r: 95, g: 95, b: 95, a: 255 }, 552 | Color { r: 115, g: 115, b: 115, a: 255 }, 553 | Color { r: 30, g: 30, b: 30, a: 255 }, 554 | Color { r: 35, g: 35, b: 35, a: 255 }, 555 | Color { r: 40, g: 40, b: 40, a: 255 }, 556 | Color { r: 43, g: 43, b: 43, a: 255 }, 557 | Color { r: 30, g: 30, b: 30, a: 255 }, 558 | ], 559 | } 560 | } 561 | } 562 | 563 | pub fn vec2(x: i32, y: i32) -> Vec2i { 564 | Vec2i { x, y } 565 | } 566 | 567 | pub fn rect(x: i32, y: i32, w: i32, h: i32) -> Rect { 568 | Rect { x, y, w, h } 569 | } 570 | 571 | pub fn color(r: u8, g: u8, b: u8, a: u8) -> Color { 572 | Color { r, g, b, a } 573 | } 574 | 575 | pub fn expand_rect(r: Rect, n: i32) -> Rect { 576 | rect(r.x - n, r.y - n, r.w + n * 2, r.h + n * 2) 577 | } 578 | 579 | pub fn intersect_rects(r1: Rect, r2: Rect) -> Rect { 580 | let x1 = i32::max(r1.x, r2.x); 581 | let y1 = i32::max(r1.y, r2.y); 582 | let mut x2 = i32::min(r1.x + r1.w, r2.x + r2.w); 583 | let mut y2 = i32::min(r1.y + r1.h, r2.y + r2.h); 584 | if x2 < x1 { 585 | x2 = x1; 586 | } 587 | if y2 < y1 { 588 | y2 = y1; 589 | } 590 | return rect(x1, y1, x2 - x1, y2 - y1); 591 | } 592 | 593 | pub fn rect_overlaps_vec2(r: Rect, p: Vec2i) -> bool { 594 | p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h 595 | } 596 | 597 | pub fn draw_frame(ctx: &mut Context, rect: Rect, colorid: ControlColor) { 598 | ctx.draw_rect(rect, ctx.style.colors[colorid as usize]); 599 | if colorid == ControlColor::ScrollBase || colorid == ControlColor::ScrollThumb || colorid == ControlColor::TitleBG { 600 | return; 601 | } 602 | if ctx.style.colors[ControlColor::Border as usize].a != 0 { 603 | ctx.draw_box(expand_rect(rect, 1), ctx.style.colors[ControlColor::Border as usize]); 604 | } 605 | } 606 | 607 | fn hash_step(h: u32, n: u32) -> u32 { 608 | (h ^ n).wrapping_mul(16777619 as u32) 609 | } 610 | 611 | fn hash_u32(hash_0: &mut Id, orig_id: u32) { 612 | let bytes = orig_id.to_be_bytes(); 613 | for b in bytes { 614 | *hash_0 = Id(hash_step(hash_0.0, b as u32)); 615 | } 616 | } 617 | 618 | fn hash_str(hash_0: &mut Id, s: &str) { 619 | for c in s.chars() { 620 | *hash_0 = Id(hash_step(hash_0.0, c as u32)); 621 | } 622 | } 623 | 624 | fn hash_bytes(hash_0: &mut Id, s: &[u8]) { 625 | for c in s { 626 | *hash_0 = Id(hash_step(hash_0.0, *c as u32)); 627 | } 628 | } 629 | 630 | impl Context { 631 | pub fn new() -> Self { 632 | let mut s = Self::default(); 633 | s.draw_frame = Some(draw_frame as fn(&mut Context, Rect, ControlColor) -> ()); 634 | s.style = Style::default(); 635 | s 636 | } 637 | 638 | pub fn begin(&mut self) { 639 | assert!((self.char_width).is_some() && (self.font_height).is_some()); 640 | self.root_list.clear(); 641 | self.text_stack.clear(); 642 | self.scroll_target = None; 643 | self.hover_root = self.next_hover_root; 644 | self.next_hover_root = None; 645 | self.mouse_delta.x = self.mouse_pos.x - self.last_mouse_pos.x; 646 | self.mouse_delta.y = self.mouse_pos.y - self.last_mouse_pos.y; 647 | self.command_list.clear(); 648 | self.frame += 1; 649 | } 650 | 651 | pub fn end(&mut self) { 652 | assert_eq!(self.container_stack.len(), 0); 653 | assert_eq!(self.clip_stack.len(), 0); 654 | assert_eq!(self.id_stack.len(), 0); 655 | assert_eq!(self.layout_stack.len(), 0); 656 | if !self.scroll_target.is_none() { 657 | self.containers[self.scroll_target.unwrap()].scroll.x += self.scroll_delta.x; 658 | self.containers[self.scroll_target.unwrap()].scroll.y += self.scroll_delta.y; 659 | } 660 | if !self.updated_focus { 661 | self.focus = None; 662 | } 663 | self.updated_focus = false; 664 | if !self.mouse_pressed.is_none() 665 | && !self.next_hover_root.is_none() 666 | && self.containers[self.next_hover_root.unwrap()].zindex < self.last_zindex 667 | && self.containers[self.next_hover_root.unwrap()].zindex >= 0 668 | { 669 | self.bring_to_front(self.next_hover_root.unwrap()); 670 | } 671 | self.key_pressed = KeyMode::NONE; 672 | self.input_text.clear(); 673 | self.mouse_pressed = MouseButton::NONE; 674 | self.scroll_delta = vec2(0, 0); 675 | self.last_mouse_pos = self.mouse_pos; 676 | let n = self.root_list.len(); 677 | quick_sort_by(self.root_list.as_slice_mut(), |a, b| { 678 | self.containers[*a].zindex.cmp(&self.containers[*b].zindex) 679 | }); 680 | 681 | for i in 0..n { 682 | if i == 0 { 683 | // root container! 684 | // if this is the first container then make the first command jump to it. 685 | // otherwise set the previous container's tail to jump to this one 686 | 687 | let cmd = &mut self.command_list[0]; 688 | assert!(match cmd { 689 | Command::Jump { .. } => true, 690 | _ => false, 691 | }); 692 | let dst_idx = self.containers[self.root_list[i as usize]].head_idx.unwrap() + 1; 693 | *cmd = Command::Jump { dst_idx: Some(dst_idx) }; 694 | assert!(dst_idx < self.command_list.len()); 695 | } else { 696 | let prev = &self.containers[self.root_list[i - 1]]; 697 | self.command_list[prev.tail_idx.unwrap()] = Command::Jump { 698 | dst_idx: Some(self.containers[self.root_list[i as usize]].head_idx.unwrap() + 1), 699 | }; 700 | } 701 | if i == n - 1 { 702 | assert!(self.containers[self.root_list[i as usize]].tail_idx.unwrap() < self.command_list.len()); 703 | assert!(match self.command_list[self.containers[self.root_list[i as usize]].tail_idx.unwrap()] { 704 | Command::Jump { .. } => true, 705 | _ => false, 706 | }); 707 | self.command_list[self.containers[self.root_list[i as usize]].tail_idx.unwrap()] = Command::Jump { dst_idx: Some(self.command_list.len()) }; 708 | // the snake eats its tail 709 | } 710 | } 711 | } 712 | 713 | pub fn set_focus(&mut self, id: Option) { 714 | self.focus = id; 715 | self.updated_focus = true; 716 | } 717 | 718 | pub fn get_id_u32(&mut self, orig_id: u32) -> Id { 719 | let mut res: Id = match self.id_stack.top() { 720 | Some(id) => *id, 721 | None => Id(2166136261), 722 | }; 723 | hash_u32(&mut res, orig_id); 724 | self.last_id = Some(res); 725 | return res; 726 | } 727 | 728 | pub fn get_id_from_ptr(&mut self, orig_id: &T) -> Id { 729 | let mut res: Id = match self.id_stack.top() { 730 | Some(id) => *id, 731 | None => Id(2166136261), 732 | }; 733 | let ptr = orig_id as *const T as *const u8 as usize; 734 | let bytes = ptr.to_le_bytes(); 735 | hash_bytes(&mut res, &bytes); 736 | self.last_id = Some(res); 737 | return res; 738 | } 739 | 740 | pub fn get_id_from_str(&mut self, s: &str) -> Id { 741 | let mut res: Id = match self.id_stack.top() { 742 | Some(id) => *id, 743 | None => Id(2166136261), 744 | }; 745 | hash_str(&mut res, s); 746 | self.last_id = Some(res); 747 | return res; 748 | } 749 | 750 | pub fn push_id_from_ptr(&mut self, orig_id: &T) { 751 | let id = self.get_id_from_ptr(orig_id); 752 | self.id_stack.push(id); 753 | } 754 | 755 | pub fn push_id_from_str(&mut self, s: &str) { 756 | let id = self.get_id_from_str(s); 757 | self.id_stack.push(id); 758 | } 759 | 760 | pub fn pop_id(&mut self) { 761 | self.id_stack.pop(); 762 | } 763 | 764 | pub fn push_clip_rect(&mut self, rect: Rect) { 765 | let last = self.get_clip_rect(); 766 | self.clip_stack.push(intersect_rects(rect, last)); 767 | } 768 | 769 | pub fn pop_clip_rect(&mut self) { 770 | self.clip_stack.pop(); 771 | } 772 | 773 | pub fn get_clip_rect(&mut self) -> Rect { 774 | *self.clip_stack.top().unwrap() 775 | } 776 | 777 | pub fn check_clip(&mut self, r: Rect) -> Clip { 778 | let cr = self.get_clip_rect(); 779 | if r.x > cr.x + cr.w || r.x + r.w < cr.x || r.y > cr.y + cr.h || r.y + r.h < cr.y { 780 | return Clip::All; 781 | } 782 | if r.x >= cr.x && r.x + r.w <= cr.x + cr.w && r.y >= cr.y && r.y + r.h <= cr.y + cr.h { 783 | return Clip::None; 784 | } 785 | return Clip::Part; 786 | } 787 | 788 | fn push_layout(&mut self, body: Rect, scroll: Vec2i) { 789 | let mut layout: Layout = Layout { 790 | body: Rect { x: 0, y: 0, w: 0, h: 0 }, 791 | next: Rect { x: 0, y: 0, w: 0, h: 0 }, 792 | position: Vec2i { x: 0, y: 0 }, 793 | size: Vec2i { x: 0, y: 0 }, 794 | max: Vec2i { x: 0, y: 0 }, 795 | widths: [0; 16], 796 | items: 0, 797 | item_index: 0, 798 | next_row: 0, 799 | next_type: LayoutPosition::None, 800 | indent: 0, 801 | }; 802 | layout.body = rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h); 803 | layout.max = vec2(-0x1000000, -0x1000000); 804 | self.layout_stack.push(layout); 805 | self.layout_row(&[0], 0); 806 | } 807 | 808 | fn get_layout(&self) -> &Layout { 809 | return self.layout_stack.top().unwrap(); 810 | } 811 | 812 | fn get_layout_mut(&mut self) -> &mut Layout { 813 | return self.layout_stack.top_mut().unwrap(); 814 | } 815 | 816 | fn pop_container(&mut self) { 817 | let cnt = self.get_current_container(); 818 | let layout = *self.get_layout(); 819 | self.containers[cnt].content_size.x = layout.max.x - layout.body.x; 820 | self.containers[cnt].content_size.y = layout.max.y - layout.body.y; 821 | 822 | self.container_stack.pop(); 823 | self.layout_stack.pop(); 824 | self.pop_id(); 825 | } 826 | 827 | pub fn get_current_container(&self) -> usize { 828 | *self.container_stack.top().unwrap() 829 | } 830 | 831 | pub fn get_current_container_rect(&self) -> Rect { 832 | self.containers[*self.container_stack.top().unwrap()].rect 833 | } 834 | 835 | pub fn set_current_container_rect(&mut self, rect: &Rect) { 836 | self.containers[*self.container_stack.top().unwrap()].rect = *rect; 837 | } 838 | 839 | pub fn get_current_container_scroll(&self) -> Vec2i { 840 | self.containers[*self.container_stack.top().unwrap()].scroll 841 | } 842 | 843 | pub fn set_current_container_scroll(&mut self, scroll: &Vec2i) { 844 | self.containers[*self.container_stack.top().unwrap()].scroll = *scroll; 845 | } 846 | 847 | pub fn get_current_container_content_size(&self) -> Vec2i { 848 | self.containers[*self.container_stack.top().unwrap()].content_size 849 | } 850 | 851 | pub fn get_current_container_body(&self) -> Rect { 852 | self.containers[*self.container_stack.top().unwrap()].body 853 | } 854 | 855 | fn get_container_index_intern(&mut self, id: Id, opt: WidgetOption) -> Option { 856 | let idx = self.container_pool.get(id); 857 | if idx.is_some() { 858 | if self.containers[idx.unwrap()].open || !opt.is_closed() { 859 | self.container_pool.update(idx.unwrap(), self.frame); 860 | } 861 | return idx; 862 | } 863 | if opt.is_closed() { 864 | return None; 865 | } 866 | let idx = self.container_pool.alloc(id, self.frame); 867 | self.containers[idx] = Container::default(); 868 | self.containers[idx].head_idx = None; 869 | self.containers[idx].tail_idx = None; 870 | self.containers[idx].open = true; 871 | self.bring_to_front(idx); 872 | Some(idx) 873 | } 874 | 875 | fn get_container_index(&mut self, name: &str) -> Option { 876 | let id = self.get_id_from_str(name); 877 | self.get_container_index_intern(id, WidgetOption::NONE) 878 | } 879 | 880 | pub fn bring_to_front(&mut self, cnt: usize) { 881 | self.last_zindex += 1; 882 | self.containers[cnt].zindex = self.last_zindex; 883 | } 884 | 885 | pub fn input_mousemove(&mut self, x: i32, y: i32) { 886 | self.mouse_pos = vec2(x, y); 887 | } 888 | 889 | pub fn input_mousedown(&mut self, x: i32, y: i32, btn: MouseButton) { 890 | self.input_mousemove(x, y); 891 | self.mouse_down |= btn; 892 | self.mouse_pressed |= btn; 893 | } 894 | 895 | pub fn input_mouseup(&mut self, x: i32, y: i32, btn: MouseButton) { 896 | self.input_mousemove(x, y); 897 | self.mouse_down &= !btn; 898 | } 899 | 900 | pub fn input_scroll(&mut self, x: i32, y: i32) { 901 | self.scroll_delta.x += x; 902 | self.scroll_delta.y += y; 903 | } 904 | 905 | pub fn input_keydown(&mut self, key: KeyMode) { 906 | self.key_pressed |= key; 907 | self.key_down |= key; 908 | } 909 | 910 | pub fn input_keyup(&mut self, key: KeyMode) { 911 | self.key_down &= !key; 912 | } 913 | 914 | pub fn input_text(&mut self, text: &str) { 915 | self.input_text += text; 916 | } 917 | 918 | pub fn push_command(&mut self, cmd: Command) -> (&mut Command, usize) { 919 | self.command_list.push(cmd) 920 | } 921 | 922 | pub fn push_text(&mut self, str: &str) -> usize { 923 | let str_start = self.text_stack.len(); 924 | for c in str.chars() { 925 | self.text_stack.push(c); 926 | } 927 | return str_start; 928 | } 929 | 930 | /// 931 | /// returns the next command to execute and the next index to use 932 | /// 933 | pub fn mu_next_command(&mut self, mut cmd_id: usize) -> Option<(Command, usize)> { 934 | if cmd_id >= self.command_list.len() { 935 | cmd_id = 0 936 | } 937 | 938 | while cmd_id != self.command_list.len() { 939 | match self.command_list[cmd_id] { 940 | Command::Jump { dst_idx } => cmd_id = dst_idx.unwrap(), 941 | _ => return Some((self.command_list[cmd_id], cmd_id + 1)), 942 | } 943 | } 944 | None 945 | } 946 | 947 | fn push_jump(&mut self, dst_idx: Option) -> usize { 948 | let (_, pos) = self.push_command(Command::Jump { dst_idx }); 949 | pos 950 | } 951 | 952 | pub fn set_clip(&mut self, rect: Rect) { 953 | self.push_command(Command::Clip { rect }); 954 | } 955 | 956 | pub fn draw_rect(&mut self, mut rect: Rect, color: Color) { 957 | rect = intersect_rects(rect, self.get_clip_rect()); 958 | if rect.w > 0 && rect.h > 0 { 959 | self.push_command(Command::Rect { rect, color }); 960 | } 961 | } 962 | 963 | pub fn draw_box(&mut self, r: Rect, color: Color) { 964 | self.draw_rect(rect(r.x + 1, r.y, r.w - 2, 1), color); 965 | self.draw_rect(rect(r.x + 1, r.y + r.h - 1, r.w - 2, 1), color); 966 | self.draw_rect(rect(r.x, r.y, 1, r.h), color); 967 | self.draw_rect(rect(r.x + r.w - 1, r.y, 1, r.h), color); 968 | } 969 | 970 | pub fn draw_text(&mut self, font: FontId, str: &str, pos: Vec2i, color: Color) { 971 | let rect: Rect = rect(pos.x, pos.y, self.get_text_width(font, str), self.get_text_height(font, str)); 972 | let clipped = self.check_clip(rect); 973 | match clipped { 974 | Clip::All => return, 975 | Clip::Part => { 976 | let clip = self.get_clip_rect(); 977 | self.set_clip(clip) 978 | } 979 | _ => (), 980 | } 981 | 982 | let str_start = self.push_text(str); 983 | self.push_command(Command::Text { 984 | str_start, 985 | str_len: str.len(), 986 | pos, 987 | color, 988 | font, 989 | }); 990 | if clipped != Clip::None { 991 | self.set_clip(UNCLIPPED_RECT); 992 | } 993 | } 994 | 995 | pub fn draw_icon(&mut self, id: Icon, rect: Rect, color: Color) { 996 | let clipped = self.check_clip(rect); 997 | match clipped { 998 | Clip::All => return, 999 | Clip::Part => { 1000 | let clip = self.get_clip_rect(); 1001 | self.set_clip(clip) 1002 | } 1003 | _ => (), 1004 | } 1005 | self.push_command(Command::Icon { id, rect, color }); 1006 | if clipped != Clip::None { 1007 | self.set_clip(UNCLIPPED_RECT); 1008 | } 1009 | } 1010 | 1011 | pub fn layout_begin_column(&mut self) { 1012 | let layout = self.layout_next(); 1013 | self.push_layout(layout, vec2(0, 0)); 1014 | } 1015 | 1016 | pub fn layout_end_column(&mut self) { 1017 | let b = self.get_layout().clone(); 1018 | self.layout_stack.pop(); 1019 | 1020 | let a = self.get_layout_mut(); 1021 | a.position.x = if a.position.x > b.position.x + b.body.x - a.body.x { 1022 | a.position.x 1023 | } else { 1024 | b.position.x + b.body.x - a.body.x 1025 | }; 1026 | a.next_row = if a.next_row > b.next_row + b.body.y - a.body.y { 1027 | a.next_row 1028 | } else { 1029 | b.next_row + b.body.y - a.body.y 1030 | }; 1031 | a.max.x = i32::max(a.max.x, b.max.x); 1032 | a.max.y = i32::max(a.max.y, b.max.y); 1033 | } 1034 | 1035 | pub fn layout_row_for_layout(layout: &mut Layout, widths: &[i32], height: i32) { 1036 | layout.items = widths.len(); 1037 | assert!(widths.len() <= 16); 1038 | for i in 0..widths.len() { 1039 | layout.widths[i] = widths[i]; 1040 | } 1041 | layout.position = vec2(layout.indent, layout.next_row); 1042 | layout.size.y = height; 1043 | layout.item_index = 0; 1044 | } 1045 | 1046 | pub fn layout_row(&mut self, widths: &[i32], height: i32) { 1047 | let layout = self.get_layout_mut(); 1048 | Self::layout_row_for_layout(layout, widths, height); 1049 | } 1050 | 1051 | pub fn layout_width(&mut self, width: i32) { 1052 | self.get_layout_mut().size.x = width; 1053 | } 1054 | 1055 | pub fn layout_height(&mut self, height: i32) { 1056 | self.get_layout_mut().size.y = height; 1057 | } 1058 | 1059 | pub fn layout_set_next(&mut self, r: Rect, position: LayoutPosition) { 1060 | let layout = self.get_layout_mut(); 1061 | layout.next = r; 1062 | layout.next_type = position; 1063 | } 1064 | 1065 | pub fn layout_next(&mut self) -> Rect { 1066 | let style = self.style; 1067 | let layout = self.get_layout_mut(); 1068 | let mut res: Rect = Rect { x: 0, y: 0, w: 0, h: 0 }; 1069 | if layout.next_type != LayoutPosition::None { 1070 | let type_0 = layout.next_type; 1071 | layout.next_type = LayoutPosition::None; 1072 | res = layout.next; 1073 | if type_0 == LayoutPosition::Absolute { 1074 | self.last_rect = res; 1075 | return self.last_rect; 1076 | } 1077 | } else { 1078 | let litems = layout.items; 1079 | let lsize_y = layout.size.y; 1080 | let mut undefined_widths = [0; 16]; 1081 | undefined_widths[0..litems as usize].copy_from_slice(&layout.widths[0..litems as usize]); 1082 | if layout.item_index == layout.items { 1083 | Self::layout_row_for_layout(layout, &undefined_widths[0..litems as usize], lsize_y); 1084 | } 1085 | res.x = layout.position.x; 1086 | res.y = layout.position.y; 1087 | res.w = if layout.items > 0 { 1088 | layout.widths[layout.item_index as usize] 1089 | } else { 1090 | layout.size.x 1091 | }; 1092 | res.h = layout.size.y; 1093 | if res.w == 0 { 1094 | res.w = style.size.x + style.padding * 2; 1095 | } 1096 | if res.h == 0 { 1097 | res.h = style.size.y + style.padding * 2; 1098 | } 1099 | if res.w < 0 { 1100 | res.w += layout.body.w - res.x + 1; 1101 | } 1102 | if res.h < 0 { 1103 | res.h += layout.body.h - res.y + 1; 1104 | } 1105 | layout.item_index += 1; 1106 | } 1107 | layout.position.x += res.w + style.spacing; 1108 | layout.next_row = if layout.next_row > res.y + res.h + style.spacing { 1109 | layout.next_row 1110 | } else { 1111 | res.y + res.h + style.spacing 1112 | }; 1113 | res.x += layout.body.x; 1114 | res.y += layout.body.y; 1115 | layout.max.x = if layout.max.x > res.x + res.w { layout.max.x } else { res.x + res.w }; 1116 | layout.max.y = if layout.max.y > res.y + res.h { layout.max.y } else { res.y + res.h }; 1117 | self.last_rect = res; 1118 | return self.last_rect; 1119 | } 1120 | 1121 | fn in_hover_root(&mut self) -> bool { 1122 | match self.hover_root { 1123 | Some(hover_root) => { 1124 | let len = self.container_stack.len(); 1125 | for i in 0..len { 1126 | if self.container_stack[len - i - 1] == hover_root { 1127 | return true; 1128 | } 1129 | if self.containers[self.container_stack[len - i - 1]].head_idx.is_some() { 1130 | break; 1131 | } 1132 | } 1133 | false 1134 | } 1135 | None => false, 1136 | } 1137 | } 1138 | 1139 | pub fn draw_control_frame(&mut self, id: Id, rect: Rect, mut colorid: ControlColor, opt: WidgetOption) { 1140 | if opt.has_no_frame() { 1141 | return; 1142 | } 1143 | 1144 | if self.focus == Some(id) { 1145 | colorid.focus() 1146 | } else if self.hover == Some(id) { 1147 | colorid.hover() 1148 | } 1149 | (self.draw_frame).expect("non-null function pointer")(self, rect, colorid); 1150 | } 1151 | 1152 | pub fn draw_control_text(&mut self, str: &str, rect: Rect, colorid: ControlColor, opt: WidgetOption) { 1153 | let mut pos: Vec2i = Vec2i { x: 0, y: 0 }; 1154 | let font = self.style.font; 1155 | let tw = self.get_text_width(font, str); 1156 | self.push_clip_rect(rect); 1157 | pos.y = rect.y + (rect.h - self.get_text_height(font, str)) / 2; 1158 | if opt.is_aligned_center() { 1159 | pos.x = rect.x + (rect.w - tw) / 2; 1160 | } else if opt.is_aligned_right() { 1161 | pos.x = rect.x + rect.w - tw - self.style.padding; 1162 | } else { 1163 | pos.x = rect.x + self.style.padding; 1164 | } 1165 | self.draw_text(font, str, pos, self.style.colors[colorid as usize]); 1166 | self.pop_clip_rect(); 1167 | } 1168 | 1169 | pub fn mouse_over(&mut self, rect: Rect) -> bool { 1170 | rect_overlaps_vec2(rect, self.mouse_pos) && rect_overlaps_vec2(self.get_clip_rect(), self.mouse_pos) && self.in_hover_root() 1171 | } 1172 | 1173 | pub fn update_control(&mut self, id: Id, rect: Rect, opt: WidgetOption) { 1174 | let mouseover = self.mouse_over(rect); 1175 | if self.focus == Some(id) { 1176 | self.updated_focus = true; 1177 | } 1178 | if opt.is_not_interactive() { 1179 | return; 1180 | } 1181 | if mouseover && self.mouse_down.is_none() { 1182 | self.hover = Some(id); 1183 | } 1184 | if self.focus == Some(id) { 1185 | if !self.mouse_pressed.is_none() && !mouseover { 1186 | self.set_focus(None); 1187 | } 1188 | if self.mouse_down.is_none() && !opt.is_holding_focus() { 1189 | self.set_focus(None); 1190 | } 1191 | } 1192 | if self.hover == Some(id) { 1193 | if !self.mouse_pressed.is_none() { 1194 | self.set_focus(Some(id)); 1195 | } else if !mouseover { 1196 | self.hover = None; 1197 | } 1198 | } 1199 | } 1200 | 1201 | pub fn get_text_width(&self, font: FontId, text: &str) -> i32 { 1202 | let mut res = 0; 1203 | let mut acc = 0; 1204 | for c in text.chars() { 1205 | if c == '\n' { 1206 | res = usize::max(res, acc); 1207 | acc = 0; 1208 | } 1209 | acc += self.char_width.expect("non-null function pointer")(font, c); 1210 | } 1211 | res = usize::max(res, acc); 1212 | res as i32 1213 | } 1214 | 1215 | pub fn get_text_height(&self, font: FontId, text: &str) -> i32 { 1216 | let font_height = self.font_height.expect("non-null function pointer")(font); 1217 | let lc = text.lines().count(); 1218 | (lc * font_height) as i32 1219 | } 1220 | 1221 | pub fn text(&mut self, text: &str) { 1222 | let font = self.style.font; 1223 | let color = self.style.colors[ControlColor::Text as usize]; 1224 | self.layout_begin_column(); 1225 | let h = self.font_height.expect("non-null function pointer")(font) as i32; 1226 | self.layout_row(&[-1], h); 1227 | for line in text.lines() { 1228 | let mut r = self.layout_next(); 1229 | let mut rx = r.x; 1230 | let words = line.split_inclusive(' '); 1231 | for w in words { 1232 | // TODO: split w when its width > w into many lines 1233 | let tw = self.get_text_width(font, w); 1234 | if tw + rx < r.x + r.w { 1235 | self.draw_text(font, w, vec2(rx, r.y), color); 1236 | rx += tw; 1237 | } else { 1238 | r = self.layout_next(); 1239 | rx = r.x; 1240 | } 1241 | } 1242 | } 1243 | self.layout_end_column(); 1244 | } 1245 | 1246 | pub fn label(&mut self, text: &str) { 1247 | let layout = self.layout_next(); 1248 | self.draw_control_text(text, layout, ControlColor::Text, WidgetOption::NONE); 1249 | } 1250 | 1251 | pub fn button_ex(&mut self, label: &str, icon: Icon, opt: WidgetOption) -> ResourceState { 1252 | let mut res = ResourceState::NONE; 1253 | let id: Id = if label.len() > 0 { 1254 | self.get_id_from_str(label) 1255 | } else { 1256 | self.get_id_u32(icon as u32) 1257 | }; 1258 | let r: Rect = self.layout_next(); 1259 | self.update_control(id, r, opt); 1260 | if self.mouse_pressed.is_left() && self.focus == Some(id) { 1261 | res |= ResourceState::SUBMIT; 1262 | } 1263 | self.draw_control_frame(id, r, ControlColor::Button, opt); 1264 | if label.len() > 0 { 1265 | self.draw_control_text(label, r, ControlColor::Text, opt); 1266 | } 1267 | if icon != Icon::None { 1268 | self.draw_icon(icon, r, self.style.colors[ControlColor::Text as usize]); 1269 | } 1270 | return res; 1271 | } 1272 | 1273 | pub fn checkbox(&mut self, label: &str, state: &mut bool) -> ResourceState { 1274 | let mut res = ResourceState::NONE; 1275 | let id: Id = self.get_id_from_ptr(state); 1276 | let mut r: Rect = self.layout_next(); 1277 | let box_0: Rect = rect(r.x, r.y, r.h, r.h); 1278 | self.update_control(id, r, WidgetOption::NONE); 1279 | if self.mouse_pressed.is_left() && self.focus == Some(id) { 1280 | res |= ResourceState::CHANGE; 1281 | *state = *state == false; 1282 | } 1283 | self.draw_control_frame(id, box_0, ControlColor::Base, WidgetOption::NONE); 1284 | if *state { 1285 | self.draw_icon(Icon::Check, box_0, self.style.colors[ControlColor::Text as usize]); 1286 | } 1287 | r = rect(r.x + box_0.w, r.y, r.w - box_0.w, r.h); 1288 | self.draw_control_text(label, r, ControlColor::Text, WidgetOption::NONE); 1289 | return res; 1290 | } 1291 | 1292 | pub fn textbox_raw(&mut self, buf: &mut dyn IString, id: Id, r: Rect, opt: WidgetOption) -> ResourceState { 1293 | let mut res = ResourceState::NONE; 1294 | self.update_control(id, r, opt | WidgetOption::HOLD_FOCUS); 1295 | if self.focus == Some(id) { 1296 | let mut len = buf.len(); 1297 | 1298 | if self.input_text.len() > 0 && self.input_text.len() + len < buf.capacity() { 1299 | buf.add_str(self.input_text.as_str()); 1300 | len += self.input_text.len() as usize; 1301 | res |= ResourceState::CHANGE 1302 | } 1303 | 1304 | if self.key_pressed.is_backspace() && len > 0 { 1305 | // skip utf-8 continuation bytes 1306 | buf.pop(); 1307 | res |= ResourceState::CHANGE 1308 | } 1309 | if self.key_pressed.is_return() { 1310 | self.set_focus(None); 1311 | res |= ResourceState::SUBMIT; 1312 | } 1313 | } 1314 | self.draw_control_frame(id, r, ControlColor::Base, opt); 1315 | if self.focus == Some(id) { 1316 | let color = self.style.colors[ControlColor::Text as usize]; 1317 | let font = self.style.font; 1318 | let textw = self.get_text_width(font, buf.as_str()); 1319 | let texth = self.get_text_height(font, buf.as_str()); 1320 | let ofx = r.w - self.style.padding - textw - 1; 1321 | let textx = r.x + (if ofx < self.style.padding { ofx } else { self.style.padding }); 1322 | let texty = r.y + (r.h - texth) / 2; 1323 | self.push_clip_rect(r); 1324 | self.draw_text(font, buf.as_str(), vec2(textx, texty), color); 1325 | self.draw_rect(rect(textx + textw, texty, 1, texth), color); 1326 | self.pop_clip_rect(); 1327 | } else { 1328 | self.draw_control_text(buf.as_str(), r, ControlColor::Text, opt); 1329 | } 1330 | return res; 1331 | } 1332 | 1333 | fn number_textbox(&mut self, precision: usize, value: &mut Real, r: Rect, id: Id) -> ResourceState { 1334 | if self.mouse_pressed.is_left() && self.key_down.is_shift() && self.hover == Some(id) { 1335 | self.number_edit = Some(id); 1336 | self.number_edit_buf.clear(); 1337 | self.number_edit_buf.append_real(precision, *value as f64); 1338 | } 1339 | 1340 | if self.number_edit == Some(id) { 1341 | let mut temp = self.number_edit_buf.clone(); 1342 | let res: ResourceState = self.textbox_raw(&mut temp, id, r, WidgetOption::NONE); 1343 | self.number_edit_buf = temp; 1344 | if res.is_submitted() || self.focus != Some(id) { 1345 | match parse_decimal(self.number_edit_buf.as_str()) { 1346 | Ok(v) => { 1347 | *value = v as Real; 1348 | self.number_edit = None; 1349 | } 1350 | _ => (), 1351 | } 1352 | self.number_edit = None; 1353 | } else { 1354 | return ResourceState::ACTIVE; 1355 | } 1356 | } 1357 | return ResourceState::NONE; 1358 | } 1359 | 1360 | pub fn textbox_ex(&mut self, buf: &mut dyn IString, opt: WidgetOption) -> ResourceState { 1361 | let id: Id = self.get_id_from_ptr(buf); 1362 | let r: Rect = self.layout_next(); 1363 | return self.textbox_raw(buf, id, r, opt); 1364 | } 1365 | 1366 | pub fn slider_ex(&mut self, value: &mut Real, low: Real, high: Real, step: Real, precision: usize, opt: WidgetOption) -> ResourceState { 1367 | let mut res = ResourceState::NONE; 1368 | let last = *value; 1369 | let mut v = last; 1370 | let id = self.get_id_from_ptr(value); 1371 | let base = self.layout_next(); 1372 | if !self.number_textbox(precision, &mut v, base, id).is_none() { 1373 | return res; 1374 | } 1375 | self.update_control(id, base, opt); 1376 | if self.focus == Some(id) && (!self.mouse_down.is_none() | self.mouse_pressed.is_left()) { 1377 | v = low + (self.mouse_pos.x - base.x) as Real * (high - low) / base.w as Real; 1378 | if step != 0. { 1379 | v = (v + step / 2 as Real) / step * step; 1380 | } 1381 | } 1382 | v = if high < (if low > v { low } else { v }) { 1383 | high 1384 | } else if low > v { 1385 | low 1386 | } else { 1387 | v 1388 | }; 1389 | *value = v; 1390 | if last != v { 1391 | res |= ResourceState::CHANGE; 1392 | } 1393 | self.draw_control_frame(id, base, ControlColor::Base, opt); 1394 | let w = self.style.thumb_size; 1395 | let x = ((v - low) * (base.w - w) as Real / (high - low)) as i32; 1396 | let thumb = rect(base.x + x, base.y, w, base.h); 1397 | self.draw_control_frame(id, thumb, ControlColor::Button, opt); 1398 | let mut buff = FixedString::<64>::new(); 1399 | buff.append_real(precision, *value as f64); 1400 | self.draw_control_text(buff.as_str(), base, ControlColor::Text, opt); 1401 | return res; 1402 | } 1403 | 1404 | pub fn number_ex(&mut self, value: &mut Real, step: Real, precision: usize, opt: WidgetOption) -> ResourceState { 1405 | let mut res = ResourceState::NONE; 1406 | let id: Id = self.get_id_from_ptr(value); 1407 | let base: Rect = self.layout_next(); 1408 | let last: Real = *value; 1409 | if !self.number_textbox(precision, value, base, id).is_none() { 1410 | return res; 1411 | } 1412 | self.update_control(id, base, opt); 1413 | if self.focus == Some(id) && self.mouse_down.is_left() { 1414 | *value += self.mouse_delta.x as Real * step; 1415 | } 1416 | if *value != last { 1417 | res |= ResourceState::CHANGE; 1418 | } 1419 | self.draw_control_frame(id, base, ControlColor::Base, opt); 1420 | let mut buff = FixedString::<64>::new(); 1421 | buff.append_real(precision, *value as f64); 1422 | self.draw_control_text(buff.as_str(), base, ControlColor::Text, opt); 1423 | return res; 1424 | } 1425 | 1426 | fn header(&mut self, label: &str, is_treenode: bool, opt: WidgetOption) -> ResourceState { 1427 | let id: Id = self.get_id_from_str(label); 1428 | let idx = self.treenode_pool.get(id); 1429 | self.layout_row(&[-1], 0); 1430 | let mut active = idx.is_some() as i32; 1431 | let expanded = if opt.is_expanded() { (active == 0) as i32 } else { active }; 1432 | let mut r = self.layout_next(); 1433 | self.update_control(id, r, WidgetOption::NONE); 1434 | active ^= (self.mouse_pressed.is_left() && self.focus == Some(id)) as i32; 1435 | if idx.is_some() { 1436 | if active != 0 { 1437 | self.treenode_pool.update(idx.unwrap(), self.frame); 1438 | } else { 1439 | self.treenode_pool.reset(idx.unwrap()); 1440 | } 1441 | } else if active != 0 { 1442 | self.treenode_pool.alloc(id, self.frame); 1443 | } 1444 | 1445 | if is_treenode { 1446 | if self.hover == Some(id) { 1447 | (self.draw_frame).expect("non-null function pointer")(self, r, ControlColor::ButtonHover); 1448 | } 1449 | } else { 1450 | self.draw_control_frame(id, r, ControlColor::Button, WidgetOption::NONE); 1451 | } 1452 | self.draw_icon( 1453 | if expanded != 0 { Icon::Expanded } else { Icon::Collapsed }, 1454 | rect(r.x, r.y, r.h, r.h), 1455 | self.style.colors[ControlColor::Text as usize], 1456 | ); 1457 | r.x += r.h - self.style.padding; 1458 | r.w -= r.h - self.style.padding; 1459 | self.draw_control_text(label, r, ControlColor::Text, WidgetOption::NONE); 1460 | return if expanded != 0 { ResourceState::ACTIVE } else { ResourceState::NONE }; 1461 | } 1462 | 1463 | pub fn header_ex(&mut self, label: &str, opt: WidgetOption) -> ResourceState { 1464 | return self.header(label, false, opt); 1465 | } 1466 | 1467 | pub fn begin_treenode_ex(&mut self, label: &str, opt: WidgetOption) -> ResourceState { 1468 | let res = self.header(label, true, opt); 1469 | if res.is_active() && self.last_id.is_some() { 1470 | self.get_layout_mut().indent += self.style.indent; 1471 | self.id_stack.push(self.last_id.unwrap()); 1472 | } 1473 | return res; 1474 | } 1475 | 1476 | pub fn end_treenode(&mut self) { 1477 | self.get_layout_mut().indent -= self.style.indent; 1478 | self.pop_id(); 1479 | } 1480 | 1481 | fn clamp(x: i32, a: i32, b: i32) -> i32 { 1482 | i32::min(b, i32::max(a, x)) 1483 | } 1484 | 1485 | fn scrollbars(&mut self, cnt_id: usize, body: &mut Rect) { 1486 | let sz = self.style.scrollbar_size; 1487 | let mut cs: Vec2i = self.containers[cnt_id].content_size; 1488 | cs.x += self.style.padding * 2; 1489 | cs.y += self.style.padding * 2; 1490 | self.push_clip_rect(body.clone()); 1491 | if cs.y > self.containers[cnt_id].body.h { 1492 | body.w -= sz; 1493 | } 1494 | if cs.x > self.containers[cnt_id].body.w { 1495 | body.h -= sz; 1496 | } 1497 | let body = *body; 1498 | let maxscroll = cs.y - body.h; 1499 | if maxscroll > 0 && body.h > 0 { 1500 | let id: Id = self.get_id_from_str("!scrollbary"); 1501 | let mut base = body; 1502 | base.x = body.x + body.w; 1503 | base.w = self.style.scrollbar_size; 1504 | self.update_control(id, base, WidgetOption::NONE); 1505 | if self.focus == Some(id) && self.mouse_down.is_left() { 1506 | self.containers[cnt_id].scroll.y += self.mouse_delta.y * cs.y / base.h; 1507 | } 1508 | self.containers[cnt_id].scroll.y = Self::clamp(self.containers[cnt_id].scroll.y, 0, maxscroll); 1509 | 1510 | (self.draw_frame).expect("non-null function pointer")(self, base, ControlColor::ScrollBase); 1511 | let mut thumb = base; 1512 | thumb.h = if self.style.thumb_size > base.h * body.h / cs.y { 1513 | self.style.thumb_size 1514 | } else { 1515 | base.h * body.h / cs.y 1516 | }; 1517 | thumb.y += self.containers[cnt_id].scroll.y * (base.h - thumb.h) / maxscroll; 1518 | (self.draw_frame).expect("non-null function pointer")(self, thumb, ControlColor::ScrollThumb); 1519 | if self.mouse_over(body) { 1520 | self.scroll_target = Some(cnt_id); 1521 | } 1522 | } else { 1523 | self.containers[cnt_id].scroll.y = 0; 1524 | } 1525 | let maxscroll_0 = cs.x - body.w; 1526 | if maxscroll_0 > 0 && body.w > 0 { 1527 | let id_0: Id = self.get_id_from_str("!scrollbarx"); 1528 | let mut base_0 = body; 1529 | base_0.y = body.y + body.h; 1530 | base_0.h = self.style.scrollbar_size; 1531 | self.update_control(id_0, base_0, WidgetOption::NONE); 1532 | if self.focus == Some(id_0) && self.mouse_down.is_left() { 1533 | self.containers[cnt_id].scroll.x += self.mouse_delta.x * cs.x / base_0.w; 1534 | } 1535 | self.containers[cnt_id].scroll.x = Self::clamp(self.containers[cnt_id].scroll.x, 0, maxscroll_0); 1536 | 1537 | (self.draw_frame).expect("non-null function pointer")(self, base_0, ControlColor::ScrollBase); 1538 | let mut thumb_0 = base_0; 1539 | thumb_0.w = if self.style.thumb_size > base_0.w * body.w / cs.x { 1540 | self.style.thumb_size 1541 | } else { 1542 | base_0.w * body.w / cs.x 1543 | }; 1544 | thumb_0.x += self.containers[cnt_id].scroll.x * (base_0.w - thumb_0.w) / maxscroll_0; 1545 | (self.draw_frame).expect("non-null function pointer")(self, thumb_0, ControlColor::ScrollThumb); 1546 | if self.mouse_over(body) { 1547 | self.scroll_target = Some(cnt_id); 1548 | } 1549 | } else { 1550 | self.containers[cnt_id].scroll.x = 0; 1551 | } 1552 | self.pop_clip_rect(); 1553 | } 1554 | 1555 | fn push_container_body(&mut self, cnt_idx: usize, body: Rect, opt: WidgetOption) { 1556 | let mut body = body; 1557 | if !opt.has_no_scroll() { 1558 | self.scrollbars(cnt_idx, &mut body); 1559 | } 1560 | self.push_layout(expand_rect(body, -self.style.padding), self.containers[cnt_idx].scroll); 1561 | self.containers[cnt_idx].body = body; 1562 | } 1563 | 1564 | fn begin_root_container(&mut self, cnt: usize) { 1565 | self.container_stack.push(cnt); 1566 | 1567 | self.root_list.push(cnt); 1568 | self.containers[cnt].head_idx = Some(self.push_jump(None)); 1569 | if rect_overlaps_vec2(self.containers[cnt].rect, self.mouse_pos) 1570 | && (self.next_hover_root.is_none() || self.containers[cnt].zindex > self.containers[self.next_hover_root.unwrap()].zindex) 1571 | { 1572 | self.next_hover_root = Some(cnt); 1573 | } 1574 | self.clip_stack.push(UNCLIPPED_RECT); 1575 | } 1576 | 1577 | fn end_root_container(&mut self) { 1578 | let cnt = self.get_current_container(); 1579 | self.containers[cnt].tail_idx = Some(self.push_jump(None)); 1580 | self.command_list[self.containers[cnt].head_idx.unwrap()] = Command::Jump { dst_idx: Some(self.command_list.len()) }; 1581 | self.pop_clip_rect(); 1582 | self.pop_container(); 1583 | } 1584 | 1585 | pub fn begin_window_ex(&mut self, title: &str, mut r: Rect, opt: WidgetOption) -> ResourceState { 1586 | let id = self.get_id_from_str(title); 1587 | let cnt_id = self.get_container_index_intern(id, opt); 1588 | if cnt_id.is_none() || !self.containers[cnt_id.unwrap()].open { 1589 | return ResourceState::NONE; 1590 | } 1591 | self.id_stack.push(id); 1592 | 1593 | if self.containers[cnt_id.unwrap()].rect.w == 0 { 1594 | self.containers[cnt_id.unwrap()].rect = r; 1595 | } 1596 | self.begin_root_container(cnt_id.unwrap()); 1597 | let mut body = self.containers[cnt_id.unwrap()].rect; 1598 | r = body; 1599 | if !opt.has_no_frame() { 1600 | (self.draw_frame).expect("non-null function pointer")(self, r, ControlColor::WindowBG); 1601 | } 1602 | if !opt.has_no_title() { 1603 | let mut tr: Rect = r; 1604 | tr.h = self.style.title_height; 1605 | (self.draw_frame).expect("non-null function pointer")(self, tr, ControlColor::TitleBG); 1606 | 1607 | // TODO: Is this necessary? 1608 | if !opt.has_no_title() { 1609 | let id = self.get_id_from_str("!title"); 1610 | self.update_control(id, tr, opt); 1611 | self.draw_control_text(title, tr, ControlColor::TitleText, opt); 1612 | if Some(id) == self.focus && self.mouse_down.is_left() { 1613 | self.containers[cnt_id.unwrap()].rect.x += self.mouse_delta.x; 1614 | self.containers[cnt_id.unwrap()].rect.y += self.mouse_delta.y; 1615 | } 1616 | body.y += tr.h; 1617 | body.h -= tr.h; 1618 | } 1619 | if !opt.has_no_close() { 1620 | let id = self.get_id_from_str("!close"); 1621 | let r: Rect = rect(tr.x + tr.w - tr.h, tr.y, tr.h, tr.h); 1622 | tr.w -= r.w; 1623 | self.draw_icon(Icon::Close, r, self.style.colors[ControlColor::TitleText as usize]); 1624 | self.update_control(id, r, opt); 1625 | if self.mouse_pressed.is_left() && Some(id) == self.focus { 1626 | self.containers[cnt_id.unwrap()].open = false; 1627 | } 1628 | } 1629 | } 1630 | self.push_container_body(cnt_id.unwrap(), body, opt); 1631 | if !opt.is_auto_sizing() { 1632 | let sz = self.style.title_height; 1633 | let id_2 = self.get_id_from_str("!resize"); 1634 | let r_0 = rect(r.x + r.w - sz, r.y + r.h - sz, sz, sz); 1635 | self.update_control(id_2, r_0, opt); 1636 | if Some(id_2) == self.focus && self.mouse_down.is_left() { 1637 | self.containers[cnt_id.unwrap()].rect.w = if 96 > self.containers[cnt_id.unwrap()].rect.w + self.mouse_delta.x { 1638 | 96 1639 | } else { 1640 | self.containers[cnt_id.unwrap()].rect.w + self.mouse_delta.x 1641 | }; 1642 | self.containers[cnt_id.unwrap()].rect.h = if 64 > self.containers[cnt_id.unwrap()].rect.h + self.mouse_delta.y { 1643 | 64 1644 | } else { 1645 | self.containers[cnt_id.unwrap()].rect.h + self.mouse_delta.y 1646 | }; 1647 | } 1648 | } 1649 | if opt.is_auto_sizing() { 1650 | let r_1 = self.get_layout().body; 1651 | self.containers[cnt_id.unwrap()].rect.w = self.containers[cnt_id.unwrap()].content_size.x + (self.containers[cnt_id.unwrap()].rect.w - r_1.w); 1652 | self.containers[cnt_id.unwrap()].rect.h = self.containers[cnt_id.unwrap()].content_size.y + (self.containers[cnt_id.unwrap()].rect.h - r_1.h); 1653 | } 1654 | 1655 | if opt.is_popup() && !self.mouse_pressed.is_none() && self.hover_root != cnt_id { 1656 | self.containers[cnt_id.unwrap()].open = false; 1657 | } 1658 | self.push_clip_rect(self.containers[cnt_id.unwrap()].body); 1659 | return ResourceState::ACTIVE; 1660 | } 1661 | 1662 | pub fn end_window(&mut self) { 1663 | self.pop_clip_rect(); 1664 | self.end_root_container(); 1665 | } 1666 | 1667 | pub fn open_popup(&mut self, name: &str) { 1668 | let cnt = self.get_container_index(name); 1669 | self.next_hover_root = cnt; 1670 | self.hover_root = self.next_hover_root; 1671 | self.containers[cnt.unwrap()].rect = rect(self.mouse_pos.x, self.mouse_pos.y, 1, 1); 1672 | self.containers[cnt.unwrap()].open = true; 1673 | self.bring_to_front(cnt.unwrap()); 1674 | } 1675 | 1676 | pub fn begin_popup(&mut self, name: &str) -> ResourceState { 1677 | let opt = 1678 | WidgetOption::POPUP | WidgetOption::AUTO_SIZE | WidgetOption::NO_RESIZE | WidgetOption::NO_SCROLL | WidgetOption::NO_TITLE | WidgetOption::CLOSED; 1679 | return self.begin_window_ex(name, rect(0, 0, 0, 0), opt); 1680 | } 1681 | 1682 | pub fn end_popup(&mut self) { 1683 | self.end_window(); 1684 | } 1685 | 1686 | pub fn begin_panel_ex(&mut self, name: &str, opt: WidgetOption) { 1687 | self.push_id_from_str(name); 1688 | let cnt_id = self.get_container_index_intern(self.last_id.unwrap(), opt); 1689 | let rect = self.layout_next(); 1690 | self.containers[cnt_id.unwrap()].rect = rect; 1691 | if !opt.has_no_frame() { 1692 | (self.draw_frame).expect("non-null function pointer")(self, rect, ControlColor::PanelBG); 1693 | } 1694 | 1695 | self.container_stack.push(cnt_id.unwrap()); 1696 | self.push_container_body(cnt_id.unwrap(), rect, opt); 1697 | self.push_clip_rect(self.containers[cnt_id.unwrap()].body); 1698 | } 1699 | 1700 | pub fn end_panel(&mut self) { 1701 | self.pop_clip_rect(); 1702 | self.pop_container(); 1703 | } 1704 | } 1705 | --------------------------------------------------------------------------------