Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ authors = ["src_resources"]

[workspace.dependencies]
gl = "0.14.0"
glfw = "0.55.0"
image = "0.25.1"
nalgebra-glm = "0.18.0"
lazy_static = "1.4.0"
russimp = { version = "3.2.0", features = ["prebuilt"] }
rand = "0.9.0-alpha.1"
rand_pcg = "0.9.0-alpha.1"
glfw = "0.59.0"
image = "0.25.6"
nalgebra-glm = "0.19.0"
lazy_static = "1.5.0"
russimp = { version = "3.2.1", features = ["prebuilt"] }
rand = "0.9.1"
rand_pcg = "0.9.0"
freetype = "0.7.2"
rodio = "0.18.1"
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ resources at once:

## Build the source code

Check the source code first:

```shell
cargo check
```

To build and run test, switch to the repository root directory and run:

```shell
Expand All @@ -47,4 +53,4 @@ For the images, audios and models used under this repository (under the `resourc
[LearnOpenGL About](https://learnopengl.com/About) page.

For the other parts, licensed under [the Apache License v2.0](https://spdx.org/licenses/Apache-2.0.html).
See [LICENSE.txt](LICENSE.txt) for details.
See [LICENSE.txt](LICENSE.txt) for details.
2 changes: 1 addition & 1 deletion crates/1.getting_started/2.1.hello_triangle/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/1.getting_started/3.1.shaders_uniform/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn main() {
// check for linking errors
gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
gl::GetProgramInfoLog(shader_program, 512, ptr::null_mut(), &mut info_log as *mut _);
let info_log_vec: Vec<_> = Vec::from(info_log).iter().map(|it| *it as u8).collect();
println!("ERROR::SHADER::PROGRAM::LINKING_FAILED\n{}", String::from_utf8(info_log_vec).unwrap());
}
Expand Down
3 changes: 1 addition & 2 deletions crates/1.getting_started/5.1.transformations/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::filesystem;
use learnopengl_shared::shader_s::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::filesystem;
use learnopengl_shared::shader_s::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
3 changes: 1 addition & 2 deletions crates/1.getting_started/6.1.coordinate_systems/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
3 changes: 1 addition & 2 deletions crates/1.getting_started/7.1.camera_circle/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowEvent, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
3 changes: 1 addition & 2 deletions crates/1.getting_started/7.2.camera_keyboard_dt/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use gl::types::*;
use glfw::{Action, Context, Key, OpenGlProfileHint, Window, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
3 changes: 1 addition & 2 deletions crates/1.getting_started/7.3.camera_mouse_zoom/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use gl::types::*;
use glfw::{Action, Context, CursorMode, Key, OpenGlProfileHint, Window, WindowHint};
use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader_m::Shader;
use image::io::Reader as ImageReader;
use image::{RgbaImage, RgbImage};
use image::{ImageReader, RgbaImage, RgbImage};

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
1 change: 1 addition & 0 deletions crates/4.advanced_opengl/10.2.asteroids/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ nalgebra-glm.workspace = true
lazy_static.workspace = true
rand.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
14 changes: 7 additions & 7 deletions crates/4.advanced_opengl/10.2.asteroids/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use learnopengl_shared::shader::Shader;
use lazy_static::lazy_static;
use rand::Rng;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down Expand Up @@ -89,27 +89,27 @@ fn main() {
// ------------------------------------------------------------------
let amount = 1000usize;
let mut model_matrices = vec![util::glm::diag_mat4(1.0); amount];
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let radius = 50f32;
let offset = 2.5f32;
for i in 0..amount {
let mut model = util::glm::diag_mat4(1.0);
// 1. translation: displace along circle with 'radius' in range [-offset, offset]
let angle = i as f32 / amount as f32 * 360.0;
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let x = angle.sin() * radius + displacement;
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let y = displacement * 0.4; // keep height of asteroid field smaller compared to width of x and z
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let z = angle.cos() * radius + displacement;
model = glm::translate(&model, &glm::vec3(x, y, z));

// 2. scale: Scale between 0.05 and 0.25f
let scale = (rng.gen::<i32>() % 20) as f32 / 100.0 + 0.05;
let scale = (rng.random::<i32>() % 20) as f32 / 100.0 + 0.05;
model = glm::scale(&model, &util::glm::scale_vec3(scale));

// 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
let rot_angle = (rng.gen::<i32>() % 360) as f32;
let rot_angle = (rng.random::<i32>() % 360) as f32;
model = glm::rotate(&model, rot_angle, &glm::vec3(0.4, 0.6, 0.8));

// 4. now add to list of matrices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ nalgebra-glm.workspace = true
lazy_static.workspace = true
rand.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
14 changes: 7 additions & 7 deletions crates/4.advanced_opengl/10.3.asteroids_instanced/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use learnopengl_shared::shader::Shader;
use lazy_static::lazy_static;
use rand::Rng;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down Expand Up @@ -91,27 +91,27 @@ fn main() {
// ------------------------------------------------------------------
let amount = 100000usize;
let mut model_matrices = vec![util::glm::diag_mat4(1.0); amount];
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let radius = 50f32;
let offset = 2.5f32;
for i in 0..amount {
let mut model = util::glm::diag_mat4(1.0);
// 1. translation: displace along circle with 'radius' in range [-offset, offset]
let angle = i as f32 / amount as f32 * 360.0;
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let x = angle.sin() * radius + displacement;
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let y = displacement * 0.4; // keep height of asteroid field smaller compared to width of x and z
let displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let displacement = (rng.random::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
let z = angle.cos() * radius + displacement;
model = glm::translate(&model, &glm::vec3(x, y, z));

// 2. scale: Scale between 0.05 and 0.25f
let scale = (rng.gen::<i32>() % 20) as f32 / 100.0 + 0.05;
let scale = (rng.random::<i32>() % 20) as f32 / 100.0 + 0.05;
model = glm::scale(&model, &util::glm::scale_vec3(scale));

// 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
let rot_angle = (rng.gen::<i32>() % 360) as f32;
let rot_angle = (rng.random::<i32>() % 360) as f32;
model = glm::rotate(&model, rot_angle, &glm::vec3(0.4, 0.6, 0.8));

// 4. now add to list of matrices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ nalgebra-glm.workspace = true
lazy_static.workspace = true
image.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader::Shader;
use lazy_static::lazy_static;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ nalgebra-glm.workspace = true
lazy_static.workspace = true
image.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use learnopengl_shared::{filesystem, util};
use learnopengl_shared::shader::Shader;
use lazy_static::lazy_static;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
1 change: 1 addition & 0 deletions crates/5.advanced_lighting/8.1.deferred_shading/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ lazy_static.workspace = true
rand.workspace = true
rand_pcg.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use lazy_static::lazy_static;
use rand::{RngCore, SeedableRng};
use rand_pcg::Pcg64;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ lazy_static.workspace = true
rand.workspace = true
rand_pcg.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use lazy_static::lazy_static;
use rand::{RngCore, SeedableRng};
use rand_pcg::Pcg64;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down
1 change: 1 addition & 0 deletions crates/5.advanced_lighting/9.ssao/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ nalgebra-glm.workspace = true
lazy_static.workspace = true
rand.workspace = true
learnopengl-shared = { path = "../../../shared" }
learnopengl-shared-ex = { path = "../../../shared-ex" }
10 changes: 5 additions & 5 deletions crates/5.advanced_lighting/9.ssao/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use learnopengl_shared::shader::Shader;
use lazy_static::lazy_static;
use rand::Rng;
use learnopengl_shared::camera::{Camera, Movement};
use learnopengl_shared::model::Model;
use learnopengl_shared_ex::model::Model;

const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
Expand Down Expand Up @@ -165,12 +165,12 @@ fn main() {

// generate sample kernel
// ----------------------
let mut rng = rand::thread_rng();
let mut rng = rand::rng();
let mut ssao_kernel: Vec<glm::TVec3<f32>> = Vec::new();
for i in 0..64 {
let mut sample = glm::vec3(rng.gen::<f32>() * 2.0 - 1.0, rng.gen::<f32>() * 2.0 - 1.0, rng.gen::<f32>());
let mut sample = glm::vec3(rng.random::<f32>() * 2.0 - 1.0, rng.random::<f32>() * 2.0 - 1.0, rng.random::<f32>());
sample = glm::normalize(&sample);
sample *= rng.gen::<f32>();
sample *= rng.random::<f32>();
let mut scale = i as f32 / 64.0;

// scale samples s.t. they're more aligned to center of kernel
Expand All @@ -183,7 +183,7 @@ fn main() {
// ----------------------
let mut ssao_noise: Vec<glm::TVec3<f32>> = Vec::new();
for _ in 0..16 {
let noise = glm::vec3(rng.gen::<f32>() * 2.0 - 1.0, rng.gen::<f32>() * 2.0 - 1.0, 0.0); // rotate around z-axis (in tangent space)
let noise = glm::vec3(rng.random::<f32>() * 2.0 - 1.0, rng.random::<f32>() * 2.0 - 1.0, 0.0); // rotate around z-axis (in tangent space)
ssao_noise.push(noise);
}
let mut noise_texture = 0u32; gl::GenTextures(1, &mut noise_texture);
Expand Down
4 changes: 2 additions & 2 deletions crates/7.in_practice/3.2d_game/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ fn is_other_power_up_active(
}

fn should_spawn(chance: u32) -> bool {
let mut rng = rand::thread_rng();
let random = rng.gen::<u32>() % chance;
let mut rng = rand::rng();
let random = rng.random::<u32>() % chance;
random == 0
}

Expand Down
6 changes: 3 additions & 3 deletions crates/7.in_practice/3.2d_game/src/particle_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ impl ParticleGenerator {
offset: glm::TVec2<f32>
) {
let particle = &mut self.particles[particle_index];
let mut rng = rand::thread_rng();
let random = ((rng.gen::<u32>() % 100) as f32 - 50.0) / 10.0;
let r_color = 0.5 + ((rng.gen::<u32>() % 100) as f32 / 100.0);
let mut rng = rand::rng();
let random = ((rng.random::<u32>() % 100) as f32 - 50.0) / 10.0;
let r_color = 0.5 + ((rng.random::<u32>() % 100) as f32 / 100.0);
particle.position = glm::vec2(object.position.x + random + offset.x, object.position.y + random + offset.y);
particle.color = glm::vec4(r_color, r_color, r_color, 1.0);
particle.life = 1.0;
Expand Down
Loading