From 86bc75846ff7f74ee9de5429dd4c6da239cdbd1e Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Mon, 18 Aug 2025 09:32:59 +0300 Subject: [PATCH 1/8] feat: Added ghostty to list of supported terminals --- src/terminal.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/terminal.zig b/src/terminal.zig index 7d01598..d81042d 100644 --- a/src/terminal.zig +++ b/src/terminal.zig @@ -76,7 +76,7 @@ fn parsePpidFromStat(stat_str: []const u8) !i32 { } fn isTerminalEmulator(process_name: []const u8) bool { - const terminal_emulators = [_][]const u8{ "alacritty", "kitty", "gnome-terminal", "xterm", "konsole", "urxvt", "st", "terminator", "tilix", "xfce4-terminal", "tmux", "screen", "terminology", "lxterminal", "rxvt", "sakura", "mate-terminal", "terminology", "konsole", "terminator" }; + const terminal_emulators = [_][]const u8{ "alacritty", "kitty", "gnome-terminal", "xterm", "konsole", "urxvt", "st", "terminator", "tilix", "xfce4-terminal", "tmux", "screen", "terminology", "lxterminal", "rxvt", "sakura", "mate-terminal", "terminology", "konsole", "terminator", "ghostty" }; for (terminal_emulators) |emulator| { if (std.mem.eql(u8, process_name, emulator)) { return true; From ab1ec104385863e708055a9d9dbcb09b4773ad94 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Wed, 20 Aug 2025 15:44:50 +0300 Subject: [PATCH 2/8] fix: Stop assuming logo lines length is the same as info length --- src/ascii_art.zig | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/ascii_art.zig b/src/ascii_art.zig index 59cd602..8555749 100644 --- a/src/ascii_art.zig +++ b/src/ascii_art.zig @@ -1,5 +1,9 @@ const std = @import("std"); +fn safeNextLine(iter: *std.mem.SplitIterator(u8, .sequence)) []const u8 { + return iter.next() orelse ""; +} + pub fn printNeofetchStyle( distro_name: []const u8, desktop_env: []const u8, @@ -19,33 +23,30 @@ pub fn printNeofetchStyle( ) !void { const logo = getDistroLogo(distro_name); - // ANSI escape codes - const blue = "\x1b[38;2;135;206;250m"; // Blue text - const bold = "\x1b[1m"; // Bold text - const reset = "\x1b[0m"; // Reset formatting + const blue = "\x1b[38;2;135;206;250m"; + const bold = "\x1b[1m"; + const reset = "\x1b[0m"; - // Split the logo into lines var logo_lines = std.mem.splitSequence(u8, logo, "\n"); - std.debug.print("{s}{s:<60}{s} {s}{s}{s}{s}\n", .{ color, logo_lines.next().?, reset, blue, bold, user_at_hostname, reset }); - std.debug.print("{s}{s:<60}{s} {s}\n", .{ color, logo_lines.next().?, reset, "-----------------" }); + std.debug.print("{s}{s:<60}{s} {s}{s}{s}{s}\n", .{ color, safeNextLine(&logo_lines), reset, blue, bold, user_at_hostname, reset }); + std.debug.print("{s}{s:<60}{s} {s}\n", .{ color, safeNextLine(&logo_lines), reset, "-----------------" }); - // Print each line with the label in bold - std.debug.print("{s}{s:<60}{s} {s}Distro: {s}\n", .{ color, logo_lines.next().?, reset, bold, distro_name }); - std.debug.print("{s}{s:<60}{s} {s}DE/WM: {s}\n", .{ color, logo_lines.next().?, reset, bold, desktop_env }); - std.debug.print("{s}{s:<60}{s} {s}Kernel Version: {s}", .{ color, logo_lines.next().?, reset, bold, kernel_version }); - std.debug.print("{s}{s:<60}{s} {s}Uptime: {s}", .{ color, logo_lines.next().?, reset, bold, uptime }); - std.debug.print("{s}{s:<60}{s} {s}Shell: {s}\n", .{ color, logo_lines.next().?, reset, bold, shell_version }); - std.debug.print("{s}{s:<60}{s} {s}Packages: {}\n", .{ color, logo_lines.next().?, reset, bold, package_count }); - std.debug.print("{s}{s:<60}{s} {s}Hardware Model: {s}\n", .{ color, logo_lines.next().?, reset, bold, hardware_model }); - std.debug.print("{s}{s:<60}{s} {s}CPU: {s}\n", .{ color, logo_lines.next().?, reset, bold, cpu }); - std.debug.print("{s}{s:<60}{s} {s}GPU: {s}\n", .{ color, logo_lines.next().?, reset, bold, gpu }); - std.debug.print("{s}{s:<60}{s} {s}Terminal: {s}\n", .{ color, logo_lines.next().?, reset, bold, terminal_name }); - std.debug.print("{s}{s:<60}{s} {s}Theme: {s}\n", .{ color, logo_lines.next().?, reset, bold, theme }); - std.debug.print("{s}{s:<60}{s} {s}Icons: {s}\n", .{ color, logo_lines.next().?, reset, bold, icons }); - std.debug.print("{s}{s:<60}{s} {s}Memory: {s}\n", .{ color, logo_lines.next().?, reset, bold, memory_info }); + std.debug.print("{s}{s:<60}{s} {s}Distro: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, distro_name }); + std.debug.print("{s}{s:<60}{s} {s}DE/WM: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, desktop_env }); + std.debug.print("{s}{s:<60}{s} {s}Kernel Version: {s}", .{ color, safeNextLine(&logo_lines), reset, bold, kernel_version }); + std.debug.print("{s}{s:<60}{s} {s}Uptime: {s}", .{ color, safeNextLine(&logo_lines), reset, bold, uptime }); + std.debug.print("{s}{s:<60}{s} {s}Shell: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, shell_version }); + std.debug.print("{s}{s:<60}{s} {s}Packages: {}\n", .{ color, safeNextLine(&logo_lines), reset, bold, package_count }); + std.debug.print("{s}{s:<60}{s} {s}Hardware Model: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, hardware_model }); + std.debug.print("{s}{s:<60}{s} {s}CPU: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, cpu }); + std.debug.print("{s}{s:<60}{s} {s}GPU: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, gpu }); + std.debug.print("{s}{s:<60}{s} {s}Terminal: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, terminal_name }); + std.debug.print("{s}{s:<60}{s} {s}Theme: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, theme }); + std.debug.print("{s}{s:<60}{s} {s}Icons: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, icons }); + std.debug.print("{s}{s:<60}{s} {s}Memory: {s}\n", .{ color, safeNextLine(&logo_lines), reset, bold, memory_info }); - // Print the remaining lines of the logo (if any) + // print remaining logo lines (if longer than info block) while (logo_lines.next()) |logo_line| { std.debug.print("{s}{s}{s}\n", .{ color, logo_line, reset }); } From 90dfccd86ffc1b4babe56e66182d79ae8714af2f Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Tue, 26 Aug 2025 12:06:34 +0300 Subject: [PATCH 3/8] chore: Updated to zig 0.15.1 --- build.zig | 16 ++++++++++------ src/hardware.zig | 10 +++++----- src/machine.zig | 10 +++++----- src/package.zig | 2 +- src/system.zig | 11 ++++++----- src/theme.zig | 10 +++++----- 6 files changed, 32 insertions(+), 27 deletions(-) diff --git a/build.zig b/build.zig index 64f563d..8d225c6 100644 --- a/build.zig +++ b/build.zig @@ -19,9 +19,11 @@ pub fn build(b: *std.Build) void { .name = "zfetch", // In this case the main source file is merely a path, however, in more // complicated build scripts, this could be a generated file. - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); // This declares intent for the executable to be installed into the @@ -55,9 +57,11 @@ pub fn build(b: *std.Build) void { // Creates a step for unit testing. This only builds the test executable // but does not run it. const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); const run_unit_tests = b.addRunArtifact(unit_tests); diff --git a/src/hardware.zig b/src/hardware.zig index e86f9c8..f963b10 100644 --- a/src/hardware.zig +++ b/src/hardware.zig @@ -61,8 +61,8 @@ pub fn getGPUInfo(allocator: std.mem.Allocator) ![]u8 { } fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]const u8 { - var result = std.ArrayList(u8).init(allocator); - defer result.deinit(); + var result = std.ArrayListUnmanaged(u8){}; + defer result.deinit(allocator); var child = std.process.Child.init(argv, allocator); child.stdout_behavior = .Pipe; @@ -70,12 +70,12 @@ fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]con try child.spawn(); - const stdout = try child.stdout.?.reader().readAllAlloc(allocator, std.math.maxInt(usize)); + const stdout = try child.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(stdout); - try result.appendSlice(stdout); + try result.appendSlice(allocator, stdout); _ = try child.wait(); - return result.toOwnedSlice(); + return result.toOwnedSlice(allocator); } diff --git a/src/machine.zig b/src/machine.zig index 7113a5c..4fb75f3 100644 --- a/src/machine.zig +++ b/src/machine.zig @@ -17,8 +17,8 @@ pub fn getHardwareModel(allocator: std.mem.Allocator) ![]u8 { } fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 { - var result = std.ArrayList(u8).init(allocator); - defer result.deinit(); + var result = std.ArrayListUnmanaged(u8){}; + defer result.deinit(allocator); var child = std.process.Child.init(argv, allocator); child.stdout_behavior = .Pipe; @@ -26,12 +26,12 @@ fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 try child.spawn(); - const stdout = try child.stdout.?.reader().readAllAlloc(allocator, std.math.maxInt(usize)); + const stdout = try child.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(stdout); - try result.appendSlice(stdout); + try result.appendSlice(allocator, stdout); _ = try child.wait(); - return result.toOwnedSlice(); + return result.toOwnedSlice(allocator); } diff --git a/src/package.zig b/src/package.zig index 3298a75..2dbc8dd 100644 --- a/src/package.zig +++ b/src/package.zig @@ -64,7 +64,7 @@ fn getFedoraPackageCount(allocator: std.mem.Allocator) !usize { try process.spawn(); - const stdout = try process.stdout.?.reader().readAllAlloc(allocator, std.math.maxInt(usize)); + const stdout = try process.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(stdout); // Wait for the process to finish and check its exit code diff --git a/src/system.zig b/src/system.zig index 5171a62..6d8100d 100644 --- a/src/system.zig +++ b/src/system.zig @@ -101,8 +101,8 @@ fn parseMemInfoValue(line: []const u8) !u64 { } pub fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 { - var result = std.ArrayList(u8).init(allocator); - defer result.deinit(); + var result = std.ArrayListUnmanaged(u8){}; // Andrew Kelley made me do this + defer result.deinit(allocator); var child = std.process.Child.init(argv, allocator); child.stdout_behavior = .Pipe; @@ -110,12 +110,13 @@ pub fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![ try child.spawn(); - const stdout = try child.stdout.?.reader().readAllAlloc(allocator, std.math.maxInt(usize)); + //const stdout = try child.stdout.?.reader(&buf).readAllAlloc(allocator, std.math.maxInt(usize)); + const stdout = try child.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(stdout); - try result.appendSlice(stdout); + try result.appendSlice(allocator, stdout); _ = try child.wait(); - return result.toOwnedSlice(); + return try result.toOwnedSlice(allocator); } diff --git a/src/theme.zig b/src/theme.zig index cb03f2c..0e87782 100644 --- a/src/theme.zig +++ b/src/theme.zig @@ -107,8 +107,8 @@ fn getGtkSettingsFromGsettings(allocator: std.mem.Allocator) !GtkSettings { } } pub fn runCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 { - var result = std.ArrayList(u8).init(allocator); - defer result.deinit(); + var result = std.ArrayListUnmanaged(u8){}; + defer result.deinit(allocator); var child = std.process.Child.init(argv, allocator); child.stdout_behavior = .Pipe; @@ -116,12 +116,12 @@ pub fn runCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 try child.spawn(); - const stdout = try child.stdout.?.reader().readAllAlloc(allocator, std.math.maxInt(usize)); + const stdout = try child.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); defer allocator.free(stdout); - try result.appendSlice(stdout); + try result.appendSlice(allocator, stdout); _ = try child.wait(); - return result.toOwnedSlice(); + return result.toOwnedSlice(allocator); } From ca135ba5e9178a2145ce7f9c1760f6047486015d Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Tue, 26 Aug 2025 15:46:58 +0300 Subject: [PATCH 4/8] ci: update to zig 0.15.1 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6275800..13c0a3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: - name: Install zig uses: mlugg/setup-zig@v1 with: - version: 0.14.0 + version: 0.15.1 - name: Build run: zig build -Dtarget=x86_64-linux-gnu From f6eeb72eef23a24b5de41a7e4afc02baa02747f5 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Thu, 28 Aug 2025 11:59:18 +0300 Subject: [PATCH 5/8] Add Nixos, Need for better ascii art --- src/ascii_art.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ascii_art.zig b/src/ascii_art.zig index 8555749..553f2e6 100644 --- a/src/ascii_art.zig +++ b/src/ascii_art.zig @@ -1,5 +1,6 @@ const std = @import("std"); +// We stop assuming logo lines is of the same length as the info block fn safeNextLine(iter: *std.mem.SplitIterator(u8, .sequence)) []const u8 { return iter.next() orelse ""; } @@ -204,6 +205,20 @@ fn getDistroLogo(distro_name: []const u8) []const u8 { \\ -+ \\ - }, + .{ + "NixOS", + \\ _ _ _ _ + \\ __/ / \_____/ \ \__ + \\ _/ _/ \_ \_ + \\ /_ / _ _____ _ \ _\ + \\ /_/ / \/ _ \/ \ \_\ + \\ \_\ \_/\_/ \_/\_/ /_/ + \\ _/ / \ \_ + \\ /__/ __ ___ __ \__\ + \\ \_ \ \ / _ \ / / _/ + \\ \_ \ V / \ V / _/ + \\ \_/ \_/ \_/ + }, }); // Use the normalized name to look up the logo From 548093a023e5cda3a4e24b8b14d79dbb8cf7aab0 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Thu, 28 Aug 2025 12:00:21 +0300 Subject: [PATCH 6/8] get some GPU hardware info --- src/hardware.zig | 82 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/src/hardware.zig b/src/hardware.zig index f963b10..ac40689 100644 --- a/src/hardware.zig +++ b/src/hardware.zig @@ -45,19 +45,81 @@ pub fn getCPUInfo(allocator: std.mem.Allocator) ![]u8 { } pub fn getGPUInfo(allocator: std.mem.Allocator) ![]u8 { - const lspci_output = try executeCommand(allocator, &[_][]const u8{"lspci"}); - defer allocator.free(lspci_output); - - // Parse the GPU information - var lines = std.mem.splitSequence(u8, lspci_output, "\n"); - while (lines.next()) |line| { - if (std.mem.indexOf(u8, line, "VGA compatible controller:")) |vga_index| { - const gpu_info = std.mem.trim(u8, line[vga_index + "VGA compatible controller:".len ..], " "); - return try allocator.dupe(u8, gpu_info); + // --- 1. Try lspci --- + if (executeCommand(allocator, &[_][]const u8{"lspci"})) |lspci_output| { + defer allocator.free(lspci_output); + + var lines = std.mem.splitSequence(u8, lspci_output, "\n"); + while (lines.next()) |line| { + if (std.mem.indexOf(u8, line, "VGA compatible controller:")) |vga_index| { + const gpu_info = std.mem.trim( + u8, + line[vga_index + "VGA compatible controller:".len ..], + " " + ); + return try allocator.dupe(u8, gpu_info); + } } + } else |_| { + // silently ignore if command missing } - return try allocator.dupe(u8, "Unknown"); + // --- 2. Try glxinfo --- + if (executeCommand(allocator, &[_][]const u8{"glxinfo"})) |glx_output| { + defer allocator.free(glx_output); + + var lines = std.mem.splitSequence(u8, glx_output, "\n"); + while (lines.next()) |line| { + if (std.mem.startsWith(u8, line, "OpenGL renderer string:")) { + const gpu_info = std.mem.trim( + u8, + line["OpenGL renderer string:".len ..], + " " + ); + return try allocator.dupe(u8, gpu_info); + } + } + } else |_| {} + + // --- 3. Try vulkaninfo --- + if (executeCommand(allocator, &[_][]const u8{"vulkaninfo"})) |vk_output| { + defer allocator.free(vk_output); + + var lines = std.mem.splitSequence(u8, vk_output, "\n"); + while (lines.next()) |line| { + if (std.mem.indexOf(u8, line, "deviceName")) |idx| { + const gpu_info = std.mem.trim( + u8, + line[idx + "deviceName".len ..], + " :\t" + ); + return try allocator.dupe(u8, gpu_info); + } + } + } else |_| {} + + // --- 4. Try sysfs (/sys/class/drm) --- + if (std.fs.cwd().openFile("/sys/class/drm/card0/device/vendor", .{})) |vendor_file| { + defer vendor_file.close(); + if (std.fs.cwd().openFile("/sys/class/drm/card0/device/device", .{})) |device_file| { + defer device_file.close(); + + const vendor = try vendor_file.readToEndAlloc(allocator, 16); + defer allocator.free(vendor); + const device = try device_file.readToEndAlloc(allocator, 16); + defer allocator.free(device); + + const combined = try std.fmt.allocPrint( + allocator, + "PCI Vendor: {s}, Device: {s}", + .{ std.mem.trim(u8, vendor, "\n "), std.mem.trim(u8, device, "\n ") } + ); + return combined; + } else |_| {} + } else |_| {} + + // --- Fallback --- + return try allocator.dupe(u8, "Unknown GPU"); } fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]const u8 { From 3d143f6a54094e7df280c55f9f03a8f0f884fb81 Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Thu, 28 Aug 2025 12:01:02 +0300 Subject: [PATCH 7/8] special uptime function --- src/main.zig | 9 ++++++++- src/system.zig | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index e578cd5..345353e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -55,7 +55,14 @@ pub fn main() !void { const shell_version = try system.getShellVersion(allocator); defer allocator.free(shell_version); - const uptime = try system.executeCommand(allocator, &[_][]const u8{ "uptime", "-p" }); + const uptime = system.executeUptimeCommand(allocator, &[_][]const u8{ "uptime", "-p" }) catch |err| blk: { + // Because NixOS does not have a -p + if (err == error.CommandFailed) { + break :blk try system.executeUptimeCommand(allocator, &[_][]const u8{ "uptime" }); + } else { + return err; + } + }; defer allocator.free(uptime); //read hardware model diff --git a/src/system.zig b/src/system.zig index 6d8100d..3a8b1e9 100644 --- a/src/system.zig +++ b/src/system.zig @@ -120,3 +120,27 @@ pub fn executeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![ return try result.toOwnedSlice(allocator); } + +pub fn executeUptimeCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![] u8 { + var result = std.ArrayListUnmanaged(u8){}; + defer result.deinit(allocator); + + var child = std.process.Child.init(argv, allocator); + child.stdout_behavior = .Pipe; + child.stderr_behavior = .Pipe; + + try child.spawn(); + + const stdout = try child.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); + defer allocator.free(stdout); + + try result.appendSlice(allocator, stdout); + + const term = try child.wait(); + if (term.Exited != 0) { + return error.CommandFailed; + } + + return result.toOwnedSlice(allocator); +} + From b4bfe566fd9927b0a479edf4543515d8e8d27a1b Mon Sep 17 00:00:00 2001 From: pop-ecx Date: Thu, 28 Aug 2025 12:01:23 +0300 Subject: [PATCH 8/8] Get NixOS package count --- src/package.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/package.zig b/src/package.zig index 2dbc8dd..3d3e7ed 100644 --- a/src/package.zig +++ b/src/package.zig @@ -14,6 +14,8 @@ pub fn getInstalledPackagesCount(allocator: std.mem.Allocator) !usize { return try getDebianPackageCount(allocator); } else if (std.mem.eql(u8, distro_family, "fedora") or std.mem.eql(u8, distro_family, "rhel")) { return try getFedoraPackageCount(allocator); + } else if (std.mem.eql(u8, distro_family, "nixos")) { + return try getNixPackageCount(allocator); } else { return error.UnsupportedDistro; } @@ -88,3 +90,29 @@ fn getFedoraPackageCount(allocator: std.mem.Allocator) !usize { return count; } + +fn getNixPackageCount(allocator: std.mem.Allocator) !usize { + var process = std.process.Child.init(&.{ "nix-store", "--query", "--requisites", "/run/current-system" }, allocator); + + process.stdout_behavior = .Pipe; + process.stderr_behavior = .Pipe; + + try process.spawn(); + const stdout = try process.stdout.?.readToEndAlloc(allocator, std.math.maxInt(usize)); + defer allocator.free(stdout); + + const term = try process.wait(); + switch (term) { + .Exited => |code| if (code != 0) return error.NixCommandFailed, + else => return error.NixCommandFailed, + } + + var count: usize = 0; + var lines = std.mem.splitSequence(u8, stdout, "\n"); + while (lines.next()) |line| { + if (line.len > 0) { + count += 1; + } + } + return count; +}