fast image operations
bendn 2023-09-05
commit 62fbd6f
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml23
-rw-r--r--LICENSE21
-rw-r--r--README.md9
-rw-r--r--rust-toolchain.toml2
-rw-r--r--src/affine.rs255
-rw-r--r--src/lib.rs287
-rw-r--r--src/overlay.rs250
-rw-r--r--test_data/3_4x4.imgbuf1
-rw-r--r--test_data/4_180x180.imgbufbin0 -> 102400 bytes
-rw-r--r--test_data/4_4x4.imgbuf1
-rw-r--r--test_results/3x3_at_out.buf1
-rw-r--r--test_results/4x3_at_out.buf1
-rw-r--r--test_results/4x4_at_out.buf1
14 files changed, 854 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..96ef6c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..1c85e52
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "fimg"
+version = "0.1.0"
+authors = ["bend-n <[email protected]>"]
+license = "MIT"
+edition = "2021"
+description = "fast image operations"
+repository = "https://github.com/bend-n/fimg"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+png = { version = "0.17", features = ["unstable"], optional = true }
+
+[features]
+save = ["png"]
+default = ["save"]
+
+[profile.release]
+debug = 2
+opt-level = 3
+lto = "thin"
+incremental = true
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1fafc15
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 bendn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f77c5cc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# fimg
+
+quick simple image operations
+
+## supported operations
+
+- [x] overlay
+- [x] rotation
+- [x] flipping \ No newline at end of file
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000..5d56faf
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
diff --git a/src/affine.rs b/src/affine.rs
new file mode 100644
index 0000000..18f19ee
--- /dev/null
+++ b/src/affine.rs
@@ -0,0 +1,255 @@
+use crate::{FromRefMut, Image};
+
+pub trait Rotations {
+ /// Rotate a image 180 degrees clockwise.
+ fn rot_180(&mut self);
+ /// Rotate a image 90 degrees clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
+ unsafe fn rot_90(&mut self);
+ /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise.
+ /// # Safety
+ ///
+ /// UB if the image is not square
+ unsafe fn rot_270(&mut self);
+}
+
+pub trait Flips {
+ /// Flip a image vertically.
+ fn flip_v(&mut self);
+
+ /// Flip a image horizontally.
+ fn flip_h(&mut self);
+}
+
+impl<const CHANNELS: usize> Flips for Image<Vec<u8>, CHANNELS> {
+ fn flip_h(&mut self) {
+ self.as_mut().flip_h();
+ }
+ fn flip_v(&mut self) {
+ self.as_mut().flip_v();
+ }
+}
+
+impl<const CHANNELS: usize> Flips for Image<&mut [u8], CHANNELS> {
+ fn flip_v(&mut self) {
+ for y in 0..self.height() / 2 {
+ for x in 0..self.width() {
+ let y2 = self.height() - y - 1;
+ // SAFETY: within bounds
+ let p2 = unsafe { self.pixel(x, y2) };
+ let p = unsafe { self.pixel(x, y) };
+ unsafe { self.set_pixel(x, y2, p) };
+ unsafe { self.set_pixel(x, y, p2) };
+ }
+ }
+ }
+
+ fn flip_h(&mut self) {
+ for y in 0..self.height() {
+ for x in 0..self.width() / 2 {
+ let x2 = self.width() - x - 1;
+ let p2 = unsafe { self.pixel(x2, y) };
+ let p = unsafe { self.pixel(x, y) };
+ unsafe { self.set_pixel(x2, y, p) };
+ unsafe { self.set_pixel(x, y, p2) };
+ }
+ }
+ }
+}
+
+impl<const CHANNELS: usize> Rotations for Image<Vec<u8>, CHANNELS> {
+ fn rot_180(&mut self) {
+ self.as_mut().rot_180();
+ }
+
+ unsafe fn rot_90(&mut self) {
+ unsafe { self.as_mut().rot_90() }
+ }
+
+ unsafe fn rot_270(&mut self) {
+ unsafe { self.as_mut().rot_270() }
+ }
+}
+
+impl<const CHANNELS: usize> Rotations for Image<&mut [u8], CHANNELS> {
+ fn rot_180(&mut self) {
+ for y in 0..self.height() / 2 {
+ for x in 0..self.width() {
+ let p = unsafe { self.pixel(x, y) };
+ let x2 = self.width() - x - 1;
+ let y2 = self.height() - y - 1;
+ let p2 = unsafe { self.pixel(x2, y2) };
+ unsafe { self.set_pixel(x, y, p2) };
+ unsafe { self.set_pixel(x2, y2, p) };
+ }
+ }
+
+ if self.height() % 2 != 0 {
+ let middle = self.height() / 2;
+
+ for x in 0..self.width() / 2 {
+ let p = unsafe { self.pixel(x, middle) };
+ let x2 = self.width() - x - 1;
+ let p2 = unsafe { self.pixel(x2, middle) };
+ unsafe { self.set_pixel(x, middle, p2) };
+ unsafe { self.set_pixel(x2, middle, p) };
+ }
+ }
+ }
+
+ #[inline]
+ unsafe fn rot_90(&mut self) {
+ // This is done by first flipping
+ self.flip_v();
+ // Then transposing the image, to save allocations.
+ // SAFETY: caller ensures rectangularity
+ unsafe { transpose(self) };
+ }
+
+ #[inline]
+ unsafe fn rot_270(&mut self) {
+ self.flip_h();
+ // SAFETY: caller ensures rectangularity
+ unsafe { transpose(self) };
+ }
+}
+
+/// # Safety
+///
+/// UB if supplied image rectangular
+unsafe fn transpose<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) {
+ debug_assert_eq!(img.width(), img.height());
+ let size = img.width();
+ for i in 0..size {
+ for j in i..size {
+ for c in 0..CHANNELS {
+ // SAFETY: caller gurantees rectangularity
+ unsafe {
+ img.buffer.swap_unchecked(
+ (i * size + j) as usize * CHANNELS + c,
+ (j * size + i) as usize * CHANNELS + c,
+ );
+ };
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::img;
+
+ #[test]
+ fn rotate_90() {
+ let mut from = img![
+ [00, 01]
+ [02, 10]
+ ];
+ unsafe { from.rot_90() };
+ assert_eq!(
+ from,
+ img![
+ [02, 00]
+ [10, 01]
+ ]
+ );
+ }
+
+ #[test]
+ fn rotate_180() {
+ let mut from = img![
+ [00, 01]
+ [02, 10]
+ ];
+ from.rot_180();
+ assert_eq!(
+ from,
+ img![
+ [10, 02]
+ [01, 00]
+ ]
+ );
+ }
+
+ #[test]
+ fn rotate_270() {
+ let mut from = img![
+ [00, 01]
+ [20, 10]
+ ];
+ unsafe { from.rot_270() };
+ assert_eq!(
+ from,
+ img![
+ [01, 10]
+ [00, 20]
+ ]
+ );
+ }
+
+ #[test]
+ fn flip_vertical() {
+ let mut from = img![
+ [90, 01]
+ [21, 42]
+ ];
+ from.flip_v();
+ assert_eq!(
+ from,
+ img![
+ [21, 42]
+ [90, 01]
+ ]
+ );
+ }
+ #[test]
+ fn flip_horizontal() {
+ let mut from = img![
+ [90, 01]
+ [21, 42]
+ ];
+ from.flip_h();
+ assert_eq!(
+ from,
+ img![
+ [01, 90]
+ [42, 21]
+ ]
+ );
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ use super::*;
+ extern crate test;
+ use crate::Image;
+ use test::Bencher;
+
+ macro_rules! bench {
+ (fn $name: ident() { run $fn: ident() }) => {
+ #[bench]
+ fn $name(b: &mut Bencher) {
+ let mut img: Image<_, 4> = Image::new(
+ 64.try_into().unwrap(),
+ 64.try_into().unwrap(),
+ include_bytes!("../test_data/4_180x180.imgbuf").to_vec(),
+ );
+ b.iter(|| {
+ for _ in 0..256 {
+ img.flip_h();
+ }
+ });
+ }
+ };
+ }
+
+ bench!(fn flip_h() { run flip_h() });
+ bench!(fn flip_v() { run flip_v() });
+ bench!(fn rotate_90() { run rot_90() });
+ bench!(fn rotate_180() { run rot_180() });
+ bench!(fn rotate_270() { run rot_270() });
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..70b91eb
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,287 @@
+#![feature(
+ slice_swap_unchecked,
+ unchecked_math,
+ portable_simd,
+ array_chunks,
+ test
+)]
+#![warn(
+ clippy::multiple_unsafe_ops_per_block,
+ clippy::missing_const_for_fn,
+ clippy::missing_safety_doc,
+ unsafe_op_in_unsafe_fn,
+ clippy::dbg_macro,
+ clippy::perf
+)]
+#![allow(clippy::zero_prefixed_literal)]
+
+use std::{num::NonZeroU32, slice::SliceIndex};
+
+mod affine;
+mod overlay;
+pub use affine::{Flips, Rotations};
+pub use overlay::{Overlay, OverlayAt};
+
+pub trait RepeatNew {
+ type Output;
+ /// Repeat self till it fills a new image of size x, y
+ /// # Safety
+ ///
+ /// UB if self's width is not a multiple of x, or self's height is not a multiple of y
+ unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output;
+}
+
+macro_rules! assert_unchecked {
+ ($cond:expr) => {{
+ if !$cond {
+ #[cfg(debug_assertions)]
+ let _ = ::core::ptr::NonNull::<()>::dangling().as_ref(); // force unsafe wrapping block
+ #[cfg(debug_assertions)]
+ panic!("assertion failed: {} returned false", stringify!($cond));
+ #[cfg(not(debug_assertions))]
+ std::hint::unreachable_unchecked()
+ }
+ }};
+}
+use assert_unchecked;
+
+impl RepeatNew for Image<&[u8], 3> {
+ type Output = Image<Vec<u8>, 3>;
+ unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output {
+ let mut img = Image::alloc(x, y); // could probably optimize this a ton but eh
+ for x in 0..(x / self.width()) {
+ for y in 0..(y / self.height()) {
+ let a: &mut Image<&mut [u8], 3> = &mut img.as_mut();
+ // SAFETY: caller upholds
+ unsafe { a.overlay_at(self, x * self.width(), y * self.height()) };
+ }
+ }
+ img
+ }
+}
+
+#[inline]
+unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize {
+ // y * w + x
+ let tmp = unsafe { (y as usize).unchecked_mul(w as usize) };
+ unsafe { tmp.unchecked_add(x as usize) }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Image<T, const CHANNELS: usize> {
+ pub buffer: T,
+ pub width: NonZeroU32,
+ pub height: NonZeroU32,
+}
+
+impl<const CHANNELS: usize> Default for Image<&'static [u8], CHANNELS> {
+ fn default() -> Self {
+ Self {
+ buffer: &[0; CHANNELS],
+ width: NonZeroU32::new(1).unwrap(),
+ height: NonZeroU32::new(1).unwrap(),
+ }
+ }
+}
+
+impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
+ #[inline]
+ pub fn height(&self) -> u32 {
+ self.height.into()
+ }
+
+ #[inline]
+ pub fn width(&self) -> u32 {
+ self.width.into()
+ }
+
+ #[inline]
+ pub const fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self {
+ Image {
+ buffer,
+ width,
+ height,
+ }
+ }
+}
+
+impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
+ #[inline]
+ #[must_use]
+ pub const fn copy(&self) -> Self {
+ Self {
+ width: self.width,
+ height: self.height,
+ buffer: self.buffer,
+ }
+ }
+}
+
+impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
+ /// # Safety
+ ///
+ /// - UB if x, y is out of bounds
+ /// - UB if buffer is too small
+ #[inline]
+ unsafe fn slice(&self, x: u32, y: u32) -> impl SliceIndex<[u8], Output = [u8]> {
+ debug_assert!(x < self.width(), "x out of bounds");
+ debug_assert!(y < self.height(), "y out of bounds");
+ let index = unsafe { really_unsafe_index(x, y, self.width()) };
+ let index = unsafe { index.unchecked_mul(CHANNELS) };
+ debug_assert!(self.buffer.len() > index);
+ index..unsafe { index.unchecked_add(CHANNELS) }
+ }
+
+ #[inline]
+ /// Returns a iterator over every pixel
+ pub fn chunked(&self) -> impl Iterator<Item = &[u8; CHANNELS]> {
+ // SAFETY: 0 sized images illegal
+ unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) };
+ // SAFETY: no half pixels!
+ unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) };
+ self.buffer.array_chunks::<CHANNELS>()
+ }
+
+ /// Return a pixel at (x, y).
+ /// # Safety
+ ///
+ /// - UB if x, y is out of bounds
+ /// - UB if buffer is too small
+ #[inline]
+ pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] {
+ let idx = unsafe { self.slice(x, y) };
+ let ptr = unsafe { self.buffer.get_unchecked(idx).as_ptr().cast() };
+ unsafe { *ptr }
+ }
+}
+
+impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
+ /// Return a mutable reference to a pixel at (x, y).
+ /// # Safety
+ ///
+ /// - UB if x, y is out of bounds
+ /// - UB if buffer is too small
+ #[inline]
+ pub unsafe fn pixel_mut(&mut self, x: u32, y: u32) -> &mut [u8] {
+ let idx = unsafe { self.slice(x, y) };
+ unsafe { self.buffer.get_unchecked_mut(idx) }
+ }
+
+ #[inline]
+ /// Returns a iterator over every pixel, mutably
+ pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> {
+ // SAFETY: 0 sized images are not allowed
+ unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) };
+ // SAFETY: buffer cannot have half pixels
+ unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) };
+ self.buffer.array_chunks_mut::<CHANNELS>()
+ }
+
+ /// Set the pixel at x, y
+ ///
+ /// # Safety
+ ///
+ /// UB if x, y is out of bounds.
+ #[inline]
+ pub unsafe fn set_pixel(&mut self, x: u32, y: u32, px: [u8; CHANNELS]) {
+ // SAFETY: Caller says that x, y is in bounds
+ let out = unsafe { self.pixel_mut(x, y) };
+ // SAFETY: px must be CHANNELS long
+ unsafe { std::ptr::copy_nonoverlapping(px.as_ptr(), out.as_mut_ptr(), CHANNELS) };
+ }
+}
+
+pub trait FromRef<const CHANNELS: usize> {
+ /// Reference the buffer
+ fn as_ref(&self) -> Image<&[u8], CHANNELS>;
+}
+
+pub trait FromRefMut<const CHANNELS: usize> {
+ /// Reference the buffer, mutably
+ fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS>;
+}
+
+impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<&mut [u8], CHANNELS> {
+ fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+ Image::new(self.width, self.height, self.buffer)
+ }
+}
+
+impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<&mut [u8], CHANNELS> {
+ fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+ Image::new(self.width, self.height, self.buffer)
+ }
+}
+
+impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<Vec<u8>, CHANNELS> {
+ fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+ Image::new(self.width, self.height, &self.buffer)
+ }
+}
+
+impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<Vec<u8>, CHANNELS> {
+ fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+ Image::new(self.width, self.height, &mut self.buffer)
+ }
+}
+
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Allocates a new image
+ ///
+ /// # Panics
+ ///
+ /// if width || height == 0
+ #[must_use]
+ pub fn alloc(width: u32, height: u32) -> Self {
+ Image {
+ width: width.try_into().unwrap(),
+ height: height.try_into().unwrap(),
+ buffer: vec![0; CHANNELS * width as usize * height as usize],
+ }
+ }
+}
+macro_rules! save {
+ ($channels:literal == $clr:ident ($clrhuman:literal)) => {
+ impl Image<&[u8], $channels> {
+ #[cfg(feature = "save")]
+ #[doc = "Save this "]
+ #[doc = $clrhuman]
+ #[doc = " image."]
+ pub fn save(&self, f: impl AsRef<std::path::Path>) {
+ let p = std::fs::File::create(f).unwrap();
+ let w = &mut std::io::BufWriter::new(p);
+ let mut enc = png::Encoder::new(w, self.width(), self.height());
+ enc.set_color(png::ColorType::$clr);
+ enc.set_depth(png::BitDepth::Eight);
+ enc.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2));
+ enc.set_source_chromaticities(png::SourceChromaticities::new(
+ (0.31270, 0.32900),
+ (0.64000, 0.33000),
+ (0.30000, 0.60000),
+ (0.15000, 0.06000),
+ ));
+ let mut writer = enc.write_header().unwrap();
+ writer.write_image_data(self.buffer).unwrap();
+ }
+ }
+ };
+}
+
+save!(3 == Rgb("RGB"));
+save!(4 == Rgba("RGBA"));
+save!(2 == GrayscaleAlpha("YA"));
+save!(1 == Grayscale("Y"));
+
+#[cfg(test)]
+macro_rules! img {
+ [[$($v:literal),+] [$($v2:literal),+]] => {{
+ let from: Image<Vec<u8>, 1> = Image::new(
+ 2.try_into().unwrap(),
+ 2.try_into().unwrap(),
+ vec![$($v,)+ $($v2,)+]
+ );
+ from
+ }}
+}
+#[cfg(test)]
+use img;
diff --git a/src/overlay.rs b/src/overlay.rs
new file mode 100644
index 0000000..c1cac44
--- /dev/null
+++ b/src/overlay.rs
@@ -0,0 +1,250 @@
+use super::{assert_unchecked, really_unsafe_index, Image};
+use std::simd::SimdInt;
+use std::simd::SimdPartialOrd;
+use std::simd::{simd_swizzle, Simd};
+
+pub trait OverlayAt<W> {
+ /// Overlay with => self at coordinates x, y, without blending
+ /// # Safety
+ ///
+ /// UB if x, y is out of bounds
+ unsafe fn overlay_at(&mut self, with: &W, x: u32, y: u32) -> &mut Self;
+}
+
+pub trait Overlay<W> {
+ /// Overlay with => self (does not blend)
+ /// # Safety
+ ///
+ /// UB if a.width != b.width || a.height != b.height
+ unsafe fn overlay(&mut self, with: &W) -> &mut Self;
+}
+
+#[inline]
+unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
+ const LAST4: Simd<u8, 16> = Simd::from_array([
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
+ ]);
+
+ let mut srci = 0;
+ let mut dsti = 0;
+ while dsti + 16 <= rgb.len() {
+ let old: Simd<u8, 16> = Simd::from_slice(unsafe { rgb.get_unchecked(dsti..dsti + 16) });
+ let new: Simd<u8, 16> = Simd::from_slice(unsafe { rgba.get_unchecked(srci..srci + 16) });
+
+ let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>();
+ let mut mask = simd_swizzle!(
+ threshold,
+ [3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0]
+ );
+ mask &= LAST4;
+
+ let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]);
+ let blended = (new_rgb & mask) | (old & !mask);
+ blended.copy_to_slice(unsafe { rgb.get_unchecked_mut(dsti..dsti + 16) });
+
+ srci += 16;
+ dsti += 12;
+ }
+
+ while dsti + 3 <= rgb.len() {
+ if unsafe { *rgba.get_unchecked(srci + 3) } >= 128 {
+ let src = unsafe { rgba.get_unchecked(srci..srci + 3) };
+ let end = unsafe { rgb.get_unchecked_mut(dsti..dsti + 3) };
+ unsafe { std::ptr::copy_nonoverlapping(src.as_ptr(), end.as_mut_ptr(), 3) };
+ }
+
+ srci += 4;
+ dsti += 3;
+ }
+}
+
+impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 4> {
+ #[inline]
+ unsafe fn overlay(&mut self, with: &Image<&[u8], 4>) -> &mut Self {
+ debug_assert!(self.width() == with.width());
+ debug_assert!(self.height() == with.height());
+ for (i, other_pixels) in with.chunked().enumerate() {
+ if other_pixels[3] >= 128 {
+ let idx_begin = unsafe { i.unchecked_mul(4) };
+ let idx_end = unsafe { idx_begin.unchecked_add(4) };
+ let own_pixels = unsafe { self.buffer.get_unchecked_mut(idx_begin..idx_end) };
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ other_pixels.as_ptr(),
+ own_pixels.as_mut_ptr(),
+ 4,
+ );
+ };
+ }
+ }
+ self
+ }
+}
+
+impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 3> {
+ #[inline]
+ unsafe fn overlay_at(&mut self, with: &Image<&[u8], 4>, x: u32, y: u32) -> &mut Self {
+ // SAFETY: caller upholds these
+ unsafe { assert_unchecked!(x + with.width() <= self.width()) };
+ unsafe { assert_unchecked!(y + with.height() <= self.height()) };
+ for j in 0..with.height() {
+ let i_x = j as usize * with.width() as usize * 4
+ ..(j as usize + 1) * with.width() as usize * 4;
+ let o_x = ((j as usize + y as usize) * self.width() as usize + x as usize) * 3
+ ..((j as usize + y as usize) * self.width() as usize
+ + x as usize
+ + with.width() as usize)
+ * 3;
+ let rgb = unsafe { self.buffer.get_unchecked_mut(o_x) };
+ let rgba = unsafe { with.buffer.get_unchecked(i_x) };
+ unsafe { blit(rgb, rgba) }
+ }
+ self
+ }
+}
+
+impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
+ #[inline]
+ unsafe fn overlay_at(&mut self, with: &Image<&[u8], 3>, x: u32, y: u32) -> &mut Self {
+ macro_rules! o3x3 {
+ ($n:expr) => {{
+ for j in 0..($n as usize) {
+ let i_x = j * ($n as usize) * 3..(j + 1) * ($n as usize) * 3;
+ let o_x = ((j + y as usize) * self.width() as usize + x as usize) * 3
+ ..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
+ * 3;
+ let a = unsafe { self.buffer.get_unchecked_mut(o_x) };
+ let b = unsafe { with.buffer.get_unchecked(i_x) };
+ a.copy_from_slice(b);
+ }
+ }};
+ }
+ // let it unroll
+ match with.width() {
+ 8 => o3x3!(8),
+ 16 => o3x3!(16), // this branch makes 8x8 0.16 times slower; but 16x16 0.2 times faster.
+ _ => o3x3!(with.width()),
+ }
+ self
+ }
+}
+
+impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 3> {
+ #[inline]
+ unsafe fn overlay(&mut self, with: &Image<&[u8], 4>) -> &mut Self {
+ debug_assert!(self.width() == with.width());
+ debug_assert!(self.height() == with.height());
+ for (i, chunk) in with
+ .buffer
+ .chunks_exact(with.width() as usize * 4)
+ .enumerate()
+ {
+ let rgb = unsafe {
+ self.buffer.get_unchecked_mut(
+ i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
+ )
+ };
+ unsafe { blit(rgb, chunk) };
+ }
+ self
+ }
+}
+
+impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 4> {
+ #[inline]
+ unsafe fn overlay_at(&mut self, with: &Image<&[u8], 4>, x: u32, y: u32) -> &mut Self {
+ for j in 0..with.height() {
+ for i in 0..with.width() {
+ let index = unsafe { really_unsafe_index(i, j, with.width()) };
+ let their_px = unsafe { with.buffer.get_unchecked(index * 4..index * 4 + 4) };
+ if unsafe { *their_px.get_unchecked(3) } >= 128 {
+ let x = unsafe { i.unchecked_add(x) };
+ let y = unsafe { j.unchecked_add(y) };
+ let index = unsafe { really_unsafe_index(x, y, self.width()) };
+ let our_px = unsafe { self.buffer.get_unchecked_mut(index * 4..index * 4 + 4) };
+ our_px.copy_from_slice(their_px);
+ }
+ }
+ }
+
+ self
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ extern crate test;
+
+ use test::Bencher;
+
+ use super::*;
+ use crate::{FromRef, FromRefMut};
+
+ #[bench]
+ fn overlay_3on3at(bench: &mut Bencher) {
+ let mut v = vec![0u8; 3 * 64 * 64];
+ let mut a: Image<_, 3> = Image::new(
+ 64.try_into().unwrap(),
+ 64.try_into().unwrap(),
+ v.as_mut_slice(),
+ );
+ let b = Image::<&[u8], 3>::new(
+ 4.try_into().unwrap(),
+ 4.try_into().unwrap(),
+ *&include_bytes!("../test_data/3_4x4.imgbuf"),
+ );
+ bench.iter(|| unsafe {
+ for x in 0..16 {
+ for y in 0..16 {
+ a.overlay_at(&b, x * 4, y * 4);
+ }
+ }
+ });
+ assert_eq!(
+ a.as_ref().buffer,
+ include_bytes!("../test_results/3x3_at_out.buf")
+ );
+ }
+
+ #[bench]
+ fn overlay_4on3at(bench: &mut Bencher) {
+ let mut a: Image<_, 3> = Image::alloc(64, 64);
+ let b = Image::<&[u8], 4>::new(
+ 4.try_into().unwrap(),
+ 4.try_into().unwrap(),
+ *&include_bytes!("../test_data/4_4x4.imgbuf"),
+ );
+ bench.iter(|| unsafe {
+ for x in 0..16 {
+ for y in 0..16 {
+ a.as_mut().overlay_at(&b, x * 4, y * 4);
+ }
+ }
+ });
+ assert_eq!(
+ a.as_ref().buffer,
+ include_bytes!("../test_results/4x3_at_out.buf")
+ );
+ }
+
+ #[bench]
+ fn overlay_4on4at(bench: &mut Bencher) {
+ let mut a: Image<_, 4> = Image::alloc(64, 64);
+ let b = Image::<&[u8], 4>::new(
+ 4.try_into().unwrap(),
+ 4.try_into().unwrap(),
+ *&include_bytes!("../test_data/4_4x4.imgbuf"),
+ );
+ bench.iter(|| unsafe {
+ for x in 0..16 {
+ for y in 0..16 {
+ a.as_mut().overlay_at(&b, x * 4, y * 4);
+ }
+ }
+ });
+ assert_eq!(
+ a.as_ref().buffer,
+ include_bytes!("../test_results/4x4_at_out.buf")
+ );
+ }
+}
diff --git a/test_data/3_4x4.imgbuf b/test_data/3_4x4.imgbuf
new file mode 100644
index 0000000..f3a8624
--- /dev/null
+++ b/test_data/3_4x4.imgbuf
@@ -0,0 +1 @@
+Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ� \ No newline at end of file
diff --git a/test_data/4_180x180.imgbuf b/test_data/4_180x180.imgbuf
new file mode 100644
index 0000000..58aabd0
--- /dev/null
+++ b/test_data/4_180x180.imgbuf
Binary files differ
diff --git a/test_data/4_4x4.imgbuf b/test_data/4_4x4.imgbuf
new file mode 100644
index 0000000..bc6cdf8
--- /dev/null
+++ b/test_data/4_4x4.imgbuf
@@ -0,0 +1 @@
+���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \ No newline at end of file
diff --git a/test_results/3x3_at_out.buf b/test_results/3x3_at_out.buf
new file mode 100644
index 0000000..21d0141
--- /dev/null
+++ b/test_results/3x3_at_out.buf
@@ -0,0 +1 @@
+Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ��ˤ�ˤӮ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ�Ӯ� \ No newline at end of file
diff --git a/test_results/4x3_at_out.buf b/test_results/4x3_at_out.buf
new file mode 100644
index 0000000..d5d8851
--- /dev/null
+++ b/test_results/4x3_at_out.buf
@@ -0,0 +1 @@
+������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ \ No newline at end of file
diff --git a/test_results/4x4_at_out.buf b/test_results/4x4_at_out.buf
new file mode 100644
index 0000000..4dedb62
--- /dev/null
+++ b/test_results/4x4_at_out.buf
@@ -0,0 +1 @@
+���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� \ No newline at end of file