diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2016-02-09 08:35:32 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2016-02-09 08:35:32 -0800 |
commit | 1e378a81ceeb06c5899f9c7bfc8dc2f46c52a446 (patch) | |
tree | a6d38070bc35996ac9ae2796af1f5992f9bb1bcf | |
parent | cfe792f894cf0880a810ff0149592a91b3930da8 (diff) |
361.28361.28
-rw-r--r-- | files.c | 53 | ||||
-rw-r--r-- | files.h | 1 | ||||
-rw-r--r-- | install-from-cwd.c | 23 | ||||
-rw-r--r-- | manifest.c | 126 | ||||
-rw-r--r-- | nvidia-installer.c | 4 | ||||
-rw-r--r-- | nvidia-installer.h | 12 | ||||
-rw-r--r-- | option_table.h | 11 | ||||
-rw-r--r-- | version.mk | 2 |
8 files changed, 170 insertions, 62 deletions
@@ -630,6 +630,8 @@ int set_destinations(Options *op, Package *p) case FILE_TYPE_OPENGL_SYMLINK: case FILE_TYPE_GLVND_LIB: case FILE_TYPE_GLVND_SYMLINK: + case FILE_TYPE_GLX_CLIENT_LIB: + case FILE_TYPE_GLX_CLIENT_SYMLINK: if (p->entries[i].compat_arch == FILE_COMPAT_ARCH_COMPAT32) { prefix = op->compat32_prefix; dir = op->compat32_libdir; @@ -1157,6 +1159,7 @@ static void add_kernel_module_helper(Options *op, Package *p, FILE_TYPE_KERNEL_MODULE, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NONE, + FILE_GLVND_DONT_CARE, 0644); } @@ -2089,6 +2092,7 @@ void process_libGL_la_files(Options *op, Package *p) FILE_TYPE_LIBGL_LA, p->entries[i].tls_class, p->entries[i].compat_arch, + p->entries[i].glvnd, p->entries[i].mode); } @@ -2165,6 +2169,7 @@ void process_dot_desktop_files(Options *op, Package *p) FILE_TYPE_DOT_DESKTOP, p->entries[i].tls_class, p->entries[i].compat_arch, + p->entries[i].glvnd, p->entries[i].mode); } } @@ -2243,6 +2248,7 @@ void process_dkms_conf(Options *op, Package *p) FILE_TYPE_DKMS_CONF, p->entries[i].tls_class, p->entries[i].compat_arch, + p->entries[i].glvnd, p->entries[i].mode); } } @@ -3135,6 +3141,7 @@ void add_libgl_abi_symlink(Options *op, Package *p) FILE_TYPE_OPENGL_SYMLINK, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NATIVE, + FILE_GLVND_DONT_CARE, 0000); } else { nvfree(libgl); @@ -3275,7 +3282,10 @@ int check_libglvnd_files(Options *op, Package *p) log_printf(op, NULL, "Will not install libglvnd libraries."); for (i = 0; i < p->num_entries; i++) { if (p->entries[i].type == FILE_TYPE_GLVND_LIB || - p->entries[i].type == FILE_TYPE_GLVND_SYMLINK) { + p->entries[i].type == FILE_TYPE_GLVND_SYMLINK || + ((p->entries[i].type == FILE_TYPE_GLX_CLIENT_LIB || + p->entries[i].type == FILE_TYPE_GLX_CLIENT_SYMLINK) && + p->entries[i].glvnd == FILE_GLVND_GLVND_ONLY)) { invalidate_package_entry(&(p->entries[i])); } } @@ -3285,3 +3295,44 @@ int check_libglvnd_files(Options *op, Package *p) return TRUE; } +/* Select between GLVND and non-GLVND installation; invalidate any + * package entries incompatible with the selection */ + +void select_glvnd(Options *op, Package *p) +{ + int i; + + if (op->expert) { + const char *choices[2] = { + "GLVND", + "non-GLVND" + }; + const char *question = "The NVIDIA OpenGL GLX client libraries may be " + "installed using the GL Vendor Neutral " + "Dispatch (GLVND) architecture, or using a " + "traditional, non-GLVND architecture. Choosing " + "GLVND will allow GLVND-compliant GLX client " + "libraries from other OpenGL implementations " + "to coexist with the NVIDIA GLX client " + "libraries, but may result in compatibility " + "problems with some programs. What type of GLX " + "client libraries do you want to install?"; + + op->glvnd_glx_client = ui_multiple_choice(op, choices, 2, + op->glvnd_glx_client ? 0 : 1, + "%s", question) == 0; + } + + ui_log(op, "Will install %sGLVND GLX client libraries.", + op->glvnd_glx_client ? "" : "non-"); + + for (i = 0; i < p->num_entries; i++) { + if (op->glvnd_glx_client && + p->entries[i].glvnd == FILE_GLVND_NON_GLVND_ONLY) { + invalidate_package_entry(&(p->entries[i])); + } else if (!op->glvnd_glx_client && + p->entries[i].glvnd == FILE_GLVND_GLVND_ONLY) { + invalidate_package_entry(&(p->entries[i])); + } + } +} @@ -72,5 +72,6 @@ int is_subdirectory(const char *dir, const char *subdir, int *is_subdir); void add_libgl_abi_symlink(Options *op, Package *p); int check_libglvnd_files(Options *op, Package *p); +void select_glvnd(Options *op, Package *p); #endif /* __NVIDIA_INSTALLER_FILES_H__ */ diff --git a/install-from-cwd.c b/install-from-cwd.c index c7f4942..da42063 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -243,6 +243,8 @@ int install_from_cwd(Options *op) if (op->no_opengl_files) { remove_opengl_files_from_package(op, p); + } else { + select_glvnd(op, p); } /* @@ -967,6 +969,22 @@ static Package *parse_manifest (Options *op) entry.target = NULL; } + /* some files are exclusive to GLVND or non-GLVND installations */ + + if (entry.caps.glvnd_select) { + char *type = read_next_word(c, &c); + + if (!type) goto invalid_manifest_file; + + if (strcmp(type, "GLVND") == 0) { + entry.glvnd = FILE_GLVND_GLVND_ONLY; + } else if (strcmp(type, "NON_GLVND") == 0) { + entry.glvnd = FILE_GLVND_NON_GLVND_ONLY; + } else { + goto invalid_manifest_file; + } + } + /* * as a convenience for later, set the 'name' pointer to * the basename contained in 'file' (ie the portion of @@ -987,6 +1005,7 @@ static Package *parse_manifest (Options *op) entry.type, entry.tls_class, entry.compat_arch, + entry.glvnd, entry.mode); entry_success = TRUE; @@ -1048,6 +1067,7 @@ void add_package_entry(Package *p, PackageEntryFileType type, PackageEntryFileTlsClass tls_class, PackageEntryFileCompatArch compat_arch, + PackageEntryFileGLVND glvnd, mode_t mode) { int n; @@ -1070,6 +1090,7 @@ void add_package_entry(Package *p, p->entries[n].mode = mode; p->entries[n].caps = get_file_type_capabilities(type); p->entries[n].compat_arch = compat_arch; + p->entries[n].glvnd = glvnd; if (stat(p->entries[n].file, &stat_buf) != -1) { p->entries[n].inode = stat_buf.st_ino; @@ -1433,6 +1454,7 @@ generate_done: FILE_TYPE_MODULE_SIGNING_KEY, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NONE, + FILE_GLVND_DONT_CARE, 0444); ui_message(op, "An X.509 certificate containing the public signing " @@ -1465,6 +1487,7 @@ generate_done: FILE_TYPE_MODULE_SIGNING_KEY, FILE_TLS_CLASS_NONE, FILE_COMPAT_ARCH_NONE, + FILE_GLVND_DONT_CARE, 0400); ui_message(op, "The private signing key will be installed to %s/%s. " @@ -34,7 +34,9 @@ _is_opengl, \ _is_temporary, \ _is_wrapper, \ - _inherit_path) \ + _inherit_path, \ + _glvnd_select \ + ) \ #_name , FILE_TYPE_ ## _name , \ { \ .has_arch = _has_arch, \ @@ -47,6 +49,7 @@ .is_temporary = _is_temporary, \ .is_wrapper = _is_wrapper, \ .inherit_path = _inherit_path, \ + .glvnd_select = _glvnd_select, \ } /* @@ -60,65 +63,68 @@ static const struct { } packageEntryFileTypeTable[] = { /* - * inherit_path ------------------------------------------+ - * is_wrapper ---------------------------------------+ | - * is_temporary ------------------------------------+ | | - * is_opengl ---------------------------------+ | | | - * is_shared_lib ------------------------------+ | | | | - * is_symlink ---------------------------+ | | | | | - * has_path ------------------------+ | | | | | | - * installable ---------------------+ | | | | | | | - * has_tls_class ------------------+ | | | | | | | | - * has_arch ---------------+ | | | | | | | | | - * | | | | | | | | | | + * glvnd_select ---------------------------------------------+ + * inherit_path ------------------------------------------+ | + * is_wrapper ---------------------------------------+ | | + * is_temporary ------------------------------------+ | | | + * is_opengl ---------------------------------+ | | | | + * is_shared_lib ------------------------------+ | | | | | + * is_symlink ---------------------------+ | | | | | | + * has_path ------------------------+ | | | | | | | + * installable ---------------------+ | | | | | | | | + * has_tls_class ------------------+ | | | | | | | | | + * has_arch ---------------+ | | | | | | | | | | + * | | | | | | | | | | | */ - { ENTRY(KERNEL_MODULE_SRC, F, F, T, F, F, F, F, F, F, T) }, - { ENTRY(KERNEL_MODULE, F, F, T, F, F, F, F, F, F, F) }, - { ENTRY(OPENGL_HEADER, F, F, T, T, F, F, T, F, F, F) }, - { ENTRY(CUDA_ICD, F, F, T, F, F, F, F, F, F, F) }, - { ENTRY(OPENGL_LIB, T, F, T, F, F, T, T, F, F, F) }, - { ENTRY(CUDA_LIB, T, F, T, T, F, T, F, F, F, F) }, - { ENTRY(OPENCL_LIB, T, F, T, T, F, T, F, F, F, F) }, - { ENTRY(OPENCL_WRAPPER_LIB, T, F, T, T, F, T, F, F, T, F) }, - { ENTRY(OPENCL_LIB_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, - { ENTRY(OPENCL_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T, F) }, - { ENTRY(LIBGL_LA, T, F, T, F, F, F, T, T, F, F) }, - { ENTRY(TLS_LIB, T, T, T, T, F, T, T, F, F, F) }, - { ENTRY(UTILITY_LIB, T, F, T, F, F, T, F, F, F, F) }, - { ENTRY(DOCUMENTATION, F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(APPLICATION_PROFILE, F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(MANPAGE, F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(EXPLICIT_PATH, F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(OPENGL_SYMLINK, T, F, F, F, T, F, T, F, F, F) }, - { ENTRY(CUDA_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, - { ENTRY(TLS_SYMLINK, T, T, F, T, T, F, T, F, F, F) }, - { ENTRY(UTILITY_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, - { ENTRY(INSTALLER_BINARY, F, F, T, F, F, F, F, F, F, F) }, - { ENTRY(UTILITY_BINARY, F, F, T, F, F, F, F, F, F, F) }, - { ENTRY(UTILITY_BIN_SYMLINK, F, F, F, F, T, F, F, F, F, F) }, - { ENTRY(DOT_DESKTOP, F, F, T, T, F, F, F, T, F, F) }, - { ENTRY(XMODULE_SHARED_LIB, F, F, T, T, F, T, F, F, F, F) }, - { ENTRY(XMODULE_SYMLINK, F, F, F, T, T, F, F, F, F, F) }, - { ENTRY(GLX_MODULE_SHARED_LIB, F, F, T, T, F, T, T, F, F, F) }, - { ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T, F, F, F) }, - { ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F, F, F, F) }, - { ENTRY(VDPAU_LIB, T, F, T, T, F, T, F, F, F, F) }, - { ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, - { ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F, F, F, F) }, - { ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, - { ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F, F, F, F) }, - { ENTRY(ENCODEAPI_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, - { ENTRY(VGX_LIB, F, F, T, F, F, T, F, F, F, F) }, - { ENTRY(VGX_LIB_SYMLINK, F, F, F, F, T, F, F, F, F, F) }, - { ENTRY(NVIDIA_MODPROBE, F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(NVIDIA_MODPROBE_MANPAGE,F, F, T, T, F, F, F, F, F, F) }, - { ENTRY(MODULE_SIGNING_KEY, F, F, T, F, F, F, F, T, F, F) }, - { ENTRY(NVIFR_LIB, T, F, T, F, F, T, F, F, F, F) }, - { ENTRY(NVIFR_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, - { ENTRY(XORG_OUTPUTCLASS_CONFIG,F, F, T, F, F, F, F, F, F, F) }, - { ENTRY(DKMS_CONF ,F, F, T, F, F, F, F, T, F, T) }, - { ENTRY(GLVND_LIB, T, F, T, F, F, T, T, F, F, F) }, - { ENTRY(GLVND_SYMLINK, T, F, F, F, T, F, T, F, F, F) }, + { ENTRY(KERNEL_MODULE_SRC, F, F, T, F, F, F, F, F, F, T, F) }, + { ENTRY(KERNEL_MODULE, F, F, T, F, F, F, F, F, F, F, F) }, + { ENTRY(OPENGL_HEADER, F, F, T, T, F, F, T, F, F, F, F) }, + { ENTRY(CUDA_ICD, F, F, T, F, F, F, F, F, F, F, F) }, + { ENTRY(OPENGL_LIB, T, F, T, F, F, T, T, F, F, F, F) }, + { ENTRY(CUDA_LIB, T, F, T, T, F, T, F, F, F, F, F) }, + { ENTRY(OPENCL_LIB, T, F, T, T, F, T, F, F, F, F, F) }, + { ENTRY(OPENCL_WRAPPER_LIB, T, F, T, T, F, T, F, F, T, F, F) }, + { ENTRY(OPENCL_LIB_SYMLINK, T, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(OPENCL_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T, F, F) }, + { ENTRY(LIBGL_LA, T, F, T, F, F, F, T, T, F, F, F) }, + { ENTRY(TLS_LIB, T, T, T, T, F, T, T, F, F, F, F) }, + { ENTRY(UTILITY_LIB, T, F, T, F, F, T, F, F, F, F, F) }, + { ENTRY(DOCUMENTATION, F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(APPLICATION_PROFILE, F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(MANPAGE, F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(EXPLICIT_PATH, F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(OPENGL_SYMLINK, T, F, F, F, T, F, T, F, F, F, F) }, + { ENTRY(CUDA_SYMLINK, T, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(TLS_SYMLINK, T, T, F, T, T, F, T, F, F, F, F) }, + { ENTRY(UTILITY_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(INSTALLER_BINARY, F, F, T, F, F, F, F, F, F, F, F) }, + { ENTRY(UTILITY_BINARY, F, F, T, F, F, F, F, F, F, F, F) }, + { ENTRY(UTILITY_BIN_SYMLINK, F, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(DOT_DESKTOP, F, F, T, T, F, F, F, T, F, F, F) }, + { ENTRY(XMODULE_SHARED_LIB, F, F, T, T, F, T, F, F, F, F, F) }, + { ENTRY(XMODULE_SYMLINK, F, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(GLX_MODULE_SHARED_LIB, F, F, T, T, F, T, T, F, F, F, F) }, + { ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T, F, F, F, F) }, + { ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(VDPAU_LIB, T, F, T, T, F, T, F, F, F, F, F) }, + { ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F, F, F, F, F) }, + { ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F, F, F, F, F) }, + { ENTRY(ENCODEAPI_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(VGX_LIB, F, F, T, F, F, T, F, F, F, F, F) }, + { ENTRY(VGX_LIB_SYMLINK, F, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(NVIDIA_MODPROBE, F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(NVIDIA_MODPROBE_MANPAGE,F, F, T, T, F, F, F, F, F, F, F) }, + { ENTRY(MODULE_SIGNING_KEY, F, F, T, F, F, F, F, T, F, F, F) }, + { ENTRY(NVIFR_LIB, T, F, T, F, F, T, F, F, F, F, F) }, + { ENTRY(NVIFR_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F, F) }, + { ENTRY(XORG_OUTPUTCLASS_CONFIG,F, F, T, F, F, F, F, F, F, F, F) }, + { ENTRY(DKMS_CONF ,F, F, T, F, F, F, F, T, F, T, F) }, + { ENTRY(GLVND_LIB, T, F, T, F, F, T, T, F, F, F, F) }, + { ENTRY(GLVND_SYMLINK, T, F, F, F, T, F, T, F, F, F, F) }, + { ENTRY(GLX_CLIENT_LIB, T, F, T, F, F, T, T, F, F, F, T) }, + { ENTRY(GLX_CLIENT_SYMLINK, T, F, F, F, T, F, T, F, F, F, T) }, }; /* @@ -130,7 +136,7 @@ PackageEntryFileCapabilities get_file_type_capabilities( ) { int i; - PackageEntryFileCapabilities nullCaps = { F, F, F, F, F, F, F, F, F, F }; + PackageEntryFileCapabilities nullCaps = { F, F, F, F, F, F, F, F, F, F, F }; for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) { if (type == packageEntryFileTypeTable[i].type) { diff --git a/nvidia-installer.c b/nvidia-installer.c index c5ec2fe..4205482 100644 --- a/nvidia-installer.c +++ b/nvidia-installer.c @@ -145,6 +145,7 @@ static Options *load_default_options(void) op->dkms = FALSE; op->check_for_alternate_installs = TRUE; op->install_uvm = TRUE; + op->glvnd_glx_client = FALSE; op->install_compat32_libs = NV_OPTIONAL_BOOL_DEFAULT; op->install_libglx_indirect = NV_OPTIONAL_BOOL_DEFAULT; op->install_libglvnd_libraries = NV_OPTIONAL_BOOL_DEFAULT; @@ -451,6 +452,9 @@ static void parse_commandline(int argc, char *argv[], Options *op) op->install_libglvnd_libraries = boolval ? NV_OPTIONAL_BOOL_TRUE : NV_OPTIONAL_BOOL_FALSE; break; + case GLVND_GLX_CLIENT_OPTION: + op->glvnd_glx_client = boolval; + break; default: goto fail; } diff --git a/nvidia-installer.h b/nvidia-installer.h index e402199..0413377 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -156,6 +156,7 @@ typedef struct __options { int x_files_packaged; int concurrency_level; int load_error_ignored; + int glvnd_glx_client; int install_libglx_indirect; int install_libglvnd_libraries; @@ -282,6 +283,8 @@ typedef enum { FILE_TYPE_DKMS_CONF, FILE_TYPE_GLVND_LIB, FILE_TYPE_GLVND_SYMLINK, + FILE_TYPE_GLX_CLIENT_LIB, + FILE_TYPE_GLX_CLIENT_SYMLINK, FILE_TYPE_MAX } PackageEntryFileType; @@ -297,6 +300,12 @@ typedef enum { FILE_COMPAT_ARCH_COMPAT32, } PackageEntryFileCompatArch; +typedef enum { + FILE_GLVND_DONT_CARE, + FILE_GLVND_GLVND_ONLY, + FILE_GLVND_NON_GLVND_ONLY, +} PackageEntryFileGLVND; + typedef struct { unsigned int has_arch : 1; unsigned int has_tls_class : 1; @@ -308,6 +317,7 @@ typedef struct { unsigned int is_temporary : 1; unsigned int is_wrapper : 1; unsigned int inherit_path : 1; + unsigned int glvnd_select : 1; } PackageEntryFileCapabilities; /* @@ -355,6 +365,7 @@ typedef struct __package_entry { PackageEntryFileType type; PackageEntryFileTlsClass tls_class; PackageEntryFileCompatArch compat_arch; + PackageEntryFileGLVND glvnd; int inherit_path_depth; mode_t mode; @@ -547,6 +558,7 @@ void add_package_entry(Package *p, PackageEntryFileType type, PackageEntryFileTlsClass tls_class, PackageEntryFileCompatArch compat_arch, + PackageEntryFileGLVND glvnd, mode_t mode); /* XXX */ diff --git a/option_table.h b/option_table.h index 1df3080..f8fed0e 100644 --- a/option_table.h +++ b/option_table.h @@ -100,6 +100,7 @@ enum { FORCE_LIBGLX_INDIRECT, NO_LIBGLX_INDIRECT, INSTALL_LIBGLVND_OPTION, + GLVND_GLX_CLIENT_OPTION, }; static const NVGetoptOption __options[] = { @@ -658,6 +659,16 @@ static const NVGetoptOption __options[] = { "Use --no-install-libglvnd to exclude the libglvnd libraries, even if " "they appear to be missing." }, + { "glvnd-glx-client", GLVND_GLX_CLIENT_OPTION, NVGETOPT_IS_BOOLEAN, NULL, + "The NVIDIA OpenGL driver may be installed with GLX client libraries " + "that conform to the GL Vendor Neutral Dispatch (GLVND) infrastructure, " + "or with legacy GLX client libraries that are not GLVND-compliant. " + "For maximum compatibility with existing OpenGL applications, the " + "installer will default to installing non-GLVND GLX client libraries. " + "The --glvnd-glx-client option will override this default and install " + "GLVND-compliant GLX client libraries instead." + }, + /* Orphaned options: These options were in the long_options table in * nvidia-installer.c but not in the help. */ { "debug", 'd', 0, NULL,NULL }, @@ -1 +1 @@ -NVIDIA_VERSION = 361.18 +NVIDIA_VERSION = 361.28 |