aboutsummaryrefslogtreecommitdiff
path: root/std/os
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-07-15 20:46:12 -0400
committerGitHub <noreply@github.com>2019-07-15 20:46:12 -0400
commit3f4abe97bdbe666dbb3532c14a97e414aae4caca (patch)
treeba08f2f14e79a8c8f7e83cea0344826fefffd9a2 /std/os
parent33eaaadd01b20d1327b67758664ce1265216e471 (diff)
parentaff90c22520bbbadd56fbfd1378f161ee8a3cdb2 (diff)
downloadzig-3f4abe97bdbe666dbb3532c14a97e414aae4caca.tar.gz
zig-3f4abe97bdbe666dbb3532c14a97e414aae4caca.zip
Merge pull request #2892 from ziglang/install-with-zig-build
move some of the installation from cmake to zig build
Diffstat (limited to 'std/os')
-rw-r--r--std/os/bits/darwin.zig42
-rw-r--r--std/os/bits/freebsd.zig18
-rw-r--r--std/os/bits/linux/arm64.zig17
-rw-r--r--std/os/bits/linux/x86_64.zig17
-rw-r--r--std/os/bits/netbsd.zig18
-rw-r--r--std/os/linux.zig9
-rw-r--r--std/os/windows.zig74
-rw-r--r--std/os/windows/bits.zig171
-rw-r--r--std/os/windows/kernel32.zig12
-rw-r--r--std/os/windows/ntdll.zig15
-rw-r--r--std/os/windows/status.zig5
11 files changed, 388 insertions, 10 deletions
diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig
index 39dae6e7a1..b8d229dbe9 100644
--- a/std/os/bits/darwin.zig
+++ b/std/os/bits/darwin.zig
@@ -44,6 +44,11 @@ pub const mach_timebase_info_data = extern struct {
};
/// Renamed to Stat to not conflict with the stat function.
+/// atime, mtime, and ctime have functions to return `timespec`,
+/// because although this is a POSIX API, the layout and names of
+/// the structs are inconsistent across operating systems, and
+/// in C, macros are used to hide the differences. Here we use
+/// methods to accomplish this.
pub const Stat = extern struct {
dev: i32,
mode: u16,
@@ -52,14 +57,14 @@ pub const Stat = extern struct {
uid: u32,
gid: u32,
rdev: i32,
- atime: usize,
- atimensec: usize,
- mtime: usize,
- mtimensec: usize,
- ctime: usize,
- ctimensec: usize,
- birthtime: usize,
- birthtimensec: usize,
+ atimesec: isize,
+ atimensec: isize,
+ mtimesec: isize,
+ mtimensec: isize,
+ ctimesec: isize,
+ ctimensec: isize,
+ birthtimesec: isize,
+ birthtimensec: isize,
size: i64,
blocks: i64,
blksize: i32,
@@ -67,6 +72,27 @@ pub const Stat = extern struct {
gen: u32,
lspare: i32,
qspare: [2]i64,
+
+ pub fn atime(self: Stat) timespec {
+ return timespec{
+ .tv_sec = self.atimesec,
+ .tv_nsec = self.atimensec,
+ };
+ }
+
+ pub fn mtime(self: Stat) timespec {
+ return timespec{
+ .tv_sec = self.mtimesec,
+ .tv_nsec = self.mtimensec,
+ };
+ }
+
+ pub fn ctime(self: Stat) timespec {
+ return timespec{
+ .tv_sec = self.ctimesec,
+ .tv_nsec = self.ctimensec,
+ };
+ }
};
pub const timespec = extern struct {
diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig
index c73887d648..198857983e 100644
--- a/std/os/bits/freebsd.zig
+++ b/std/os/bits/freebsd.zig
@@ -73,6 +73,12 @@ pub const msghdr_const = extern struct {
msg_flags: i32,
};
+/// Renamed to Stat to not conflict with the stat function.
+/// atime, mtime, and ctime have functions to return `timespec`,
+/// because although this is a POSIX API, the layout and names of
+/// the structs are inconsistent across operating systems, and
+/// in C, macros are used to hide the differences. Here we use
+/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
ino: u64,
@@ -96,6 +102,18 @@ pub const Stat = extern struct {
flags: u32,
gen: u64,
__spare: [10]u64,
+
+ pub fn atime(self: Stat) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: Stat) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: Stat) timespec {
+ return self.ctim;
+ }
};
pub const timespec = extern struct {
diff --git a/std/os/bits/linux/arm64.zig b/std/os/bits/linux/arm64.zig
index bd381c16e7..e19b631292 100644
--- a/std/os/bits/linux/arm64.zig
+++ b/std/os/bits/linux/arm64.zig
@@ -396,6 +396,11 @@ pub const msghdr_const = extern struct {
};
/// Renamed to Stat to not conflict with the stat function.
+/// atime, mtime, and ctime have functions to return `timespec`,
+/// because although this is a POSIX API, the layout and names of
+/// the structs are inconsistent across operating systems, and
+/// in C, macros are used to hide the differences. Here we use
+/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
ino: u64,
@@ -414,6 +419,18 @@ pub const Stat = extern struct {
mtim: timespec,
ctim: timespec,
__unused: [3]isize,
+
+ pub fn atime(self: Stat) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: Stat) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: Stat) timespec {
+ return self.ctim;
+ }
};
pub const timespec = extern struct {
diff --git a/std/os/bits/linux/x86_64.zig b/std/os/bits/linux/x86_64.zig
index d85cac564c..499f925280 100644
--- a/std/os/bits/linux/x86_64.zig
+++ b/std/os/bits/linux/x86_64.zig
@@ -493,6 +493,11 @@ pub const msghdr_const = extern struct {
};
/// Renamed to Stat to not conflict with the stat function.
+/// atime, mtime, and ctime have functions to return `timespec`,
+/// because although this is a POSIX API, the layout and names of
+/// the structs are inconsistent across operating systems, and
+/// in C, macros are used to hide the differences. Here we use
+/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
ino: u64,
@@ -511,6 +516,18 @@ pub const Stat = extern struct {
mtim: timespec,
ctim: timespec,
__unused: [3]isize,
+
+ pub fn atime(self: Stat) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: Stat) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: Stat) timespec {
+ return self.ctim;
+ }
};
pub const timespec = extern struct {
diff --git a/std/os/bits/netbsd.zig b/std/os/bits/netbsd.zig
index d83ea82b06..ef58bd1356 100644
--- a/std/os/bits/netbsd.zig
+++ b/std/os/bits/netbsd.zig
@@ -73,6 +73,12 @@ pub const msghdr_const = extern struct {
msg_flags: i32,
};
+/// Renamed to Stat to not conflict with the stat function.
+/// atime, mtime, and ctime have functions to return `timespec`,
+/// because although this is a POSIX API, the layout and names of
+/// the structs are inconsistent across operating systems, and
+/// in C, macros are used to hide the differences. Here we use
+/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
mode: u32,
@@ -94,6 +100,18 @@ pub const Stat = extern struct {
flags: u32,
gen: u32,
__spare: [2]u32,
+
+ pub fn atime(self: Stat) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: Stat) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: Stat) timespec {
+ return self.ctim;
+ }
};
pub const timespec = extern struct {
diff --git a/std/os/linux.zig b/std/os/linux.zig
index 9d3746418f..053f30d265 100644
--- a/std/os/linux.zig
+++ b/std/os/linux.zig
@@ -94,6 +94,15 @@ pub inline fn vfork() usize {
return @inlineCall(syscall0, SYS_vfork);
}
+pub fn futimens(fd: i32, times: *const [2]timespec) usize {
+ return utimensat(fd, null, times, 0);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn utimensat(dirfd: i32, path: ?[*]const u8, times: *const [2]timespec, flags: u32) usize {
+ return syscall4(SYS_utimensat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(times), flags);
+}
+
pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
}
diff --git a/std/os/windows.zig b/std/os/windows.zig
index 2377fc00e7..ac76e8f58f 100644
--- a/std/os/windows.zig
+++ b/std/os/windows.zig
@@ -752,6 +752,66 @@ pub fn HeapDestroy(hHeap: HANDLE) void {
assert(kernel32.HeapDestroy(hHeap) != 0);
}
+pub const GetFileInformationByHandleError = error{Unexpected};
+
+pub fn GetFileInformationByHandle(
+ hFile: HANDLE,
+) GetFileInformationByHandleError!BY_HANDLE_FILE_INFORMATION {
+ var info: BY_HANDLE_FILE_INFORMATION = undefined;
+ const rc = ntdll.GetFileInformationByHandle(hFile, &info);
+ if (rc == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return info;
+}
+
+pub const SetFileTimeError = error{Unexpected};
+
+pub fn SetFileTime(
+ hFile: HANDLE,
+ lpCreationTime: ?*const FILETIME,
+ lpLastAccessTime: ?*const FILETIME,
+ lpLastWriteTime: ?*const FILETIME,
+) SetFileTimeError!void {
+ const rc = kernel32.SetFileTime(hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+ if (rc == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+/// A file time is a 64-bit value that represents the number of 100-nanosecond
+/// intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated
+/// Universal Time (UTC).
+/// This function returns the number of nanoseconds since the canonical epoch,
+/// which is the POSIX one (Jan 01, 1970 AD).
+pub fn fromSysTime(hns: i64) i64 {
+ const adjusted_epoch = hns + std.time.epoch.windows * (std.time.ns_per_s / 100);
+ return adjusted_epoch * 100;
+}
+
+pub fn toSysTime(ns: i64) i64 {
+ const hns = @divFloor(ns, 100);
+ return hns - std.time.epoch.windows * (std.time.ns_per_s / 100);
+}
+
+pub fn fileTimeToNanoSeconds(ft: FILETIME) i64 {
+ const hns = @bitCast(i64, (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime);
+ return fromSysTime(hns);
+}
+
+/// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME.
+pub fn nanoSecondsToFileTime(ns: i64) FILETIME {
+ const adjusted = @bitCast(u64, toSysTime(ns));
+ return FILETIME{
+ .dwHighDateTime = @truncate(u32, adjusted >> 32),
+ .dwLowDateTime = @truncate(u32, adjusted),
+ };
+}
+
pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
}
@@ -761,9 +821,8 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
}
pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
- // TODO well defined copy elision
+ // TODO https://github.com/ziglang/zig/issues/2765
var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
-
// > File I/O functions in the Windows API convert "/" to "\" as part of
// > converting the name to an NT-style name, except when using the "\\?\"
// > prefix as detailed in the following sections.
@@ -806,3 +865,14 @@ pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
}
return error.Unexpected;
}
+
+
+/// Call this when you made a windows NtDll call
+/// and you get an unexpected status.
+pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
+ if (std.os.unexpected_error_tracing) {
+ std.debug.warn("error.Unexpected NTSTATUS={}\n", status);
+ std.debug.dumpCurrentStackTrace(null);
+ }
+ return error.Unexpected;
+}
diff --git a/std/os/windows/bits.zig b/std/os/windows/bits.zig
index fe72a710eb..79697995f4 100644
--- a/std/os/windows/bits.zig
+++ b/std/os/windows/bits.zig
@@ -6,6 +6,7 @@ const assert = std.debug.assert;
const maxInt = std.math.maxInt;
pub const ERROR = @import("error.zig");
+pub const STATUS = @import("status.zig");
pub const LANG = @import("lang.zig");
pub const SUBLANG = @import("sublang.zig");
@@ -59,6 +60,7 @@ pub const ULONGLONG = u64;
pub const LONGLONG = i64;
pub const HLOCAL = HANDLE;
pub const LANGID = c_ushort;
+pub const NTSTATUS = ULONG;
pub const va_list = *@OpaqueType();
@@ -69,6 +71,147 @@ pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
+pub const FILE_ALL_INFORMATION = extern struct {
+ BasicInformation: FILE_BASIC_INFORMATION,
+ StandardInformation: FILE_STANDARD_INFORMATION,
+ InternalInformation: FILE_INTERNAL_INFORMATION,
+ EaInformation: FILE_EA_INFORMATION,
+ AccessInformation: FILE_ACCESS_INFORMATION,
+ PositionInformation: FILE_POSITION_INFORMATION,
+ ModeInformation: FILE_MODE_INFORMATION,
+ AlignmentInformation: FILE_ALIGNMENT_INFORMATION,
+ NameInformation: FILE_NAME_INFORMATION,
+};
+
+pub const FILE_BASIC_INFORMATION = extern struct {
+ CreationTime: LARGE_INTEGER,
+ LastAccessTime: LARGE_INTEGER,
+ LastWriteTime: LARGE_INTEGER,
+ ChangeTime: LARGE_INTEGER,
+ FileAttributes: ULONG,
+};
+
+pub const FILE_STANDARD_INFORMATION = extern struct {
+ AllocationSize: LARGE_INTEGER,
+ EndOfFile: LARGE_INTEGER,
+ NumberOfLinks: ULONG,
+ DeletePending: BOOLEAN,
+ Directory: BOOLEAN,
+};
+
+pub const FILE_INTERNAL_INFORMATION = extern struct {
+ IndexNumber: LARGE_INTEGER,
+};
+
+pub const FILE_EA_INFORMATION = extern struct {
+ EaSize: ULONG,
+};
+
+pub const FILE_ACCESS_INFORMATION = extern struct {
+ AccessFlags: ACCESS_MASK,
+};
+
+pub const FILE_POSITION_INFORMATION = extern struct {
+ CurrentByteOffset: LARGE_INTEGER,
+};
+
+pub const FILE_MODE_INFORMATION = extern struct {
+ Mode: ULONG,
+};
+
+pub const FILE_ALIGNMENT_INFORMATION = extern struct {
+ AlignmentRequirement: ULONG,
+};
+
+pub const FILE_NAME_INFORMATION = extern struct {
+ FileNameLength: ULONG,
+ FileName: [1]WCHAR,
+};
+
+pub const IO_STATUS_BLOCK = extern struct {
+ Status: usize,
+ Information: ULONG_PTR,
+};
+
+pub const FILE_INFORMATION_CLASS = extern enum {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileUnusedInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileRenameInformationBypassAccessCheck,
+ FileLinkInformationBypassAccessCheck,
+ FileVolumeNameInformation,
+ FileIdInformation,
+ FileIdExtdDirectoryInformation,
+ FileReplaceCompletionInformation,
+ FileHardLinkFullIdInformation,
+ FileIdExtdBothDirectoryInformation,
+ FileDispositionInformationEx,
+ FileRenameInformationEx,
+ FileRenameInformationExBypassAccessCheck,
+ FileDesiredStorageClassInformation,
+ FileStatInformation,
+ FileMemoryPartitionInformation,
+ FileStatLxInformation,
+ FileCaseSensitiveInformation,
+ FileLinkInformationEx,
+ FileLinkInformationExBypassAccessCheck,
+ FileStorageReserveIdInformation,
+ FileCaseSensitiveInformationForceAccessCheck,
+ FileMaximumInformation
+};
+
pub const OVERLAPPED = extern struct {
Internal: ULONG_PTR,
InternalHigh: ULONG_PTR,
@@ -104,6 +247,19 @@ pub const FileIdInfo = 18;
pub const FileIdExtdDirectoryInfo = 19;
pub const FileIdExtdDirectoryRestartInfo = 20;
+pub const BY_HANDLE_FILE_INFORMATION = extern struct {
+ dwFileAttributes: DWORD,
+ ftCreationTime: FILETIME,
+ ftLastAccessTime: FILETIME,
+ ftLastWriteTime: FILETIME,
+ dwVolumeSerialNumber: DWORD,
+ nFileSizeHigh: DWORD,
+ nFileSizeLow: DWORD,
+ nNumberOfLinks: DWORD,
+ nFileIndexHigh: DWORD,
+ nFileIndexLow: DWORD,
+};
+
pub const FILE_NAME_INFO = extern struct {
FileNameLength: DWORD,
FileName: [1]WCHAR,
@@ -561,3 +717,18 @@ pub const EXCEPTION_POINTERS = extern struct {
};
pub const VECTORED_EXCEPTION_HANDLER = stdcallcc fn (ExceptionInfo: *EXCEPTION_POINTERS) c_long;
+
+pub const OBJECT_ATTRIBUTES = extern struct {
+ Length: ULONG,
+ RootDirectory: HANDLE,
+ ObjectName: *UNICODE_STRING,
+ Attributes: ULONG,
+ SecurityDescriptor: ?*c_void,
+ SecurityQualityOfService: ?*c_void,
+};
+
+pub const UNICODE_STRING = extern struct {
+ Length: USHORT,
+ MaximumLength: USHORT,
+ Buffer: [*]WCHAR,
+}; \ No newline at end of file
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
index 494da90d72..e4edc349ab 100644
--- a/std/os/windows/kernel32.zig
+++ b/std/os/windows/kernel32.zig
@@ -83,6 +83,11 @@ pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHA
pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
+pub extern "kernel32" stdcallcc fn GetFileInformationByHandle(
+ hFile: HANDLE,
+ lpFileInformation: *BY_HANDLE_FILE_INFORMATION,
+) BOOL;
+
pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
in_hFile: HANDLE,
in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
@@ -165,6 +170,13 @@ pub extern "kernel32" stdcallcc fn SetFilePointerEx(
in_dwMoveMethod: DWORD,
) BOOL;
+pub extern "kernel32" stdcallcc fn SetFileTime(
+ hFile: HANDLE,
+ lpCreationTime: ?*const FILETIME,
+ lpLastAccessTime: ?*const FILETIME,
+ lpLastWriteTime: ?*const FILETIME,
+) BOOL;
+
pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
diff --git a/std/os/windows/ntdll.zig b/std/os/windows/ntdll.zig
index e5469cdcf9..746403fa6d 100644
--- a/std/os/windows/ntdll.zig
+++ b/std/os/windows/ntdll.zig
@@ -1,3 +1,18 @@
usingnamespace @import("bits.zig");
pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
+pub extern "NtDll" stdcallcc fn NtQueryInformationFile(FileHandle: HANDLE, IoStatusBlock: *IO_STATUS_BLOCK, FileInformation: *c_void, Length: ULONG, FileInformationClass: FILE_INFORMATION_CLASS,) NTSTATUS;
+pub extern "NtDll" stdcallcc fn NtCreateFile(
+ FileHandle: *HANDLE,
+ DesiredAccess: ACCESS_MASK,
+ ObjectAttributes: *OBJECT_ATTRIBUTES,
+ IoStatusBlock: *IO_STATUS_BLOCK,
+ AllocationSize: *LARGE_INTEGER,
+ FileAttributes: ULONG,
+ ShareAccess: ULONG,
+ CreateDisposition: ULONG,
+ CreateOptions: ULONG,
+ EaBuffer: *c_void,
+ EaLength: ULONG,
+) NTSTATUS;
+pub extern "NtDll" stdcallcc fn NtClose(Handle: HANDLE) NTSTATUS; \ No newline at end of file
diff --git a/std/os/windows/status.zig b/std/os/windows/status.zig
new file mode 100644
index 0000000000..668a736e90
--- /dev/null
+++ b/std/os/windows/status.zig
@@ -0,0 +1,5 @@
+/// The operation completed successfully.
+pub const SUCCESS = 0x00000000;
+
+/// The data was too large to fit into the specified buffer.
+pub const BUFFER_OVERFLOW = 0x80000005; \ No newline at end of file