add unit functions (#3604)

* add unit functions

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* update docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* empty

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Jess Frazelle
2024-08-21 12:12:56 -07:00
committed by GitHub
parent d656a389f8
commit be047f5111
118 changed files with 782 additions and 69 deletions

View File

@ -1424,6 +1424,7 @@ dependencies = [
"js-sys",
"kittycad",
"lazy_static",
"measurements",
"mime_guess",
"parse-display",
"pretty_assertions",
@ -1595,6 +1596,15 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "measurements"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5b734b4e8187ea5777bc29c086f0970a27d8de42061b48f5af32cafc0ca904b"
dependencies = [
"libm",
]
[[package]]
name = "memchr"
version = "2.7.1"

View File

@ -28,6 +28,7 @@ gltf-json = "1.4.1"
image = { version = "0.25.1", default-features = false, features = ["png"] }
kittycad = { workspace = true, features = ["clap"] }
lazy_static = "1.5.0"
measurements = "0.11.0"
mime_guess = "2.0.5"
parse-display = "0.9.1"
pyo3 = { version = "0.22.2", optional = true }

View File

@ -2114,39 +2114,6 @@ mod tests {
.unwrap()
}
#[test]
fn how_does_sketchgroup_serialize() {
let sg = SketchGroup {
id: uuid::Uuid::new_v4(),
value: vec![],
on: SketchSurface::Plane(Box::new(Plane {
id: uuid::Uuid::new_v4(),
value: PlaneType::XY,
origin: Point3d::default(),
x_axis: Point3d::default(),
y_axis: Point3d::default(),
z_axis: Point3d::default(),
meta: Vec::new(),
})),
start: BasePath {
from: [0.0, 0.0],
to: [0.0, 0.0],
tag: None,
geo_meta: GeoMeta {
id: uuid::Uuid::new_v4(),
metadata: Metadata {
source_range: SourceRange([0, 0]),
},
},
},
tags: HashMap::new(),
original_id: uuid::Uuid::new_v4(),
meta: Vec::new(),
};
let jstr = serde_json::to_string_pretty(&sg).unwrap();
println!("{jstr}");
}
#[tokio::test(flavor = "multi_thread")]
async fn test_execute_assign_two_variables() {
let ast = r#"const myVar = 5

View File

@ -1,9 +1,9 @@
use std::any::type_name;
use anyhow::Result;
use kittycad::types::OkWebSocketResponseData;
use serde::de::DeserializeOwned;
use super::{shapes::SketchSurfaceOrGroup, sketch::FaceTag, FnAsArg};
use crate::{
ast::types::{parse_json_number_as_f64, TagDeclarator},
errors::{KclError, KclErrorDetails},
@ -11,6 +11,7 @@ use crate::{
DynamicState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, KclValue, Metadata,
ProgramMemory, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
},
std::{shapes::SketchSurfaceOrGroup, sketch::FaceTag, FnAsArg},
};
#[derive(Debug, Clone)]
@ -39,6 +40,25 @@ impl Args {
}
}
#[cfg(test)]
pub(crate) async fn new_test_args() -> Result<Self> {
use std::sync::Arc;
Ok(Self {
args: Vec::new(),
source_range: SourceRange::default(),
ctx: ExecutorContext {
engine: Arc::new(Box::new(crate::engine::conn_mock::EngineConnection::new().await?)),
fs: Arc::new(crate::fs::FileManager::new()),
stdlib: Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
is_mock: true,
},
current_program_memory: ProgramMemory::default(),
dynamic_state: DynamicState::default(),
})
}
// Add a modeling command to the batch but don't fire it right away.
pub(crate) async fn batch_modeling_cmd(
&self,

View File

@ -72,8 +72,8 @@ pub async fn assert_gt(args: Args) -> Result<KclValue, KclError> {
///
/// ```no_run
/// let n = 1.0285
/// let m = 1.0286
/// assertEqual(n, m, 0.01, "n is within the given tolerance for m")
/// let o = 1.0286
/// assertEqual(n, o, 0.01, "n is within the given tolerance for o")
/// ```
#[stdlib {
name = "assertEqual",

View File

@ -18,6 +18,7 @@ pub mod shapes;
pub mod shell;
pub mod sketch;
pub mod types;
pub mod units;
pub mod utils;
use std::collections::HashMap;
@ -118,6 +119,12 @@ lazy_static! {
Box::new(crate::std::math::Ln),
Box::new(crate::std::math::ToDegrees),
Box::new(crate::std::math::ToRadians),
Box::new(crate::std::units::Mm),
Box::new(crate::std::units::Inch),
Box::new(crate::std::units::Ft),
Box::new(crate::std::units::M),
Box::new(crate::std::units::Cm),
Box::new(crate::std::units::Yd),
Box::new(crate::std::polar::Polar),
Box::new(crate::std::assert::Assert),
Box::new(crate::std::assert::AssertEqual),

View File

@ -0,0 +1,336 @@
//! Functions related to unitsematics.
use anyhow::Result;
use derive_docs::stdlib;
use schemars::JsonSchema;
use crate::{errors::KclError, executor::KclValue, settings::types::UnitLength, std::Args};
/// Millimeters conversion factor for current projects units.
pub async fn mm(args: Args) -> Result<KclValue, KclError> {
let result = inner_mm(&args)?;
args.make_user_val_from_f64(result)
}
/// Millimeters conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to millimeters.
///
/// For example, if the current project uses inches, this function will return `(1/25.4)`.
/// If the current project uses millimeters, this function will return `1`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * mm()` is more readable that your intent is "I want 10 millimeters" than
/// `10 * (1/25.4)`, if the project settings are in inches.
///
/// ```no_run
/// const totalWidth = 10 * mm()
/// ```
#[stdlib {
name = "mm",
tags = ["units"],
}]
fn inner_mm(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(1.0),
UnitLength::In => Ok(measurements::Length::from_millimeters(1.0).as_inches()),
UnitLength::Ft => Ok(measurements::Length::from_millimeters(1.0).as_feet()),
UnitLength::M => Ok(measurements::Length::from_millimeters(1.0).as_meters()),
UnitLength::Cm => Ok(measurements::Length::from_millimeters(1.0).as_centimeters()),
UnitLength::Yd => Ok(measurements::Length::from_millimeters(1.0).as_yards()),
}
}
/// Inches conversion factor for current projects units.
pub async fn inch(args: Args) -> Result<KclValue, KclError> {
let result = inner_inch(&args)?;
args.make_user_val_from_f64(result)
}
/// Inches conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to inches.
///
/// For example, if the current project uses inches, this function will return `1`.
/// If the current project uses millimeters, this function will return `25.4`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * inch()` is more readable that your intent is "I want 10 inches" than
/// `10 * 25.4`, if the project settings are in millimeters.
///
/// ```no_run
/// const totalWidth = 10 * inch()
/// ```
#[stdlib {
name = "inch",
tags = ["units"],
}]
fn inner_inch(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(measurements::Length::from_inches(1.0).as_millimeters()),
UnitLength::In => Ok(1.0),
UnitLength::Ft => Ok(measurements::Length::from_inches(1.0).as_feet()),
UnitLength::M => Ok(measurements::Length::from_inches(1.0).as_meters()),
UnitLength::Cm => Ok(measurements::Length::from_inches(1.0).as_centimeters()),
UnitLength::Yd => Ok(measurements::Length::from_inches(1.0).as_yards()),
}
}
/// Feet conversion factor for current projects units.
pub async fn ft(args: Args) -> Result<KclValue, KclError> {
let result = inner_ft(&args)?;
args.make_user_val_from_f64(result)
}
/// Feet conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to feet.
///
/// For example, if the current project uses inches, this function will return `12`.
/// If the current project uses millimeters, this function will return `304.8`.
/// If the current project uses feet, this function will return `1`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * ft()` is more readable that your intent is "I want 10 feet" than
/// `10 * 304.8`, if the project settings are in millimeters.
///
/// ```no_run
/// const totalWidth = 10 * ft()
/// ```
#[stdlib {
name = "ft",
tags = ["units"],
}]
fn inner_ft(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(measurements::Length::from_feet(1.0).as_millimeters()),
UnitLength::In => Ok(measurements::Length::from_feet(1.0).as_inches()),
UnitLength::Ft => Ok(1.0),
UnitLength::M => Ok(measurements::Length::from_feet(1.0).as_meters()),
UnitLength::Cm => Ok(measurements::Length::from_feet(1.0).as_centimeters()),
UnitLength::Yd => Ok(measurements::Length::from_feet(1.0).as_yards()),
}
}
/// Meters conversion factor for current projects units.
pub async fn m(args: Args) -> Result<KclValue, KclError> {
let result = inner_m(&args)?;
args.make_user_val_from_f64(result)
}
/// Meters conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to meters.
///
/// For example, if the current project uses inches, this function will return `39.3701`.
/// If the current project uses millimeters, this function will return `1000`.
/// If the current project uses meters, this function will return `1`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * m()` is more readable that your intent is "I want 10 meters" than
/// `10 * 1000`, if the project settings are in millimeters.
///
/// ```no_run
/// const totalWidth = 10 * m()
/// ```
#[stdlib {
name = "m",
tags = ["units"],
}]
fn inner_m(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(measurements::Length::from_meters(1.0).as_millimeters()),
UnitLength::In => Ok(measurements::Length::from_meters(1.0).as_inches()),
UnitLength::Ft => Ok(measurements::Length::from_meters(1.0).as_feet()),
UnitLength::M => Ok(1.0),
UnitLength::Cm => Ok(measurements::Length::from_meters(1.0).as_centimeters()),
UnitLength::Yd => Ok(measurements::Length::from_meters(1.0).as_yards()),
}
}
/// Centimeters conversion factor for current projects units.
pub async fn cm(args: Args) -> Result<KclValue, KclError> {
let result = inner_cm(&args)?;
args.make_user_val_from_f64(result)
}
/// Centimeters conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to centimeters.
///
/// For example, if the current project uses inches, this function will return `0.393701`.
/// If the current project uses millimeters, this function will return `10`.
/// If the current project uses centimeters, this function will return `1`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * cm()` is more readable that your intent is "I want 10 centimeters" than
/// `10 * 10`, if the project settings are in millimeters.
///
/// ```no_run
/// const totalWidth = 10 * cm()
/// ```
#[stdlib {
name = "cm",
tags = ["units"],
}]
fn inner_cm(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(measurements::Length::from_centimeters(1.0).as_millimeters()),
UnitLength::In => Ok(measurements::Length::from_centimeters(1.0).as_inches()),
UnitLength::Ft => Ok(measurements::Length::from_centimeters(1.0).as_feet()),
UnitLength::M => Ok(measurements::Length::from_centimeters(1.0).as_meters()),
UnitLength::Cm => Ok(1.0),
UnitLength::Yd => Ok(measurements::Length::from_centimeters(1.0).as_yards()),
}
}
/// Yards conversion factor for current projects units.
pub async fn yd(args: Args) -> Result<KclValue, KclError> {
let result = inner_yd(&args)?;
args.make_user_val_from_f64(result)
}
/// Yards conversion factor for current projects units.
///
/// No matter what units the current project uses, this function will always return the conversion
/// factor to yards.
///
/// For example, if the current project uses inches, this function will return `36`.
/// If the current project uses millimeters, this function will return `914.4`.
/// If the current project uses yards, this function will return `1`.
///
/// **Caution**: This function is only intended to be used when you absolutely MUST
/// have different units in your code than the project settings. Otherwise, it is
/// a bad pattern to use this function.
///
/// We merely provide these functions for convenience and readability, as
/// `10 * yd()` is more readable that your intent is "I want 10 yards" than
/// `10 * 914.4`, if the project settings are in millimeters.
///
/// ```no_run
/// const totalWidth = 10 * yd()
/// ```
#[stdlib {
name = "yd",
tags = ["units"],
}]
fn inner_yd(args: &Args) -> Result<f64, KclError> {
match args.ctx.settings.units {
UnitLength::Mm => Ok(measurements::Length::from_yards(1.0).as_millimeters()),
UnitLength::In => Ok(measurements::Length::from_yards(1.0).as_inches()),
UnitLength::Ft => Ok(measurements::Length::from_yards(1.0).as_feet()),
UnitLength::M => Ok(measurements::Length::from_yards(1.0).as_meters()),
UnitLength::Cm => Ok(measurements::Length::from_yards(1.0).as_centimeters()),
UnitLength::Yd => Ok(1.0),
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_mm() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::Mm;
let result = inner_mm(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::In;
let result = inner_mm(&args).unwrap();
assert_eq!(result, 1.0 / 25.4);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_inch() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::In;
let result = inner_inch(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::Mm;
let result = inner_inch(&args).unwrap();
assert_eq!(result, 25.4);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_ft() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::Ft;
let result = inner_ft(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::Mm;
let result = inner_ft(&args).unwrap();
assert_eq!(result, 304.8);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_m() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::M;
let result = inner_m(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::Mm;
let result = inner_m(&args).unwrap();
assert_eq!(result, 1000.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_cm() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::Cm;
let result = inner_cm(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::Mm;
let result = inner_cm(&args).unwrap();
assert_eq!(result, 10.0);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_units_inner_yd() {
let mut args = Args::new_test_args().await.unwrap();
args.ctx.settings.units = UnitLength::Yd;
let result = inner_yd(&args).unwrap();
assert_eq!(result, 1.0);
args.ctx.settings.units = UnitLength::Mm;
let result = inner_yd(&args).unwrap();
assert_eq!(result, 914.4);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,13 +1,13 @@
const ANSWER = 41803
fn m = (s) => {
fn t = (s) => {
return (ANSWER * s + 12345) % 214748
}
let xs = 205804
let ys = 71816
let ox = 35 - (m(xs) % 70)
let oy = 35 - (m(ys) % 70)
let ox = 35 - (t(xs) % 70)
let oy = 35 - (t(ys) % 70)
const r = startSketchOn('XZ')
|> startProfileAt([ox, oy], %)
|> line([1, 0], %)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB