Merge pull request #239 from tkaaad97/fix_enable_cap

Add enums to group "EnableCap"
diff --git a/api/GL/glext.h b/api/GL/glext.h
index 39267fe..151dcf2 100644
--- a/api/GL/glext.h
+++ b/api/GL/glext.h
@@ -51,7 +51,7 @@
 #define GLAPI extern
 #endif
 
-#define GL_GLEXT_VERSION 20181130
+#define GL_GLEXT_VERSION 20190204
 
 #include <KHR/khrplatform.h>
 
diff --git a/api/GL/glxext.h b/api/GL/glxext.h
index 38f6c67..bb13702 100755
--- a/api/GL/glxext.h
+++ b/api/GL/glxext.h
@@ -34,7 +34,7 @@
 **   https://github.com/KhronosGroup/OpenGL-Registry
 */
 
-#define GLX_GLXEXT_VERSION 20181130
+#define GLX_GLXEXT_VERSION 20190204
 
 /* Generated C header for:
  * API: glx
diff --git a/api/GL/wgl.h b/api/GL/wgl.h
index 3391185..afeee84 100644
--- a/api/GL/wgl.h
+++ b/api/GL/wgl.h
@@ -39,7 +39,7 @@
 #include <windows.h>
 #endif
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: wgl
@@ -409,7 +409,7 @@
 #define WGL_GPU_NUM_RB_AMD                0x21A7
 #define WGL_GPU_NUM_SPI_AMD               0x21A8
 typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids);
-typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data);
+typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, INT property, GLenum dataType, UINT size, void *data);
 typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc);
 typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id);
 typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList);
@@ -419,7 +419,7 @@
 typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
 #ifdef WGL_WGLEXT_PROTOTYPES
 UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids);
-INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data);
+INT WINAPI wglGetGPUInfoAMD (UINT id, INT property, GLenum dataType, UINT size, void *data);
 UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc);
 HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id);
 HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList);
@@ -816,12 +816,12 @@
 #define WGL_NV_present_video 1
 DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);
 #define WGL_NUM_VIDEO_SLOTS_NV            0x20F0
-typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
-typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
+typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);
+typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
 typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue);
 #ifdef WGL_WGLEXT_PROTOTYPES
-int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
-BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
+int WINAPI wglEnumerateVideoDevicesNV (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);
+BOOL WINAPI wglBindVideoDeviceNV (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
 BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue);
 #endif
 #endif /* WGL_NV_present_video */
@@ -926,14 +926,14 @@
 typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
 typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);
 typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
-typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
+typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
 typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
 typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
 #ifdef WGL_WGLEXT_PROTOTYPES
 BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
 BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator);
 INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
-INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
+INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
 BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
 BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
 #endif
diff --git a/api/GL/wglext.h b/api/GL/wglext.h
index a9a5a5b..e36c02a 100755
--- a/api/GL/wglext.h
+++ b/api/GL/wglext.h
@@ -39,7 +39,7 @@
 #include <windows.h>
 #endif
 
-#define WGL_WGLEXT_VERSION 20181130
+#define WGL_WGLEXT_VERSION 20190204
 
 /* Generated C header for:
  * API: wgl
@@ -318,7 +318,7 @@
 #define WGL_GPU_NUM_RB_AMD                0x21A7
 #define WGL_GPU_NUM_SPI_AMD               0x21A8
 typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids);
-typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data);
+typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, INT property, GLenum dataType, UINT size, void *data);
 typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc);
 typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id);
 typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList);
@@ -328,7 +328,7 @@
 typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
 #ifdef WGL_WGLEXT_PROTOTYPES
 UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids);
-INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data);
+INT WINAPI wglGetGPUInfoAMD (UINT id, INT property, GLenum dataType, UINT size, void *data);
 UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc);
 HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id);
 HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList);
@@ -725,12 +725,12 @@
 #define WGL_NV_present_video 1
 DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);
 #define WGL_NUM_VIDEO_SLOTS_NV            0x20F0
-typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
-typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
+typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);
+typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
 typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue);
 #ifdef WGL_WGLEXT_PROTOTYPES
-int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
-BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
+int WINAPI wglEnumerateVideoDevicesNV (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);
+BOOL WINAPI wglBindVideoDeviceNV (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
 BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue);
 #endif
 #endif /* WGL_NV_present_video */
@@ -835,14 +835,14 @@
 typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
 typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);
 typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
-typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
+typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
 typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
 typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
 #ifdef WGL_WGLEXT_PROTOTYPES
 BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
 BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator);
 INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
-INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
+INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
 BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
 BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
 #endif
diff --git a/api/GLES/gl.h b/api/GLES/gl.h
index 0d49769..681ecc9 100644
--- a/api/GLES/gl.h
+++ b/api/GLES/gl.h
@@ -36,7 +36,7 @@
 
 #include <GLES/glplatform.h>
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: gles1
diff --git a/api/GLES/glext.h b/api/GLES/glext.h
index 41de807..f9d2852 100644
--- a/api/GLES/glext.h
+++ b/api/GLES/glext.h
@@ -38,7 +38,7 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: gles1
diff --git a/api/GLES2/gl2.h b/api/GLES2/gl2.h
index cf3b7f3..d63eda1 100644
--- a/api/GLES2/gl2.h
+++ b/api/GLES2/gl2.h
@@ -44,7 +44,7 @@
 #define GL_GLES_PROTOTYPES 1
 #endif
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: gles2
diff --git a/api/GLES2/gl2ext.h b/api/GLES2/gl2ext.h
index 81d712e..dccffce 100644
--- a/api/GLES2/gl2ext.h
+++ b/api/GLES2/gl2ext.h
@@ -38,7 +38,7 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: gles2
diff --git a/api/GLES3/gl3.h b/api/GLES3/gl3.h
index 4570785..7c41bb4 100644
--- a/api/GLES3/gl3.h
+++ b/api/GLES3/gl3.h
@@ -44,7 +44,7 @@
 #define GL_GLES_PROTOTYPES 1
 #endif
 
-/* Generated on date 20181130 */
+/* Generated on date 20190204 */
 
 /* Generated C header for:
  * API: gles2
diff --git a/index_es.php b/index_es.php
index 0dada0f..3b2aeeb 100644
--- a/index_es.php
+++ b/index_es.php
@@ -56,11 +56,12 @@
      Documentation </h2>
 
 <ul>
-<li> OpenGL ES 3.2 Specification (May 14, 2018)
+<li> OpenGL ES 3.2 Specification (February 2, 2019)
      <a href="specs/es/3.2/es_spec_3.2.pdf"> without changes marked </a>
      and
      <a href="specs/es/3.2/es_spec_3.2.withchanges.pdf"> with changes marked </a>. </li>
-<li> OpenGL ES Shading Language 3.20 Specification (May 11, 2018)
+<li> OpenGL ES Shading Language 3.20 Specification (December 12, 2018)
+     <a href="specs/es/3.2/GLSL_ES_Specification_3.20.html"> (HTML) </a>
      <a href="specs/es/3.2/GLSL_ES_Specification_3.20.pdf"> (PDF) </a>
 <li> <a href="http://www.khronos.org/opengles/sdk/docs/man32/">
      OpenGL ES 3.2 Online Manual Pages.</a> </li>
diff --git a/index_gl.php b/index_gl.php
index d72b667..c96075b 100644
--- a/index_gl.php
+++ b/index_gl.php
@@ -48,7 +48,7 @@
 
 <ul>
 <li> <b> Current Specifications (OpenGL 4.6) </b>
-<li> OpenGL 4.6 API Specification (updated May 14, 2018)
+<li> OpenGL 4.6 API Specification (February 2, 2019)
     <ul>
     <li> <a href="specs/gl/glspec46.core.pdf"> Core Profile Specification
          </a> </li>
@@ -60,7 +60,8 @@
          Compatibility Profile Specification with changes marked </a>
          </li>
     </ul> </li>
-<li> OpenGL Shading Language 4.60 Specification (updated May 11, 2018)
+<li> OpenGL Shading Language 4.60 Specification (December 12, 2018)
+     <a href="specs/gl/GLSLangSpec.4.60.html"> (HTML) </a> </li>
      <a href="specs/gl/GLSLangSpec.4.60.pdf"> (PDF) </a> </li>
 
 <li> <a href="http://www.opengl.org/sdk/docs/man4/"> OpenGL 4.5 API and
diff --git a/specs/es/3.2/GLSL_ES_Specification_3.20.html b/specs/es/3.2/GLSL_ES_Specification_3.20.html
new file mode 100644
index 0000000..128d8d6
--- /dev/null
+++ b/specs/es/3.2/GLSL_ES_Specification_3.20.html
@@ -0,0 +1,15228 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.7.1">
+<meta name="author" content="Robert J. Simpson, Qualcomm (Editor) ; John Kessenich, Dave Baldwin and Randi Rost (Version 1.1 Authors)">
+<title>The OpenGL ES&#174; Shading Language, Version 3.20.5</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
+<style>
+/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
+/* Uncomment @import statement below to use as custom stylesheet */
+/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
+audio,canvas,video{display:inline-block}
+audio:not([controls]){display:none;height:0}
+script{display:none!important}
+html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
+a{background:transparent}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+dfn{font-style:italic}
+hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.center{margin-left:auto;margin-right:auto}
+.stretch{width:100%}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:none}
+p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
+ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
+ul.square{list-style-type:square}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
+abbr{text-transform:none}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
+blockquote cite::before{content:"\2014 \0020"}
+blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
+table thead,table tfoot{background:#f7f8f7}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
+.clearfix::after,.float-group::after{clear:both}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
+pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menuref{color:#000}
+.menuseq b:not(.caret),.menuref{font-weight:inherit}
+.menuseq{word-spacing:-.02em}
+.menuseq b.caret{font-size:1.25em;line-height:.8}
+.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
+b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
+b.button::before{content:"[";padding:0 3px 0 2px}
+b.button::after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
+#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
+#content{margin-top:1.25em}
+#content::before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
+#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span::before{content:"\00a0\2013\00a0"}
+#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark::before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber::after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+@media screen and (min-width:768px){#toctitle{font-size:1.375em}
+body.toc2{padding-left:15em;padding-right:0}
+#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
+@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{width:20em}
+#toc.toc2 #toctitle{font-size:1.375em}
+#toc.toc2>ul{font-size:.95em}
+#toc.toc2 ul ul{padding-left:1.25em}
+body.toc2.toc-right{padding-left:0;padding-right:20em}}
+#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+#content #toc>:first-child{margin-top:0}
+#content #toc>:last-child{margin-bottom:0}
+#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
+#content{margin-bottom:.625em}
+.sect1{padding-bottom:.625em}
+@media screen and (min-width:768px){#content{margin-bottom:1.25em}
+.sect1{padding-bottom:1.25em}}
+.sect1:last-child{padding-bottom:0}
+.sect1+.sect1{border-top:1px solid #efefed}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
+.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
+table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
+.exampleblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child{margin-bottom:0}
+.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+.sidebarblock>:first-child{margin-top:0}
+.sidebarblock>:last-child{margin-bottom:0}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
+.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
+.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
+@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
+@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
+.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
+.listingblock:hover code[data-lang]::before{display:block}
+.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
+.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
+table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
+table.pyhltable td.code{padding-left:.75em;padding-right:0}
+pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
+pre.pygments .lineno{display:inline-block;margin-right:.25em}
+table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
+.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
+.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
+.quoteblock .quoteblock blockquote::before{display:none}
+.verseblock{margin:0 1em 1.25em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract{margin:0 1em 1.25em;display:block}
+.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
+.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{word-spacing:0;line-height:1.6}
+.quoteblock.abstract blockquote::before,.quoteblock.abstract p::before{display:none}
+table.tableblock{max-width:100%;border-collapse:separate}
+p.tableblock:last-child{margin-bottom:0}
+td.tableblock>.content{margin-bottom:-1.25em}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
+table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
+table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
+table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
+table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
+table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
+table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
+table.frame-all{border-width:1px}
+table.frame-sides{border-width:0 1px}
+table.frame-topbot,table.frame-ends{border-width:1px 0}
+table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
+table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+td>div.verse{white-space:pre}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
+ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
+ul.unstyled,ol.unstyled{margin-left:0}
+ul.checklist{margin-left:.625em}
+ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
+ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
+ul.inline>li{margin-left:1.25em}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
+.colist td:not([class]):first-child img{max-width:none}
+.colist td:not([class]):last-child{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
+.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
+.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
+.gist .file-data>table td.line-data{width:99%}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background-color:#00fafa}
+.black{color:#000}
+.black-background{background-color:#000}
+.blue{color:#0000bf}
+.blue-background{background-color:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background-color:#fa00fa}
+.gray{color:#606060}
+.gray-background{background-color:#7d7d7d}
+.green{color:#006000}
+.green-background{background-color:#007d00}
+.lime{color:#00bf00}
+.lime-background{background-color:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background-color:#7d0000}
+.navy{color:#000060}
+.navy-background{background-color:#00007d}
+.olive{color:#606000}
+.olive-background{background-color:#7d7d00}
+.purple{color:#600060}
+.purple-background{background-color:#7d007d}
+.red{color:#bf0000}
+.red-background{background-color:#fa0000}
+.silver{color:#909090}
+.silver-background{background-color:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background-color:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background-color:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background-color:#fafa00}
+span.icon>.fa{cursor:default}
+a span.icon>.fa{cursor:inherit}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]::after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
+.print-only{display:none!important}
+@page{margin:1.25cm .75cm}
+@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
+html{font-size:80%}
+a{color:inherit!important;text-decoration:underline!important}
+a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
+a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
+abbr[title]::after{content:" (" attr(title) ")"}
+pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
+thead{display:table-header-group}
+svg{max-width:100%}
+p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
+h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
+#toc,.sidebarblock,.exampleblock>.content{background:none!important}
+#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
+body.book #header{text-align:center}
+body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
+body.book #header .details{border:0!important;display:block;padding:0!important}
+body.book #header .details span:first-child{margin-left:0!important}
+body.book #header .details br{display:block}
+body.book #header .details br+span::before{content:none!important}
+body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
+body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
+.listingblock code[data-lang]::before{display:block}
+#footer{padding:0 .9375em}
+.hide-on-print{display:none!important}
+.print-only{display:block!important}
+.hide-for-print{display:none!important}
+.show-for-print{display:inherit!important}}
+@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
+.sect1{padding:0!important}
+.sect1+.sect1{border:0}
+#footer{background:none}
+#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
+@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
+</style>
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+<style>
+/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
+/*pre.CodeRay {background-color:#f7f7f8;}*/
+.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em}
+.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)}
+.CodeRay .line-numbers strong{color:rgba(0,0,0,.4)}
+table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none}
+table.CodeRay td{vertical-align: top;line-height:1.45}
+table.CodeRay td.line-numbers{text-align:right}
+table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)}
+table.CodeRay td.code{padding:0 0 0 .5em}
+table.CodeRay td.code>pre{padding:0}
+.CodeRay .debug{color:#fff !important;background:#000080 !important}
+.CodeRay .annotation{color:#007}
+.CodeRay .attribute-name{color:#000080}
+.CodeRay .attribute-value{color:#700}
+.CodeRay .binary{color:#509}
+.CodeRay .comment{color:#998;font-style:italic}
+.CodeRay .char{color:#04d}
+.CodeRay .char .content{color:#04d}
+.CodeRay .char .delimiter{color:#039}
+.CodeRay .class{color:#458;font-weight:bold}
+.CodeRay .complex{color:#a08}
+.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
+.CodeRay .color{color:#099}
+.CodeRay .class-variable{color:#369}
+.CodeRay .decorator{color:#b0b}
+.CodeRay .definition{color:#099}
+.CodeRay .delimiter{color:#000}
+.CodeRay .doc{color:#970}
+.CodeRay .doctype{color:#34b}
+.CodeRay .doc-string{color:#d42}
+.CodeRay .escape{color:#666}
+.CodeRay .entity{color:#800}
+.CodeRay .error{color:#808}
+.CodeRay .exception{color:inherit}
+.CodeRay .filename{color:#099}
+.CodeRay .function{color:#900;font-weight:bold}
+.CodeRay .global-variable{color:#008080}
+.CodeRay .hex{color:#058}
+.CodeRay .integer,.CodeRay .float{color:#099}
+.CodeRay .include{color:#555}
+.CodeRay .inline{color:#000}
+.CodeRay .inline .inline{background:#ccc}
+.CodeRay .inline .inline .inline{background:#bbb}
+.CodeRay .inline .inline-delimiter{color:#d14}
+.CodeRay .inline-delimiter{color:#d14}
+.CodeRay .important{color:#555;font-weight:bold}
+.CodeRay .interpreted{color:#b2b}
+.CodeRay .instance-variable{color:#008080}
+.CodeRay .label{color:#970}
+.CodeRay .local-variable{color:#963}
+.CodeRay .octal{color:#40e}
+.CodeRay .predefined{color:#369}
+.CodeRay .preprocessor{color:#579}
+.CodeRay .pseudo-class{color:#555}
+.CodeRay .directive{font-weight:bold}
+.CodeRay .type{font-weight:bold}
+.CodeRay .predefined-type{color:inherit}
+.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
+.CodeRay .key{color:#808}
+.CodeRay .key .delimiter{color:#606}
+.CodeRay .key .char{color:#80f}
+.CodeRay .value{color:#088}
+.CodeRay .regexp .delimiter{color:#808}
+.CodeRay .regexp .content{color:#808}
+.CodeRay .regexp .modifier{color:#808}
+.CodeRay .regexp .char{color:#d14}
+.CodeRay .regexp .function{color:#404;font-weight:bold}
+.CodeRay .string{color:#d20}
+.CodeRay .string .string .string{background:#ffd0d0}
+.CodeRay .string .content{color:#d14}
+.CodeRay .string .char{color:#d14}
+.CodeRay .string .delimiter{color:#d14}
+.CodeRay .shell{color:#d14}
+.CodeRay .shell .delimiter{color:#d14}
+.CodeRay .symbol{color:#990073}
+.CodeRay .symbol .content{color:#a60}
+.CodeRay .symbol .delimiter{color:#630}
+.CodeRay .tag{color:#008080}
+.CodeRay .tag-special{color:#d70}
+.CodeRay .variable{color:#036}
+.CodeRay .insert{background:#afa}
+.CodeRay .delete{background:#faa}
+.CodeRay .change{color:#aaf;background:#007}
+.CodeRay .head{color:#f8f;background:#505}
+.CodeRay .insert .insert{color:#080}
+.CodeRay .delete .delete{color:#800}
+.CodeRay .change .change{color:#66f}
+.CodeRay .head .head{color:#f4f}
+</style>
+<link rel="stylesheet" href="../katex/katex.min.css">
+<script src="../katex/katex.min.js"></script>
+<script src="../katex/contrib/auto-render.min.js"></script>
+    <!-- Use KaTeX to render math once document is loaded, see
+         https://github.com/Khan/KaTeX/tree/master/contrib/auto-render -->
+<script>
+    document.addEventListener("DOMContentLoaded", function () {
+        renderMathInElement(
+            document.body,
+            {
+                delimiters: [
+                    { left: "$$", right: "$$", display: true},
+                    { left: "\\[", right: "\\]", display: true},
+                    { left: "$", right: "$", display: false},
+                    { left: "\\(", right: "\\)", display: false}
+                ]
+            }
+        );
+    });
+</script></head>
+<body class="book toc2 toc-left" style="max-width: 100;">
+<div id="header">
+<h1>The OpenGL ES<sup>&#174;</sup> Shading Language, Version 3.20.5</h1>
+<div class="details">
+<span id="author" class="author">Robert J. Simpson, Qualcomm (Editor) ; John Kessenich, Dave Baldwin and Randi Rost (Version 1.1 Authors)</span><br>
+<span id="revnumber">version 3.20.5,</span>
+<span id="revdate">Wed, 12 Dec 2018 23:37:49 +0000</span>
+<br><span id="revremark">Git branch information not available</span>
+</div>
+<div id="toc" class="toc2">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#introduction">1. Introduction</a>
+<ul class="sectlevel2">
+<li><a href="#changes">1.1. Changes</a></li>
+<li><a href="#overview">1.2. Overview</a></li>
+<li><a href="#error-handling">1.3. Error Handling</a></li>
+<li><a href="#typographical-conventions">1.4. Typographical Conventions</a></li>
+<li><a href="#compatibility">1.5. Compatibility</a></li>
+</ul>
+</li>
+<li><a href="#overview-of-opengl-shading">2. Overview of OpenGL ES Shading</a>
+<ul class="sectlevel2">
+<li><a href="#vertex-processor">2.1. Vertex Processor</a></li>
+<li><a href="#tessellation-control-processor">2.2. Tessellation Control Processor</a></li>
+<li><a href="#tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</a></li>
+<li><a href="#geometry-processor">2.4. Geometry Processor</a></li>
+<li><a href="#fragment-processor">2.5. Fragment Processor</a></li>
+<li><a href="#compute-processor">2.6. Compute Processor</a></li>
+</ul>
+</li>
+<li><a href="#basics">3. Basics</a>
+<ul class="sectlevel2">
+<li><a href="#character-set">3.1. Character Set</a></li>
+<li><a href="#source-strings">3.2. Source Strings</a></li>
+<li><a href="#version-declaration">3.3. Version Declaration</a></li>
+<li><a href="#preprocessor">3.4. Preprocessor</a></li>
+<li><a href="#comments">3.5. Comments</a></li>
+<li><a href="#tokens">3.6. Tokens</a></li>
+<li><a href="#keywords">3.7. Keywords</a></li>
+<li><a href="#identifiers">3.8. Identifiers</a></li>
+<li><a href="#definitions">3.9. Definitions</a></li>
+<li><a href="#logical-phases-of-compilation">3.10. Logical Phases of Compilation</a></li>
+</ul>
+</li>
+<li><a href="#variables-and-types">4. Variables and Types</a>
+<ul class="sectlevel2">
+<li><a href="#basic-types">4.1. Basic Types</a></li>
+<li><a href="#scoping">4.2. Scoping</a></li>
+<li><a href="#storage-qualifiers">4.3. Storage Qualifiers</a></li>
+<li><a href="#layout-qualifiers">4.4. Layout Qualifiers</a></li>
+<li><a href="#interpolation-qualifiers">4.5. Interpolation Qualifiers</a></li>
+<li><a href="#parameter-qualifiers">4.6. Parameter Qualifiers</a></li>
+<li><a href="#precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</a></li>
+<li><a href="#variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</a></li>
+<li><a href="#the-precise-qualifier">4.9. The Precise Qualifier</a></li>
+<li><a href="#memory-qualifiers">4.10. Memory Qualifiers</a></li>
+<li><a href="#order-of-qualification">4.11. Order and Repetition of Qualification</a></li>
+<li><a href="#empty-declarations">4.12. Empty Declarations</a></li>
+</ul>
+</li>
+<li><a href="#operators-and-expressions">5. Operators and Expressions</a>
+<ul class="sectlevel2">
+<li><a href="#operators">5.1. Operators</a></li>
+<li><a href="#array-operations">5.2. Array Operations</a></li>
+<li><a href="#function-calls">5.3. Function Calls</a></li>
+<li><a href="#constructors">5.4. Constructors</a></li>
+<li><a href="#vector-components">5.5. Vector Components</a></li>
+<li><a href="#matrix-components">5.6. Matrix Components</a></li>
+<li><a href="#structure-and-array-operations">5.7. Structure and Array Operations</a></li>
+<li><a href="#assignments">5.8. Assignments</a></li>
+<li><a href="#expressions">5.9. Expressions</a></li>
+<li><a href="#vector-and-matrix-operations">5.10. Vector and Matrix Operations</a></li>
+<li><a href="#evaluation-of-expressions">5.11. Evaluation of Expressions</a></li>
+</ul>
+</li>
+<li><a href="#statements-and-structure">6. Statements and Structure</a>
+<ul class="sectlevel2">
+<li><a href="#function-definitions">6.1. Function Definitions</a></li>
+<li><a href="#selection">6.2. Selection</a></li>
+<li><a href="#iteration">6.3. Iteration</a></li>
+<li><a href="#jumps">6.4. Jumps</a></li>
+</ul>
+</li>
+<li><a href="#built-in-variables">7. Built-In Variables</a>
+<ul class="sectlevel2">
+<li><a href="#built-in-language-variables">7.1. Built-In Language Variables</a></li>
+<li><a href="#built-in-constants">7.2. Built-In Constants</a></li>
+<li><a href="#built-in-uniform-state">7.3. Built-In Uniform State</a></li>
+<li><a href="#redeclaring-built-in-blocks">7.4. Redeclaring Built-In Blocks</a></li>
+</ul>
+</li>
+<li><a href="#built-in-functions">8. Built-In Functions</a>
+<ul class="sectlevel2">
+<li><a href="#angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</a></li>
+<li><a href="#exponential-functions">8.2. Exponential Functions</a></li>
+<li><a href="#common-functions">8.3. Common Functions</a></li>
+<li><a href="#floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</a></li>
+<li><a href="#geometric-functions">8.5. Geometric Functions</a></li>
+<li><a href="#matrix-functions">8.6. Matrix Functions</a></li>
+<li><a href="#vector-relational-functions">8.7. Vector Relational Functions</a></li>
+<li><a href="#integer-functions">8.8. Integer Functions</a></li>
+<li><a href="#texture-functions">8.9. Texture Functions</a></li>
+<li><a href="#atomic-counter-functions">8.10. Atomic Counter Functions</a></li>
+<li><a href="#atomic-memory-functions">8.11. Atomic Memory Functions</a></li>
+<li><a href="#image-functions">8.12. Image Functions</a></li>
+<li><a href="#geometry-shader-functions">8.13. Geometry Shader Functions</a></li>
+<li><a href="#fragment-processing-functions">8.14. Fragment Processing Functions</a></li>
+<li><a href="#shader-invocation-control-functions">8.15. Shader Invocation Control Functions</a></li>
+<li><a href="#shader-memory-control-functions">8.16. Shader Memory Control Functions</a></li>
+</ul>
+</li>
+<li><a href="#shader-interface-matching">9. Shader Interface Matching</a>
+<ul class="sectlevel2">
+<li><a href="#input-output-matching-by-name-in-linked-programs">9.1. Input Output Matching by Name in Linked Programs</a></li>
+<li><a href="#matching-of-qualifiers">9.2. Matching of Qualifiers</a></li>
+</ul>
+</li>
+<li><a href="#shading-language-grammar">10. Shading Language Grammar</a></li>
+<li><a href="#counting-of-inputs-and-outputs">11. Counting of Inputs and Outputs</a></li>
+<li><a href="#acknowledgments">12. Acknowledgments</a></li>
+<li><a href="#references">13. Normative References</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div style="page-break-after: always;"></div>
+<div class="paragraph">
+<p>Copyright &#169; 2008-2018 The Khronos Group Inc. All Rights Reserved.</p>
+</div>
+<div class="paragraph">
+<p>This specification is protected by copyright laws and contains material
+proprietary to the Khronos Group, Inc. It or any components may not be
+reproduced, republished, distributed, transmitted, displayed, broadcast,
+or otherwise exploited in any manner without the express prior written
+permission of Khronos Group. You may use this specification for
+implementing the functionality therein, without altering or removing any
+trademark, copyright or other notice from the specification, but the
+receipt or possession of this specification does not convey any rights
+to reproduce, disclose, or distribute its contents, or to manufacture,
+use, or sell anything that it may describe, in whole or in part.</p>
+</div>
+<div class="paragraph">
+<p>Khronos Group grants express permission to any current Promoter,
+Contributor or Adopter member of Khronos to copy and redistribute
+UNMODIFIED versions of this specification in any fashion, provided that
+NO CHARGE is made for the specification and the latest available update
+of the specification for any version of the API is used whenever
+possible. Such distributed specification may be reformatted AS LONG AS
+the contents of the specification are not changed in any way. The
+specification may be incorporated into a product that is sold as long as
+such product includes significant independent work developed by the
+seller. A link to the current version of this specification on the
+Khronos Group website should be included whenever possible with
+specification distributions.</p>
+</div>
+<div class="paragraph">
+<p>Khronos Group makes no, and expressly disclaims any, representations or
+warranties, express or implied, regarding this specification, including,
+without limitation, any implied warranties of merchantability or fitness
+for a particular purpose or noninfringement of any intellectual
+property. Khronos Group makes no, and expressly disclaims any,
+warranties, express or implied, regarding the correctness, accuracy,
+completeness, timeliness, and reliability of the specification. Under no
+circumstances will the Khronos Group, or any of its Promoters,
+Contributors or Members or their respective partners, officers,
+directors, employees, agents, or representatives be liable for any
+damages, whether direct, indirect, special or consequential damages for
+lost revenues, lost profits, or otherwise, arising from or in connection
+with these materials.</p>
+</div>
+<div class="paragraph">
+<p>Khronos, Vulkan, SYCL, SPIR, WebGL, EGL, COLLADA, StreamInput, OpenVX,
+OpenKCam, glTF, OpenKODE, OpenVG, OpenWF, OpenSL ES, OpenMAX, OpenMAX
+AL, OpenMAX IL and OpenMAX DL are trademarks and WebCL is a
+certification mark of the Khronos Group Inc. OpenCL is a trademark of
+Apple Inc. and OpenGL and OpenML are registered trademarks and the
+OpenGL ES and OpenGL SC logos are trademarks of Silicon Graphics
+International used under license by Khronos. All other product names,
+trademarks, and/or company names are used solely for identification and
+belong to their respective owners.</p>
+</div>
+<div style="page-break-after: always;"></div>
+<!-- toc disabled -->
+</div>
+</div>
+<div class="sect1">
+<h2 id="introduction">1. Introduction</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This document specifies only version 3.20 of the OpenGL ES Shading Language.
+It requires __VERSION__ to substitute 320, and requires
+<strong>#version</strong> to accept only
+<code>320 es</code>.
+If <strong>#version</strong> is declared with a smaller number, the language accepted is a
+previous version of the shading language, which will be supported depending
+on the version and type of context in the OpenGL ES API.
+See the <a href="#references">OpenGL ES Specification</a> for details on what language versions are
+supported.</p>
+</div>
+<div class="paragraph">
+<p>All references in this specification to the <a href="#references">OpenGL ES Specification</a> are to
+version 3.2.</p>
+</div>
+<div class="sect2">
+<h3 id="changes">1.1. Changes</h3>
+<div class="sect3">
+<h4 id="changes-from-glsl-es-3.2-revision-4">1.1.1. Changes from GLSL ES 3.2 revision 4</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Clarified that this specification completely defines the OpenGL ES Shading Language.
+Normatively reference C++ only for the preprocessor.</p>
+</li>
+<li>
+<p>Private GLSL issues 7, 38: Corrected the values of some builtin constants.
+The values were given correctly in the OpenGL ES Specification.</p>
+</li>
+<li>
+<p>Private GLSL issue 30: Clarify that output packing rules apply to the last
+vertex pipeline stage, not necessarily the vertex stage.</p>
+</li>
+<li>
+<p>Private GLSL issue 15: Clarify the ordering of bindings for arrays of arrays.</p>
+</li>
+<li>
+<p>Private GLSL issue 14: Uniform variables need only match at link time if they
+are statically used.</p>
+</li>
+<li>
+<p>For <strong>precise</strong> computations, the controlling expressions for
+control flow and ternary operators (<strong>?:</strong>) are not included.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="changes-from-glsl-es-3.2-revision-3">1.1.2. Changes from GLSL ES 3.2 revision 3</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Matching of default uniforms when shaders are linked.</p>
+</li>
+<li>
+<p><em>gl_DepthRange</em> is only guaranteed to be available in the fragment
+stage.</p>
+</li>
+<li>
+<p>Clarification of definition of static use.</p>
+</li>
+<li>
+<p>Sampling behavior in the absence of <strong>sample</strong> and <strong>centroid</strong>.</p>
+</li>
+<li>
+<p>Clarified the requirements when the specification uses the terms
+<em>should</em>/<em>should not</em> and <em>undefined behavior</em>.</p>
+</li>
+<li>
+<p>Arrayed blocks cannot have layout location qualifiers on members</p>
+</li>
+<li>
+<p><strong>barrier</strong>() defines a partial order which includes tessellation control
+shader outputs.</p>
+</li>
+<li>
+<p>Vertex shader integer output qualification.</p>
+</li>
+<li>
+<p>Incorrect use of predefined pragmas.</p>
+</li>
+<li>
+<p>Clarified use of <strong>readonly</strong> and <strong>writeonly</strong> qualifiers.</p>
+</li>
+<li>
+<p>USAMPLERBUFFER added to grammar.</p>
+</li>
+<li>
+<p>Clarified precision qualifiers can be used in interface blocks.</p>
+</li>
+<li>
+<p>Clarified <strong>memoryBarrierShared</strong> only applies to the current workgroup.</p>
+</li>
+<li>
+<p>The layout qualifier <em>invocations</em> must not be zero.</p>
+</li>
+<li>
+<p>The layout qualifier <em>local_size</em> must not be zero.</p>
+</li>
+<li>
+<p>Clarified the definition of static assignment.</p>
+</li>
+<li>
+<p>Removed list of types with no default precision.</p>
+</li>
+<li>
+<p>Removed scoping rules from the grammar. Refer instead to the <a href="#scoping">scoping</a> section.</p>
+</li>
+<li>
+<p>Require a statement after the final label of a switch.</p>
+</li>
+<li>
+<p>Define <strong>gl_BoundingBox</strong>.</p>
+</li>
+<li>
+<p><strong>length</strong>() expressions returning a constant-value may not include side effects.</p>
+</li>
+<li>
+<p>Clarified that variables may be declared <strong>readonly writeonly</strong>.</p>
+</li>
+<li>
+<p>Use of constant expressions within <strong>#line</strong> directives is undefined.</p>
+</li>
+<li>
+<p><strong>gl_in</strong> can be redeclared using unsized-array syntax.</p>
+</li>
+<li>
+<p>Clarified which sampler types may be used for depth and stencil textures.</p>
+</li>
+<li>
+<p>Added order-of-operation and other explanations to the
+<a href="#the-precise-qualifier">Precise Qualifier</a> section.</p>
+</li>
+<li>
+<p>The <strong>precise</strong> qualifier applied to a block/struct applies recursively to the members.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="changes-from-glsl-es-3.2-revision-2">1.1.3. Changes from GLSL ES 3.2 revision 2</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Updated value for <em>gl_MaxTessControlTotalOutputComponents</em></p>
+</li>
+<li>
+<p>Clarified the allowed character set for pre-processing</p>
+</li>
+<li>
+<p>Integer division wrapping behavior</p>
+</li>
+<li>
+<p>Clarified pre-processor expressions (<em>pp-constant-expression</em>)</p>
+</li>
+<li>
+<p>UBO and SSBO precisions do not need to match for linked shaders
+(consistent with GLSL ES 3.1)</p>
+</li>
+<li>
+<p><strong>modf</strong> function</p>
+</li>
+<li>
+<p>Sequence and ternary operators with <strong>void</strong> type</p>
+</li>
+<li>
+<p>Sequence and ternary operators with array types</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="changes-from-glsl-es-3.2-revision-1">1.1.4. Changes from GLSL ES 3.2 revision 1</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Signed zeros must be supported</p>
+</li>
+<li>
+<p>Layout qualifier table</p>
+</li>
+<li>
+<p>Allowed optimizations when evaluating expressions</p>
+</li>
+<li>
+<p>Updated value for <em>gl_MaxTessControlInputComponents</em></p>
+</li>
+<li>
+<p>Updated value for <em>gl_MaxTessControlOutputComponents</em></p>
+</li>
+<li>
+<p>Updated value for <em>gl_MaxTessEvaluationInputComponents</em></p>
+</li>
+<li>
+<p>Updated value for <em>gl_MaxTessEvaluationOutputComponents</em></p>
+</li>
+<li>
+<p>Updated value for <em>gl_MaxGeometryOutputComponents</em></p>
+</li>
+<li>
+<p>Require precisions in blocks to match when linking</p>
+</li>
+<li>
+<p>Updated conclusions in issues section</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="changes-from-glsl-es-3.1-revision-4">1.1.5. Changes from GLSL ES 3.1 revision 4</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Added the following extensions:</p>
+<div class="ulist">
+<ul>
+<li>
+<p><a href="https://www.opengl.org/registry/specs/KHR/blend_equation_advanced.txt">KHR_blend_equation_advanced</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_sample_variables.txt">OES_sample_variables</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_image_atomic.txt">OES_shader_image_atomic</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_multisample_interpolation.txt">OES_shader_multisample_interpolation</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_storage_multisample_2d_array.txt">OES_texture_storage_multisample_2d_array</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_geometry_shader.txt">OES_geometry_shader</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_gpu_shader5.txt">OES_gpu_shader5</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_primitive_bounding_box.txt">OES_primitive_bounding_box</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_shader_io_blocks.txt">OES_shader_io_blocks</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_tessellation_shader.txt">OES_tessellation_shader</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_buffer.txt">OES_texture_buffer</a></p>
+</li>
+<li>
+<p><a href="https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map_array.txt">OES_texture_cube_map_array</a></p>
+</li>
+<li>
+<p><a href="https://www.opengl.org/registry/specs/KHR/robustness.txt">KHR_robustness</a></p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="overview">1.2. Overview</h3>
+<div class="paragraph">
+<p>This document describes <em>The OpenGL ES Shading Language, version 3.20</em>.</p>
+</div>
+<div class="paragraph">
+<p>Independent compilation units written in this language are called <em>shaders</em>.
+A <em>program</em> is a set of shaders that are compiled and linked
+together.
+The aim of this document is to thoroughly specify the programming language.
+The <a href="#references">OpenGL ES Specification</a> will specify the OpenGL ES entry points used to
+manipulate and communicate with programs and shaders.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="error-handling">1.3. Error Handling</h3>
+<div class="paragraph">
+<p>Compilers, in general, accept programs that are ill-formed, due to the
+impossibility of detecting all ill-formed programs.
+Portability is only ensured for well-formed programs, which this
+specification describes.
+Compilers are encouraged to detect ill-formed programs and issue diagnostic
+messages, but are not required to do so for all cases.</p>
+</div>
+<div class="paragraph">
+<p>The compilation process is implementation-dependent but is generally split
+into a number of stages, each of which occurs at one of the following times:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A call to <em>glCompileShader</em></p>
+</li>
+<li>
+<p>A call to <em>glLinkProgram</em></p>
+</li>
+<li>
+<p>A draw call or a call to <em>glValidateProgram</em></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The implementation should report errors as early a possible but in any case
+must satisfy the following:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>All lexical, grammatical and semantic errors must have been detected
+following a call to <em>glLinkProgram</em></p>
+</li>
+<li>
+<p>Errors due to mismatch between the shaders (link-time errors) must have
+been detected following a call to <em>glLinkProgram</em></p>
+</li>
+<li>
+<p>Errors due to exceeding resource limits must have been detected
+following any draw call or a call to <em>glValidateProgram</em></p>
+</li>
+<li>
+<p>A call to <em>glValidateProgram</em> must report all errors associated with a
+program object given the current GL state.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Where the specification uses the terms <em>required</em>, <em>must</em>/<em>must</em> <em>not</em>,
+<em>does</em>/<em>does</em> <em>not</em>, <em>disallowed</em>, or <em>not</em> <em>supported</em>, the compiler or
+linker is required to detect and report any violations.
+Similarly when a condition or situation is an <strong>error</strong>, it must be reported.
+Use of any feature marked as <em>reserved</em> is an error.
+Where the specification uses the terms <em>should</em>/<em>should</em> <em>not</em>, <em>undefined</em>
+<em>behavior</em>, <em>undefined</em> <em>value</em> or <em>undefined</em> <em>*results*</em>, implementations
+will not produce a compile-time error but are encouraged to issue a warning
+for violations.
+The run-time behavior of the program in these cases is not constrained (and
+so may include termination or system instability).
+It is expected that systems will be designed to handle these cases
+gracefully but specification of this is outside the scope of OpenGL ES.</p>
+</div>
+<div class="paragraph">
+<p>Implementations may not in general support functionality beyond the mandated
+parts of the specification without use of the relevant extension.
+The only exceptions are:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>If a feature is marked as optional.</p>
+</li>
+<li>
+<p>Where a maximum value is stated (e.g. the maximum number of vertex
+outputs), the implementation may support a higher value than that
+specified.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Where the implementation supports more than the mandated specification,
+off-target compilers are encouraged to issue warnings if these features are
+used.</p>
+</div>
+<div class="paragraph">
+<p>The compilation process is split between the compiler and linker.
+The allocation of tasks between the compiler and linker is implementation
+dependent.
+Consequently there are many errors which may be detected either at compile
+or link time, depending on the implementation.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="typographical-conventions">1.4. Typographical Conventions</h3>
+<div class="paragraph">
+<p>Italic, bold, and font choices have been used in this specification
+primarily to improve readability.
+Code fragments use a fixed width font.
+Identifiers embedded in text are italicized.
+Keywords embedded in text are bold.
+Operators are called by their name, followed by their symbol in bold in
+parentheses.
+The clarifying grammar fragments in the text use bold for literals and
+italics for non-terminals.
+The official grammar in &#8220;<a href="#shading-language-grammar">Shading Language
+Grammar</a>&#8221; uses all capitals for terminals and lower case for
+non-terminals.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="compatibility">1.5. Compatibility</h3>
+<div class="paragraph">
+<p>The OpenGL ES 3.2 API is designed to work with GLSL ES v1.00, GLSL
+ES 3.00, GLSL ES 3.10 and GLSL ES 3.20.
+In general a shader written for versions prior to OpenGL ES 3.2
+should work without modification in OpenGL ES 3.2.</p>
+</div>
+<div class="paragraph">
+<p>When porting applications from an earlier to later version of the API, the
+following points should be noted:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Not all language constructs present in earlier versions of the language
+are available in later versions e.g. attribute and varying qualifiers
+are present in v1.00 but not v3.00.
+However, the functionality of GLSL ES 3.20 is a super-set of GLSL
+ES 3.10.</p>
+</li>
+<li>
+<p>Some features of later versions of the API require language features
+that are not present in earlier version of the language.</p>
+</li>
+<li>
+<p>It is an error to link shaders if they are written in different versions
+of the language.</p>
+</li>
+<li>
+<p>The OpenGL ES 2.0 and 3.0 APIs do not support shaders written in GLSL ES
+3.20.</p>
+</li>
+<li>
+<p>Using GLSL ES 1.00 shaders within OpenGL ES 3.x may extend the resources
+available beyond the minima specified in GLSL ES 1.0.
+Shaders which make use of this will not necessarily run on an OpenGL ES
+2.0 implementation: Similarly for GLSL ES 3.00 shaders running within
+OpenGL ES 3.2.</p>
+</li>
+<li>
+<p>Support of line continuation and support of UTF-8 characters within
+comments is optional in GLSL ES 1.00 when used with the OpenGL ES 2.0
+API.
+However, support is mandated for both of these when a GLSL ES 1.00
+shader is used with the OpenGL ES 3.x APIs.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="overview-of-opengl-shading">2. Overview of OpenGL ES Shading</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The OpenGL ES Shading Language is actually several closely related languages.
+These languages are used to create shaders for each of the programmable
+processors contained in the OpenGL ES processing pipeline.
+Currently, these processors are the vertex, tessellation control,
+tessellation evaluation, geometry, fragment, and compute processors.</p>
+</div>
+<div class="paragraph">
+<p>Compilation units for these processors are referred to as <em>shaders</em> and the
+processors themselves are also referred to as <em>shader stages</em>.
+Only one shader can be run on a processor at any one time; there is no
+support for linking multiple compilation units together for a single shader
+stage.
+One or more shaders are linked together to form a single program and each
+program contains shader <em>executables</em> for one or more consecutive shader
+stages.</p>
+</div>
+<div class="paragraph">
+<p>Unless otherwise noted in this paper, a language feature applies to all
+languages, and common usage will refer to these languages as a single
+language.
+The specific languages will be referred to by the name of the processor they
+target: vertex, tessellation control, tessellation evaluation, geometry,
+fragment, or compute.</p>
+</div>
+<div class="paragraph">
+<p>Most OpenGL ES state is not tracked or made available to shaders.
+Typically, user-defined variables will be used for communicating between
+different stages of the OpenGL ES pipeline.
+However, a small amount of state is still tracked and automatically made
+available to shaders, and there are a few built-in variables for interfaces
+between different stages of the OpenGL ES pipeline.</p>
+</div>
+<div class="sect2">
+<h3 id="vertex-processor">2.1. Vertex Processor</h3>
+<div class="paragraph">
+<p>The <em>vertex processor</em> is a programmable unit that operates on incoming
+vertices and their associated data.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+<em>vertex shaders</em>.</p>
+</div>
+<div class="paragraph">
+<p>The vertex processor operates on one vertex at a time.
+It does not replace graphics operations that require knowledge of several
+vertices at a time.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tessellation-control-processor">2.2. Tessellation Control Processor</h3>
+<div class="paragraph">
+<p>The <em>tessellation control processor</em> is a programmable unit that operates on
+a patch of incoming vertices and their associated data, emitting a new
+output patch.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+tessellation control shaders.</p>
+</div>
+<div class="paragraph">
+<p>The tessellation control shader is invoked for each vertex of the output
+patch.
+Each invocation can read the attributes of any vertex in the input or output
+patches, but can only write per-vertex attributes for the corresponding
+output patch vertex.
+The shader invocations collectively produce a set of per-patch attributes
+for the output patch.</p>
+</div>
+<div class="paragraph">
+<p>After all tessellation control shader invocations have completed, the output
+vertices and per-patch attributes are assembled to form a patch to be used
+by subsequent pipeline stages.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control shader invocations run mostly independently, with
+undefined relative execution order.
+However, the built-in function <strong>barrier</strong>() can be used to control execution
+order by synchronizing invocations, effectively dividing tessellation
+control shader execution into a set of phases.
+Tessellation control shaders will get undefined results if one invocation
+reads from a per-vertex or per-patch attribute written by another invocation
+at any point during the same phase, or if two invocations attempt to write
+different values to the same per-patch output
+in a single phase.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</h3>
+<div class="paragraph">
+<p>The <em>tessellation evaluation processor</em> is a programmable unit that
+evaluates the position and other attributes of a vertex generated by the
+tessellation primitive generator, using a patch of incoming vertices and
+their associated data.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+tessellation evaluation shaders.</p>
+</div>
+<div class="paragraph">
+<p>Each invocation of the tessellation evaluation executable computes the
+position and attributes of a single vertex generated by the tessellation
+primitive generator.
+The executable can read the attributes of any vertex in the input patch,
+plus the tessellation coordinate, which is the relative location of the
+vertex in the primitive being tessellated.
+The executable writes the position and other attributes of the vertex.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="geometry-processor">2.4. Geometry Processor</h3>
+<div class="paragraph">
+<p>The <em>geometry processor</em> is a programmable unit that operates on data for
+incoming vertices for a primitive assembled after vertex processing and
+outputs a sequence of vertices forming output primitives.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+<em>geometry shaders</em>.</p>
+</div>
+<div class="paragraph">
+<p>A single invocation of the geometry shader executable on the geometry
+processor will operate on a declared input primitive with a fixed number of
+vertices.
+This single invocation can emit a variable number of vertices that are
+assembled into primitives of a declared output primitive type and passed to
+subsequent pipeline stages.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="fragment-processor">2.5. Fragment Processor</h3>
+<div class="paragraph">
+<p>The <em>fragment processor</em> is a programmable unit that operates on fragment
+values and their associated data.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+<em>fragment shaders</em>.</p>
+</div>
+<div class="paragraph">
+<p>A fragment shader cannot change a fragment&#8217;s (<em>x</em>, <em>y</em>) position.
+Access to neighboring fragments is not allowed.
+The values computed by the fragment shader are ultimately used to update
+framebuffer memory or texture memory, depending on the current OpenGL ES
+state and the OpenGL ES command that caused the fragments to be generated.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="compute-processor">2.6. Compute Processor</h3>
+<div class="paragraph">
+<p>The <em>compute processor</em> is a programmable unit that operates independently
+from the other shader processors.
+Compilation units written in the OpenGL ES Shading Language to run on this processor are called
+<em>compute shaders</em>.</p>
+</div>
+<div class="paragraph">
+<p>A compute shader has access to many of the same resources as fragment and
+other shader processors, such as textures, buffers, image variables, and
+atomic counters.
+It does not have fixed-function outputs.
+It is not part of the graphics pipeline and its visible side effects are
+through changes to images, storage buffers, and atomic counters.</p>
+</div>
+<div class="paragraph">
+<p>A compute shader operates on a group of work items called a <em>workgroup</em>.
+A workgroup is a collection of shader invocations that execute the same
+code, potentially in parallel.
+An invocation within a workgroup may share data with other members of the
+same workgroup through shared variables and issue memory and control flow
+barriers to synchronize with other members of the same workgroup.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="basics">3. Basics</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="character-set">3.1. Character Set</h3>
+<div class="paragraph">
+<p>The source character set used for the OpenGL ES Shading Language is Unicode in the UTF-8
+encoding scheme.
+Invalid UTF-8 characters are ignored.
+During pre-processing, the following applies:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A byte with the value zero is always interpreted as the end of the
+string</p>
+</li>
+<li>
+<p>Backslash ('\'), is used to indicate line continuation when immediately
+preceding a new-line.</p>
+</li>
+<li>
+<p>White space consists of one or more of the following characters: the
+space character, horizontal tab, vertical tab, form feed,
+carriage-return, line-feed.</p>
+</li>
+<li>
+<p>The number sign (<strong>#</strong>) is used for preprocessor directives</p>
+</li>
+<li>
+<p>Macro names are restricted to:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>The letters <strong>a-z</strong>, <strong>A-Z</strong>, and the underscore (<strong>_</strong>).</p>
+</li>
+<li>
+<p>The numbers <strong>0-9</strong>, except for the first character of a macro name.</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>After preprocessing, only the following characters are allowed in the
+resulting stream of GLSL tokens:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The letters <strong>a-z</strong>, <strong>A-Z</strong>, and the underscore (<strong>_</strong>).</p>
+</li>
+<li>
+<p>The numbers <strong>0-9</strong>.</p>
+</li>
+<li>
+<p>The symbols period (<strong>.</strong>), plus (<strong>+</strong>), dash (<strong>-</strong>), slash (<strong>/</strong>), asterisk
+(<strong>*</strong>), percent (<strong>%</strong>), angled brackets (<strong>&lt;</strong> and <strong>&gt;</strong>), square brackets
+(<strong>[</strong> and <strong>]</strong>), parentheses (<strong>(</strong> and <strong>)</strong>), braces (<strong>{</strong> and <strong>}</strong>), caret
+(<strong>^</strong>), vertical bar (<strong>|</strong>), ampersand (<strong>&amp;</strong>), tilde (<strong>~</strong>), equals (<strong>=</strong>),
+exclamation point (<strong>!</strong>), colon (<strong>:</strong>), semicolon (<strong>;</strong>), comma (<strong>,</strong>), and
+question mark (<strong>?</strong>).</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>There are no digraphs or trigraphs.
+There are no escape sequences or other uses of the backslash beyond use as
+the line-continuation character.</p>
+</div>
+<div class="paragraph">
+<p>Lines are relevant for compiler diagnostic messages and the preprocessor.
+They are terminated by carriage-return or line-feed.
+If both are used together, it will count as only a single line termination.
+For the remainder of this document, any of these combinations is simply
+referred to as a new-line.
+Lines may be of arbitrary length.</p>
+</div>
+<div class="paragraph">
+<p>In general, the language&#8217;s use of this character set is case sensitive.</p>
+</div>
+<div class="paragraph">
+<p>There are no character or string data types, so no quoting characters are
+included.</p>
+</div>
+<div class="paragraph">
+<p>There is no end-of-file character.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="source-strings">3.2. Source Strings</h3>
+<div class="paragraph">
+<p>The source for a single shader is an array of strings of characters from the
+character set.
+A single shader is made from the concatenation of these strings.
+Each string can contain multiple lines, separated by new-lines.
+No new-lines need be present in a string; a single line can be formed from
+multiple strings.
+No new-lines or other characters are inserted by the implementation when it
+concatenates the strings to form a single shader.</p>
+</div>
+<div class="paragraph">
+<p>Diagnostic messages returned from compiling a shader must identify both the
+line number within a string and which source string the message applies to.
+Source strings are counted sequentially with the first string being string
+0.
+Line numbers are one more than the number of new-lines that have been
+processed, including counting the new-lines that will be removed by the
+line-continuation character (<strong>\</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Lines separated by the line-continuation character preceding a new-line are
+concatenated together before either comment processing or preprocessing.
+This means that no white space is substituted for the line-continuation
+character.
+That is, a single token could be formed by the concatenation by taking the
+characters at the end of one line concatenating them with the characters at
+the beginning of the next line.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> f\
+oo;
+<span class="comment">// forms a single line equivalent to &quot;float foo;&quot;</span>
+<span class="comment">// (assuming '\' is the last character before the new-line and &quot;oo&quot; are</span>
+<span class="comment">// the first two characters of the next line)</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="version-declaration">3.3. Version Declaration</h3>
+<div class="paragraph">
+<p>Shaders must declare the version of the language they are written to.
+The version is specified in the first line of a shader by a character
+string:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#version</span> number es</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>number</em> must be a version of the language, following the same
+convention as __VERSION__ above.
+The directive &#8220;<strong>#version 320 es</strong>&#8221; is required in any shader that
+uses version 3.20 of the language.
+Any <em>number</em> representing a version of the language a compiler does not
+support will cause an error to be generated.
+Version 1.00 of the language does not require shaders to include this
+directive, and shaders that do not include a <strong>#version</strong> directive will be
+treated as targeting version 1.00.</p>
+</div>
+<div class="paragraph">
+<p>Shaders declaring version 3.20 of the shading language cannot be
+linked with shaders declaring a previous version.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>#version</strong> directive must be present in the first line of a shader and
+must be followed by a newline.
+It may contain optional white-space as specified below but no other
+characters are allowed.
+The directive is only permitted in the first line of a shader.</p>
+</div>
+<div class="paragraph">
+<p>Processing of the #version directive occurs before all other preprocessing,
+including line concatenation and comment processing.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>version-declaration</em> : </dt>
+<dd>
+<p><em>whitespace<sub>opt</sub></em> POUND <em>whitespace<sub>opt</sub></em> VERSION <em>whitespace</em> <em>number</em>
+<em>whitespace</em> ES <em>whitespace<sub>opt</sub></em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Tokens:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>POUND <strong>#</strong><br>
+VERSION <strong>version</strong><br>
+ES <strong>es</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+<div class="sect2">
+<h3 id="preprocessor">3.4. Preprocessor</h3>
+<div class="paragraph">
+<p>There is a preprocessor that processes the source strings as part of the
+compilation process.
+Except as noted below, it behaves as the C++ standard preprocessor (see
+&#8220;<a href="#references">Normative References</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>The complete list of preprocessor directives is as follows.</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#<br>
+#define<br>
+#undef<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#if<br>
+#ifdef<br>
+#ifndef<br>
+#else<br>
+#elif<br>
+#endif<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#error<br>
+#pragma<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#extension<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#line</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The following
+operator is
+also available:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>defined<br></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Note that the version directive is not considered to be a preprocessor
+directive and so is not listed here.</p>
+</div>
+<div class="paragraph">
+<p>Each number sign (<strong>#</strong>) can be preceded in its line only by spaces or
+horizontal tabs.
+It may also be followed by spaces and horizontal tabs, preceding the
+directive.
+Each directive is terminated by a new-line.
+Preprocessing does not change the number or relative location of new-lines
+in a source string.</p>
+</div>
+<div class="paragraph">
+<p>The number sign (<strong>#</strong>) on a line by itself is ignored.
+Any directive not listed above will cause an error.</p>
+</div>
+<div class="paragraph">
+<p><strong>#define</strong> and <strong>#undef</strong> functionality are defined as is standard for C++
+preprocessors for macro definitions both with and without macro parameters.</p>
+</div>
+<div class="paragraph">
+<p>The following predefined macros are available:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>__LINE__<br>
+__FILE__<br>
+__VERSION__<br>
+GL_ES</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>__LINE__ will substitute a decimal integer constant that is one more than
+the number of preceding new-lines in the current source string.</p>
+</div>
+<div class="paragraph">
+<p>__FILE__ will substitute a decimal integer constant that says which source
+string number is currently being processed.</p>
+</div>
+<div class="paragraph">
+<p>__VERSION__ will substitute a decimal integer reflecting the version
+number of the OpenGL ES Shading Language.
+The version of the shading language described in this document will have
+__VERSION__ substitute the decimal integer 320.</p>
+</div>
+<div class="paragraph">
+<p>GL_ES will be defined and set to 1.
+This is not true for the non-ES OpenGL Shading Language, so it can be used
+to do a compile time test to determine if a shader is running on an ES
+system.</p>
+</div>
+<div class="paragraph">
+<p>By convention, all macro names containing two consecutive underscores (__)
+are reserved for use by underlying software layers.
+Defining
+such a name in a shader does not itself result in an error, but may
+result in unintended behaviors that stem from having multiple definitions of
+the same name.
+All macro names prefixed with &#8220;GL_&#8221; (&#8220;GL&#8221; followed by a single
+underscore) are also reserved, and defining
+such a name results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>It is an error to undefine or to redefine a built-in (pre-defined) macro
+name.</p>
+</div>
+<div class="paragraph">
+<p>Implementations must support macro-name lengths of up to 1024 characters.
+It is an error to declare a name with a length greater than this.</p>
+</div>
+<div class="paragraph">
+<p><strong>#if</strong>, <strong>#ifdef</strong>, <strong>#ifndef</strong>, <strong>#else</strong>, <strong>#elif</strong>, and <strong>#endif</strong> are defined to
+operate as is standard for C++ preprocessors except for the following:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Expressions following <strong>#if</strong> and <strong>#elif</strong> are
+restricted to <em>pp-constant-expressions</em> as defined below.</p>
+</li>
+<li>
+<p>Undefined identifiers not consumed by the <strong>defined</strong> operator do not
+default to '0'.
+Use of such identifiers causes an error.</p>
+</li>
+<li>
+<p>Character constants are not supported.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>As in C++, a macro name defined with an empty replacement list does not
+default to '0' when used in a preprocessor expression.</p>
+</div>
+<div class="paragraph">
+<p>A <em>pp-constant-expression</em> is an integral expression, evaluated at
+compile-time during preprocessing and formed from literal integer constants
+and the following operators:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Precedence</th>
+<th class="tableblock halign-left valign-top">Operator class</th>
+<th class="tableblock halign-left valign-top">Operators</th>
+<th class="tableblock halign-left valign-top">Associativity</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">unary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">defined<br>
+                                         + - ~ !</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;&lt; &gt;&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt; &gt; &lt;= &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">12 (lowest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The <strong>defined</strong> operator can be used in either of the following ways:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">defined identifier
+defined ( identifier )</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There are no number sign based operators (e.g. no <strong><mark></strong> or <strong></mark>@</strong>), no <strong>##</strong>
+operator, nor is there a <strong>sizeof</strong> operator.</p>
+</div>
+<div class="paragraph">
+<p>The semantics of applying operators in the preprocessor match those standard
+in the C++ preprocessor with the following exceptions:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The 2<sup>nd</sup> operand in a logical and ('&amp;&amp;') operation is evaluated if and
+only if the 1<sup>st</sup> operand evaluates to non-zero.</p>
+</li>
+<li>
+<p>The 2<sup>nd</sup> operand in a logical or ('||') operation is evaluated if and
+only if the 1<sup>st</sup> operand evaluates to zero.</p>
+</li>
+<li>
+<p>There is no boolean type and no boolean literals.
+A <em>true</em> or <em>false</em> result is returned as integer <em>one</em> or <em>zero</em>
+respectively.
+Wherever a boolean operand is expected, any non-zero integer is
+interpreted as <em>true</em> and a zero integer as <em>false</em>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>If an operand is not evaluated, the presence of undefined identifiers in the
+operand will not cause an error.</p>
+</div>
+<div class="paragraph">
+<p><strong>#error</strong> will cause the implementation to put a compile-time diagnostic message
+into the shader object&#8217;s information log (see section 7.12 &#8220;Shader, Program
+and Program Pipeline Queries&#8221; of the <a href="#references">OpenGL ES Specification</a> for how to
+access a shader object&#8217;s information log).
+The message will be the tokens following the <strong>#error</strong> directive, up to the
+first new-line.
+The implementation must treat the presence of a <strong>#error</strong> directive as a
+compile-time error.</p>
+</div>
+<div class="paragraph">
+<p><strong>#pragma</strong> allows implementation-dependent compiler control.
+Tokens following <strong>#pragma</strong> are not subject to preprocessor macro expansion.
+If an implementation does not recognize the tokens following <strong>#pragma</strong>, then
+it will ignore that pragma.
+The following pragmas are defined as part of the language.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>STDGL</strong> pragma is used to reserve pragmas for use by future revisions of
+this language.
+No implementation may use a pragma whose first token is <strong>STDGL</strong>.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> optimize(on)
+<span class="preprocessor">#pragma</span> optimize(off)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to turn off optimizations as an aid in developing and debugging
+shaders.
+It can only be used outside function definitions.
+By default, optimization is turned on for all shaders.
+The debug pragma</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> debug(on)
+<span class="preprocessor">#pragma</span> debug(off)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to enable compiling and annotating a shader with debug
+information, so that it can be used with a debugger.
+It can only be used outside function definitions.
+By default, debug is turned off.</p>
+</div>
+<div class="paragraph">
+<p>The scope as well as the effect of the optimize and debug pragmas is
+implementation-dependent except that their use must not generate an error.
+Incorrect use of predefined pragmas does not cause an error.</p>
+</div>
+<div class="paragraph">
+<p>By default, compilers of this language must issue compile-time
+syntactic, semantic,
+and
+grammatical errors for shaders that do not conform to this specification.
+Any extended behavior must first be enabled.
+Directives to control the behavior of the compiler with respect to
+extensions are declared with the <strong>#extension</strong> directive</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> extension_name : behavior
+<span class="preprocessor">#extension</span> all : behavior</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>extension_name</em> is the name of an extension.
+Extension names are not documented in this specification.
+The token <strong>all</strong> means the behavior applies to all extensions supported by
+the compiler.
+The <em>behavior</em> can be one of the following:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Behavior</th>
+<th class="tableblock halign-left valign-top">Effect</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>require</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br>
+              Give a compile-time error on the <strong>#extension</strong> if the extension
+              <em>extension_name</em> is not supported, or if <strong>all</strong> is specified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>enable</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.<br>
+              Give an error on the <strong>#extension</strong> if <strong>all</strong> is
+              specified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>warn</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>,
+              except issue warnings on any detectable use of that extension,
+              unless such use is supported by other enabled or required
+              extensions.<br>
+              If <strong>all</strong> is specified, then warn on all detectable uses of any
+              extension used.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>disable</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave (including issuing errors and warnings) as if the
+              extension <em>extension_name</em> is not part of the language
+              definition.<br>
+              If <strong>all</strong> is specified, then behavior must revert back to that
+              of the non-extended core version of the language being
+              compiled to.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The <strong>extension</strong> directive is a simple, low-level mechanism to set the
+behavior for each extension.
+It does not define policies such as which combinations are appropriate,
+those must be defined elsewhere.
+Order of directives matters in setting the behavior for each extension:
+Directives that occur later override those seen earlier.
+The <strong>all</strong> variant sets the behavior for all extensions, overriding all
+previously issued <strong>extension</strong> directives, but only for the <em>behaviors</em>
+<strong>warn</strong> and <strong>disable</strong>.</p>
+</div>
+<div class="paragraph">
+<p>The initial state of the compiler is as if the directive</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> all : disable</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>was issued, telling the compiler that all error and warning reporting must
+be done according to this specification, ignoring any extensions.</p>
+</div>
+<div class="paragraph">
+<p>Each extension can define its allowed granularity of scope.
+If nothing is said, the granularity is a shader (that is, a single
+compilation unit), and the extension directives must occur before any
+non-preprocessor tokens.
+If necessary, the linker can enforce granularities larger than a single
+compilation unit, in which case each involved shader will have to contain
+the necessary extension directive.</p>
+</div>
+<div class="paragraph">
+<p>Macro expansion is not done on lines containing <strong>#extension</strong> and <strong>#version</strong>
+directives.</p>
+</div>
+<div class="paragraph">
+<p>For each extension there is an associated macro.
+The macro is always defined in an implementation that supports the
+extension.
+This allows the following construct to be used:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#ifdef</span> OES_extension_name
+    <span class="preprocessor">#extension</span> OES_extension_name : enable
+    <span class="comment">// code that requires the extension</span>
+<span class="preprocessor">#else</span>
+    <span class="comment">// alternative code</span>
+<span class="preprocessor">#endif</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><strong>#line</strong> must have, after macro substitution, one of the following forms:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#line</span> line
+<span class="preprocessor">#line</span> line source-<span class="predefined-type">string</span>-number</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>line</em> and <em>source-string-number</em> are
+<em>pp-constant-expressions</em>.
+If these constant expressions are not integer literals then behavior is undefined.
+After processing this directive (including its new-line), the implementation
+will behave as if it is compiling at line number <em>line</em> and source string
+number <em>source-string-number</em>.
+Subsequent source strings will be numbered sequentially, until another
+<strong>#line</strong> directive overrides that numbering.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="title">Note</div>
+<div class="paragraph">
+<p>Some implementations have allowed constant expressions in #line directives and
+some have not. Even where expressions are supported the grammar is ambiguous and so
+results are implementation dependent. For example,
++ #line +2 +2               // Line number set to 4, or file to 2 and line to 2</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>If during macro expansion a preprocessor directive is encountered, the
+results are undefined; the compiler may or may not report an error in such
+cases.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="comments">3.5. Comments</h3>
+<div class="paragraph">
+<p>Comments are delimited by <strong>/*</strong> and <strong>*/</strong>, or by <strong>//</strong> and a new-line.
+// style comments include the initial // marker and continue up to, but
+not including, the terminating newline.
+/*...*/ comments include both the start and end marker.
+The begin comment delimiters (/* or //) are not recognized as comment
+delimiters inside of a comment, hence comments cannot be nested.
+Comments are treated syntactically as a single space.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tokens">3.6. Tokens</h3>
+<div class="paragraph">
+<p>The language, after preprocessing, is a sequence of tokens.
+A token can be</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>token</em> : </dt>
+<dd>
+<p><em>keyword</em><br>
+<em>identifier</em><br>
+<em>integer-constant</em><br>
+<em>floating-constant</em><br>
+<em>operator</em><br>
+<strong>;</strong> <strong>{</strong> <strong>}</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="keywords">3.7. Keywords</h3>
+<div class="paragraph">
+<p>The following are the keywords in the language and (after
+preprocessing) can only be used as described in this specification,
+or an error results:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>const</strong> <strong>uniform</strong> <strong>buffer</strong> <strong>shared</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>coherent</strong> <strong>volatile</strong> <strong>restrict</strong> <strong>readonly</strong> <strong>writeonly</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>atomic_uint</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>layout</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>centroid</strong> <strong>flat</strong> <strong>smooth</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>patch</strong> <strong>sample</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>invariant</strong> <strong>precise</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>break</strong> <strong>continue</strong> <strong>do</strong> <strong>for</strong> <strong>while</strong> <strong>switch</strong> <strong>case</strong> <strong>default</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>if</strong> <strong>else</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>in</strong> <strong>out</strong> <strong>inout</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>int</strong> <strong>void</strong> <strong>bool</strong> <strong>true</strong> <strong>false</strong> <strong>float</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>discard</strong> <strong>return</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>vec2</strong> <strong>vec3</strong> <strong>vec4</strong> <strong>ivec2</strong> <strong>ivec3</strong> <strong>ivec4</strong> <strong>bvec2</strong> <strong>bvec3</strong> <strong>bvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>uint</strong> <strong>uvec2</strong> <strong>uvec3</strong> <strong>uvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat2</strong> <strong>mat3</strong> <strong>mat4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat2x2</strong> <strong>mat2x3</strong> <strong>mat2x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat3x2</strong> <strong>mat3x3</strong> <strong>mat3x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat4x2</strong> <strong>mat4x3</strong> <strong>mat4x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>lowp</strong> <strong>mediump</strong> <strong>highp</strong> <strong>precision</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2D</strong> <strong>sampler2DShadow</strong> <strong>sampler2DArray</strong> <strong>sampler2DArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isampler2D</strong> <strong>isampler2DArray</strong> <strong>usampler2D</strong> <strong>usampler2DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DMS</strong> <strong>isampler2DMS</strong> <strong>usampler2DMS</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DMSArray</strong> <strong>isampler2DMSArray</strong> <strong>usampler2DMSArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler3D</strong> <strong>isampler3D</strong> <strong>usampler3D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerCube</strong> <strong>samplerCubeShadow</strong> <strong>isamplerCube</strong> <strong>usamplerCube</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerCubeArray</strong> <strong>samplerCubeArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isamplerCubeArray</strong> <strong>usamplerCubeArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerBuffer</strong> <strong>isamplerBuffer</strong> <strong>usamplerBuffer</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2D</strong> <strong>iimage2D</strong> <strong>uimage2D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DArray</strong> <strong>iimage2DArray</strong> <strong>uimage2DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image3D</strong> <strong>iimage3D</strong> <strong>uimage3D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageCube</strong> <strong>iimageCube</strong> <strong>uimageCube</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageCubeArray</strong> <strong>iimageCubeArray</strong> <strong>uimageCubeArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageBuffer</strong> <strong>iimageBuffer</strong> <strong>uimageBuffer</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>struct</strong></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The following are the keywords reserved for future use.
+Using them will result in an error:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>attribute</strong> <strong>varying</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>noperspective</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>subroutine</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>common</strong> <strong>partition</strong> <strong>active</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>asm</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>class</strong> <strong>union</strong> <strong>enum</strong> <strong>typedef</strong> <strong>template</strong> <strong>this</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>resource</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>goto</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>inline</strong> <strong>noinline</strong> <strong>public</strong> <strong>static</strong> <strong>extern</strong> <strong>external</strong> <strong>interface</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>long</strong> <strong>short</strong> <strong>half</strong> <strong>fixed</strong> <strong>unsigned</strong> <strong>superp</strong>
+<strong>double</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>input</strong> <strong>output</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>hvec2</strong> <strong>hvec3</strong> <strong>hvec4</strong> <strong>fvec2</strong> <strong>fvec3</strong> <strong>fvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dvec2</strong> <strong>dvec3</strong> <strong>dvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat2</strong> <strong>dmat3</strong> <strong>dmat4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat2x2</strong> <strong>dmat2x3</strong> <strong>dmat2x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat3x2</strong> <strong>dmat3x3</strong> <strong>dmat3x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat4x2</strong> <strong>dmat4x3</strong> <strong>dmat4x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>filter</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sizeof</strong> <strong>cast</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>namespace</strong> <strong>using</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler1D</strong> <strong>sampler1DShadow</strong> <strong>sampler1DArray</strong> <strong>sampler1DArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isampler1D</strong> <strong>isampler1DArray</strong> <strong>usampler1D</strong> <strong>usampler1DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DRect</strong> <strong>sampler2DRectShadow</strong> <strong>isampler2DRect</strong> <strong>usampler2DRect</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler3DRect</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image1D</strong> <strong>iimage1D</strong> <strong>uimage1D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image1DArray</strong> <strong>iimage1DArray</strong> <strong>uimage1DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DRect</strong> <strong>iimage2DRect</strong> <strong>uimage2DRect</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DMS</strong> <strong>iimage2DMS</strong> <strong>uimage2DMS</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DMSArray</strong> <strong>iimage2DMSArray</strong> <strong>uimage2DMSArray</strong></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>In addition, all identifiers containing two consecutive underscores (__)
+are reserved for use by underlying software layers.
+Defining such a name in a shader does not itself result in an error, but may
+result in unintended behaviors that stem from having multiple definitions of
+the same name.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="identifiers">3.8. Identifiers</h3>
+<div class="paragraph">
+<p>Identifiers are used for variable names, function names, structure names,
+and field selectors (field selectors select components of
+<code><a href="#vector-components">vectors</a></code> and <code><a href="#matrix-components">matrices</a></code>,
+similarly to structure members).
+Identifiers have the form:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>identifier</em> : </dt>
+<dd>
+<p><em>nondigit</em><br>
+<em>identifier</em> <em>nondigit</em><br>
+<em>identifier</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>nondigit</em> : one of </dt>
+<dd>
+<p><strong>_</strong> <strong>a b c d e f g h i j k l m n o p q r s t u v w x y z</strong><br>
+<strong>A B C D E F G H I J K L M N O P Q R S T U V W X Y Z</strong></p>
+</dd>
+<dt class="hdlist1"><em>digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7 8 9</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Identifiers starting with &#8220;gl_&#8221; are reserved for use by OpenGL ES, and
+in general, may not be declared in a shader;
+this results in an error.
+However, as noted in the specification, there are some cases where
+previously declared variables can be redeclared, and predeclared &#8220;gl_&#8221;
+names are allowed to be redeclared in a shader only for these specific
+purposes.</p>
+</div>
+<div class="paragraph">
+<p>Implementations must support identifier lengths of up to 1024 characters.
+It is an error if the length exceeds this value.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="definitions">3.9. Definitions</h3>
+<div class="paragraph">
+<p>Some language rules described below depend on the following definitions.</p>
+</div>
+<div class="sect3">
+<h4 id="static-use">3.9.1. Static Use</h4>
+<div class="paragraph">
+<p>A shader contains a <em>static use</em> of a variable <em>x</em> if, after preprocessing,
+the shader contains a statement that would access any part of <em>x</em>,
+whether or not flow of control will cause that statement to be executed.
+Such a variable is referred to as being <em>statically used</em>. If the access is a
+write then <em>x</em> is further said to be <em>statically assigned</em>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-and-non-uniform-control-flow">3.9.2. Uniform and Non-Uniform Control Flow</h4>
+<div class="paragraph">
+<p>When executing statements in a fragment shader, control flow starts as
+<em>uniform control flow</em>; all fragments enter the same control path into
+<em>main()</em>.
+Control flow becomes <em>non-uniform</em> when different fragments take different
+paths through control-flow statements (selection, iteration, and jumps).
+Control flow subsequently returns to being uniform after such divergent
+sub-statements or skipped code completes, until the next time different
+control paths are taken.</p>
+</div>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">main()
+{
+    <span class="predefined-type">float</span> a = ...; <span class="comment">// this is uniform control flow</span>
+    <span class="keyword">if</span> (a &lt; b) {   <span class="comment">// this expression is true for some fragments, not all</span>
+        ...;       <span class="comment">// non-uniform control flow</span>
+    } <span class="keyword">else</span> {
+        ...;       <span class="comment">// non-uniform control flow</span>
+    }
+    ...;           <span class="comment">// uniform control flow again</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Other examples of non-uniform control flow can occur within switch
+statements and after conditional breaks, continues, early returns, and after
+fragment discards, when the condition is true for some fragments but not
+others.
+Loop iterations that only some fragments execute are also non-uniform
+control flow.</p>
+</div>
+<div class="paragraph">
+<p>This is similarly defined for other shader stages, based on the per-instance
+data items they process.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="dynamically-uniform-expressions">3.9.3. Dynamically Uniform Expressions</h4>
+<div class="paragraph">
+<p>A fragment-shader expression is <em>dynamically uniform</em> if all fragments
+evaluating it get the same resulting value.
+When loops are involved, this refers to the expression&#8217;s value for the same
+loop iteration.
+When functions are involved, this refers to calls from the same call point.</p>
+</div>
+<div class="paragraph">
+<p>This is similarly defined for other shader stages, based on the per-instance
+data they process.</p>
+</div>
+<div class="paragraph">
+<p>Note that constant expressions are trivially dynamically uniform.
+It follows that typical loop counters based on these are also dynamically
+uniform.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="logical-phases-of-compilation">3.10. Logical Phases of Compilation</h3>
+<div class="paragraph">
+<p>The compilation units for the shader processors are processed separately
+before optionally being linked together in the final stage of compilation.
+The logical phases of compilation are:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Source strings are input as byte sequences.
+The value 'zero' is interpreted as a terminator.</p>
+</li>
+<li>
+<p>Source strings are concatenated to form a single input.
+Zero bytes are discarded but all other values are retained.</p>
+</li>
+<li>
+<p>Each string is interpreted according to the UTF-8 standard, with the
+exception that all invalid byte sequences are retained in their original
+form for subsequent processing.</p>
+</li>
+<li>
+<p>Each {carriage-return, line-feed} and {line-feed, carriage return}
+sequence is replaced by a single newline.
+All remaining carriage-return and line-feed characters are then each
+replaced by a newline.</p>
+</li>
+<li>
+<p>Line numbering for each character, which is equal to the number of
+preceding newlines plus one, is noted.
+Note this can only be subsequently changed by the #line directive and is
+not affected by the removal of newlines in phase 6 of compilation.</p>
+</li>
+<li>
+<p>Wherever a backslash ('\') occurs immediately before a newline, both are
+deleted.
+Note that no whitespace is substituted, thereby allowing a single
+preprocessing token to span a newline.
+This operation is not recursive; any new {backslash newline} sequences
+generated are not removed.</p>
+</li>
+<li>
+<p>All comments are replaced with a single space.
+All (non-zero) characters and invalid UTF-8 byte sequences are allowed
+within comments.
+'//' style comments include the initial '//' marker and continue up to,
+but not including, the terminating newline.
+'/<strong>&#8230;&#8203;</strong>/' comments include both the start and end marker.</p>
+</li>
+<li>
+<p>The source string is converted into a sequence of preprocessing tokens.
+These tokens include preprocessing numbers, identifiers and
+preprocessing operations.
+The line number associated with each token is copied from the line
+number of the first character of the token.</p>
+</li>
+<li>
+<p>The preprocessor is run.
+Directives are executed and macro expansion is performed.</p>
+</li>
+<li>
+<p>White space and newlines are discarded.</p>
+</li>
+<li>
+<p>Preprocessing tokens are converted into tokens.</p>
+</li>
+<li>
+<p>The syntax is analyzed according to the GLSL ES grammar.</p>
+</li>
+<li>
+<p>The result is checked according to the semantic rules of the language.</p>
+</li>
+<li>
+<p>Optionally, the shaders are linked together to form one or more programs
+or separable programs.
+When a pair of shaders from consecutive stages are linked into the same
+program, any outputs and corresponding inputs not used in both shaders
+may be discarded.</p>
+</li>
+<li>
+<p>The binary is generated.</p>
+</li>
+</ol>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="variables-and-types">4. Variables and Types</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>All variables and functions must be declared before being used.
+Variable and function names are identifiers.</p>
+</div>
+<div class="paragraph">
+<p>There are no default types.
+All variable and function declarations must have a declared type, and
+optionally qualifiers.
+A variable is declared by specifying its type followed by one or more names
+separated by commas.
+In many cases, a variable can be initialized as part of its declaration by
+using the assignment operator (<strong>=</strong>).</p>
+</div>
+<div class="paragraph">
+<p>User-defined types may be defined using <strong>struct</strong> to aggregate a list of
+existing types into a single name.</p>
+</div>
+<div class="paragraph">
+<p>The OpenGL ES Shading Language is type safe.
+There are no implicit conversions between types.</p>
+</div>
+<div class="sect2">
+<h3 id="basic-types">4.1. Basic Types</h3>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>A <em>basic type</em> is a type defined by a keyword in the language.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The OpenGL ES Shading Language supports the following basic data types, grouped as follows.</p>
+</div>
+<div class="sect3">
+<h4 id="_transparent_types">4.1.1. Transparent Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>void</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for functions that do not return a value</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bool</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a conditional type, taking on values of true or false</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a signed integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uint</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">an unsigned integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>float</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point scalar</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 2 × 2 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 3 × 3 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 4 × 4 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat4</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Note that where the following tables say &#8220;accessing a texture&#8221;, the
+<strong>sampler*</strong> opaque types access textures, and the <strong>image*</strong> opaque types
+access images, of a specified type.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_floating_point_opaque_types">4.1.2. Floating-Point Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2D</strong><br>
+  <strong>image2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArray</strong><br>
+  <strong>image2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArrayShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler3D</strong><br>
+  <strong>image3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCube</strong><br>
+  <strong>imageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArray</strong><br>
+  <strong>imageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArrayShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerBuffer</strong><br>
+  <strong>imageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a buffer texture</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_signed_integer_opaque_types">4.1.3. Signed Integer Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2D</strong><br>
+  <strong>iimage2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DArray</strong><br>
+  <strong>iimage2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler3D</strong><br>
+  <strong>iimage3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCube</strong><br>
+  <strong>iimageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCubeArray</strong><br>
+  <strong>iimageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerBuffer</strong><br>
+  <strong>iimageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer buffer texture</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_unsigned_integer_opaque_types">4.1.4. Unsigned Integer Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2D</strong><br>
+  <strong>uimage2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DArray</strong><br>
+  <strong>uimage2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler3D</strong><br>
+  <strong>uimage3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCube</strong><br>
+  <strong>uimageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCubeArray</strong><br>
+  <strong>uimageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerBuffer</strong><br>
+  <strong>uimageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer buffer texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>atomic_uint</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer atomic counter</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>In addition, a shader can aggregate these basic types using arrays and
+structures to build more complex types.</p>
+</div>
+<div class="paragraph">
+<p>There are no pointer types.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="void">4.1.5. Void</h4>
+<div class="paragraph">
+<p>Functions that do not return a value must be declared as <strong>void</strong>.
+There is no default function return type.
+The keyword <strong>void</strong> cannot be used in any other declarations (except for
+empty formal or actual parameter lists), or an error results.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="booleans">4.1.6. Booleans</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>A <em>boolean type</em> is any boolean scalar or vector type (<strong>bool</strong>, <strong>bvec2</strong>,
+<strong>bvec3</strong>, <strong>bvec4</strong>)</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>To make conditional execution of code easier to express, the type <strong>bool</strong> is
+supported.
+There is no expectation that hardware directly supports variables of this
+type.
+It is a genuine Boolean type, holding only one of two values meaning either
+true or false.
+Two keywords <strong>true</strong> and <strong>false</strong> can be used as literal Boolean constants.
+Booleans are declared and optionally initialized as in the follow example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">bool</span> success;      <span class="comment">// declare &quot;success&quot; to be a Boolean</span>
+<span class="predefined-type">bool</span> done = <span class="predefined-constant">false</span>; <span class="comment">// declare and initialize &quot;done&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Expressions used for conditional jumps (<strong>if</strong>, <strong>for</strong>, <strong>?:</strong>, <strong>while</strong>,
+<strong>do</strong>-<strong>while</strong>) must evaluate to the type <strong>bool</strong>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="integers">4.1.7. Integers</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definitions</dt>
+<dd>
+<p>An <em>integral type</em> is any signed or unsigned, scalar or vector integer type.
+It excludes arrays and structures.</p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>A <em>scalar integral type</em> is a scalar signed or unsigned integer type:</p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>A <em>vector integral type</em> is a vector of signed or unsigned integers:</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Signed and unsigned integer variables are fully supported.
+In this document, the term <em>integer</em> is meant to generally include both
+signed and unsigned integers.
+<strong>highp</strong> unsigned
+integers have exactly 32 bits of precision.
+<strong>highp</strong> signed
+integers use 32 bits, including a sign bit, in two&#8217;s complement form.</p>
+</div>
+<div class="paragraph">
+<p><strong>mediump</strong> and <strong>lowp</strong> integers have implementation-defined numbers of bits.
+See &#8220;<a href="#range-and-precision">Range and Precision</a>&#8221; for details.
+For all precisions,
+operations resulting in overflow or
+underflow will not cause any exception, nor will they saturate, rather they
+will &#8220;wrap&#8221; to yield the low-order
+n bits of the result where n is the size in bits of the integer.
+However, for the case where the minimum representable value is divided by
+-1, it is allowed to return either the minimum representable value or the
+maximum representable value.</p>
+</div>
+<div class="paragraph">
+<p>Integers are declared and optionally initialized with integer expressions,
+as in the following example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> i, j = <span class="integer">42</span>; <span class="comment">// default integer literal type is int</span>
+uint k = <span class="integer">3</span>u;   <span class="comment">// &quot;u&quot; establishes the type as uint</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Literal integer constants can be expressed in decimal (base 10), octal (base
+8), or hexadecimal (base 16) as follows.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>integer-constant</em> : </dt>
+<dd>
+<p><em>decimal-constant</em> <em>integer-suffix<sub>opt</sub></em><br>
+<em>octal-constant</em> <em>integer-suffix<sub>opt</sub></em><br>
+<em>hexadecimal-constant</em> <em>integer-suffix<sub>opt</sub></em></p>
+</dd>
+<dt class="hdlist1"><em>integer-suffix</em> : one of </dt>
+<dd>
+<p><strong>u</strong> <strong>U</strong></p>
+</dd>
+<dt class="hdlist1"><em>decimal-constant</em> : </dt>
+<dd>
+<p><em>nonzero-digit</em><br>
+<em>decimal-constant</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>octal-constant</em> : </dt>
+<dd>
+<p><strong>0</strong><br>
+<em>octal-constant</em> <em>octal-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>hexadecimal-constant</em> : </dt>
+<dd>
+<p><strong>0x</strong> <em>hexadecimal-digit</em><br>
+<strong>0X</strong> <em>hexadecimal-digit</em><br>
+<em>hexadecimal-constant</em> <em>hexadecimal-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>digit</em> : </dt>
+<dd>
+<p><strong>0</strong><br>
+<em>nonzero-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>nonzero-digit</em> : one of </dt>
+<dd>
+<p><strong>1 2 3 4 5 6 7 8 9</strong></p>
+</dd>
+<dt class="hdlist1"><em>octal-digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7</strong></p>
+</dd>
+<dt class="hdlist1"><em>hexadecimal-digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7 8 9<br>
+a b c d e f<br>
+A B C D E F</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>No white space is allowed between the digits of an integer constant,
+including after the leading <strong>0</strong> or after the leading <strong>0x</strong> or <strong>0X</strong> of a
+constant, or before the suffix <strong>u</strong> or <strong>U</strong>.
+When the suffix <strong>u</strong> or <strong>U</strong> is present, the literal has type <strong>uint</strong>,
+otherwise the type is <strong>int</strong>.
+A leading unary minus sign (-) is interpreted as an arithmetic unary
+negation, not as part of the constant.
+Hence, literals themselves are always expressed with non-negative syntax,
+though they could result in a negative value.</p>
+</div>
+<div class="paragraph">
+<p>It is an error to provide a literal integer whose bit pattern
+cannot fit in 32 bits.
+The bit pattern of the literal is always used unmodified.
+So a signed literal whose bit pattern includes a set sign bit creates a
+negative value.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="integer">1</span>             <span class="comment">// OK. Signed integer, value 1</span>
+<span class="integer">1</span>u            <span class="comment">// OK. Unsigned integer, value 1</span>
+-<span class="integer">1</span>            <span class="comment">// OK. Unary minus applied to signed integer.</span>
+              <span class="comment">// result is a signed integer, value -1</span>
+-<span class="integer">1</span>u           <span class="comment">// OK. Unary minus applies to unsigned integer.</span>
+              <span class="comment">// Result is an unsigned integer, value 0xffffffff</span>
+<span class="hex">0xA0000000</span>    <span class="comment">// OK. 32-bit signed hexadecimal</span>
+<span class="hex">0xABcdEF00</span>u   <span class="comment">// OK. 32-bit unsigned hexadecimal</span>
+<span class="hex">0xffffffff</span>    <span class="comment">// OK. Signed integer, value -1</span>
+<span class="hex">0x80000000</span>    <span class="comment">// OK. Evaluates to -2147483648</span>
+<span class="hex">0xffffffff</span>u   <span class="comment">// OK. Unsigned integer, value 0xffffffff</span>
+<span class="hex">0xfffffffff</span>   <span class="comment">// Error: needs more than 32 bits</span>
+<span class="integer">3000000000</span>    <span class="comment">// OK. A signed decimal literal taking 32 bits.</span>
+              <span class="comment">// It evaluates to -1294967296</span>
+<span class="integer">2147483648</span>    <span class="comment">// OK. Evaluates to -2147483648 (the literal set the sign bit)</span>
+<span class="integer">5000000000</span>    <span class="comment">// Error: needs more than 32 bits</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="floats">4.1.8. Floats</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>A <em>floating-point type</em> is any floating-point scalar, vector or matrix type.
+It excludes arrays and structures.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Floats are available for use in a variety of scalar calculations.
+Floating-point variables are defined as in the following example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a, b = <span class="float">1</span><span class="float">.5</span>;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>As an input value to one of the processing units, a floating-point variable
+is expected to match the IEEE 754 single precision floating-point definition
+for precision and dynamic range.
+<strong>highp</strong> floating-point variables within a shader are encoded according to
+the IEEE 754 specification for single-precision floating-point values
+(logically, not necessarily physically).
+While encodings are logically IEEE 754, operations (addition,
+multiplication, etc.) are not necessarily performed as required by IEEE 754.
+See &#8220;<a href="#range-and-precision">Range and Precision</a>&#8221; for more details on
+precision and usage of NaNs (Not a Number) and Infs (positive or negative
+infinities).</p>
+</div>
+<div class="paragraph">
+<p>Floating-point constants are defined as follows.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>floating-constant</em> : </dt>
+<dd>
+<p><em>fractional-constant</em> <em>exponent-part<sub>opt</sub></em> <em>floating-suffix<sub>opt</sub></em><br>
+<em>digit-sequence</em> <em>exponent-part</em> <em>floating-suffix<sub>opt</sub></em></p>
+</dd>
+<dt class="hdlist1"><em>fractional-constant</em> : </dt>
+<dd>
+<p><em>digit-sequence</em> <strong>.</strong> <em>digit-sequence</em><br>
+<em>digit-sequence</em> <strong>.</strong><br>
+<strong>.</strong> <em>digit-sequence</em></p>
+</dd>
+<dt class="hdlist1"><em>exponent-part</em> : </dt>
+<dd>
+<p><strong>e</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em><br>
+<strong>E</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em></p>
+</dd>
+<dt class="hdlist1"><em>sign</em> : one of </dt>
+<dd>
+<p><strong>+</strong> <strong>-</strong></p>
+</dd>
+<dt class="hdlist1"><em>digit-sequence</em> : </dt>
+<dd>
+<p><em>digit</em><br>
+<em>digit-sequence</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>floating-suffix</em> : one of </dt>
+<dd>
+<p><strong>f</strong> <strong>F</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>A decimal point (<strong>.</strong>) is not needed if the exponent part is present.
+No white space may appear anywhere within a floating-point constant,
+including before a suffix.
+A leading unary minus sign (<strong>-</strong>) is interpreted as a unary operator and is
+not part of the floating-point constant.</p>
+</div>
+<div class="paragraph">
+<p>There is no limit on the number of digits in any <em>digit-sequence</em>.
+If the value of the floating-point number is too large (small) to be stored
+as a single precision value, it is converted to positive (negative)
+infinity.
+A value with a magnitude too small to be represented as a mantissa and
+exponent is converted to zero.
+Implementations may also convert subnormal (denormalized) numbers to zero.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="vectors">4.1.9. Vectors</h4>
+<div class="paragraph">
+<p>The OpenGL ES Shading Language includes data types for generic 2-, 3-, and 4-component vectors
+of floating-point values, integers, and Booleans.
+Floating-point vector variables can be used to store colors, normals,
+positions, texture coordinates, texture lookup results and the like.
+Boolean vectors can be used for component-wise comparisons of numeric
+vectors.
+Some examples of vector declarations are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec2 texcoord1, texcoord2;
+vec3 position;
+vec4 myRGBA;
+ivec2 textureLookup;
+bvec3 less;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Initialization of vectors can be done with constructors.
+See &#8220;<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="matrices">4.1.10. Matrices</h4>
+<div class="paragraph">
+<p>The OpenGL ES Shading Language has built-in types for 2 × 2, 2 × 3, 2 × 4, 3
+× 2, 3 × 3, 3 × 4, 4 × 2, 4 × 3, and 4 ×
+4 matrices of floating-point numbers.
+The first number in the type is the number of columns, the second is the
+number of rows.
+If there is only one number, the matrix is square.
+Example matrix declarations:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2 mat2D;
+mat3 optMatrix;
+mat4 view, projection;
+mat4x4 view; <span class="comment">// an alternate way of declaring a mat4</span>
+mat3x2 m;    <span class="comment">// a matrix with 3 columns and 2 rows</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Initialization of matrix values is done with constructors (described in
+&#8220;<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>&#8221;) in
+column-major order.</p>
+</div>
+<div class="paragraph">
+<p><strong>mat2</strong> is an alias for <strong>mat2x2</strong>, not a distinct type.
+Similarly for <strong>mat3</strong> and <strong>mat4.</strong> The following is legal:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2 a;
+mat2x2 b = a;</code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="opaque-types">4.1.11. Opaque Types</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>An <em>opaque type</em> is a type where the internal structure of the type is
+hidden from the language.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The opaque types, as listed in the following sections, declare variables
+that are effectively opaque handles to other objects.
+These objects are accessed through built-in functions, not through direct
+reading or writing of the declared variable.
+They can only be declared as function parameters or in <strong>uniform</strong>-qualified
+variables (see &#8220;<a href="#uniform-variables">Uniform Variables</a>&#8221;).
+The only opaque types that take memory qualifiers are the image types.
+Except for array indexing, structure member selection, and parentheses,
+opaque variables are not allowed to be operands in expressions; such use
+results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>When aggregated into arrays within a shader, opaque types can only be
+indexed with a dynamically uniform integral expression (see &#8220;Dynamically
+Uniform Expressions&#8221;) unless otherwise noted; otherwise, results are
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>Opaque variables cannot be treated as l-values; hence cannot be used as
+<strong>out</strong> or <strong>inout</strong> function parameters, nor can they be assigned into.
+Any such use results in a compile-time error.
+However, they can be passed as <strong>in</strong> parameters with matching types and
+memory qualifiers.
+They cannot be declared with an initializer.</p>
+</div>
+<div class="paragraph">
+<p>Because a single opaque type declaration effectively declares two objects,
+the opaque handle itself and the object it is a handle to, there is room for
+both a storage qualifier and a memory qualifier.
+The storage qualifier will qualify the opaque handle, while the memory
+qualifier will qualify the object it is a handle to.</p>
+</div>
+<div class="sect4">
+<h5 id="samplers">Samplers</h5>
+<div class="paragraph">
+<p>Sampler types (e.g. <strong>sampler2D</strong>) are opaque types, declared and behaving as
+described above for opaque types.</p>
+</div>
+<div class="paragraph">
+<p>Sampler variables are handles to
+two-, and three- dimensional textures, cube maps, depth textures (shadowing),
+etc., as enumerated in the basic types tables.
+There are distinct sampler types for each texture target, and for each of
+float, integer, and unsigned integer data types.
+Texture accesses are done through built-in texture functions (described in
+&#8220;<a href="#texture-functions">Texture Functions</a>&#8221;) and samplers are used to
+specify which texture to access and how it is to be filtered.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="images">Images</h5>
+<div class="paragraph">
+<p>Image types are opaque types, declared and behaving as described above for
+opaque types.
+They can be further qualified with memory qualifiers.
+When aggregated into arrays within a shader, images can only be indexed with
+a constant integral expression.</p>
+</div>
+<div class="paragraph">
+<p>Image variables are handles to
+two-, or three-dimensional images
+corresponding to all or a portion of a single level of a texture image bound
+to an image unit.
+There are distinct image variable types for each texture target, and for
+each of float, integer, and unsigned integer data types.
+Image accesses should use an image type that matches the target of the
+texture whose level is bound to the image unit, or for non-layered bindings
+of 3D or array images should use the image type that matches the
+dimensionality of the layer of the image (i.e., a layer of 3D, 2DArray,
+Cube, or CubeArray should use
+<strong>image2D</strong>).
+If the image target type does not match the bound image in this manner, if
+the data type does not match the bound image, or if the format layout
+qualifier does not match the image unit format as described in section
+8.22
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL ES Specification</a>, the
+results of image accesses are undefined but cannot include program
+termination.</p>
+</div>
+<div class="paragraph">
+<p>Image variables are used in the image load, store, and atomic functions
+described in &#8220;<a href="#image-functions">Image Functions</a>&#8221; to specify an image to
+access.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="atomic-counters">Atomic Counters</h5>
+<div class="paragraph">
+<p>Atomic counter types (e.g. <strong>atomic_uint</strong>) are opaque handles to counters,
+declared and behaving as described above for opaque types.
+The variables they declare specify which counter to access when using the
+built-in atomic counter functions as described in
+&#8220;<a href="#atomic-counter-functions">Atomic Counter Functions</a>&#8221;.
+They are bound to buffers as described in
+&#8220;<a href="#atomic-counter-layout-qualifiers">Atomic Counter Layout Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Atomic counters aggregated into arrays within a shader can only be indexed
+with dynamically uniform integral expressions, otherwise results are
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>Members of structures cannot be declared as atomic counter types.</p>
+</div>
+<div class="paragraph">
+<p>The default precision of all atomic types is <strong>highp</strong>.
+It is an error to declare an atomic type with a different precision or to
+specify the default precision for an atomic type to be <strong>lowp</strong> or <strong>mediump</strong>.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="structures">4.1.12. Structures</h4>
+<div class="paragraph">
+<p>User-defined types can be created by aggregating other already defined types
+into a structure using the <strong>struct</strong> keyword.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light {
+    <span class="predefined-type">float</span> intensity;
+    vec3 position;
+} lightVar;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In this example, <em>light</em> becomes the name of the new type, and <em>lightVar</em>
+becomes a variable of type <em>light</em>.
+To declare variables of the new type, use its name (without the keyword
+<strong>struct</strong>).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">light lightVar2;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>More formally, structures are declared as follows.
+However, the definitive grammar is as given in
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221;.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>struct-definition</em> : </dt>
+<dd>
+<p><em>qualifier<sub>opt</sub></em> <strong>struct</strong> name<sub>opt</sub>_ <strong>{</strong> <em>member-list</em> <strong>}</strong>
+<em>declarators<sub>opt</sub></em> <strong>;</strong></p>
+</dd>
+<dt class="hdlist1"><em>member-list</em> : </dt>
+<dd>
+<p><em>member-declaration</em> <strong>;</strong><br>
+<em>member-declaration</em> <em>member-list</em> <strong>;</strong></p>
+</dd>
+<dt class="hdlist1"><em>member-declaration</em> : </dt>
+<dd>
+<p><em>basic-type</em> <em>declarators</em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>name</em> becomes the user-defined type, and can be used to declare
+variables to be of this new type.
+The <em>name</em> shares the same name space as other variables, types, and
+functions.
+All previously visible variables, types, constructors, or functions with
+that name are hidden.
+The optional <em>qualifier</em> only applies to any <em>declarators</em>, and is not part
+of the type being defined for <em>name</em>.</p>
+</div>
+<div class="paragraph">
+<p>Structures must have at least one member declaration.
+Member declarators may contain precision qualifiers, but use of any other
+qualifier results in an error.
+Bit fields are not supported.
+Member types must be already defined (there are no forward references).
+Member declarations cannot contain initializers.
+Member declarators can contain arrays.
+Such arrays must have a size specified, and the size must be a constant
+integral expression that&#8217;s greater than zero (see
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;).
+Each level of structure has its own name space for names given in member
+declarators; such names need only be unique within that name space.</p>
+</div>
+<div class="paragraph">
+<p>Anonymous structures are not supported.
+Embedded structure definitions are not supported.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S { <span class="predefined-type">float</span> f; }; <span class="comment">// Allowed: S is defined as a structure.</span>
+
+<span class="keyword">struct</span> T {
+    S;              <span class="comment">// Error: anonymous structures disallowed</span>
+    <span class="keyword">struct</span> { ... }; <span class="comment">// Error: embedded structures disallowed</span>
+    S s;            <span class="comment">// Allowed: nested structure with a name.</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Structures can be initialized at declaration time using constructors, as
+discussed in &#8220;<a href="#structure-constructors">Structure Constructors</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Any restrictions on the usage of a type or qualifier also apply to any
+structure that contains a member of that type or qualifier.
+This also applies to structure members that are structures, recursively.</p>
+</div>
+<div class="paragraph">
+<p>Structures can contain variables of any type except:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>atomic_uint</strong> (since there is no mechanism to specify the binding)</p>
+</li>
+<li>
+<p>image types (since there is no mechanism to specify the format
+qualifier)</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="arrays">4.1.13. Arrays</h4>
+<div class="paragraph">
+<p>Variables of the same type can be aggregated into arrays by declaring a name
+followed by brackets (<strong>[ ]</strong>) enclosing an optional size.</p>
+</div>
+<div class="paragraph">
+<p>When present, the array size must be a constant integral expression (see
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;) greater than zero.
+The type of the size parameter can be a signed or unsigned integer and the
+choice of type does not affect the type of the resulting array.
+Arrays only have a single dimension (a single number within &#8220;[ ]&#8221;),
+however, arrays of arrays can be declared.
+Any type can be formed into an array.</p>
+</div>
+<div class="paragraph">
+<p>Arrays are sized either at compile-time or at run-time.
+To size an array at compile-time, either the size must be specified within
+the brackets as above or must be inferred from the type of the initializer.</p>
+</div>
+<div class="paragraph">
+<p>If an array is declared as the last member of a shader storage block and the
+size is not specified at compile-time, it is sized at run-time.
+In all other cases, arrays are sized only at compile-time.
+An array declaration sized at compile-time which leaves the size of the
+array unspecified is an error.</p>
+</div>
+<div class="paragraph">
+<p>For compile-time sized arrays, it is illegal to index an array with a
+constant integral expression greater than or equal to the declared size or
+with a negative constant expression.
+Arrays declared as formal parameters in a function declaration must also
+specify a size.
+Undefined behavior results from indexing an array with a non-constant
+expression that&#8217;s greater than or equal to the array&#8217;s size or less than 0.
+If robust buffer access is enabled (see section 10.3.5 &#8220;Robust Buffer
+Access&#8221; of the <a href="#references">OpenGL ES Specification</a>), such indexing must not result in
+abnormal program termination.
+The results are still undefined, but implementations are encouraged to
+produce zero values for such accesses.</p>
+</div>
+<div class="paragraph">
+<p>Some examples are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> frequencies[<span class="integer">3</span>];
+uniform vec4 lightPosition[<span class="integer">4</span>u];
+<span class="directive">const</span> <span class="predefined-type">int</span> numLights = <span class="integer">2</span>;
+light lights[numLights];
+vec4 a[<span class="integer">3</span>][<span class="integer">2</span>];
+a.length() <span class="comment">// this is 3</span>
+a[x].length() <span class="comment">// this is 2</span>
+<span class="comment">// a shader storage block, introduced in section 4.3.7 &quot;Buffer Variables&quot;</span>
+buffer b {
+    <span class="predefined-type">float</span> u[]; <span class="comment">// an error</span>
+    vec4 v[];  <span class="comment">// okay, v will be sized at run-time</span>
+} name[<span class="integer">3</span>];     <span class="comment">// when the block is arrayed, all u will be the same size,</span>
+               <span class="comment">// but not necessarily all v, if sized dynamically</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When the <strong>length</strong>() method will return a compile-time constant, the
+expression in brackets (x above) will be evaluated and subject to the rules
+required for array indices, but the array will not be dereferenced.
+Thus, behavior is well defined even if the run-time value of the expression
+is out of bounds.</p>
+</div>
+<div class="paragraph">
+<p>An array type can be formed by specifying a non-array type
+(<a href="#type_specifier_nonarray">[type_specifier_nonarray]</a>) followed by an <a href="#array_specifier">[array_specifier]</a>.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that the construct <em>type [size]</em> does not always result in an array of
+length <em>size</em> of type <em>type</em>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">2</span>][<span class="integer">3</span>] <span class="comment">// an array of size [2] of array of size [3] of float,</span>
+            <span class="comment">// not size [3] of float[2]</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This type can be used anywhere any other type can be used, including as the
+return value from a function</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] foo() { }</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>as a constructor of an array:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>as an unnamed parameter:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> foo(<span class="predefined-type">float</span>[<span class="integer">5</span>])</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and as an alternate way of declaring a variable or function parameter:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] a;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>An array type can also be formed without specifying a size if the definition
+includes an initializer:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> x[] = <span class="predefined-type">float</span>[<span class="integer">2</span>] (<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>); <span class="comment">// declares an array of size 2</span>
+<span class="predefined-type">float</span> y[] = <span class="predefined-type">float</span>[] (<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>); <span class="comment">// declares an array of size 3</span>
+<span class="predefined-type">float</span> a[<span class="integer">5</span>];
+<span class="predefined-type">float</span> b[] = a;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that the initializer itself does not need to be a constant expression
+but the length of the initializer will be a constant expression.</p>
+</div>
+<div class="paragraph">
+<p>Arrays can have initializers formed from array constructors:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+<span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);  <span class="comment">// same thing</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>An array of arrays can be declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 a[<span class="integer">3</span>][<span class="integer">2</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>which declares a one-dimensional array of size 3 of one-dimensional arrays
+of size 2 of <strong>vec4</strong>.
+The following declarations do the same thing:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4[<span class="integer">2</span>] a[<span class="integer">3</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span>
+vec4[<span class="integer">3</span>][<span class="integer">2</span>] a; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When in transparent memory (like in a uniform block), the layout is that the
+inner-most (right-most in declaration) dimensions iterate faster than the
+outer dimensions.
+That is, for the above, the order in memory would be:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>Low address : a[0][0] : a[0][1] : a[1][0] : a[1][1] : a[2][0] : a[2][1]
+: High address</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The last member of a shader storage block (see &#8220;<a href="#buffer-variables">Buffer
+Variables</a>&#8221;), may be declared without specifying a size.
+For such arrays, the effective array size is inferred at run-time from the
+size of the data store backing the shader storage block.
+Such runtime-sized arrays may be indexed with general integer expressions,
+but may not be passed as an argument to a function or indexed with a
+negative constant expression.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S { <span class="predefined-type">float</span> f; };
+buffer ShaderStorageBlock1
+{
+    vec4 a[]; <span class="comment">// illegal</span>
+    vec4 b[]; <span class="comment">// legal, runtime-sized arrays are last member</span>
+};
+buffer ShaderStorageBlock2
+{
+    vec4 a[<span class="integer">4</span>]; <span class="comment">// legal, size declared</span>
+    S b[]; <span class="comment">// legal, runtime-sized arrays are allowed,</span>
+    <span class="comment">// including arrays of structures</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>However, it is a compile-time error to assign to a runtime-sized array.
+Assignments to individual elements of the array is allowed.</p>
+</div>
+<div class="paragraph">
+<p>Arrays have a fixed number of elements.
+This can be obtained by using the <strong>length</strong>() method:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>];
+a.length(); <span class="comment">// returns 5</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The return value is a signed integral expression.
+For compile-time sized arrays, the value returned by the length method is a
+constant expression.
+For run-time sized arrays , the value returned will not be constant
+expression and will be determined at run time based on the size of the
+buffer object providing storage for the block.</p>
+</div>
+<div class="paragraph">
+<p>The precision is determined using the same rules as for other cases where
+there is no intrinsic precision.
+See &#8220;<a href="#precision-qualifiers">Precision Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Any restrictions on the usage of a type also apply to arrays of that type.
+This applies recursively.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="scoping">4.2. Scoping</h3>
+<div class="paragraph">
+<p>The scope of a declaration determines where the declaration is visible.
+GLSL ES uses a system of statically nested scopes.
+This allows names to be redefined within a shader.</p>
+</div>
+<div class="sect3">
+<h4 id="definition-of-terms">4.2.1. Definition of Terms</h4>
+<div class="paragraph">
+<p>The term <em>scope</em> refers to a specified region of the program where names are
+guaranteed to be visible.
+For example, a <em>compound_statement_with_scope</em> ('{' <em>statement</em> <em>statement</em>
+&#8230;&#8203;
+'}') defines a scope.</p>
+</div>
+<div class="paragraph">
+<p>A <em>nested scope</em> is a scope defined within an outer scope.</p>
+</div>
+<div class="paragraph">
+<p>The terms '<em>same scope'</em> and '<em>current scope</em>' are equivalent to the term
+'<em>scope</em>' but used to emphasize that nested scopes are excluded.</p>
+</div>
+<div class="paragraph">
+<p>The <em>scope of a declaration</em> is the region or regions of the program where
+that declaration is visible.</p>
+</div>
+<div class="paragraph">
+<p>A <em>name space</em> defines where names may be defined.
+Within a single name space, a name has at most one entry, specifying it to
+be one of: structure, variable, or function.</p>
+</div>
+<div class="paragraph">
+<p>In general, each scope has an associated name space.
+However, in certain cases e.g. for uniforms, multiple scopes share the same
+name space.
+In these cases, conflicting declarations are an error, even though the name
+is only visible in the scopes where it is declared.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="types-of-scope">4.2.2. Types of Scope</h4>
+<div class="paragraph">
+<p>The scope of a variable is determined by where it is declared.
+If it is declared outside all function definitions, it has global scope,
+which starts from where it is declared and persists to the end of the shader
+it is declared in.
+If it is declared in a <strong>while</strong> test or a <strong>for</strong> statement, then it is scoped
+to the end of the following sub-statement (specified as
+<em>statement-no-new-scope</em> in the grammar).
+Otherwise, if it is declared as a statement within a compound statement, it
+is scoped to the end of that compound statement.
+If it is declared as a parameter in a function definition, it is scoped
+until the end of that function definition.
+A function&#8217;s parameter declarations and body together form a single scope.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> f( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> k)
+{
+    <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// redeclaration error of the name k</span>
+    ...
+}
+<span class="predefined-type">int</span> f(<span class="predefined-type">int</span> k)
+{
+    {
+       <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// 2nd k is parameter, initializing nested first k</span>
+       <span class="predefined-type">int</span> m = k <span class="comment">// use of new k, which is hiding the parameter</span>
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For both for and while loops, the sub-statement itself does not introduce a
+new scope for variable names, so the following has a redeclaration
+compile-time error:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> ( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> i = <span class="integer">0</span>; i &lt; <span class="integer">10</span>; i++)
+{
+    <span class="predefined-type">int</span> i; <span class="comment">// redeclaration error</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The body of a <strong>do</strong>-<strong>while</strong> loop introduces a new scope lasting only between
+the do and while (not including the while test expression), whether or not
+the body is simple or compound:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> _i_ = <span class="integer">17</span>;
+<span class="keyword">do</span>
+    <span class="predefined-type">int</span> i = <span class="integer">4</span>; <span class="comment">// okay, in nested scope</span>
+<span class="keyword">while</span> (i == <span class="integer">0</span>); <span class="comment">// i is 17, scoped outside the do-while body</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The statement following a <strong>switch</strong> (&#8230;&#8203;) forms a nested scope.</p>
+</div>
+<div class="paragraph">
+<p>Representing the if construct as:</p>
+</div>
+<div class="paragraph">
+<p><strong>if</strong> if-expression <strong>then</strong> if-statement <strong>else</strong> else-statement,</p>
+</div>
+<div class="paragraph">
+<p>a variable declared in the if-statement is scoped to the end of the
+if-statement.
+A variable declared in the else-statement is scoped to the end of the
+else-statement.
+This applies both when these statements are simple statements and when they
+are compound statements.
+The if-expression does not allow new variables to be declared, hence does
+not form a new scope.</p>
+</div>
+<div class="paragraph">
+<p>Within a declaration, the scope of a name starts immediately after the
+initializer if present or immediately after the name being declared if not.
+Several examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x = <span class="integer">1</span>;
+{
+    <span class="predefined-type">int</span> x = <span class="integer">2</span>,<span class="comment">/* 2nd x visible here */</span> y = x; <span class="comment">// y is initialized to 2</span>
+    <span class="predefined-type">int</span> z = z; <span class="comment">// error if z not previously defined.</span>
+}
+{
+<span class="predefined-type">int</span> x = x; <span class="comment">// x is initialized to '1'</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A structure name declaration is visible at the end of the <em>struct_specifier</em>
+in which it was declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S
+{
+    <span class="predefined-type">int</span> x;
+};
+{
+    S S = S(<span class="integer">0</span>); <span class="comment">// 'S' is only visible as a struct and constructor</span>
+    S; <span class="comment">// 'S' is now visible as a variable</span>
+}
+<span class="predefined-type">int</span> x = x; <span class="comment">// Error if x has not been previously defined.</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="redeclaring-names">4.2.3. Redeclaring Names</h4>
+<div class="paragraph">
+<p>All variable names, structure type names, and function names in a given
+scope share the same name space.
+Function names can be redeclared in the same scope, with the same or
+different parameters, without error.
+Otherwise, within a shader, a declared name cannot be redeclared in the same
+scope; doing so results in a redeclaration error.
+If a nested scope redeclares a name used in an outer scope, it hides all
+existing uses of that name.
+There is no way to access the hidden name or make it unhidden, without
+exiting the scope that hid it.</p>
+</div>
+<div class="paragraph">
+<p>Names of built-in functions cannot be redeclared as functions.
+Therefore overloading or redefining built-in functions is an error.</p>
+</div>
+<div class="paragraph">
+<p>A <em>declaration</em> is considered to be a statement that adds a name or
+signature to the symbol table.
+A <em>definition</em> is a statement that fully defines that name or signature.
+E.g.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> f();<span class="comment">// declaration;</span>
+<span class="predefined-type">int</span> f() {<span class="keyword">return</span> <span class="integer">0</span>;}<span class="comment">// declaration and definition</span>
+<span class="predefined-type">int</span> x; <span class="comment">// declaration and definition</span>
+<span class="predefined-type">int</span> a[<span class="integer">4</span>];<span class="comment">// array declaration and definition</span>
+<span class="keyword">struct</span> S {<span class="predefined-type">int</span> x;};<span class="comment">// structure declaration and definition</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The determination of equivalence of two declarations depends on the type of
+declaration.
+For functions, the whole function signature must be considered (see
+&#8220;Function Definitions&#8221;).
+For variables (including arrays) and structures only the names must match.</p>
+</div>
+<div class="paragraph">
+<p>Within each scope, a name may be declared either as a variable declaration
+<em>or</em> as function declarations <em>or</em> as a structure.</p>
+</div>
+<div class="paragraph">
+<p>Examples of combinations that are allowed:</p>
+</div>
+<div class="paragraph">
+<p>1.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}
+<span class="directive">void</span> f(<span class="predefined-type">float</span>) {...}<span class="comment">// function overloading allowed</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>2.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>);<span class="comment">// 1^st^ declaration (allowed)</span>
+<span class="directive">void</span> f(<span class="predefined-type">int</span>);<span class="comment">// repeated declaration (allowed)</span>
+<span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}<span class="comment">// single definition (allowed)</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Examples of combinations that are disallowed:</p>
+</div>
+<div class="paragraph">
+<p>1.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}
+<span class="directive">void</span> f(<span class="predefined-type">int</span>) {...}<span class="comment">// Error: repeated definition</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>2.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> f(<span class="predefined-type">int</span>);
+<span class="keyword">struct</span> f {<span class="predefined-type">int</span> x;};<span class="comment">// Error: type 'f' conflicts with function 'f'</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>3.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> f {<span class="predefined-type">int</span> x;};
+<span class="predefined-type">int</span> f;<span class="comment">// Error: conflicts with the type 'f'</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>4.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> a[<span class="integer">3</span>];
+<span class="predefined-type">int</span> a[<span class="integer">3</span>];<span class="comment">// Error: repeated array definition</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>5.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x;
+<span class="predefined-type">int</span> x;<span class="comment">// Error: repeated variable definition</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="global-scope">4.2.4. Global Scope</h4>
+<div class="paragraph">
+<p>The built-in functions are scoped in the global scope users declare global
+variables in.
+That is, a shader&#8217;s global scope, available for user-defined functions and
+global variables, is the same as the scope containing the built-in
+functions.
+Function declarations (prototypes) cannot occur inside of functions; they
+must be at global scope.
+Hence it is not possible to hide a name with a function.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="shared-globals">4.2.5. Shared Globals</h4>
+<div class="paragraph">
+<p>Shared globals are variables that can be accessed by multiple compilation
+units.
+In GLSL ES the only shared globals are uniforms.
+Vertex shader outputs are not considered to be shared globals since they
+must pass through the rasterization stage before they are used as input by
+the fragment shader.</p>
+</div>
+<div class="paragraph">
+<p>Shared globals share the same name space, and must be declared with the same
+type and precision.
+They will share the same storage.
+Shared global arrays must have the same base type and the same explicit
+size.
+Scalars must have exactly the same precision, type name and type definition.
+Structures must have the same name, sequence of type names, and type
+definitions, and member names to be considered the same type.
+This rule applies recursively for nested or embedded types.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="storage-qualifiers">4.3. Storage Qualifiers</h3>
+<div class="paragraph">
+<p>Variable declarations may have at most one storage qualifier specified in
+front of the type.
+These are summarized as</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Storage Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;none: default&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">local read/write memory, or an input parameter to a
+                      function</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>const</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a compile-time constant</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">linkage into a shader from a previous stage, variable
+                      is copied in</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">linkage out of a shader to a subsequent stage,
+                      variable is copied out</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">value does not change across the primitive being
+                      processed, uniforms form the linkage between a shader,
+                      OpenGL ES, and the application</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>buffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">value is stored in a buffer object, and can be read or
+                      written both by shader invocations and the OpenGL ES
+                      API</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>shared</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compute shader only; variable storage is shared across
+                      all work items in a workgroup</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Some input and output qualified variables can be qualified with at most one
+additional auxiliary storage qualifier:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Auxiliary Storage Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">centroid-based interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sample</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">per-sample interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">per-tessellation-patch attributes</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Local variables can only use the <strong>const</strong> storage qualifier (or use no
+storage qualifier).</p>
+</div>
+<div class="paragraph">
+<p>Note that function parameters can use <strong>const</strong>, <strong>in</strong>, and <strong>out</strong> qualifiers,
+but as <em>parameter qualifiers</em>.
+Parameter qualifiers are discussed in
+&#8220;<a href="#function-calling-conventions">Function Calling Conventions</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Function return types and structure members do not use storage qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Data types for communication from one run of a shader executable to its next
+run (to communicate between fragments or between vertices) do not exist.
+This would prevent parallel execution of the same shader executable on
+multiple vertices or fragments.</p>
+</div>
+<div class="paragraph">
+<p>In declarations of global variables with no storage qualifier or with a
+const qualifier, any initializer must be a constant expression.
+Declarations of global variables with other storage qualifiers may not
+contain initializers.
+Global variables without storage qualifiers that are not initialized in
+their declaration or by the application will not be initialized by
+OpenGL ES, but rather will enter <em>main()</em> with undefined values.</p>
+</div>
+<div class="sect3">
+<h4 id="default-storage-qualifier">4.3.1. Default Storage Qualifier</h4>
+<div class="paragraph">
+<p>If no qualifier is present on a global variable, then the variable has no
+linkage to the application or shaders running on other pipeline stages.
+For either global or local unqualified variables, the declaration will
+appear to allocate memory associated with the processor it targets.
+This variable will provide read/write access to this allocated memory.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="constant-qualifier">4.3.2. Constant Qualifier</h4>
+<div class="paragraph">
+<p>Named compile-time constants
+can be declared using
+the <strong>const</strong> qualifier.
+Any variables qualified as constant are read-only variables for that shader.
+Declaring variables as constant allows more descriptive shaders than using
+hard-wired numerical constants.
+The <strong>const</strong> qualifier can be used with any of the non-void transparent basic
+data types, as well as with structures and arrays of these.
+It is an error to write to a <strong>const</strong> variable outside of its
+declaration, so they must be initialized when declared.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> vec3 zAxis = vec3 (<span class="float">0</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Structure members may not be qualified with <strong>const</strong>.
+Structure variables can be declared as <strong>const</strong>, and initialized with a
+structure
+constructor.</p>
+</div>
+<div class="paragraph">
+<p>Initializers for <strong>const</strong> declarations
+must be constant expressions, as defined in
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="constant-expressions">4.3.3. Constant Expressions</h4>
+<div class="paragraph">
+<p>A <em>constant expression</em> is one of</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A literal value (e.g. <strong>5</strong> or <strong>true</strong>).</p>
+</li>
+<li>
+<p>A global or local variable qualified as <strong>const</strong> (i.e., not including
+function parameters).</p>
+</li>
+<li>
+<p>An expression formed by an operator on operands that are all constant
+expressions, including getting an element of a constant array, or a
+member of a constant structure, or components of a constant vector.
+However, the lowest precedence operators of the sequence operator (<strong>,</strong>)
+and the assignment operators (<strong>=</strong>, <strong>+=</strong>, <strong>&#8230;&#8203;</strong>) are not included in the
+operators that can create a constant expression.</p>
+</li>
+<li>
+<p>The <strong>length</strong>() method on a compile-time sized array, whether or not the
+object itself is constant.</p>
+</li>
+<li>
+<p>A constructor whose arguments are all constant expressions.</p>
+</li>
+<li>
+<p>A built-in function call whose arguments are all constant expressions,
+with the exception of the texture lookup functions.
+This rule excludes functions with a <strong>void</strong> return or functions that have
+an <strong>out</strong> parameter.
+The built-in functions <strong>dFdx</strong>, <strong>dFdy</strong>, and <strong>fwidth</strong> must return 0 when
+evaluated inside an initializer with an argument that is a constant
+expression.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Function calls to user-defined functions (non-built-in functions) cannot be
+used to form constant expressions.</p>
+</div>
+<div class="paragraph">
+<p>Scalar, vector, matrix, array and structure variables are constant
+expressions if qualified as <strong>const</strong>.
+Opaque types cannot be constant expressions.</p>
+</div>
+<div class="paragraph">
+<p>A <em>constant integral expression</em> is a constant expression that evaluates to
+a scalar signed or unsigned integer.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions will be evaluated in an invariant way so as to create
+the same value in multiple shaders when the same constant expressions appear
+in those shaders.
+See &#8220;<a href="#the-invariant-qualifier">The Invariant Qualifier</a>&#8221; for more details
+on how to create invariant expressions and
+&#8220;<a href="#precision-qualifiers">Precision Qualifiers</a>&#8221; for detail on how
+expressions are evaluated.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions respect the <strong>precise</strong> and <strong>invariant</strong> qualifiers but
+will be always be evaluated in an invariant way, independent of the use of
+such qualification, so as to create the same value in multiple shaders when
+the same constant expressions appear in those shaders.
+See &#8220;<a href="#the-invariant-qualifier">The Invariant Qualifier</a>&#8221; and
+&#8220;<a href="#the-precise-qualifier">The Precise Qualifier</a>&#8221; for more details on how
+to create invariant expressions.</p>
+</div>
+<div class="paragraph">
+<p>Constant
+expressions may be evaluated by the compiler&#8217;s
+host platform, and are therefore not required to compute the same value that
+the same expression would evaluate to on the shader execution target.
+However, the host must use the same or greater precision than the target
+would use.
+When the precision qualification cannot be determined, the expression is
+evaluated at <strong>highp</strong>.
+See &#8220;<a href="#default-precision-qualifiers">Default Precision Qualifiers</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="input-variables">4.3.4. Input Variables</h4>
+<div class="paragraph">
+<p>Shader input variables are declared with the <strong>in</strong> storage qualifier.
+They form the input interface between previous stages of the OpenGL ES
+pipeline and the declaring shader.
+Input variables must be declared at global scope.
+Values from the previous pipeline stage are copied into input variables at
+the beginning of shader execution.
+It is an error to write to a variable declared as an input.</p>
+</div>
+<div class="paragraph">
+<p>Only the input variables that are
+actually
+read need to be written by the
+previous stage; it is allowed to have superfluous declarations of input
+variables.</p>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#built-in-variables">Built-In Variables</a>&#8221; for a list of the built-in
+input names.</p>
+</div>
+<div class="paragraph">
+<p>Vertex shader input variables (or attributes) receive per-vertex data.
+It is an error to use auxiliary storage or interpolation qualifiers
+on a vertex shader input.
+The values copied in are established by the OpenGL ES API or through the use
+of the layout identifier <strong>location</strong>.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a vertex shader input with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>An array</p>
+</li>
+<li>
+<p>A structure</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Example declarations in a vertex shader:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 position;
+in vec3 normal;
+in vec2 texCoord[<span class="integer">4</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is expected that graphics hardware will have a small number of fixed
+vector locations for passing vertex inputs.
+Therefore, the OpenGL ES Shading Language defines each non-matrix input variable as taking up
+one such vector location.
+There is an implementation-dependent limit on the number of locations that
+can be used, and if this is exceeded it will cause a link-time error.
+(Declared input variables that are not statically used do not count against
+this limit.) A scalar input counts the same amount against this limit as a
+<strong>vec4</strong>, so applications may want to consider packing groups of four
+unrelated float inputs together into a vector to better utilize the
+capabilities of the underlying hardware.
+A matrix input will use up multiple locations.
+The number of locations used will equal the number of columns in the matrix.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control, evaluation, and geometry shader input variables get
+the per-vertex values written out by output variables of the same names in
+the previous active shader stage.
+For these inputs, <strong>centroid</strong> and interpolation qualifiers are allowed, but
+have no effect.
+Since tessellation control, tessellation evaluation, and geometry shaders
+operate on a set of vertices, each input variable (or input block, see
+interface blocks below) needs to be declared as an array.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in <span class="predefined-type">float</span> foo[]; <span class="comment">// geometry shader input for vertex &quot;out float foo&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each element of such an array corresponds to one vertex of the primitive
+being processed.
+Each array can optionally have a size declared.
+For geometry shaders, the array size will be set by, (or if provided must be
+consistent with) the input <strong>layout</strong> declaration(s) establishing the type of
+input primitive, as described later in &#8220;<a href="#input-layout-qualifiers">Input
+Layout Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Some inputs and outputs are <em>arrayed</em>, meaning that for an interface between
+two shader stages either the input or output declaration requires an extra
+level of array indexing for the declarations to match.
+For example, with the interface between a vertex shader and a geometry
+shader, vertex shader output variables and geometry shader input variables
+of the same name must have matching types, except that the geometry shader
+will have one more array dimension than the vertex shader, to allow for
+vertex indexing.
+If such an arrayed interface variable is not declared with the necessary
+additional input or output array dimension, a link-time error will result.
+Geometry shader inputs, tessellation control shader inputs and outputs, and
+tessellation evaluation inputs all have an additional level of arrayness
+relative to other shader inputs and outputs.
+These inputs and outputs are known as <em>per-vertex-arrayed</em> inputs and
+outputs.
+Component limits for arrayed interfaces (e.g.
+<em>gl_MaxTessControlInputComponents</em>) are limits per vertex, not limits for
+the entire interface.</p>
+</div>
+<div class="paragraph">
+<p>For non-arrayed interfaces (meaning array dimensionally stays the same
+between stages), it is a link-time error if the input variable is not
+declared with the same type, including array dimensionality, as the matching
+output variable.</p>
+</div>
+<div class="paragraph">
+<p>The link-time type-matching rules apply to all declared input and output
+variables, whether or not they are used.</p>
+</div>
+<div class="paragraph">
+<p>Additionally, tessellation evaluation shaders support per-patch input
+variables declared with the <strong>patch</strong> and <strong>in</strong> qualifiers.
+Per-patch input variables are filled with the values of per-patch output
+variables written by the tessellation control shader.
+Per-patch inputs may be declared as one-dimensional arrays, but are not
+indexed by vertex number.
+Applying the <strong>patch</strong> qualifier to inputs can only be done in tessellation
+evaluation shaders.
+As with other input variables, per-patch inputs must be declared using the
+same type and qualification as per-patch outputs from the previous
+(tessellation control) shader stage.
+It is a compile-time error to use <strong>patch</strong> with inputs in any other stage.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a tessellation control, tessellation
+evaluation or geometry shader input with, or that contains, any of the
+following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>A structure containing an array</p>
+</li>
+<li>
+<p>A structure containing a structure</p>
+</li>
+<li>
+<p>For per-vertex-arrayed variables:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>Per-vertex-arrayed arrays of arrays</p>
+</li>
+<li>
+<p>Per-vertex-arrayed arrays of structures</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>For non-per-vertex-arrayed variables:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>An array of arrays</p>
+</li>
+<li>
+<p>An array of structures</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment shader inputs get per-fragment values, typically interpolated from
+a previous stage&#8217;s outputs.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a fragment shader input with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>An array of arrays</p>
+</li>
+<li>
+<p>An array of structures</p>
+</li>
+<li>
+<p>A structure containing an array</p>
+</li>
+<li>
+<p>A structure containing a structure</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment shader inputs that are, or contain, integral
+types must be
+qualified with the interpolation qualifier <strong>flat</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Fragment inputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec3 normal;
+centroid in vec2 TexCoord;
+flat in vec3 myColor;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The fragment shader inputs form an interface with the last active shader in
+the vertex processing pipeline.
+For this interface, the last active shader stage output variables and
+fragment shader input variables of the same name must match in type and
+qualification, with a few exceptions: The storage qualifiers must, of
+course, differ (one is <strong>in</strong> and one is <strong>out</strong>).
+Also,
+auxiliary qualification (e.g. <strong>centroid</strong>) may differ.
+When
+auxiliary qualifiers do not match, those provided in
+the fragment shader supersede those provided in previous stages.
+If any such qualifiers are completely missing in the fragment shaders, then
+the default is used, rather than any qualifiers that may have been declared
+in previous stages.
+That is, what matters is what is declared in the fragment shaders, not what
+is declared in shaders in previous stages.</p>
+</div>
+<div class="paragraph">
+<p>When an interface between shader stages is formed using shaders from two
+separate program objects, it is not possible to detect mismatches between
+inputs and outputs when the programs are linked.
+When there are mismatches between inputs and outputs on such interfaces,
+attempting to use the two programs in the same program pipeline will result
+in program pipeline validation failures, as described in section 7.4.1
+&#8220;Shader Interface Matching&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>Shaders can ensure matches across such interfaces either by using input and
+output layout qualifiers (sections &#8220;<a href="#input-layout-qualifiers">Input Layout
+Qualifiers</a>&#8221; and &#8220;<a href="#output-layout-qualifiers">Output Layout
+Qualifiers</a>&#8221;) or by using identical input and output declarations of
+blocks or variables.
+Complete rules for interface matching are found in section 7.4.1 &#8220;Shader
+Interface Matching&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>Compute shaders do not permit user-defined input variables and do not form a
+formal interface with any other shader stage.
+See &#8220;<a href="#compute-shader-special-variables">Compute Shader Special
+Variables</a>&#8221; for a description of built-in compute shader input variables.
+All other input to a compute shader is retrieved explicitly through image
+loads, texture fetches, loads from uniforms or uniform buffers, or other
+user supplied code.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-variables">4.3.5. Uniform Variables</h4>
+<div class="paragraph">
+<p>The <strong>uniform</strong> qualifier is used to declare global variables whose values are
+the same across the entire primitive being processed.
+All <strong>uniform</strong> variables are read-only.
+Except for variables declared within a uniform block, all uniform variables
+are initialized to 0 at link time and may be updated through the API.</p>
+</div>
+<div class="paragraph">
+<p>Example declarations are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform vec4 lightPosition;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>uniform</strong> qualifier can be used with any of the basic data types, or
+when declaring a variable whose type is a structure, or an array of any of
+these.</p>
+</div>
+<div class="paragraph">
+<p>There is an implementation-dependent limit on the amount of storage for
+uniforms that can be used for each type of shader and if this is exceeded it
+will cause a compile-time or link-time error.
+Uniform variables that are declared but not
+statically
+used do not count against this limit.
+The number of user-defined uniform variables and the number of built-in
+uniform variables that are used within a shader are added together to
+determine whether available uniform storage has been exceeded.</p>
+</div>
+<div class="paragraph">
+<p>Uniforms in shaders all share a single global name space when linked into a
+program or separable program.
+Hence, the types,
+precisions,
+and any location specifiers of all statically used uniform variables with the
+same name must match across all shaders that are linked into a single program.
+However it is not required to repeat the
+location specifier in all the linked shaders.
+While this single uniform name space is cross stage, a uniform variable
+name&#8217;s scope is per stage: If a uniform variable name is declared in one
+stage (e.g. a vertex shader) but not in another (e.g. a fragment shader),
+then that name is still available in the other stage for a different use.</p>
+</div>
+<div class="paragraph">
+<p>A compile or link-time error is generated if any of the explicitly given or
+compiler generated uniform locations is greater than the
+implementation-defined maximum number of uniform locations minus one.</p>
+</div>
+<div class="paragraph">
+<p>Unlike locations for inputs and outputs, uniform locations are logical
+values, not register locations, and there is no concept of overlap.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">2</span>) uniform mat4 x;
+layout(location = <span class="integer">3</span>) uniform mat4 y; <span class="comment">// No overlap with x</span>
+layout(location = <span class="integer">2</span>) in mat4 x;
+layout(location = <span class="integer">3</span>) in mat4 y; <span class="comment">// Error, locations conflict with x</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="output-variables">4.3.6. Output Variables</h4>
+<div class="paragraph">
+<p>Shader output variables are declared with the <strong>out</strong> storage qualifier.
+They form the output interface between the declaring shader and the
+subsequent stages of the OpenGL ES pipeline.
+Output variables must be declared at global scope.
+During shader execution they will behave as normal unqualified global
+variables.
+Their values are copied out to the subsequent pipeline stage on shader exit.
+Only output variables that are read by the subsequent pipeline stage need to
+be written; it is allowed to have superfluous declarations of output
+variables.</p>
+</div>
+<div class="paragraph">
+<p>There is <em>not</em> an <strong>inout</strong> storage qualifier for declaring a single variable
+name as both input and output to a shader.
+Also, a variable cannot be declared with both the <strong>in</strong> and the <strong>out</strong>
+qualifiers, this will result in a compile-time or link-time error.
+Output variables must be declared with different names than input variables.
+However, nesting an input or output inside an interface block with an
+instance name allows the same names with one referenced through a block
+instance name.</p>
+</div>
+<div class="paragraph">
+<p>Vertex, tessellation evaluation, and geometry output variables output
+per-vertex data and are declared using the <strong>out</strong> storage qualifier.
+Applying <strong>patch</strong> to an output can only be done in a tessellation control
+shader.
+It is a compile-time error to use <strong>patch</strong> on outputs in any other stage.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a vertex, tessellation evaluation,
+tessellation control, or geometry shader output with, or that contains, any
+of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>A structure containing an array</p>
+</li>
+<li>
+<p>A structure containing a structure</p>
+</li>
+<li>
+<p>For per-vertex-arrayed variables (applies to tessellation control,
+tessellation evaluation and geometry shaders):</p>
+<div class="ulist">
+<ul>
+<li>
+<p>Per-vertex-arrayed arrays of arrays</p>
+</li>
+<li>
+<p>Per-vertex-arrayed arrays of structures</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>For non-per-vertex-arrayed variables:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>An array of arrays</p>
+</li>
+<li>
+<p>An array of structures</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Vertex shader outputs may be qualified with the interpolation qualifier
+<strong>flat</strong><sup>1</sup>.</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">1</dt>
+<dd>
+<p>Unlike previous versions of the OpenGL ES Shading Language, there is no requirement for
+outputs containing integers to be qualified as <strong>flat</strong>, since the vertex
+shader may interface with the tessellation control shader.
+However, in all cases, the qualifier must match across interfaces.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Individual outputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec3 normal;
+centroid out vec2 TexCoord;
+invariant centroid out vec4 Color;
+flat out vec3 myColor;
+sample out vec4 perSampleColor;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These can also appear in interface blocks, as described in
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221;.
+Interface blocks allow simpler addition of arrays to the interface from
+vertex to geometry shader.
+They also allow a fragment shader to have the same input interface as a
+geometry shader for a given vertex shader.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control shader output variables are used to output
+per-vertex and per-patch data.
+Per-vertex output variables are arrayed (see <em>arrayed</em> under
+&#8220;<a href="#input-variables">Input Variables</a>&#8221;) and declared using the <strong>out</strong>
+qualifier without the <strong>patch</strong> qualifier.
+Per-patch output variables are declared using the <strong>patch</strong> and <strong>out</strong>
+qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Since tessellation control shaders produce an arrayed primitive comprising
+multiple vertices, each per-vertex output variable (or output block, see
+interface blocks below) needs to be declared as an array.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out <span class="predefined-type">float</span> foo[]; <span class="comment">// feeds next stage input &quot;in float foo[]&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each element of such an array corresponds to one vertex of the primitive
+being produced.
+Each array can optionally have a size declared.
+The array size will be set by (or if provided must be consistent with) the
+output layout declaration(s) establishing the number of vertices in the
+output patch, as described later in
+&#8220;<a href="#tessellation-control-outputs">Tessellation Control Outputs</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Each tessellation control shader invocation has a corresponding output patch
+vertex, and may assign values to per-vertex outputs only if they belong to
+that corresponding vertex.
+If a per-vertex output variable is used as an l-value, it is a compile-time
+or link-time error if the expression indicating the vertex index is not the
+identifier <em>gl_InvocationID</em>.</p>
+</div>
+<div class="paragraph">
+<p>The order of execution of a tessellation control shader invocation relative
+to the other invocations for the same input patch is undefined unless the
+built-in function <strong>barrier</strong>() is used.
+This provides some control over relative execution order.
+When a shader invocation calls <strong>barrier</strong>(), its execution pauses until all
+other invocations have reached the same point of execution.
+Output variable assignments performed by any invocation executed prior to
+calling <strong>barrier</strong>() will be visible to any other invocation after the call
+to <strong>barrier</strong>() returns.</p>
+</div>
+<div class="paragraph">
+<p>Because tessellation control shader invocations execute in undefined order
+between barriers, the values of per-vertex or per-patch output variables
+will sometimes be undefined.
+Consider the beginning and end of shader execution and each call to
+<strong>barrier</strong>() as synchronization points.
+The value of an output variable will be undefined in any of the three
+following cases:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>At the beginning of execution.</p>
+</li>
+<li>
+<p>At each synchronization point, unless</p>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p>the value was well-defined after the previous synchronization point and
+was not written by any invocation since, or</p>
+</li>
+<li>
+<p>the value was written by exactly one shader invocation since the previous
+synchronization point, or</p>
+</li>
+<li>
+<p>the value was written by multiple shader invocations since the previous
+synchronization point, and the last write performed by all such
+invocations wrote the same value.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</li>
+<li>
+<p>When read by a shader invocation, if</p>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p>the value was undefined at the previous synchronization point and has not
+been written by the same shader invocation since, or</p>
+</li>
+<li>
+<p>the output variable is written to by any other shader invocation between
+the previous and next synchronization points, even if that assignment
+occurs in code following the read.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Fragment outputs output per-fragment data and are declared using the <strong>out</strong>
+storage qualifier.
+It is an error to use auxiliary storage qualifiers or
+interpolation qualifiers in a fragment shader output declaration.
+It is a compile-time error to declare a fragment shader output with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>A matrix type</p>
+</li>
+<li>
+<p>A structure</p>
+</li>
+<li>
+<p>An array of arrays</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment shader outputs declared as arrays may only be indexed by a constant
+integral expression.</p>
+</div>
+<div class="paragraph">
+<p>Fragment outputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec4 FragmentColor;
+out uint Luminosity;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Compute shaders have no built-in output variables, do not support
+user-defined output variables and do not form a formal interface with any
+other shader stage.
+All outputs from a compute shader take the form of the side effects such as
+image stores and operations on atomic counters.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="buffer-variables">4.3.7. Buffer Variables</h4>
+<div class="paragraph">
+<p>The <strong>buffer</strong> qualifier is used to declare global variables whose values are
+stored in the data store of a buffer object bound through the OpenGL ES API.
+Buffer variables can be read and written, with the underlying storage shared
+among all active shader invocations.
+Buffer variable memory reads and writes within a single shader invocation
+are processed in order.
+However, the order of reads and writes performed in one invocation relative
+to those performed by another invocation is largely undefined.
+Buffer variables may be qualified with memory qualifiers affecting how the
+underlying memory is accessed, as described in &#8220;<a href="#memory-qualifiers">Memory
+Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>buffer</strong> qualifier can be used to declare interface blocks (see
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221;), which are then referred to as
+shader storage blocks.
+It is a compile-time error to declare buffer variables outside a block.
+Buffer variables cannot have initializers.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="title">Note</div>
+<div class="paragraph">
+<p>The terms <em>shader storage buffer (object)</em>, and <em>shader storage block</em> are
+often used interchangeably.
+The former generally refers to the underlying storage whereas the latter
+refers only to the interface definition in the shader.
+Similarly for <em>uniform buffer objects</em> and _uniform blocks.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// use buffer to create a buffer block (shader storage block)</span>
+buffer BufferName { <span class="comment">// externally visible name of buffer</span>
+    <span class="predefined-type">int</span> count;      <span class="comment">// typed, shared memory...</span>
+    ...             <span class="comment">// ...</span>
+    vec4 v[];       <span class="comment">// last member may be an array that is not sized</span>
+                    <span class="comment">// until after link time (dynamically sized)</span>
+} Name;             <span class="comment">// name of block within the shader</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There are implementation-dependent limits on the number of shader storage
+blocks used for each type of shader, the combined number of shader storage
+blocks used for a program, and the amount of storage required by each
+individual shader storage block.
+If any of these limits are exceeded, it will cause a compile-time or
+link-time error.</p>
+</div>
+<div class="paragraph">
+<p>If multiple shaders are linked together, then they will share a single
+global buffer variable name space.
+Hence, the types of all declared buffer variables with the same name must
+match across all shaders that are linked into a single program.</p>
+</div>
+<div class="paragraph">
+<p>Precision qualifiers for such variables need not match.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="shared-variables">4.3.8. Shared Variables</h4>
+<div class="paragraph">
+<p>The <strong>shared</strong> qualifier is used to declare global variables that have storage
+shared between all work items in a compute shader workgroup.
+Variables declared as <strong>shared</strong> may only be used in compute shaders (see
+&#8220;<a href="#compute-processor">Compute Processor</a>&#8221;).
+Any other declaration of a <strong>shared</strong> variable is an error.
+Shared variables are implicitly coherent (see
+&#8220;<a href="#memory-qualifiers">Memory Qualifiers</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>Variables declared as <strong>shared</strong> may not have initializers and their contents
+are undefined at the beginning of shader execution.
+Any data written to <strong>shared</strong> variables will be visible to other work items
+(executing the same shader) within the same workgroup.</p>
+</div>
+<div class="paragraph">
+<p>In the absence of synchronization, the order of reads and writes to the same
+<strong>shared</strong> variable by different invocations of a shader is not defined.</p>
+</div>
+<div class="paragraph">
+<p>In order to achieve ordering with respect to reads and writes to <strong>shared</strong>
+variables, control flow barriers must be employed using the <strong>barrier</strong>() function
+(see &#8220;<a href="#shader-invocation-control-functions">Shader Invocation Control
+Functions</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>There is a limit to the total size of all variables declared as <strong>shared</strong> in a
+single program.
+This limit, expressed in units of basic machine units may be determined by
+using the OpenGL ES API to query the value of
+MAX_COMPUTE_SHARED_MEMORY_SIZE.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="interface-blocks">4.3.9. Interface Blocks</h4>
+<div class="paragraph">
+<p>Input, output, uniform, and buffer variable declarations can be grouped into
+named interface blocks to provide coarser granularity backing than is
+achievable with individual declarations.
+They can have an optional instance name, used in the shader to reference
+their members.
+An output block of one programmable stage is backed by a corresponding input
+block in the subsequent programmable stage.
+A <em>uniform block</em> is backed by the application with a buffer object.
+A block of buffer variables, called a <em>shader storage block</em>, is also backed
+by the application with a buffer object.
+It is a compile-time error to have an input block in a vertex shader or an
+output block in a fragment shader.
+These uses are reserved for future use.</p>
+</div>
+<div class="paragraph">
+<p>An interface block is started by an <strong>in</strong>, <strong>out</strong>, <strong>uniform</strong>, or <strong>buffer</strong>
+keyword, followed by a block name, followed by an open curly brace (<strong>{</strong>) as
+follows:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>interface-block</em> : </dt>
+<dd>
+<p><em>layout-qualifier<sub>opt</sub></em> <em>interface-qualifier</em> <em>block-name</em> <strong>{</strong>
+<em>member-list</em> <strong>}</strong> <em>instance-name<sub>opt</sub></em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>interface-qualifier</em> : </dt>
+<dd>
+<p><strong>in</strong><br>
+<strong>out</strong><br>
+<strong>patch</strong> <strong>in</strong> // Note: Qualifiers can be in any order.<br>
+<strong>patch</strong> <strong>out</strong><br>
+<strong>uniform</strong><br>
+<strong>buffer</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>member-list</em> : </dt>
+<dd>
+<p><em>member-declaration</em><br>
+<em>member-declaration</em> <em>member-list</em></p>
+</dd>
+<dt class="hdlist1"><em>member-declaration</em> : </dt>
+<dd>
+<p><em>layout-qualifier<sub>opt</sub></em> <em>qualifiers<sub>opt</sub></em> <em>type</em> <em>declarators</em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>instance-name</em> : </dt>
+<dd>
+<p><em>identifier</em><br>
+<em>identifier</em> <strong>[</strong> <strong>]</strong><br>
+<em>identifier</em> <strong>[</strong> <em>constant-integral-expression</em> <strong>]</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Each of the above elements is discussed below, with the exception of layout
+qualifiers (<em>layout-qualifier</em>), which are defined in the next section.</p>
+</div>
+<div class="paragraph">
+<p>First, an example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform Transform {
+    mat4 ModelViewMatrix;
+    mat4 ModelViewProjectionMatrix;
+    uniform mat3 NormalMatrix;      <span class="comment">// allowed restatement of qualifier</span>
+    <span class="predefined-type">float</span> Deformation;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The above establishes a uniform block named &#8220;Transform&#8221; with four uniforms
+grouped inside it.</p>
+</div>
+<div class="paragraph">
+<p>Types and declarators are the same as for other input, output, uniform, and
+buffer variable declarations outside blocks, with these exceptions:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Opaque types are not allowed</p>
+</li>
+<li>
+<p>Structure definitions cannot be nested inside a block</p>
+</li>
+<li>
+<p>Arrays of arrays of blocks are not allowed, except for the case in the
+tessellation pipe where the declaration is a per-vertex-array of arrays
+of blocks.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>If no optional qualifier is used in a member-declaration, the qualification
+of the member includes all <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> as
+determined by <em>interface-qualifier</em>.
+If optional qualifiers are used, they can include interpolation qualifiers,
+auxiliary storage qualifiers,
+precision qualifiers,
+and storage qualifiers and they must declare
+an input, output, or uniform member consistent with the interface qualifier
+of the block: Input variables, output variables, uniform variables, and
+<strong>buffer</strong> members can only be in <strong>in</strong> blocks, <strong>out</strong> blocks, <strong>uniform</strong> blocks,
+and shader storage blocks, respectively.</p>
+</div>
+<div class="paragraph">
+<p>Repeating the <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> interface
+qualifier for a member&#8217;s storage qualifier is optional.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in Material {
+    smooth in vec4 Color1; <span class="comment">// legal, input inside in block</span>
+    smooth vec4 Color2;    <span class="comment">// legal, 'in' inherited from 'in Material'</span>
+    vec2 TexCoord;         <span class="comment">// legal, TexCoord is an input</span>
+    uniform <span class="predefined-type">float</span> Atten;   <span class="comment">// illegal, mismatched storage qualifier</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A <em>shader interface</em> is defined to be one of these:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>All the uniform variables and uniform blocks declared in a program.
+This spans all compilation units linked together within one program.</p>
+</li>
+<li>
+<p>All the <strong>buffer</strong> blocks declared in a program.</p>
+</li>
+<li>
+<p>The boundary between adjacent programmable pipeline stages: This spans
+all the outputs declared in all compilation units of the first stage and
+all the inputs declared in all compilation units of the second stage.
+Note that for the purposes of this definition, the fragment shader and
+the preceding shader are considered to have a shared boundary even
+though in practice, all values passed to the fragment shader first pass
+through the rasterizer and interpolator.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The block name (<em>block-name</em>) is used to match within shader interfaces: an
+output block of one pipeline stage will be matched to an input block with
+the same name in the subsequent pipeline stage.
+For uniform or shader storage blocks, the application uses the block name to
+identify the block.
+Block names have no other use within a shader beyond interface matching; it
+is an error
+to use a block name at global scope for anything other than as a
+block name (e.g. use of a block name for a global variable name or function
+name is currently reserved).
+It is a compile-time error to use the same block name for more than one
+block declaration in the same shader interface (as defined above) within one
+shader, even if the block contents are identical.</p>
+</div>
+<div class="paragraph">
+<p>Matched block names within a shader interface (as defined above) must match
+in terms of having the same number of declarations with the same sequence of
+types and the same sequence of member names, as well as having matching
+member-wise layout qualification
+as defined in &#8220;<a href="#matching-of-qualifiers">Matching of Qualifiers</a>&#8221;.
+Matched uniform or shader storage block names (but not input or output block
+names) must also either all be lacking an instance name or all having an
+instance name, putting their members at the same scoping level.
+When instance names are present on matched block names, it is allowed for
+the instance names to differ; they need not match for the blocks to match.
+Furthermore, if a matching block is declared as an array, then the array
+sizes must also match (or follow array matching rules for the shader
+interface between consecutive shader stages).
+Any mismatch will generate a link-time error.
+A block name is allowed to have different definitions in different shader
+interfaces within the same shader, allowing, for example, an input block and
+output block to have the same name.</p>
+</div>
+<div class="paragraph">
+<p>If an instance name (<em>instance-name</em>) is not used, the names declared inside
+the block are scoped at the global level and accessed as if they were
+declared outside the block.
+If an instance name (<em>instance-name</em>) is used, then it puts all the members
+inside a scope within its own name space, accessed with the field selector
+(<strong>.</strong>) operator (analogously to structures).
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in Light {
+    vec4 LightPos;
+    vec3 LightColor;
+};
+in ColoredTexture {
+    vec4 Color;
+    vec2 TexCoord;
+} Material;           <span class="comment">// instance name</span>
+vec3 Color;           <span class="comment">// different Color than Material.Color</span>
+vec4 LightPos;        <span class="comment">// illegal, already defined</span>
+...
+... = LightPos;       <span class="comment">// accessing LightPos</span>
+... = Material.Color; <span class="comment">// accessing Color in ColoredTexture block</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Outside the shading language (i.e., in the API), members are similarly
+identified except the block name is always used in place of the instance
+name (API accesses are to shader interfaces, not to shaders).
+If there is no instance name, then the API does not use the block name to
+access a member, just the member name.</p>
+</div>
+<div class="paragraph">
+<p>Within a shader interface, all declarations of the same global name must be
+for the same object and must match in type and in whether they declare a
+variable or member of a block with no instance name.
+The API also needs this name to uniquely identify an object in the shader
+interface.
+It is a link-time error if any particular shader interface contains</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>two different blocks, each having no instance name, and each having a
+member of the same name, or</p>
+</li>
+<li>
+<p>a variable outside a block, and a block with no instance name, where the
+variable has the same name as a member in the block.</p>
+</li>
+</ul>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out Vertex {
+    vec4 Position;  <span class="comment">// API transform/feedback will use &quot;Vertex.Position&quot;</span>
+    vec2 Texture;
+} Coords;           <span class="comment">// shader will use &quot;Coords.Position&quot;</span>
+out Vertex2 {
+    vec4 Color;     <span class="comment">// API will use &quot;Color&quot;</span>
+    <span class="predefined-type">float</span> Color2;
+};
+
+<span class="comment">// in same program as Vertex2 above:</span>
+out Vertex3 {
+    <span class="predefined-type">float</span> Intensity;
+    vec4 Color;     <span class="comment">// ERROR, name collision with Color in Vertex2</span>
+};
+<span class="predefined-type">float</span> Color2;       <span class="comment">// ERROR, collides with Color2 in Vertex2</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For blocks declared as arrays, the array index must also be included when
+accessing members, as in this example</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform Transform { <span class="comment">// API uses &quot;Transform[2]&quot; to refer to instance 2</span>
+    mat4 ModelViewMatrix;
+    mat4 ModelViewProjectionMatrix;
+    <span class="predefined-type">float</span> Deformation;
+} transforms[<span class="integer">4</span>];
+...
+... = transforms[<span class="integer">2</span>].ModelViewMatrix; <span class="comment">// shader access of instance 2</span>
+<span class="comment">// API uses &quot;Transform.ModelViewMatrix&quot; to query an offset or other query</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For uniform or shader storage blocks declared as an array, each individual
+array element corresponds to a separate buffer object bind range, backing
+one instance of the block.
+As the array size indicates the number of buffer objects needed, uniform and
+shader storage block array declarations must specify an array size.
+All indices used to index a shader storage block array must be constant
+integral expressions.
+A uniform block array can only be indexed with a dynamically uniform
+integral expression, otherwise results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>When using OpenGL ES API entry points to identify the name of an individual
+block in an array of blocks, the name string may include an array index
+(e.g. <em>Transform[2]</em>).
+When using OpenGL ES API entry points to refer to offsets or other
+characteristics of a block member, an array index must not be specified
+(e.g. <em>Transform.ModelViewMatrix</em>).
+See section 7.3.1 &#8220;Program Interfaces&#8221; of the <a href="#references">OpenGL ES Specification</a> for
+details.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control, tessellation evaluation and geometry shader input
+blocks must be declared as arrays and follow the array declaration and
+linking rules for all shader inputs for the respective stages.
+All other input and output block arrays must specify an array size.</p>
+</div>
+<div class="paragraph">
+<p>There are implementation-dependent limits on the number of uniform blocks
+and the number of shader storage blocks that can be used per stage.
+If either limit is exceeded, it will cause a link-time error.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="layout-qualifiers">4.4. Layout Qualifiers</h3>
+<div class="paragraph">
+<p>Layout qualifiers can appear in several forms of declaration.
+They can appear as part of an interface block definition or block member, as
+shown in the grammar in the previous section.
+They can also appear with just an <em>interface-qualifier</em> to establish layouts
+of other declarations made with that qualifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="paragraph">
+<p><em>layout-qualifier</em> <em>interface-qualifier</em> <strong>;</strong></p>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Or, they can appear with an individual variable declared with an interface
+qualifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="paragraph">
+<p><em>layout-qualifier</em> <em>interface-qualifier</em> <em>declaration</em> <strong>;</strong></p>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Declarations of layouts can only be made at global scope or block members,
+and only where indicated in the following subsections; their details are
+specific to what the interface qualifier is, and are discussed individually.</p>
+</div>
+<div class="paragraph">
+<p>The <em>layout-qualifier</em> expands to:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier</em> : </dt>
+<dd>
+<p><strong>layout</strong> <strong>(</strong> <em>layout-qualifier-id-list</em> <strong>)</strong></p>
+</dd>
+<dt class="hdlist1"><em>layout-qualifier-id-list</em> : </dt>
+<dd>
+<p><em>layout-qualifier-id</em><br>
+<em>layout-qualifier-id</em> <strong>,</strong> <em>layout-qualifier-id-list</em></p>
+</dd>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>layout-qualifier-name</em><br>
+<em>layout-qualifier-name</em> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>shared</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-value</em> : </dt>
+<dd>
+<p><em>integer-constant</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The tokens used for <em>layout-qualifier-name</em> are identifiers, not keywords,
+however, the <strong>shared</strong> keyword is allowed as a <em>layout-qualifier-id</em>.
+Generally, they can be listed in any order.
+Order-dependent meanings exist only if explicitly called out below.
+As for other identifiers, they are case sensitive.</p>
+</div>
+<div class="paragraph">
+<p>The set of allowed layout qualifiers depends on the shader, the interface
+and the variable type as specified in the following sections.
+For example, a sampler in the default uniform block in a fragment shader can
+have <strong>location</strong> and <strong>binding</strong> layout qualifiers but no others.
+Invalid use of layout qualifiers is an error.</p>
+</div>
+<div class="paragraph">
+<p>The following table summarizes the use of layout qualifiers.
+It shows for each one what kinds of declarations it may be applied to.
+These are all discussed in detail in the following sections.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Layout Qualifier</th>
+<th class="tableblock halign-left valign-top">Qualifier Only</th>
+<th class="tableblock halign-left valign-top">Individual Variable</th>
+<th class="tableblock halign-left valign-top">Block</th>
+<th class="tableblock halign-left valign-top">Block Member</th>
+<th class="tableblock halign-left valign-top">Allowed Interfaces</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>shared</strong><br>
+  <strong>packed</strong><br>
+  <strong>std140</strong><br>
+  <strong>std430</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top" rowspan="4"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>row_major</strong><br>
+  <strong>column_major</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">opaque types only</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">atomic counters only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X<sup>1</sup></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">all <strong>in</strong> / <strong>out</strong>, except for compute</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles</strong><br>
+  <strong>quads</strong><br>
+  <strong>isolines</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>equal_spacing</strong><br>
+  <strong>fractional_even_spacing</strong><br>
+  <strong>fractional_odd_spacing</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>cw</strong><br>
+  <strong>ccw</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>point_mode</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>points</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong>/<strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ <strong>points</strong> ]<br>
+  <strong>lines</strong><br>
+  <strong>lines_adjacency</strong><br>
+  <strong>triangles</strong><br>
+  <strong>triangles_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invocations</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>early_fragment_tests</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">fragment <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>local_size_x</strong> =<br>
+  <strong>local_size_y</strong> =<br>
+  <strong>local_size_z</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compute <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vertices</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation control <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ <strong>points</strong> ]<br>
+  <strong>line_strip</strong><br>
+  <strong>triangle_strip</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>max_vertices</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>rgba32f</strong><br>
+  <strong>rgba16f</strong><br>
+  <strong>r32f</strong><br>
+  <strong>rgba8</strong><br>
+  <strong>rgba8_snorm</strong><br>
+  <strong>rgba32i</strong><br>
+  <strong>rgba16i</strong><br>
+  <strong>rgba8i</strong><br>
+  <strong>r32i</strong><br>
+  <strong>rgba32ui</strong><br>
+  <strong>rgba16ui</strong><br>
+  <strong>rgba8ui</strong><br>
+  <strong>r32ui</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">image types only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_multiply</strong><br>
+  <strong>blend_support_screen</strong><br>
+  <strong>blend_support_overlay</strong><br>
+  <strong>blend_support_darken</strong><br>
+  <strong>blend_support_lighten</strong><br>
+  <strong>blend_support_colordodge blend_support_colorburn</strong><br>
+  <strong>blend_support_hardlight</strong><br>
+  <strong>blend_support_softlight</strong><br>
+  <strong>blend_support_difference</strong><br>
+  <strong>blend_support_exclusion</strong><br>
+  <strong>blend_support_hsl_hue</strong><br>
+  <strong>blend_support_hsl_saturation</strong><br>
+  <strong>blend_support_hsl_color blend_support_hsl_luminosity</strong><br>
+  <strong>blend_support_all_equations</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">fragment <strong>out</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">1</dt>
+<dd>
+<p>Location qualifiers are not allowed for members of an arrayed block,
+except for per-vertex-arrays (see &#8220;<a href="#interface-blocks">Interface
+Blocks</a>&#8221;).</p>
+</dd>
+</dl>
+</div>
+<div class="sect3">
+<h4 id="input-layout-qualifiers">4.4.1. Input Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers specific to a particular shader language are discussed in
+separate sections below.</p>
+</div>
+<div class="paragraph">
+<p>All shaders except compute shaders allow <strong>location</strong> layout qualifiers on
+input variable declarations, input block declarations, and input block
+member declarations.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in vec4 normal;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the shader input <em>normal</em> is assigned to vector location
+number
+3.
+For vertex shader inputs, the location specifies the number of the
+vertex attribute from which input values are taken.
+For inputs of all other shader types, the location specifies a vector number
+that can be used to match against outputs from a previous shader stage, even
+if that shader is in a different program object.</p>
+</div>
+<div class="paragraph">
+<p>The following language describes how many locations are consumed by a given
+type.
+However, geometry shader inputs, tessellation control shader inputs and
+outputs, and tessellation evaluation inputs all have an additional level of
+arrayness relative to other shader inputs and outputs.
+This outer array level is removed from the type before considering how many
+locations the type consumes.</p>
+</div>
+<div class="paragraph">
+<p>If a shader input is any scalar or vector type, it will consume a single
+location.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input (after potentially removing an outer array level as
+just described above) is an array of size <em>n</em> and each of the elements takes
+<em>m</em> locations, it will be assigned <em>m</em> * <em>n</em> consecutive locations starting
+with the location specified.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">6</span>) in vec4 colors[<span class="integer">3</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the shader input <em>colors</em> is assigned to vector location
+numbers 6, 7, and 8.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input is an <em>n</em> × <em>m</em>
+matrix, it will be assigned multiple locations starting with the location
+specified.
+The number of locations assigned for each matrix will be the same as for an
+<em>n</em>-element array of <em>m</em>-component vectors.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">9</span>) in mat4 transforms[<span class="integer">2</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that shader input <em>transforms</em> is assigned to vector
+locations 9-16, with <em>transforms[0]</em> being assigned to locations 9-12, and
+<em>transforms[1]</em> being assigned to locations 13-16.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input is a structure or block, its members will be assigned
+consecutive locations in their order of declaration, with the first member
+assigned the location provided in the layout qualifier.
+For a structure, this process applies to the entire structure.
+It is a compile-time error to use a <strong>location</strong> qualifier on a member of a
+structure.
+For a block, this process applies to the entire block, or until the first
+member is reached that has a <strong>location</strong> layout qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When a block member is declared with a <strong>location</strong> qualifier, its location
+comes from that qualifier; the member&#8217;s <strong>location</strong> qualifier overrides the
+block-level declaration.
+Subsequent members are again assigned consecutive locations, based on the
+newest location, until the next member declared with a <strong>location</strong> qualifier.
+The values used for locations do not have to be declared in increasing
+order.</p>
+</div>
+<div class="paragraph">
+<p>If a block has no block-level <strong>location</strong> layout qualifier, it is required
+that either all or none of its members have a <strong>location</strong> layout qualifier,
+or a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>If an input is declared as an array of blocks, excluding per-vertex-arrays
+as required for tessellation, it is an error to declare a member of the
+block with a <strong>location</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>The locations consumed by block and structure members are determined by
+applying the rules above recursively as though the structure member were
+declared as an input variable of the same type.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in <span class="keyword">struct</span> S
+{
+    vec3 a;                      <span class="comment">// gets location 3</span>
+    mat2 b;                      <span class="comment">// gets locations 4 and 5</span>
+    vec4 c[<span class="integer">2</span>];                   <span class="comment">// gets locations 6 and 7</span>
+    layout(location = <span class="integer">8</span>) vec2 A; <span class="comment">// ERROR, can't use on struct member</span>
+} s;
+layout(location = <span class="integer">4</span>) in block
+{
+    vec4 d;                      <span class="comment">// gets location 4</span>
+    vec4 e;                      <span class="comment">// gets location 5</span>
+    layout(location = <span class="integer">7</span>) vec4 f; <span class="comment">// gets location 7</span>
+    vec4 g;                      <span class="comment">// gets location 8</span>
+    layout(location = <span class="integer">1</span>) vec4 h; <span class="comment">// gets location 1</span>
+    vec4 i;                      <span class="comment">// gets location 2</span>
+    vec4 j;                      <span class="comment">// gets location 3</span>
+    vec4 k;                      <span class="comment">// ERROR, location 4 already used</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The number of input locations available to a shader is limited.
+For vertex shaders, the limit is the advertised number of vertex attributes.
+For all other shaders, the limit is implementation-dependent and must be no
+less than one fourth of the advertised maximum input component count.</p>
+</div>
+<div class="paragraph">
+<p>A program will fail to link if any attached shader uses a location greater
+than or equal to the number of supported locations, unless device-dependent
+optimizations are able to make the program fit within available hardware
+resources.</p>
+</div>
+<div class="paragraph">
+<p>A program will fail to link if explicit location assignments leave the
+linker unable to find space for other variables without explicit
+assignments.</p>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if a non-vertex input matches an output from
+a previous shader stage, the <strong>location</strong> layout qualifier (if any) must
+match.</p>
+</div>
+<div class="paragraph">
+<p>If a vertex shader input variable with no location assigned in the shader
+text has a location specified through the OpenGL ES API, the API-assigned
+location will be used.
+Otherwise, such variables will be assigned a location by the linker.
+See section 11.1.1 &#8220;Vertex Attributes&#8221; of the <a href="#references">OpenGL ES Specification</a> for
+more details.</p>
+</div>
+<div class="paragraph">
+<p>It is an error if more than one input or element of a matrix input is bound
+to the same location.</p>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-inputs">Tessellation Evaluation Inputs</h5>
+<div class="paragraph">
+<p>Additional input layout qualifier identifiers allowed for tessellation
+evaluation shaders are described below.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>primitive_mode</em><br>
+<em>vertex_spacing</em><br>
+<em>ordering</em><br>
+<em>point_mode</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>primitive-mode</strong> is used to specify a tessellation primitive mode to be
+used by the tessellation primitive generator.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>primitive-mode</em>: </dt>
+<dd>
+<p><strong>triangles</strong><br>
+<strong>quads</strong><br>
+<strong>isolines</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>If present, the <em>primitive-mode</em> specifies that the tessellation primitive
+generator should subdivide a triangle into smaller triangles, a quad into
+triangles, or a quad into a collection of lines, respectively.</p>
+</div>
+<div class="paragraph">
+<p>A second group of layout identifiers, <em>vertex spacing</em>, is used to specify
+the spacing used by the tessellation primitive generator when subdividing an
+edge.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>vertex-spacing</em>: </dt>
+<dd>
+<p><strong>equal_spacing</strong><br>
+<strong>fractional_even_spacing</strong><br>
+<strong>fractional_odd_spacing</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p><strong>equal_spacing</strong> specifies that edges should be divided into a collection of
+equal-sized segments;</p>
+</div>
+<div class="paragraph">
+<p><strong>fractional_even_spacing</strong> specifies that edges should be divided into an
+even number of equal-length segments plus two additional shorter
+&#8220;fractional&#8221; segments; or</p>
+</div>
+<div class="paragraph">
+<p><strong>fractional_odd_spacing</strong> specifies that edges should be divided into an odd
+number of equal-length segments plus two additional shorter &#8220;fractional&#8221;
+segments.</p>
+</div>
+<div class="paragraph">
+<p>A third group of layout identifiers, <em>ordering</em>, specifies whether the
+tessellation primitive generator produces triangles in clockwise or
+counter-clockwise order, according to the coordinate system depicted in the
+<a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>ordering</em>: </dt>
+<dd>
+<p><strong>cw</strong><br>
+<strong>ccw</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifiers <strong>cw</strong> and <strong>ccw</strong> indicate clockwise and counter-clockwise
+triangles, respectively.
+If the tessellation primitive generator does not produce triangles, the
+order is ignored.</p>
+</div>
+<div class="paragraph">
+<p>Finally, <em>point mode</em> indicates that the tessellation primitive generator
+should produce one point for each distinct vertex in the subdivided
+primitive, rather than generating lines or triangles.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>point-mode</em>: </dt>
+<dd>
+<p><strong>point_mode</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Any or all of these identifiers may be specified one or more times in a
+single input layout declaration.</p>
+</div>
+<div class="paragraph">
+<p>The tessellation evaluation shader object in a program must declare a
+primitive mode in its input layout.
+Declaring vertex spacing, ordering, or point mode identifiers is optional.
+If spacing or vertex ordering declarations are omitted, the tessellation
+primitive generator will use equal spacing or counter-clockwise vertex
+ordering, respectively.
+If a point mode declaration is omitted, the tessellation primitive generator
+will produce lines or triangles according to the primitive mode.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-inputs">Geometry Shader Inputs</h5>
+<div class="paragraph">
+<p>Additional layout qualifier identifiers for geometry shader inputs include
+<em>primitive</em> identifiers and an <em>invocation count</em> identifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>points</strong><br>
+<strong>lines</strong><br>
+<strong>lines_adjacency</strong><br>
+<strong>triangles</strong><br>
+<strong>triangles_adjacency</strong><br>
+<strong>invocations</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifiers <strong>points</strong>, <strong>lines</strong>, <strong>lines_adjacency</strong>, <strong>triangles</strong>, and
+<strong>triangles_adjacency</strong> are used to specify the type of input primitive
+accepted by the geometry shader, and only one of these is accepted.
+The geometry shader must declare this input primitive layout.</p>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>invocations</strong> is used to specify the number of times the
+geometry shader executable is invoked for each input primitive received.
+Invocation count declarations are optional.
+If no invocation count is declared in the geometry shader, it will be run
+once for each input primitive.
+If an invocation count is declared, all such declarations must specify the
+same count.
+If a shader specifies an invocation count greater than the
+implementation-dependent maximum, or less than or equal to zero,
+a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(triangles, invocations = <span class="integer">6</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that all inputs to the geometry shader are triangles and that
+the geometry shader executable is run six times for each triangle processed.</p>
+</div>
+<div class="paragraph">
+<p>All geometry shader input unsized array declarations will be sized by an
+earlier input primitive layout qualifier, when present, as per the following
+table.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Layout</th>
+<th class="tableblock halign-left valign-top">Size of Input Arrays</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>points</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The intrinsically declared input array <em>gl_in[]</em> will also be sized by any
+input primitive-layout declaration.
+Hence, the expression</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_in.length()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will return the value from the table above.</p>
+</div>
+<div class="paragraph">
+<p>An input can be declared without an array size if there is a previous layout
+which specifies the size.
+For built-in inputs (e.g. <em>gl_in[]</em>), a layout must be declared before any
+use.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error if a layout declaration&#8217;s array size (from the
+table above) does not match all the explicit array sizes specified in
+declarations of an input variables in the same shader.
+The following includes examples of compile-time errors:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// code sequence within one shader...</span>
+in vec4 Color2[<span class="integer">2</span>];    <span class="comment">// legal, size is 2</span>
+in vec4 Color3[<span class="integer">3</span>];    <span class="comment">// illegal, input sizes are inconsistent</span>
+layout(lines) in;     <span class="comment">// legal for Color2, input size is 2, matching Color2</span>
+in vec4 Color4[<span class="integer">3</span>];    <span class="comment">// illegal, contradicts layout of lines</span>
+layout(lines) in;     <span class="comment">// legal, matches other layout() declaration</span>
+layout(triangles) in; <span class="comment">// illegal, does not match earlier layout() declaration</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a link-time error if not all provided sizes (sized input arrays and
+layout size) match in the geometry shader of a program.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="fragment-shader-inputs">Fragment Shader Inputs</h5>
+<div class="paragraph">
+<p>Fragment shaders allow the following layout qualifier on <strong>in</strong> only (not with
+variable declarations):</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>early_fragment_tests</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>to request that fragment tests be performed before fragment shader
+execution, as described in section 13.8.4 &#8220;Early Fragment Tests&#8221; of the
+<a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(early_fragment_tests) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Specifying this will make per-fragment tests be performed before fragment
+shader execution.
+In addition it is an error to statically write to <em>gl_FragDepth</em> in the
+fragment shader.
+If this is not declared, per-fragment tests will be performed after fragment
+shader execution.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="compute-shader-inputs">Compute Shader Inputs</h5>
+<div class="paragraph">
+<p>There are no layout location qualifiers for compute shader inputs.</p>
+</div>
+<div class="paragraph">
+<p>Layout qualifier identifiers for compute shader inputs are the workgroup
+size qualifiers:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>local_size_x</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>local_size_y</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>local_size_z</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> qualifiers are used
+to declare a fixed workgroup size by the compute shader in the first,
+second, and third dimension, respectively.
+If a shader does not specify a size for one of the dimensions, that
+dimension will have a size of 1.</p>
+</div>
+<div class="paragraph">
+<p>For example, the following declaration in a compute shader</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">32</span>, local_size_y = <span class="integer">32</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is used to declare a two-dimensional compute shader with a workgroup size of 32
+X 32 elements, which is equivalent to a three-dimensional compute shader
+where the third dimension has size one.</p>
+</div>
+<div class="paragraph">
+<p>As another example, the declaration</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">8</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>effectively specifies that a one-dimensional compute shader is being
+compiled, and its size is 8 elements.</p>
+</div>
+<div class="paragraph">
+<p>If the fixed workgroup size of the shader in any dimension is less than
+or equal to zero or greater than the maximum size supported by the
+implementation for that dimension, a compile-time error results.
+Also, if such a layout qualifier is declared more than once in the same
+shader, all those declarations must set the same set of workgroup
+sizes and set them to the same values; otherwise a compile-time error
+results.</p>
+</div>
+<div class="paragraph">
+<p>Furthermore, if a program object contains a compute shader, that shader must
+contain an input layout qualifier specifying a fixed workgroup size for
+the program, or a link-time error will occur.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="output-layout-qualifiers">4.4.2. Output Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Some output layout qualifiers apply to all shader stages and some apply only
+to specific stages.
+The latter are discussed in separate sections below.</p>
+</div>
+<div class="paragraph">
+<p>As with input layout qualifiers, all shaders except compute shaders allow
+<strong>location</strong> layout qualifiers on output variable declarations, output block
+declarations, and output block member declarations.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The usage and rules for applying the <strong>location</strong> qualifier
+to blocks and structures are exactly as described in
+&#8220;<a href="#input-layout-qualifiers">Input Layout Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>The qualifier may appear at most once within a declaration.
+For example, in a fragment shader,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) out vec4 color;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the fragment shader output <em>color</em> is assigned to</p>
+</div>
+<div class="paragraph">
+<p>fragment color 3.</p>
+</div>
+<div class="paragraph">
+<p>For fragment shader outputs, the location
+specifies
+the color output number
+receiving the values of the output.
+For outputs of all other shader stages, the location specifies a vector
+number that can be used to match against inputs in a subsequent shader
+stage, even if that shader is in a different program object.</p>
+</div>
+<div class="paragraph">
+<p>Declared outputs of scalar or vector type consume a single location.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is an array, it will be assigned consecutive
+locations starting with the location specified.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">2</span>) out vec4 colors[<span class="integer">3</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that <em>colors</em> is assigned to vector location numbers 2, 3,
+and 4.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is an <em>n</em> × <em>m</em>
+matrix, it will be assigned multiple locations starting with the location
+specified.
+The number of locations assigned will be the same as for an <em>n</em>-element
+array of <em>m</em>-component vectors.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is a structure, its members will be assigned
+consecutive locations in the order of declaration, with the first member
+assigned the location specified for the structure.
+The number of locations consumed by a structure member is determined by
+applying the rules above recursively as though the structure member were
+declared as an output variable of the same type.</p>
+</div>
+<div class="paragraph">
+<p><strong>location</strong> layout qualifiers may be used on output variables declared as
+structures.
+However, it is a compile-time error to use a <strong>location</strong> qualifier on a
+structure member.
+Location layout qualifiers may be used on output blocks and output block
+members.</p>
+</div>
+<div class="paragraph">
+<p>If an output is declared as an array of blocks, excluding per-vertex-arrays
+as required for tessellation, it is an error to declare a member of the
+block with a <strong>location</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>The number of output locations available to a shader is limited.
+For fragment shaders, the limit is the advertised number of draw buffers.</p>
+</div>
+<div class="paragraph">
+<p>For all other shaders, the limit is implementation-dependent and must be no
+less than one fourth of the advertised maximum output component count
+(compute shaders have no outputs).
+A program will fail to link if any attached shader uses a location greater
+than or equal to the number of supported locations, unless device-dependent
+optimizations are able to make the program fit within available hardware
+resources.</p>
+</div>
+<div class="paragraph">
+<p>Compile-time errors may also be given if at compile time it is known the
+link will fail.
+A negative output location will result in an error.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error if any of the following occur:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>any two fragment shader output variables are assigned to the same
+location.</p>
+</li>
+<li>
+<p>if any two output variables from the same vertex, tessellation or
+geometry shader stage are assigned to the same location.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>For all shader types, a program will fail to link if explicit location
+assignments leave the linker unable to find space for other variables
+without explicit assignments.</p>
+</div>
+<div class="paragraph">
+<p>If an output variable has no location assigned in the shader text, it will
+be assigned a location by the linker.
+See section 11.1.3 &#8220;Shader Execution&#8221; of the <a href="#references">OpenGL ES Specification</a> for
+more details.</p>
+</div>
+<div class="paragraph">
+<p>If there is only a single output, the location does not need to be
+specified, in which case it defaults to zero.
+This applies for all output types, including arrays.
+If there is more than one fragment output, the location must be specified
+for all outputs.</p>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if a non-fragment output matches an input
+from a subsequent shader stage, the <strong>location</strong> layout qualifier (if any)
+must match.</p>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-outputs">Tessellation Control Outputs</h5>
+<div class="paragraph">
+<p>Tessellation control shaders allow output layout qualifiers only on the
+interface
+qualifier <strong>out</strong>, not on an output block, block member, or variable
+declaration.
+The output layout qualifier identifiers allowed for tessellation control
+shaders are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>vertices</strong> specifies the number of vertices in the output
+patch produced by the tessellation control shader, which also specifies the
+number of times the tessellation control shader is invoked.
+It is a compile- or link-time error for the output vertex count to be less
+than or equal to zero, or greater than the implementation-dependent maximum
+patch size.</p>
+</div>
+<div class="paragraph">
+<p>The intrinsically declared tessellation control output array <em>gl_out[]</em> will
+also be sized by any output layout declaration.
+Hence, the expression</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_out.length()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will return the output patch vertex count specified in a previous output
+layout qualifier.
+For outputs declared without an array size, including intrinsically declared
+outputs (i.e., <em>gl_out</em>), a layout must be declared before any use of the
+method <strong>length</strong>() or other array use that requires its size to be known.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error if the output patch vertex count specified in an
+output layout qualifier does not match the array size specified in any
+output variable declaration in the same shader.</p>
+</div>
+<div class="paragraph">
+<p>All tessellation control shader layout declarations in a program must
+specify the same output patch vertex count.
+There must be at least one layout qualifier specifying an output patch
+vertex count in any program containing a tessellation control shader.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-outputs">Geometry Outputs</h5>
+<div class="paragraph">
+<p>Geometry shaders can have two additional types of output layout identifiers:
+an output primitive type and a maximum output vertex count.
+The primitive type and vertex count identifiers are allowed only on the
+interface qualifier <strong>out</strong>, not on an output block, block member, or variable
+declaration.</p>
+</div>
+<div class="paragraph">
+<p>The layout qualifier identifiers for geometry shader outputs are</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>points</strong><br>
+<strong>line_strip</strong><br>
+<strong>triangle_strip</strong><br>
+<strong>max_vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The primitive type identifiers <strong>points</strong>, <strong>line_strip</strong>, and <strong>triangle_strip</strong>
+are used to specify the type of output primitive produced by the geometry
+shader, and only one of these is accepted.
+The geometry shader object in a program must declare an output primitive
+type, and all geometry shader output primitive type declarations in a
+program must declare the same primitive type.</p>
+</div>
+<div class="paragraph">
+<p>The vertex count identifier <strong>max_vertices</strong> is used to specify the maximum
+number of vertices the shader will ever emit in a single invocation.
+The geometry shader object in a program must declare a maximum output vertex
+count, and all geometry shader output vertex count declarations in a program
+must declare the same count.</p>
+</div>
+<div class="paragraph">
+<p>In this example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(triangle_strip, max_vertices = <span class="integer">60</span>) out; <span class="comment">// order does not matter</span>
+layout(max_vertices = <span class="integer">60</span>) out;  <span class="comment">// redeclaration okay</span>
+layout(triangle_strip) out;     <span class="comment">// redeclaration okay</span>
+layout(points) out;             <span class="comment">// error, contradicts triangle_strip</span>
+layout(max_vertices = <span class="integer">30</span>) out;  <span class="comment">// error, contradicts 60</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>all outputs from the geometry shader are triangles and at most 60 vertices
+will be emitted by the shader.
+It is an error for the maximum number of vertices to be greater than
+<em>gl_MaxGeometryOutputVertices</em>.</p>
+</div>
+<div class="paragraph">
+<p>All geometry shader output layout declarations in a program must declare the
+same layout and same value for <strong>max_vertices</strong>.
+If geometry shaders are in a program, there must be at least one geometry
+output layout declaration somewhere in that
+program.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="fragment-outputs">Fragment Outputs</h5>
+<div class="paragraph">
+<p>Fragment shaders can have an output layout for redeclaring the built-in
+variable <em>gl_FragDepth</em>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// redeclaration that changes nothing is allowed +</span>
+out <span class="predefined-type">float</span> gl_FragDepth;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The built-in <em>gl_FragDepth</em> is only predeclared in fragment shaders, so
+redeclaring it in any other shader language results in an error.</p>
+</div>
+<div class="paragraph">
+<p>Fragment shaders additionally support layout qualifiers specifying a set of
+advanced blend equations supported when the fragment shader is used.
+These layout qualifiers are only permitted on the interface qualifier <strong>out</strong>,
+and use the identifiers specified in the &#8220;Layout Qualifier&#8221; column of the
+table below.</p>
+</div>
+<div class="paragraph">
+<p>If a layout qualifier in the table below is specified in the fragment
+shader, the fragment shader may be used with the corresponding advanced
+blend equation in the &#8220;Blend Equation(s) Supported&#8221; column.
+Additionally, the special qualifier <strong>blend_support_all_equations</strong> indicates
+that the shader may be used with any advanced blending equation supported by
+the <a href="#references">OpenGL ES Specification</a>.
+It is not an error to specify more than one of these identifiers in any
+fragment shader.
+Specifying more than one qualifier or <strong>blend_support_all_equations</strong> means
+that the fragment shader may be used with multiple advanced blend equations.
+Additionally, it is not an error to specify any single one of these layout
+qualifiers more than once.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Layout Qualifier</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Blend Equations(s) Supported</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_multiply</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">MULTIPLY</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_screen</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">SCREEN</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_overlay</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">OVERLAY</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_darken</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">DARKEN</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_lighten</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">LIGHTEN</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_colordodge</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">COLORDODGE</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_colorburn</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">COLORBURN</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hardlight</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">HARDLIGHT</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_softlight</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">SOFTLIGHT</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_difference</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">DIFFERENCE</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_exclusion</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">EXCLUSION</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_hue</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">HSL_HUE</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_saturation</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">HSL_SATURATION</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_color</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">HSL_COLOR</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_hsl_luminosity</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">HSL_LUMINOSITY</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>blend_support_all_equations</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">all blend equations</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-variable-layout-qualifiers">4.4.3. Uniform Variable Layout Qualifiers</h4>
+<div class="paragraph">
+<p>The following layout qualifier can be used for all default-block uniform
+variables but not for variables in uniform or shader storage blocks.
+The layout qualifier identifier for uniform variables is:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The location specifies the location by which the OpenGL ES API can reference
+the uniform and update its value.
+Individual elements of a uniform array are assigned consecutive locations
+with the first element taking location <strong>location</strong>.
+No two default-block uniform variables in the program can have the same
+location, even if they are unused, otherwise a compile-time or link-time
+error will be generated.
+Valid locations for default-block uniform variable locations are in the
+range of 0 to the implementation-defined maximum number of uniform locations
+minus one.</p>
+</div>
+<div class="paragraph">
+<p>Locations can be assigned to default-block uniform arrays and structures.
+The first inner-most scalar, vector or matrix member or element takes the
+specified <strong>location</strong> and the compiler assigns the next inner-most member or
+element the next incremental location value.
+Each subsequent inner-most member or element gets incremental locations for
+the entire structure or array.
+This rule applies to nested structures and arrays and gives each inner-most
+scalar, vector, or matrix member a unique location.
+When the linker generates locations for uniforms without an explicit
+location, it assumes for all uniforms with an explicit location all their
+array elements and structure members are used and the linker will not
+generate a conflicting location, even if that element or member is deemed
+unused.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-and-shader-storage-block-layout-qualifiers">4.4.4. Uniform and Shader Storage Block Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers can be used for uniform and shader storage blocks, but not
+for non-block uniform declarations.
+The layout qualifier identifiers (and <strong>shared</strong> keyword) for uniform and
+shader storage blocks are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>shared</strong><br>
+<strong>packed</strong><br>
+<strong>std140</strong><br>
+<strong>std430</strong><br>
+<strong>row_major</strong><br>
+<strong>column_major</strong><br>
+<strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>None of these have any semantic effect at all on the usage of the variables
+being declared; they only describe how data is laid out in memory.
+For example, matrix semantics are always column-based, as described in the
+rest of this specification, no matter what layout qualifiers are being used.</p>
+</div>
+<div class="paragraph">
+<p>Uniform and shader storage block layout qualifiers can be declared for
+global scope, on a single uniform or shader storage block, or on a single
+block member declaration.</p>
+</div>
+<div class="paragraph">
+<p>Default layouts are established at global scope for uniform blocks as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) uniform;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and for shader storage blocks as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) buffer;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When this is done, the previous default qualification is first inherited and
+then overridden as per the override rules listed below for each qualifier
+listed in the declaration.
+The result becomes the new default qualification scoped to subsequent
+uniform or shader storage block definitions.</p>
+</div>
+<div class="paragraph">
+<p>The initial state of compilation
+is as if the following were declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(shared, column_major) uniform;
+layout(shared, column_major) buffer;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Uniform and shader storage blocks can be declared with optional layout
+qualifiers, and so can their individual member declarations.
+Such block layout qualification is scoped only to the content of the block.
+As with global layout declarations, block layout qualification first
+inherits from the current default qualification and then overrides it.
+Similarly, individual member layout qualification is scoped just to the
+member declaration, and inherits from and overrides the block&#8217;s
+qualification.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>shared</strong> qualifier overrides only the <strong>std140</strong>, <strong>std430</strong>, and <strong>packed</strong>
+qualifiers; other qualifiers are inherited.
+The compiler/linker will ensure that multiple programs and programmable
+stages containing this definition will share the same memory layout for this
+block, as long as they also matched in their <strong>row_major</strong> and/or
+<strong>column_major</strong> qualifications.
+This allows use of the same buffer to back the same block definition across
+different programs.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>packed</strong> qualifier overrides only <strong>std140</strong>, <strong>std430</strong>, and <strong>shared</strong>;
+other qualifiers are inherited.
+When <strong>packed</strong> is used, no shareable layout is guaranteed.
+The compiler and linker can optimize memory use based on what variables
+actively get used and on other criteria.
+Offsets must be queried, as there is no other way of guaranteeing where (and
+which) variables reside within the block.</p>
+</div>
+<div class="paragraph">
+<p>It is a link-time error to access the same packed uniform or shader storage
+block in multiple stages within a program.
+Attempts to access the same packed uniform or shader storage block across
+programs can result in conflicting member offsets and in undefined values
+being read.
+However, implementations may aid application management of packed blocks by
+using canonical layouts for packed blocks.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>std140</strong> and <strong>std430</strong> qualifiers override only the <strong>packed</strong>, <strong>shared</strong>,
+<strong>std140</strong>, and <strong>std430</strong> qualifiers; other qualifiers are inherited.
+The <strong>std430</strong> qualifier is supported only for shader storage blocks; a shader
+using the <strong>std430</strong> qualifier on a uniform block will fail to compile.</p>
+</div>
+<div class="paragraph">
+<p>The layout is explicitly determined by this, as described in section 7.6.2.2
+&#8220;Standard Uniform Block Layout&#8221; of the <a href="#references">OpenGL ES Specification</a>.
+Hence, as in <strong>shared</strong> above, the resulting layout is shareable across
+programs.</p>
+</div>
+<div class="paragraph">
+<p>Layout qualifiers on member declarations cannot use the <strong>shared</strong>, <strong>packed</strong>,
+<strong>std140</strong>, or <strong>std430</strong> qualifiers.
+These can only be used at global scope (without an object) or on a block
+declaration, or an error results.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>row_major</strong> and <strong>column_major</strong> qualifiers only affect the layout of
+matrices, including all matrices contained in structures and arrays they are
+applied to, to all depths of nesting.
+These qualifiers can be applied to other types, but will have no effect.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>row_major</strong> qualifier overrides only the <strong>column_major</strong> qualifier; other
+qualifiers are inherited.
+Elements within a matrix row will be contiguous in memory.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>column_major</strong> qualifier overrides only the <strong>row_major</strong> qualifier; other
+qualifiers are inherited.
+Elements within a matrix column will be contiguous in memory.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>binding</strong> qualifier specifies the uniform buffer binding point
+corresponding to the uniform or shader storage block, which will be used to
+obtain the values of the member variables of the block.
+It is a compile-time error to specify the <strong>binding</strong> qualifier for the global
+scope or for block member declarations.
+Any uniform or shader storage block declared without a <strong>binding</strong> qualifier
+is initially assigned to block binding point zero.
+After a program is linked, the binding points used for uniform
+(but not shader storage) blocks
+declared with or without a <strong>binding</strong> qualifier can be updated
+by the OpenGL ES API.</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> qualifier is used with a uniform block or shader storage
+block instanced as an array, the first element of the array takes the
+specified block binding and each subsequent element takes the next
+consecutive binding point.
+For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a
+binding point, and they are ordered per the array of array ordering
+described in &#8220;<a href="#arrays.">Arrays.</a>&#8221;</p>
+</div>
+<div class="paragraph">
+<p>If the binding point for any uniform or shader storage block instance is
+less than zero, or greater than or equal to the corresponding
+implementation-dependent maximum number of buffer bindings, a compile-time
+error will occur.
+When the <strong>binding</strong> qualifier is used with a uniform or shader storage block
+instanced as an array of size <em>N</em>, all elements of the array from <strong>binding</strong>
+through <em>binding + N - 1</em> must be within this range.</p>
+</div>
+<div class="paragraph">
+<p>When multiple arguments are listed in a <strong>layout</strong> declaration, the effect
+will be the same as if they were declared one at a time, in order from left
+to right, each in turn inheriting from and overriding the result from the
+previous qualification.</p>
+</div>
+<div class="paragraph">
+<p>For example</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(row_major, column_major)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>results in the qualification being <strong>column_major</strong>.
+Other examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(shared, row_major) uniform; <span class="comment">// default is now shared and row_major</span>
+
+layout(std140) uniform Transform { <span class="comment">// layout of this block is std140</span>
+    mat4 M1;                       <span class="comment">// row major</span>
+    layout(column_major) mat4 M2;  <span class="comment">// column major</span>
+    mat3 N1;                       <span class="comment">// row major</span>
+};
+
+uniform T2 {                       <span class="comment">// layout of this block is shared</span>
+    ...
+};
+
+layout(column_major) uniform T3 {  <span class="comment">// shared and column major</span>
+    mat4 M3;                       <span class="comment">// column major</span>
+    layout(row_major) mat4 m4;     <span class="comment">// row major</span>
+    mat3 N2;                       <span class="comment">// column major</span>
+};</code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="opaque-uniform-layout-qualifiers">4.4.5. Opaque Uniform Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Uniform layout qualifiers can be used to bind opaque uniform variables to
+specific buffers or units.
+Samplers can be bound to texture image units, images can be bound to image
+units, and atomic counters can be bound to buffers.</p>
+</div>
+<div class="paragraph">
+<p>Sampler, image and atomic counter types take the uniform layout qualifier
+identifier for binding:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>binding</strong> specifies which unit will be bound.
+Any uniform sampler, image or atomic counter
+variable declared without a binding qualifier
+is initially bound to unit zero.
+After a program is linked, the unit referenced by a sampler
+uniform variable declared with or without a <strong>binding</strong> qualifier can be
+updated by the OpenGL ES API.</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> qualifier is used with an array, the first element of the
+array takes the specified unit and each subsequent element takes the next
+consecutive unit.
+For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a
+binding point, and they are ordered per the array of array ordering
+described in &#8220;<a href="#arrays.">Arrays.</a>&#8221;</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> is less than zero, or greater than or equal to the
+implementation-dependent maximum supported number of units, a compile-time
+error will occur.
+When the <strong>binding</strong> qualifier is used with an array of size <em>N</em>, all elements
+of the array from <strong>binding</strong> through <em>binding + N - 1</em> must be within this
+range.</p>
+</div>
+<div class="paragraph">
+<p>A link-time error will result if two shaders in a program specify different
+<em>layout-qualifier-value</em> bindings for the same opaque-uniform name.
+However, it is not an error to specify a binding on some but not all
+declarations for the same name, as shown in the examples below.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// in one shader...</span>
+layout(binding=<span class="integer">3</span>) uniform sampler2D s; <span class="comment">// s bound to unit 3</span>
+
+<span class="comment">// in another shader...</span>
+uniform sampler2D s;                   <span class="comment">// okay, s still bound at 3</span>
+
+<span class="comment">// in another shader...</span>
+layout(binding=<span class="integer">4</span>) uniform sampler2D s; <span class="comment">// ERROR: contradictory bindings</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="atomic-counter-layout-qualifiers">4.4.6. Atomic Counter Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Atomic counter layout qualifiers can be used on atomic counter declarations.
+The atomic counter qualifiers are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>offset</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint a;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the opaque handle to the atomic counter <em>a</em> will be
+bound to atomic counter buffer binding point 2 at an offset of 4 basic
+machine units into that buffer.
+The default <em>offset</em> for binding point 2 will be post incremented by 4 (the
+size of an atomic counter).</p>
+</div>
+<div class="paragraph">
+<p>A subsequent atomic counter declaration will inherit the previous (post
+incremented) offset.
+For example, a subsequent declaration of</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the atomic counter <em>bar</em> has a binding to buffer binding
+point 2 at an offset of 8 basic machine units into that buffer.
+The offset for binding point 2 will again be post-incremented by 4 (the size
+of an atomic counter).</p>
+</div>
+<div class="paragraph">
+<p>When multiple variables are listed in a layout declaration, the effect will
+be the same as if they were declared one at a time, in order from left to
+right.</p>
+</div>
+<div class="paragraph">
+<p>Binding points are not inherited, only offsets.
+Each binding point tracks its own current default <em>offset</em> for inheritance
+of subsequent variables using the same <strong>binding</strong>.
+The initial state of compilation is that all <strong>binding</strong> points have an
+<em>offset</em> of 0.
+The <em>offset</em> can be set per binding point at global scope (without declaring
+a variable).
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Establishes that the next <strong>atomic_uint</strong> declaration for binding point 2 will
+inherit <em>offset</em> 4 (but does not establish a default <strong>binding</strong>):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar; <span class="comment">// offset is 4</span>
+layout(offset = <span class="integer">8</span>) uniform atomic_uint bar;  <span class="comment">// error, no default binding</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Atomic counters may share the same binding point, but if a binding is
+shared, their offsets must be either explicitly or implicitly (from
+inheritance) unique and non overlapping.</p>
+</div>
+<div class="paragraph">
+<p>Example valid uniform declarations, assuming top of shader:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding=<span class="integer">3</span>, offset=<span class="integer">4</span>) uniform atomic_uint a; <span class="comment">// offset = 4</span>
+layout(binding=<span class="integer">2</span>) uniform atomic_uint b;           <span class="comment">// offset = 0</span>
+layout(binding=<span class="integer">3</span>) uniform atomic_uint c;           <span class="comment">// offset = 8</span>
+layout(binding=<span class="integer">2</span>) uniform atomic_uint d;           <span class="comment">// offset = 4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Example of an invalid uniform declaration:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(offset=<span class="integer">4</span>) ...               <span class="comment">// error, must include binding</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... a; <span class="comment">// okay</span>
+layout(binding=<span class="integer">2</span>, offset=<span class="integer">0</span>) ... b; <span class="comment">// okay</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... c; <span class="comment">// error, offsets must not be shared</span>
+                                   <span class="comment">// between a and c</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">2</span>) ... d; <span class="comment">// error, overlaps offset 0 of a</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to bind an atomic counter with a binding value
+greater than or equal to <em>gl_MaxAtomicCounterBindings</em>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="format-layout-qualifiers">4.4.7. Format Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Format layout qualifiers can be used on image variable declarations (those
+declared with a basic type having &#8220;<strong>image</strong>&#8221; in its keyword).
+The format layout qualifier identifiers for image variable declarations are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>float-image-format-qualifier</em><br>
+<em>int-image-format-qualifier</em><br>
+<em>uint-image-format-qualifier</em><br>
+<strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>float-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32f</strong><br>
+<strong>rgba16f</strong><br>
+<strong>r32f</strong><br>
+<strong>rgba8</strong><br>
+<strong>rgba8_snorm</strong></p>
+</dd>
+<dt class="hdlist1"><em>int-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32i</strong><br>
+<strong>rgba16i</strong><br>
+<strong>rgba8i</strong><br>
+<strong>r32i</strong></p>
+</dd>
+<dt class="hdlist1"><em>uint-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32ui</strong><br>
+<strong>rgba16ui</strong><br>
+<strong>rgba8ui</strong><br>
+<strong>r32ui</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>A format layout qualifier specifies the image format associated with a
+declared image variable.
+Only one format qualifier may be specified for any image variable
+declaration.
+For image variables with floating-point component types (keywords starting
+with &#8220;<strong>image</strong>&#8221;), signed integer component types (keywords starting with
+&#8220;<strong>iimage</strong>&#8221;), or unsigned integer component types (keywords starting with
+&#8220;<strong>uimage</strong>&#8221;), the format qualifier used must match the
+<em>float-image-format-qualifier</em>, <em>int-image-format-qualifier</em>, or
+<em>uint-image-format-qualifier</em> grammar rules, respectively.
+It is an error to declare an image variable where the format
+qualifier does not match the image variable type.</p>
+</div>
+<div class="paragraph">
+<p>Any image variable must specify a format layout qualifier.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>binding</strong> qualifier was described in
+&#8220;<a href="#opaque-uniform-layout-qualifiers">Opaque Uniform Layout Qualifiers</a>&#8221;.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="interpolation-qualifiers">4.5. Interpolation Qualifiers</h3>
+<div class="paragraph">
+<p>Inputs and outputs that could be interpolated can be further qualified by at
+most one of the following interpolation qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">perspective correct interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>flat</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">no interpolation</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The presence of and type of interpolation is controlled by the above
+interpolation qualifiers as well as the auxiliary storage qualifiers
+<strong>centroid</strong> and <strong>sample</strong>.
+When no interpolation qualifier is present, smooth interpolation is used.
+It is a compile-time error to use more than one interpolation qualifier.
+The auxiliary storage qualifier <strong>patch</strong> is not used for interpolation; it is
+a compile-time error to use interpolation qualifiers with <strong>patch</strong>.</p>
+</div>
+<div class="paragraph">
+<p>A variable qualified as <strong>flat</strong> will not be interpolated.
+Instead, it will have the same value for every fragment within a primitive.
+This value will come from a single provoking vertex, as described by the
+<a href="#references">OpenGL ES Specification</a>.
+A variable qualified as <strong>flat</strong> may also be qualified as <strong>centroid</strong> or
+<strong>sample</strong>, which will mean the same thing as qualifying it only as <strong>flat</strong>.</p>
+</div>
+<div class="paragraph">
+<p>A variable qualified as <strong>smooth</strong> will be interpolated in a
+perspective-correct manner over the primitive being rendered.</p>
+</div>
+<div class="paragraph">
+<p>Interpolation in a perspective correct manner is specified in equations 13.4
+of the <a href="#references">OpenGL ES Specification</a>, section 13.4.1 &#8220;Line Segments&#8221; and
+equation 13.7, section 13.5.1 &#8220;Polygon Interpolation&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>When multisample rasterization is disabled, or for fragment shader input
+variables qualified with neither <strong>centroid</strong> nor <strong>sample</strong>, the value of the
+assigned variable may be interpolated anywhere within the pixel and a single
+value may be assigned to each sample within the pixel, to the extent
+permitted by the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>When multisample rasterization is enabled, <strong>centroid</strong> and <strong>sample</strong> may be
+used to control the location and frequency of the sampling of the qualified
+fragment shader input.
+If a fragment shader input is qualified with <strong>centroid</strong>, a single value may
+be assigned to that variable for all samples in the pixel, but that value
+must be interpolated at a location that lies in both the pixel and in the
+primitive being rendered, including any of the pixel&#8217;s samples covered by
+the primitive.
+Because the location at which the variable is interpolated may be different
+in neighboring pixels, and derivatives may be computed by computing
+differences between neighboring pixels, derivatives of centroid-sampled
+inputs may be less accurate than those for non-centroid interpolated
+variables.
+If a fragment shader input is qualified with <strong>sample</strong>, a separate value must
+be assigned to that variable for each covered sample in the pixel, and that
+value must be sampled at the location of the individual sample.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="parameter-qualifiers">4.6. Parameter Qualifiers</h3>
+<div class="paragraph">
+<p>In addition to precision qualifiers and memory qualifiers, parameters can
+have these parameter qualifiers.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;none: default&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed into a function</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed back out of a function,
+                   but not initialized for use when passed in</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inout</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed both into and out of a
+                   function</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Parameter qualifiers are discussed in more detail in
+&#8220;<a href="#function-calling-conventions">Function Calling Conventions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</h3>
+<div class="sect3">
+<h4 id="range-and-precision">4.7.1. Range and Precision</h4>
+<div class="paragraph">
+<p>The precision of <strong>highp</strong> floating-point variables is defined by the IEEE 754
+standard for 32-bit floating-point numbers.
+This includes support for NaNs (Not a Number) and Infs (positive or negative
+infinities) and positive and negative zeros.</p>
+</div>
+<div class="paragraph">
+<p>The following rules apply to
+<strong>highp</strong>
+operations:
+Signed infinities and zeros are generated as dictated by IEEE, but subject
+to the precisions allowed in the following table.
+Any subnormal (denormalized) value input into a shader or potentially
+generated by any operation in a shader can be flushed to 0.
+The rounding mode cannot be set and is undefined but must not affect the
+result by more than 1 ULP.
+NaNs are not required to be generated.
+Support for signaling NaNs is not required and exceptions are never raised.
+Operations including built-in functions that operate on a NaN are not
+required to return a NaN as the result.
+However if NaNs are generated, <strong>isnan</strong>() must return the correct value.</p>
+</div>
+<div class="paragraph">
+<p>Precisions are expressed in terms of maximum relative error in units of ULP
+(units in the last place), unless otherwise noted.</p>
+</div>
+<div class="paragraph">
+<p>For single precision operations, precisions are required as follows:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Operation</th>
+<th class="tableblock halign-left valign-top">Precision</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> + <em>b</em>, <em>a</em> - <em>b</em>, <em>a</em> * <em>b</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;, &lt;=, ==, &gt;, &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correct result.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> / <em>b</em>, 1.0 / <em>b</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2.5 ULP for <span class="eq">|b|</span> in the range <span class="eq">[2<sup>-126</sup>, 2<sup>126</sup>]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> * <em>b</em> + <em>c</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded single operation or
+                                    sequence of two correctly rounded operations.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>fma</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <em>a</em> * <em>b</em> + <em>c</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>pow</strong>(<em>x</em>, <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <strong>exp2</strong>(<em>y</em> * <strong>log2</strong>(<em>x</em>)).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>exp</strong>(<em>x</em>), <strong>exp2</strong>(<em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(3 + 2 · |x|)</span> ULP.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>log</strong>(), <strong>log2</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3 ULP outside the range <span class="eq">[0.5,2.0]</span>.<br>
+                                    Absolute error &lt; 2<sup>-21</sup> inside the range
+                                    <span class="eq">[0.5,2.0]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sqrt</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from 1.0 / <strong>inversesqrt</strong>().</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inversesqrt</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2 ULP.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">implicit and explicit
+  conversions between types</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Built-in functions defined in the specification with an equation built from
+the above operations inherit the above errors.
+These include, for example, the geometric functions, the common functions,
+and many of the matrix functions.
+Built-in functions not listed above and not defined as equations of the
+above have undefined precision.
+These include, for example, the trigonometric functions and determinant.</p>
+</div>
+<div class="paragraph">
+<p>Storage requirements are declared through use of <em>precision qualifiers</em>.
+The precision of operations must preserve the storage precisions of the
+variables involved.</p>
+</div>
+<div class="paragraph">
+<p><strong>highp</strong> floating-point values are stored in IEEE 754 single precision
+floating-point format.
+<strong>mediump</strong> and <strong>lowp</strong> floating-point values have minimum range and precision
+requirements as detailed below and have maximum range and precision as
+defined by IEEE 754.</p>
+</div>
+<div class="paragraph">
+<p>All integral types are assumed to be implemented as integers and so may not
+be emulated by floating-point values.
+<strong>highp</strong> signed integers are represented as twos-complement 32-bit signed
+integers.
+<strong>highp</strong> unsigned integers are represented as unsigned 32-bit integers.
+<strong>mediump</strong> integers (signed and unsigned) must be represented as an integer
+with between 16 and 32 bits inclusive.
+<strong>lowp</strong> integers (signed and unsigned) must be represented as an integer with
+between 9 and 32 bits inclusive.</p>
+</div>
+<div class="paragraph">
+<p>The required ranges and precisions for precision qualifiers are:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Floating-Point Range</th>
+<th class="tableblock halign-left valign-top">Floating-Point Magnitude Range</th>
+<th class="tableblock halign-left valign-top">Floating-Point Precision</th>
+<th class="tableblock halign-left valign-top">Signed Integer Range</th>
+<th class="tableblock halign-left valign-top">Unsigned Integer Range</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>highp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754<br>
+      <span class="eq">(-2<sup>128</sup>,2<sup>128</sup>)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754<br>
+      0.0, <span class="eq">[2<sup>-126</sup>,2<sup>128</sup>)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Subset of IEEE-754 relative:<br>
+      <span class="eq">2<sup>-24</sup></span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>31</sup>,2<sup>31</sup>-1]</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>32</sup>-1]</span></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mediump</strong> (minimum requirements)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(-2<sup>14</sup>,2<sup>14</sup>)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(2<sup>14</sup>,2<sup>14</sup>)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Relative:<br>
+      <span class="eq">2<sup>-10</sup></span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>15</sup>,2<sup>15</sup>-1]</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>16</sup>-1]</span></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong> (minimum requirements)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(-2,2)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(2<sup>-8</sup>,2)</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Absolute:<br>
+      <span class="eq">2<sup>-8</sup></span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[-2<sup>8</sup>,2<sup>8</sup>-1]</span></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">[0,2<sup>9</sup>-1]</span></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p><em>Relative precision</em> is defined as the worst case (i.e. largest) ratio of
+the smallest step in relation to the value for all non-zero values:</p>
+</div>
+<div class="stemblock">
+<div class="content">
+\[\begin{aligned}
+    \mathit{Precision}_{relative} = {
+        \left| {
+            { \left| v_1 - v_2 \right| }_{min} } \over { v_1 }
+        \right|
+    }_{max}, &amp;
+    v_1,v_2 \neq 0, v_1 \neq v_2
+\end{aligned}\]
+</div>
+</div>
+<div class="paragraph">
+<p>It is therefore twice the maximum rounding error when converting from a real
+number.</p>
+</div>
+<div class="paragraph">
+<p>In addition, the range and precision of a <strong>mediump</strong> floating-point value
+must be the same as or greater than the range and precision of a <strong>lowp</strong>
+floating-point value.
+The range and precision of a <strong>highp</strong> floating-point value must be the same
+as or greater than the range and precision of a <strong>mediump</strong> floating-point
+value.</p>
+</div>
+<div class="paragraph">
+<p>The range of a <strong>mediump</strong> integer value must be the same as or greater than
+the range of a <strong>lowp</strong> integer value.
+The range of a <strong>highp</strong> integer value must be the same as or greater than the
+range of a <strong>mediump</strong> integer value.</p>
+</div>
+<div class="paragraph">
+<p>Within the above specification, an implementation is allowed to vary the
+representation of numeric values, both within a shader and between different
+shaders.
+If necessary, this variance can be controlled using the invariance
+qualifier.</p>
+</div>
+<div class="paragraph">
+<p>The actual ranges and precisions provided by an implementation can be
+queried through the API.
+See the <a href="#references">OpenGL ES Specification</a> specification for details on how to do
+this.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="conversion-between-precisions">4.7.2. Conversion between precisions</h4>
+<div class="paragraph">
+<p>Within the same type, conversion from a lower to a higher precision must be
+exact.
+When converting from a higher precision to a lower precision, if the value
+is representable by the implementation of the target precision, the
+conversion must also be exact.
+If the value is not representable, the behavior is dependent on the type:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>For signed and unsigned integers, the value is truncated; bits in
+positions not present in the target precision are set to zero.
+(Positions start at zero and the least significant bit is considered to
+be position zero for this purpose.)</p>
+</li>
+<li>
+<p>For floating-point values, the value should either clamp to +Inf or
+-Inf, or to the maximum or minimum value that the implementation
+supports.
+While this behavior is implementation-dependent, it should be consistent
+for a given implementation.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="precision-qualifiers">4.7.3. Precision Qualifiers</h4>
+<div class="paragraph">
+<p>Any
+floating-point, integer, or opaque-type declaration can have the type
+preceded by one of these precision qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Qualifier</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Meaning</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>highp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The variable satisfies the minimum requirements for <strong>highp</strong>
+              described above. <strong>highp</strong> variables have the maximum range and
+              precision available but may cause operations to run more
+              slowly on some implementations.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mediump</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The variable satisfies the minimum requirements for <strong>mediump</strong>
+              described above. <strong>mediump</strong> variables may typically be used to
+              store high dynamic range colors and low precision geometry.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The variable satisfies the minimum requirements for <strong>lowp</strong>
+              described above. <strong>lowp</strong> variables may typically be used to
+              store 8-bit color values.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">lowp <span class="predefined-type">float</span> color;
+out mediump vec2 P;
+lowp ivec2 foo(lowp mat3);
+highp mat4 m;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Literal constants do not have precision qualifiers.
+Neither do Boolean variables.
+Neither do constructors.</p>
+</div>
+<div class="paragraph">
+<p>For this paragraph, &#8220;operation&#8221; includes operators, built-in functions,
+and constructors, and &#8220;operand&#8221; includes function arguments and
+constructor arguments.
+The precision used to internally evaluate an operation, and the precision
+qualification subsequently associated with any resulting intermediate
+values, must be at least as high as the highest precision qualification of
+the operands consumed by the operation.</p>
+</div>
+<div class="paragraph">
+<p>In cases where operands do not have a precision qualifier, the precision
+qualification will come from the other operands.
+If no operands have a precision qualifier, then the precision qualifications
+of the operands of the next consuming operation in the expression will be
+used.
+This rule can be applied recursively until a precision qualified operand is
+found.
+If necessary, it will also include the precision qualification of l-values
+for assignments, of the declared variable for initializers, of formal
+parameters for function call arguments, or of function return types for
+function return values.
+If the precision cannot be determined by this method e.g. if an entire
+expression is composed only of operands with no precision qualifier, and the
+result is not assigned or passed as an argument, then it is evaluated at the
+default precision of the type or greater.
+When this occurs in the fragment shader, the default precision must be
+defined.</p>
+</div>
+<div class="paragraph">
+<p>For example, consider the statements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform highp <span class="predefined-type">float</span> h1;
+highp <span class="predefined-type">float</span> h2 = <span class="float">2</span><span class="float">.3</span> * <span class="float">4</span><span class="float">.7</span>; <span class="comment">// operation and result are highp</span>
+precision
+mediump <span class="predefined-type">float</span> m;
+m = <span class="float">3</span><span class="float">.7</span> * h1 * h2; <span class="comment">// all operations are highp precision</span>
+h2 = m * h1; <span class="comment">// operation is highp precision</span>
+m = h2 - h1; <span class="comment">// operation is highp precision</span>
+h2 = m + m; <span class="comment">// addition and result at mediump precision</span>
+<span class="directive">void</span> f(highp <span class="predefined-type">float</span> p);
+f(<span class="float">3</span><span class="float">.3</span>); <span class="comment">// 3.3 will be passed in at highp precision</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Precision qualifiers, as with other qualifiers, do not affect the basic type
+of the variable.
+In particular, there are no constructors for precision conversions;
+constructors only convert types.
+Similarly, precision qualifiers, as with other qualifiers, do not contribute
+to function overloading based on parameter types.
+As discussed in &#8220;<a href="#function-calling-conventions">Function Calling
+Conventions</a>&#8221;, function input and output is done through copies, and
+therefore qualifiers do not have to match.</p>
+</div>
+<div class="paragraph">
+<p>Precision qualifiers for outputs in one shader matched to inputs in another
+shader need not match when both shaders are linked into the same program.
+When both shaders are in separate programs, mismatched precision qualifiers
+will result in a program interface mismatch that will result in program
+pipeline validation failures, as described in section 7.4.1 &#8220;Shader
+Interface Matching&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>The precision of a variable is determined when the variable is declared and
+cannot be subsequently changed.</p>
+</div>
+<div class="paragraph">
+<p>Where the precision of a constant integral or constant floating-point
+expression is not specified, evaluation is performed at <strong>highp</strong>.
+This rule does not affect the precision qualification of the expression.</p>
+</div>
+<div class="paragraph">
+<p>The evaluation of constant expressions must be invariant and will usually be
+performed at compile time.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="default-precision-qualifiers">4.7.4. Default Precision Qualifiers</h4>
+<div class="paragraph">
+<p>The precision statement</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision precision-qualifier type;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to establish a default precision qualifier.
+The <em>type</em> field can be either <strong>int</strong>, <strong>float</strong>, or any of the opaque types,
+and the <em>precision-qualifier</em> can be <strong>lowp</strong>, <strong>mediump</strong>, or <strong>highp</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Any other types or qualifiers will result in an error.
+If <em>type</em> is <strong>float</strong>, the directive applies to non-precision-qualified
+floating-point type (scalar, vector, and matrix) declarations.
+If <em>type</em> is <strong>int</strong>, the directive applies to all non-precision-qualified
+integer type (scalar, vector, signed, and unsigned) declarations.
+This includes global variable declarations, function return declarations,
+function parameter declarations, and local variable declarations.</p>
+</div>
+<div class="paragraph">
+<p>Non-precision qualified declarations will use the precision qualifier
+specified in the most recent <strong>precision</strong> statement that is still in scope.
+The <strong>precision</strong> statement has the same scoping rules as variable
+declarations.
+If it is declared inside a compound statement, its effect stops at the end
+of the inner-most statement it was declared in.
+Precision statements in nested scopes override precision statements in outer
+scopes.
+Multiple precision statements for the same basic type can appear inside the
+same scope, with later statements overriding earlier statements within that
+scope.</p>
+</div>
+<div class="paragraph">
+<p>All languages except for the fragment language have the following
+predeclared globally scoped default precision statements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision highp <span class="predefined-type">float</span>;
+precision highp <span class="predefined-type">int</span>;
+precision lowp sampler2D;
+precision lowp samplerCube;
+precision highp atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The fragment language has the following predeclared globally scoped default
+precision statements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision mediump <span class="predefined-type">int</span>;
+precision lowp sampler2D;
+precision lowp samplerCube;
+precision highp atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The fragment language has no default precision qualifier for floating-point
+types.
+Hence for <strong>float</strong>, floating-point vector and matrix variable declarations,
+either the declaration must include a precision qualifier or the default
+float precision must have been previously declared.
+Similarly, there is no default precision qualifier in any of the languages
+for any type not listed above.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="available-precision-qualifiers">4.7.5. Available Precision Qualifiers</h4>
+<div class="paragraph">
+<p>The built-in macro GL_FRAGMENT_PRECISION_HIGH is defined to one:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_FRAGMENT_PRECISION_HIGH <span class="integer">1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This macro is available in all languages except compute.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</h3>
+<div class="paragraph">
+<p>In this section, <em>variance</em> refers to the possibility of getting different
+values from the same expression in different programs.
+For example, consider the situation where two vertex shaders, in different
+programs, each set <em>gl_Position</em> with the same expression, and the input
+values into that expression are the same when both shaders run.
+It is possible, due to independent compilation of the two shaders, that the
+values assigned to <em>gl_Position</em> are not exactly the same when the two
+shaders run.
+In this example, this can cause problems with alignment of geometry in a
+multi-pass algorithm.</p>
+</div>
+<div class="paragraph">
+<p>In general, such variance between shaders is allowed.
+When such variance does not exist for a particular output variable, that
+variable is said to be <em>invariant</em>.</p>
+</div>
+<div class="sect3">
+<h4 id="the-invariant-qualifier">4.8.1. The Invariant Qualifier</h4>
+<div class="paragraph">
+<p>To ensure that a particular output variable is invariant, it is necessary to
+use the <strong>invariant</strong> qualifier.
+It can either be used to qualify a previously declared variable as being
+invariant:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant gl_Position; <span class="comment">// make existing gl_Position be invariant</span>
+out vec3 Color;
+invariant Color;       <span class="comment">// make existing Color be invariant</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>or as part of a declaration when a variable is declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant centroid out vec3 Color;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Only variables output from a shader can be candidates for invariance.
+This includes user-defined output variables and the built-in output
+variables.
+As only outputs can be declared as invariant, an output from one shader
+stage will still match an input of a subsequent stage without the input
+being declared as invariant.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>invariant</strong> keyword can be followed by a comma separated list of
+previously declared identifiers.
+All uses of <strong>invariant</strong> must be at global scope or on block
+members, and before any use of the variables being declared as invariant.</p>
+</div>
+<div class="paragraph">
+<p>To guarantee invariance of a particular output variable across two programs,
+the following must also be true:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The output variable is declared as invariant in both programs.</p>
+</li>
+<li>
+<p>The same values must be input to all shader input variables consumed by
+expressions and control flow contributing to the value assigned to the
+output variable.</p>
+</li>
+<li>
+<p>The texture formats, texel values, and texture filtering are set the
+same way for any texture function calls contributing to the value of the
+output variable.</p>
+</li>
+<li>
+<p>All input values are all operated on in the same way.
+    All operations in the consuming expressions and any intermediate
+    expressions must be the same, with the same order of operands and same
+    associativity, to give the same order of evaluation.
+    Intermediate variables and functions must be declared as the same type
+    with the same explicit or implicit precision
+qualifiers and the same constant qualifiers.
+    Any control flow affecting the output value must be the same, and any
+    expressions consumed to determine this control flow must also follow
+    these invariance rules.</p>
+</li>
+<li>
+<p>All the data flow and control flow leading to setting the invariant
+output variable reside in a single compilation unit.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Essentially, all the data flow and control flow leading to an invariant
+output must match.</p>
+</div>
+<div class="paragraph">
+<p>Initially, by default, all output variables are allowed to be variant.
+To force all output variables to be invariant, use the pragma</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL invariant(all)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>before all declarations in a shader.
+If this pragma is used after the declaration of any variables or functions,
+then the set of outputs that behave as invariant is undefined.</p>
+</div>
+<div class="paragraph">
+<p>Generally, invariance is ensured at the cost of flexibility in optimization,
+so performance can be degraded by use of invariance.
+Hence, use of this pragma is intended as a debug aid, to avoid individually
+declaring all output variables as invariant.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="invariance-within-a-shader">4.8.2. Invariance Within a Shader</h4>
+<div class="paragraph">
+<p>When a value is stored in a variable, it is usually assumed it will remain
+constant unless explicitly changed.
+However, during the process of optimization, it is possible that the
+compiler may choose to recompute a value rather than store it in a register.
+Since the precision of operations is not completely specified (e.g. a low
+precision operation may be done at medium or high precision), it would be
+possible for the recomputed value to be different from the original value.</p>
+</div>
+<div class="paragraph">
+<p>Values are allowed to be variant within a shader.
+To prevent this, the invariant qualifier or invariant pragma must be used.</p>
+</div>
+<div class="paragraph">
+<p>Within a shader, there is no invariance for values generated by different
+non-constant expressions, even if those expressions are identical.</p>
+</div>
+<div class="paragraph">
+<p>Example 1:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision mediump;
+vec4 col;
+vec2 a = ...
+...
+col = texture(tex, a);<span class="comment">// a has a value _a1 _</span>
+...
+col = texture(tex, a); <span class="comment">// a has a value a2 where possibly a1 != a2</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To enforce invariance in this example use:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL invariant(all)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Example 2:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec2 m = ...;
+vec2 n = ...;
+vec2 a = m + n;
+vec2 b = m + n; <span class="comment">// a and b are not guaranteed to be exactly equal</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There is no mechanism to enforce invariance between a and b.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="invariance-of-constant-expressions">4.8.3. Invariance of Constant Expressions</h4>
+<div class="paragraph">
+<p>Invariance must be guaranteed for constant expressions.
+A particular constant expression must evaluate to the same result if it
+appears again in the same shader or a different shader.
+This includes the same expression appearing in two shaders of the same
+language or shaders of two different languages.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions must evaluate to the same result when operated on as
+already described above for invariant variables.
+Constant expressions are not invariant with respect to equivalent
+non-constant expressions, even when the <strong>invariant</strong> qualifier or pragma is
+used.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="invariance-of-undefined-values">4.8.4. Invariance of Undefined Values</h4>
+<div class="paragraph">
+<p>Undefined values are not invariant nor can they be made invariant by use of
+the invariant qualifier or pragma.
+In some implementations, undefined values may cause unexpected behavior if
+they are used in control-flow expressions e.g. in the following case, one,
+both or neither functions may be executed and this may not be consistent
+over multiple invocations of the shader:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x; <span class="comment">// undefined value</span>
+<span class="keyword">if</span> (x == <span class="integer">1</span>)
+{
+    f(); <span class="comment">// Undefined whether f() is executed</span>
+}
+<span class="keyword">if</span> (x == <span class="integer">2</span>)
+{
+    g(); <span class="comment">// Undefined whether g() is executed.</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that an undefined value is a value that has not been specified.
+A value that has been specified but has a potentially large error due to,
+for example, lack of precision in an expression, is not undefined and so can
+be made invariant.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="the-precise-qualifier">4.9. The Precise Qualifier</h3>
+<div class="paragraph">
+<p>Some algorithms require floating-point computations to exactly follow the
+order of operations specified in the source code and to treat all operations
+consistently, even if the implementation supports optimizations that could
+produce nearly equivalent results with higher performance.
+For example, many GL implementations support a &#8220;multiply-add&#8221; instruction
+that can compute a floating-point expression such as</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">result = (a * b) + (c * d);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>in two operations instead of three operations; one multiply and one
+multiply-add instead of two multiplies and one add.
+The result of a floating-point multiply-add might not always be identical to
+first doing a multiply yielding a floating-point result and then doing a
+floating-point add.
+Hence, in this example, the two multiply operations would not be treated
+consistently; the two multiplies could effectively appear to have differing
+precisions.</p>
+</div>
+<div class="paragraph">
+<p>The key computation that needs to be made consistent appears when
+tessellating, where intermediate points for subdivision are synthesized in
+different directions, yet need to yield the same result, as shown in the
+diagram below.</p>
+</div>
+<div id="img-precise" class="imageblock">
+<div class="content">
+<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KCjxzdmcgdmVyc2lvbj0iMS4yIiBiYXNlUHJvZmlsZT0idGlueSIgd2lkdGg9IjIxMG1tIiBoZWlnaHQ9IjI5N21tIiB2aWV3Qm94PSIwIDAgMjEwMDAgMjk3MDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSIgc3Ryb2tlLXdpZHRoPSIyOC4yMjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6b29vPSJodHRwOi8veG1sLm9wZW5vZmZpY2Uub3JnL3N2Zy9leHBvcnQiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIj4KIDxkZWZzIGNsYXNzPSJDbGlwUGF0aEdyb3VwIj4KICA8Y2xpcFBhdGggaWQ9InByZXNlbnRhdGlvbl9jbGlwX3BhdGgiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIxMDAwIiBoZWlnaHQ9IjI5NzAwIi8+CiAgPC9jbGlwUGF0aD4KIDwvZGVmcz4KIDxkZWZzPgogIDxmb250IGlkPSJFbWJlZGRlZEZvbnRfMSIgaG9yaXotYWR2LXg9IjIwNDgiPgogICA8Zm9udC1mYWNlIGZvbnQtZmFtaWx5PSJMaWJlcmF0aW9uIFNhbnMgZW1iZWRkZWQiIHVuaXRzLXBlci1lbT0iMjA0OCIgZm9udC13ZWlnaHQ9Im5vcm1hbCIgZm9udC1zdHlsZT0ibm9ybWFsIiBhc2NlbnQ9IjE4NTIiIGRlc2NlbnQ9IjQyMyIvPgogICA8bWlzc2luZy1nbHlwaCBob3Jpei1hZHYteD0iMjA0OCIgZD0iTSAwLDAgTCAyMDQ3LDAgMjA0NywyMDQ3IDAsMjA0NyAwLDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idyIgaG9yaXotYWR2LXg9IjE1MDkiIGQ9Ik0gMTE3NCwwIEwgOTY1LDAgNzkyLDY5OCBDIDc4Nyw3MTYgNzgxLDczOCA3NzYsNzY1IDc3MCw3OTIgNzY0LDgxOCA3NTksODQzIDc1Miw4NzIgNzQ2LDkwMyA3NDAsOTM0IDczNCw5MDQgNzI4LDg3NCA3MjEsODQ1IDcxNiw4MjAgNzEwLDc5MyA3MDQsNzY2IDY5Nyw3MzkgNjkxLDcxNSA2ODYsNjk0IEwgNTA4LDAgMzAwLDAgLTMsMTA4MiAxNzUsMTA4MiAzNTgsMzQ3IEMgMzYzLDMzMiAzNjcsMzEzIDM3MiwyOTEgMzc3LDI2OCAzODEsMjQ2IDM4NiwyMjUgMzkxLDIwMCAzOTYsMTc1IDQwMSwxNDkgNDA2LDE3NCA0MTIsMTk5IDQxOCwyMjMgNDIzLDI0NCA0MjksMjY1IDQzNCwyODYgNDM5LDMwNyA0NDQsMzI1IDQ0OCwzMzkgTCA2NDQsMTA4MiA4MzcsMTA4MiAxMDI2LDMzOSBDIDEwMzEsMzIyIDEwMzYsMzAyIDEwNDEsMjgwIDEwNDYsMjU4IDEwNTEsMjM3IDEwNTYsMjE4IDEwNjEsMTk1IDEwNjcsMTcyIDEwNzIsMTQ5IDEwNzcsMTc0IDEwODMsMTk5IDEwODgsMjIzIDEwOTMsMjQ0IDEwOTgsMjY1IDExMDMsMjg4IDExMDgsMzEwIDExMTIsMzMwIDExMTcsMzQ3IEwgMTMwOCwxMDgyIDE0ODQsMTA4MiAxMTc0LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idiIgaG9yaXotYWR2LXg9IjEwMzMiIGQ9Ik0gNjEzLDAgTCA0MDAsMCA3LDEwODIgMTk5LDEwODIgNDM3LDM3OCBDIDQ0MiwzNjMgNDQ3LDM0NiA0NTQsMzI1IDQ2MCwzMDQgNDY2LDI4MiA0NzMsMjU5IDQ4MCwyMzYgNDg2LDIxNSA0OTIsMTk0IDQ5NywxNzMgNTAyLDE1NSA1MDYsMTQxIDUxMCwxNTUgNTE1LDE3MyA1MjIsMTk0IDUyOCwyMTUgNTM0LDIzNiA1NDEsMjU4IDU0OCwyODAgNTU1LDMwMiA1NjIsMzIzIDU2OSwzNDQgNTc1LDM2MSA1ODAsMzc2IEwgODI2LDEwODIgMTAxNywxMDgyIDYxMywwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InUiIGhvcml6LWFkdi14PSI4NzQiIGQ9Ik0gMzE0LDEwODIgTCAzMTQsMzk2IEMgMzE0LDM0MyAzMTgsMjk5IDMyNiwyNjQgMzMzLDIyOSAzNDYsMjAwIDM2MywxNzkgMzgwLDE1NyA0MDMsMTQyIDQzMiwxMzMgNDYwLDEyNCA0OTUsMTE5IDUzNywxMTkgNTgwLDExOSA2MTgsMTI3IDY1MywxNDIgNjg3LDE1NyA3MTYsMTc4IDc0MSwyMDcgNzY1LDIzNSA3ODQsMjcwIDc5NywzMTIgODEwLDM1MyA4MTcsNDAxIDgxNyw0NTUgTCA4MTcsMTA4MiA5OTcsMTA4MiA5OTcsMjMxIEMgOTk3LDIwOCA5OTcsMTg1IDk5OCwxNjAgOTk4LDEzNSA5OTgsMTExIDk5OSw4OSAxMDAwLDY2IDEwMDAsNDcgMTAwMSwzMSAxMDAyLDE1IDEwMDIsNSAxMDAzLDAgTCA4MzMsMCBDIDgzMiwzIDgzMiwxMiA4MzEsMjcgODMwLDQyIDgzMCw1OSA4MjksNzggODI4LDk3IDgyNywxMTYgODI2LDEzNiA4MjUsMTU1IDgyNSwxNzIgODI1LDE4NSBMIDgyMiwxODUgQyA4MDUsMTU0IDc4NiwxMjUgNzY1LDEwMCA3NDQsNzUgNzIwLDUzIDY5MywzNiA2NjYsMTggNjM0LDQgNTk5LC02IDU2NCwtMTUgNTIzLC0yMCA0NzYsLTIwIDQxNiwtMjAgMzY0LC0xMyAzMjEsMiAyNzgsMTcgMjQyLDM5IDIxNCw3MCAxODYsMTAxIDE2NiwxNDAgMTUzLDE4OCAxNDAsMjM2IDEzMywyOTQgMTMzLDM2MSBMIDEzMywxMDgyIDMxNCwxMDgyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InQiIGhvcml6LWFkdi14PSI1MzEiIGQ9Ik0gNTU0LDggQyA1MjcsMSA0OTksLTUgNDcxLC0xMCA0NDIsLTE0IDQwOSwtMTYgMzcyLC0xNiAyMjgsLTE2IDE1Niw2NiAxNTYsMjI5IEwgMTU2LDk1MSAzMSw5NTEgMzEsMTA4MiAxNjMsMTA4MiAyMTYsMTMyNCAzMzYsMTMyNCAzMzYsMTA4MiA1MzYsMTA4MiA1MzYsOTUxIDMzNiw5NTEgMzM2LDI2OCBDIDMzNiwyMTYgMzQ1LDE4MCAzNjIsMTU5IDM3OSwxMzggNDA4LDEyNyA0NTAsMTI3IDQ2NywxMjcgNDg0LDEyOCA1MDEsMTMxIDUxNywxMzQgNTM1LDEzNyA1NTQsMTQxIEwgNTU0LDggWiIvPgogICA8Z2x5cGggdW5pY29kZT0icyIgaG9yaXotYWR2LXg9IjkwMSIgZD0iTSA5NTAsMjk5IEMgOTUwLDI0OCA5NDAsMjAzIDkyMSwxNjQgOTAxLDEyNCA4NzIsOTEgODM1LDY0IDc5OCwzNyA3NTIsMTYgNjk4LDIgNjQzLC0xMyA1ODEsLTIwIDUxMSwtMjAgNDQ4LC0yMCAzOTIsLTE1IDM0MiwtNiAyOTEsNCAyNDcsMjAgMjA5LDQxIDE3MSw2MiAxMzksOTEgMTE0LDEyNiA4OCwxNjEgNjksMjAzIDU3LDI1NCBMIDIxNiwyODUgQyAyMzEsMjI3IDI2MywxODUgMzExLDE1OCAzNTksMTMxIDQyNiwxMTcgNTExLDExNyA1NTAsMTE3IDU4NSwxMjAgNjE4LDEyNSA2NTAsMTMwIDY3OCwxNDAgNzAxLDE1MyA3MjQsMTY2IDc0MywxODMgNzU2LDIwNSA3NjksMjI2IDc3NSwyNTMgNzc1LDI4NSA3NzUsMzE4IDc2NywzNDUgNzUyLDM2NiA3MzcsMzg3IDcxNSw0MDQgNjg4LDQxOCA2NjEsNDMyIDYyOCw0NDQgNTg5LDQ1NSA1NTAsNDY1IDUwNyw0NzYgNDYwLDQ4OSA0MTcsNTAwIDM3NCw1MTMgMzMxLDUyNyAyODgsNTQxIDI1MCw1NjAgMjE2LDU4MyAxODEsNjA2IDE1Myw2MzQgMTMyLDY2OCAxMTEsNzAyIDEwMCw3NDUgMTAwLDc5NiAxMDAsODk1IDEzNSw5NzAgMjA2LDEwMjIgMjc2LDEwNzMgMzc4LDEwOTkgNTEzLDEwOTkgNjMyLDEwOTkgNzI3LDEwNzggNzk4LDEwMzYgODY4LDk5NCA5MTIsOTI3IDkzMSw4MzQgTCA3NjksODE0IEMgNzYzLDg0MiA3NTIsODY2IDczNiw4ODUgNzIwLDkwNCA3MDEsOTE5IDY3OCw5MzEgNjU1LDk0MiA2MzAsOTUxIDYwMiw5NTYgNTczLDk2MSA1NDQsOTYzIDUxMyw5NjMgNDMyLDk2MyAzNzIsOTUxIDMzMyw5MjYgMjk0LDkwMSAyNzUsODY0IDI3NSw4MTQgMjc1LDc4NSAyODIsNzYxIDI5Nyw3NDIgMzExLDcyMyAzMzEsNzA3IDM1Nyw2OTQgMzgyLDY4MSA0MTMsNjY5IDQ0OSw2NjAgNDg1LDY1MCA1MjUsNjQwIDU2OCw2MjkgNTk3LDYyMiA2MjYsNjE0IDY1Niw2MDYgNjg2LDU5NyA3MTUsNTg3IDc0NCw1NzYgNzcyLDU2NCA3OTksNTUwIDgyNCw1MzUgODQ5LDUxOSA4NzAsNTAwIDg4OSw0NzggOTA4LDQ1NiA5MjMsNDMwIDkzNCw0MDEgOTQ1LDM3MiA5NTAsMzM4IDk1MCwyOTkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iciIgaG9yaXotYWR2LXg9IjUzMCIgZD0iTSAxNDIsMCBMIDE0Miw4MzAgQyAxNDIsODUzIDE0Miw4NzYgMTQyLDkwMCAxNDEsOTIzIDE0MSw5NDYgMTQwLDk2OCAxMzksOTkwIDEzOSwxMDExIDEzOCwxMDMwIDEzNywxMDQ5IDEzNywxMDY3IDEzNiwxMDgyIEwgMzA2LDEwODIgQyAzMDcsMTA2NyAzMDgsMTA0OSAzMDksMTAzMCAzMTAsMTAxMCAzMTEsOTkwIDMxMiw5NjkgMzEzLDk0OCAzMTMsOTI5IDMxNCw5MTAgMzE0LDg5MSAzMTQsODc0IDMxNCw4NjEgTCAzMTgsODYxIEMgMzMxLDkwMiAzNDQsOTM4IDM1OSw5NjkgMzczLDk5OSAzOTAsMTAyNCA0MDksMTA0NCA0MjgsMTA2MyA0NTEsMTA3OCA0NzgsMTA4OCA1MDUsMTA5NyA1MzcsMTEwMiA1NzUsMTEwMiA1OTAsMTEwMiA2MDQsMTEwMSA2MTcsMTA5OSA2MzAsMTA5NiA2NDEsMTA5NCA2NDgsMTA5MiBMIDY0OCw5MjcgQyA2MzYsOTMwIDYyMiw5MzMgNjA2LDkzNSA1OTAsOTM2IDU3Miw5MzcgNTUyLDkzNyA1MTEsOTM3IDQ3Niw5MjggNDQ3LDkwOSA0MTgsODkwIDM5NCw4NjUgMzc2LDgzMiAzNTcsNzk5IDM0NCw3NTkgMzM1LDcxNCAzMjYsNjY4IDMyMiw2MTggMzIyLDU2NCBMIDMyMiwwIDE0MiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InAiIGhvcml6LWFkdi14PSI5NTMiIGQ9Ik0gMTA1Myw1NDYgQyAxMDUzLDQ2NCAxMDQ2LDM4OCAxMDMzLDMxOSAxMDIwLDI1MCA5OTgsMTkwIDk2NywxNDAgOTM2LDkwIDg5NSw1MSA4NDQsMjMgNzkzLC02IDczMCwtMjAgNjU1LC0yMCA1NzgsLTIwIDUxMCwtNSA0NTIsMjQgMzk0LDUzIDM1MCwxMDEgMzE5LDE2OCBMIDMxNCwxNjggQyAzMTUsMTY3IDMxNSwxNjEgMzE2LDE1MCAzMTYsMTM5IDMxNiwxMjYgMzE3LDExMCAzMTcsOTQgMzE3LDc2IDMxOCw1NyAzMTgsMzcgMzE4LDE3IDMxOCwtMiBMIDMxOCwtNDI1IDEzOCwtNDI1IDEzOCw4NjEgQyAxMzgsODg3IDEzOCw5MTIgMTM4LDkzNiAxMzcsOTYwIDEzNyw5ODIgMTM2LDEwMDIgMTM1LDEwMjEgMTM1LDEwMzggMTM0LDEwNTIgMTMzLDEwNjYgMTMzLDEwNzYgMTMyLDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDgwIDMwOCwxMDczIDMwOSwxMDYxIDMxMCwxMDQ5IDMxMSwxMDM1IDMxMiwxMDE4IDMxMywxMDAxIDMxNCw5ODIgMzE1LDk2MyAzMTYsOTQ0IDMxNiw5MjUgMzE2LDkwOCBMIDMyMCw5MDggQyAzMzcsOTQzIDM1Niw5NzIgMzc3LDk5NyAzOTgsMTAyMSA0MjMsMTA0MSA0NTAsMTA1NyA0NzcsMTA3MiA1MDgsMTA4NCA1NDIsMTA5MSA1NzUsMTA5OCA2MTMsMTEwMSA2NTUsMTEwMSA3MzAsMTEwMSA3OTMsMTA4OCA4NDQsMTA2MSA4OTUsMTAzNCA5MzYsOTk3IDk2Nyw5NDkgOTk4LDkwMCAxMDIwLDg0MiAxMDMzLDc3NCAxMDQ2LDcwNSAxMDUzLDYyOSAxMDUzLDU0NiBaIE0gODY0LDU0MiBDIDg2NCw2MDkgODYwLDY2OCA4NTIsNzIwIDg0NCw3NzIgODMwLDgxNiA4MTEsODUyIDc5MSw4ODggNzY1LDkxNSA3MzIsOTM0IDY5OSw5NTMgNjU4LDk2MiA2MDksOTYyIDU2OSw5NjIgNTMxLDk1NiA0OTYsOTQ1IDQ2MSw5MzQgNDMwLDkxMiA0MDQsODgwIDM3Nyw4NDggMzU2LDgwNCAzNDEsNzQ4IDMyNiw2OTEgMzE4LDYxOCAzMTgsNTI4IDMxOCw0NTEgMzI0LDM4NyAzMzcsMzM0IDM1MCwyODEgMzY4LDIzOCAzOTMsMjA1IDQxNywxNzIgNDQ3LDE0OSA0ODMsMTM1IDUxOSwxMjAgNTYwLDExMyA2MDcsMTEzIDY1NywxMTMgNjk5LDEyMyA3MzIsMTQyIDc2NSwxNjEgNzkxLDE4OSA4MTEsMjI2IDgzMCwyNjMgODQ0LDMwOCA4NTIsMzYxIDg2MCw0MTQgODY0LDQ3NCA4NjQsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9Im8iIGhvcml6LWFkdi14PSI5ODAiIGQ9Ik0gMTA1Myw1NDIgQyAxMDUzLDM1MyAxMDExLDIxMiA5MjgsMTE5IDg0NSwyNiA3MjQsLTIwIDU2NSwtMjAgNDkwLC0yMCA0MjIsLTkgMzYzLDE0IDMwNCwzNyAyNTQsNzEgMjEzLDExOCAxNzIsMTY1IDE0MCwyMjMgMTE5LDI5NCA5NywzNjQgODYsNDQ3IDg2LDU0MiA4Niw5MTUgMjQ4LDExMDIgNTcxLDExMDIgNjU1LDExMDIgNzI4LDEwOTAgNzg5LDEwNjcgODUwLDEwNDQgOTAwLDEwMDkgOTM5LDk2MiA5NzgsOTE1IDEwMDYsODU3IDEwMjUsNzg3IDEwNDQsNzE3IDEwNTMsNjM1IDEwNTMsNTQyIFogTSA4NjQsNTQyIEMgODY0LDYyNiA4NTgsNjk1IDg0NSw3NTAgODMyLDgwNSA4MTMsODQ4IDc4OCw4ODEgNzYzLDkxNCA3MzIsOTM3IDY5Niw5NTAgNjYwLDk2MyA2MTksOTY5IDU3NCw5NjkgNTI4LDk2OSA0ODcsOTYyIDQ1MCw5NDkgNDEzLDkzNSAzODEsOTEyIDM1NSw4NzkgMzI5LDg0NiAzMDksODAyIDI5Niw3NDcgMjgyLDY5MiAyNzUsNjI0IDI3NSw1NDIgMjc1LDQ1OCAyODIsMzg5IDI5NywzMzQgMzEyLDI3OSAzMzIsMjM1IDM1OCwyMDIgMzgzLDE2OSA0MTQsMTQ2IDQ0OSwxMzMgNDg0LDEyMCA1MjIsMTEzIDU2MywxMTMgNjA5LDExMyA2NTEsMTIwIDY4OCwxMzMgNzI1LDE0NiA3NTcsMTY4IDc4MywyMDEgODA5LDIzNCA4MjksMjc4IDg0MywzMzMgODU3LDM4OCA4NjQsNDU4IDg2NCw1NDIgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibiIgaG9yaXotYWR2LXg9Ijg3NCIgZD0iTSA4MjUsMCBMIDgyNSw2ODYgQyA4MjUsNzM5IDgyMSw3ODMgODE0LDgxOCA4MDYsODUzIDc5Myw4ODIgNzc2LDkwNCA3NTksOTI1IDczNiw5NDEgNzA4LDk1MCA2NzksOTU5IDY0NCw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTYgNDg3LDk0MSA0NTIsOTI2IDQyMyw5MDQgMzk5LDg3NiAzNzQsODQ3IDM1NSw4MTIgMzQyLDc3MSAzMjksNzI5IDMyMiw2ODEgMzIyLDYyNyBMIDMyMiwwIDE0MiwwIDE0Miw4NTEgQyAxNDIsODc0IDE0Miw4OTggMTQyLDkyMyAxNDEsOTQ4IDE0MSw5NzEgMTQwLDk5NCAxMzksMTAxNiAxMzksMTAzNSAxMzgsMTA1MSAxMzcsMTA2NyAxMzcsMTA3NyAxMzYsMTA4MiBMIDMwNiwxMDgyIEMgMzA3LDEwNzkgMzA3LDEwNzAgMzA4LDEwNTUgMzA5LDEwNDAgMzEwLDEwMjQgMzExLDEwMDUgMzEyLDk4NiAzMTIsOTY2IDMxMyw5NDcgMzE0LDkyNyAzMTQsOTEwIDMxNCw4OTcgTCAzMTcsODk3IEMgMzM0LDkyOCAzNTMsOTU3IDM3NCw5ODIgMzk1LDEwMDcgNDE5LDEwMjkgNDQ2LDEwNDcgNDczLDEwNjQgNTA1LDEwNzggNTQwLDEwODggNTc1LDEwOTcgNjE2LDExMDIgNjYzLDExMDIgNzIzLDExMDIgNzc1LDEwOTUgODE4LDEwODAgODYxLDEwNjUgODk3LDEwNDMgOTI1LDEwMTIgOTUzLDk4MSA5NzQsOTQyIDk4Nyw4OTQgMTAwMCw4NDUgMTAwNiw3ODggMTAwNiw3MjEgTCAxMDA2LDAgODI1LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibSIgaG9yaXotYWR2LXg9IjE0NTciIGQ9Ik0gNzY4LDAgTCA3NjgsNjg2IEMgNzY4LDczOSA3NjUsNzgzIDc1OCw4MTggNzUxLDg1MyA3NDAsODgyIDcyNSw5MDQgNzA5LDkyNSA2ODgsOTQxIDY2Myw5NTAgNjM4LDk1OSA2MDcsOTYzIDU3MCw5NjMgNTMyLDk2MyA0OTgsOTU2IDQ2Nyw5NDEgNDM2LDkyNiA0MTAsOTA0IDM4OSw4NzYgMzY3LDg0NyAzNTAsODEyIDMzOSw3NzEgMzI3LDcyOSAzMjEsNjgxIDMyMSw2MjcgTCAzMjEsMCAxNDIsMCAxNDIsODUxIEMgMTQyLDg3NCAxNDIsODk4IDE0Miw5MjMgMTQxLDk0OCAxNDEsOTcxIDE0MCw5OTQgMTM5LDEwMTYgMTM5LDEwMzUgMTM4LDEwNTEgMTM3LDEwNjcgMTM3LDEwNzcgMTM2LDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDc5IDMwNywxMDcwIDMwOCwxMDU1IDMwOSwxMDQwIDMxMCwxMDI0IDMxMSwxMDA1IDMxMiw5ODYgMzEyLDk2NiAzMTMsOTQ3IDMxNCw5MjcgMzE0LDkxMCAzMTQsODk3IEwgMzE3LDg5NyBDIDMzMyw5MjggMzUwLDk1NyAzNjksOTgyIDM4OCwxMDA3IDQxMCwxMDI5IDQzNSwxMDQ3IDQ2MCwxMDY0IDQ4OCwxMDc4IDUyMSwxMDg4IDU1MywxMDk3IDU5MCwxMTAyIDYzMywxMTAyIDcxNSwxMTAyIDc4MCwxMDg2IDgyOCwxMDUzIDg3NSwxMDIwIDkwOCw5NjggOTI3LDg5NyBMIDkzMCw4OTcgQyA5NDYsOTI4IDk2NCw5NTcgOTg0LDk4MiAxMDA0LDEwMDcgMTAyNywxMDI5IDEwNTQsMTA0NyAxMDgxLDEwNjQgMTExMSwxMDc4IDExNDQsMTA4OCAxMTc3LDEwOTcgMTIxNSwxMTAyIDEyNTgsMTEwMiAxMzEzLDExMDIgMTM2MCwxMDk1IDE0MDAsMTA4MCAxNDM5LDEwNjUgMTQ3MiwxMDQzIDE0OTcsMTAxMiAxNTIyLDk4MSAxNTQxLDk0MiAxNTUzLDg5NCAxNTY1LDg0NSAxNTcxLDc4OCAxNTcxLDcyMSBMIDE1NzEsMCAxMzkzLDAgMTM5Myw2ODYgQyAxMzkzLDczOSAxMzkwLDc4MyAxMzgzLDgxOCAxMzc2LDg1MyAxMzY1LDg4MiAxMzUwLDkwNCAxMzM0LDkyNSAxMzEzLDk0MSAxMjg4LDk1MCAxMjYzLDk1OSAxMjMyLDk2MyAxMTk1LDk2MyAxMTU3LDk2MyAxMTIzLDk1NiAxMDkyLDk0MiAxMDYxLDkyNyAxMDM1LDkwNiAxMDE0LDg3OCA5OTIsODUwIDk3NSw4MTUgOTY0LDc3MyA5NTIsNzMxIDk0Niw2ODIgOTQ2LDYyNyBMIDk0NiwwIDc2OCwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImwiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM4LDAgTCAxMzgsMTQ4NCAzMTgsMTQ4NCAzMTgsMCAxMzgsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJrIiBob3Jpei1hZHYteD0iOTAxIiBkPSJNIDgxNiwwIEwgNDUwLDQ5NCAzMTgsMzg1IDMxOCwwIDEzOCwwIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCw1NTcgNzkzLDEwODIgMTAwNCwxMDgyIDU2NSw2MTcgMTAyNywwIDgxNiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImkiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM3LDEzMTIgTCAxMzcsMTQ4NCAzMTcsMTQ4NCAzMTcsMTMxMiAxMzcsMTMxMiBaIE0gMTM3LDAgTCAxMzcsMTA4MiAzMTcsMTA4MiAzMTcsMCAxMzcsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJoIiBob3Jpei1hZHYteD0iODc0IiBkPSJNIDMxNyw4OTcgQyAzMzcsOTM0IDM1OSw5NjUgMzgyLDk5MSA0MDUsMTAxNiA0MzEsMTAzNyA0NTksMTA1NCA0ODcsMTA3MSA1MTgsMTA4MyA1NTEsMTA5MSA1ODQsMTA5OCA2MjIsMTEwMiA2NjMsMTEwMiA3MzIsMTEwMiA3ODksMTA5MyA4MzQsMTA3NCA4NzgsMTA1NSA5MTMsMTAyOSA5MzksOTk2IDk2NCw5NjIgOTgyLDkyMiA5OTIsODc1IDEwMDEsODI4IDEwMDYsNzc3IDEwMDYsNzIxIEwgMTAwNiwwIDgyNSwwIDgyNSw2ODYgQyA4MjUsNzMyIDgyMiw3NzIgODE3LDgwNyA4MTEsODQyIDgwMCw4NzEgNzg0LDg5NCA3NjgsOTE3IDc0NSw5MzQgNzE2LDk0NiA2ODcsOTU3IDY0OSw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTUgNDg3LDk0MCA0NTIsOTI1IDQyMyw5MDMgMzk5LDg3NSAzNzQsODQ3IDM1NSw4MTMgMzQyLDc3MyAzMjksNzMzIDMyMiw2ODggMzIyLDYzOCBMIDMyMiwwIDE0MiwwIDE0MiwxNDg0IDMyMiwxNDg0IDMyMiwxMDk4IEMgMzIyLDEwNzYgMzIyLDEwNTQgMzIxLDEwMzIgMzIwLDEwMTAgMzIwLDk5MCAzMTksOTcxIDMxOCw5NTIgMzE3LDkzNyAzMTYsOTI0IDMxNSw5MTEgMzE1LDkwMiAzMTQsODk3IEwgMzE3LDg5NyBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJnIiBob3Jpei1hZHYteD0iOTI3IiBkPSJNIDU0OCwtNDI1IEMgNDg2LC00MjUgNDMxLC00MTkgMzgzLC00MDYgMzM1LC0zOTMgMjk0LC0zNzUgMjYwLC0zNTIgMjI2LC0zMjggMTk4LC0zMDAgMTc3LC0yNjcgMTU2LC0yMzQgMTQwLC0xOTggMTMxLC0xNTggTCAzMTIsLTEzMiBDIDMyNCwtMTgyIDM1MSwtMjIwIDM5MiwtMjQ4IDQzMywtMjc0IDQ4NiwtMjg4IDU1MywtMjg4IDU5NCwtMjg4IDYzMSwtMjgyIDY2NCwtMjcxIDY5NywtMjYwIDcyNiwtMjQxIDc0OSwtMjE3IDc3MiwtMTkxIDc5MCwtMTU5IDgwMywtMTE5IDgxNiwtNzkgODIyLC0zMCA4MjIsMjcgTCA4MjIsMjAxIDgyMCwyMDEgQyA4MDcsMTc0IDc5MCwxNDggNzcxLDEyMyA3NTEsOTggNzI3LDc1IDY5OSw1NiA2NzAsMzcgNjM3LDIxIDYwMCwxMCA1NjMsLTIgNTIwLC04IDQ3MiwtOCA0MDMsLTggMzQ1LDQgMjk2LDI3IDI0Nyw1MCAyMDcsODQgMTc2LDEzMCAxNDUsMTc2IDEyMiwyMzMgMTA4LDMwMiA5MywzNzAgODYsNDQ5IDg2LDUzOSA4Niw2MjYgOTMsNzA0IDEwOCw3NzMgMTIyLDg0MiAxNDUsOTAxIDE3OCw5NTAgMjEwLDk5OCAyNTIsMTAzNSAzMDQsMTA2MSAzNTUsMTA4NiA0MTgsMTA5OSA0OTIsMTA5OSA1NjksMTA5OSA2MzUsMTA4MiA2OTIsMTA0NyA3NDgsMTAxMiA3OTEsOTYyIDgyMiw4OTcgTCA4MjQsODk3IEMgODI0LDkxNCA4MjUsOTMyIDgyNiw5NTMgODI3LDk3NCA4MjgsOTkzIDgyOSwxMDEyIDgzMCwxMDMwIDgzMSwxMDQ2IDgzMiwxMDU5IDgzMywxMDcyIDgzNSwxMDgwIDgzNiwxMDgyIEwgMTAwNywxMDgyIEMgMTAwNiwxMDc2IDEwMDYsMTA2NiAxMDA1LDEwNTIgMTAwNCwxMDM3IDEwMDQsMTAyMCAxMDAzLDEwMDAgMTAwMiw5ODAgMTAwMiw5NTggMTAwMiw5MzQgMTAwMSw5MDkgMTAwMSw4ODQgMTAwMSw4NTggTCAxMDAxLDMxIEMgMTAwMSwtMTIwIDk2NCwtMjM0IDg5MCwtMzExIDgxNSwtMzg3IDcwMSwtNDI1IDU0OCwtNDI1IFogTSA4MjIsNTQxIEMgODIyLDYxNiA4MTQsNjgxIDc5OCw3MzUgNzgxLDc4OCA3NjAsODMyIDczMyw4NjYgNzA2LDkwMCA2NzYsOTI1IDY0Miw5NDEgNjA3LDk1NyA1NzIsOTY1IDUzNiw5NjUgNDkwLDk2NSA0NTEsOTU3IDQxOCw5NDEgMzg1LDkyNSAzNTcsOTAwIDMzNiw4NjYgMzE0LDgzMSAyOTgsNzg3IDI4OCw3MzQgMjc3LDY4MCAyNzIsNjE2IDI3Miw1NDEgMjcyLDQ2MyAyNzcsMzk4IDI4OCwzNDUgMjk4LDI5MiAzMTQsMjQ5IDMzNSwyMTYgMzU2LDE4MyAzODMsMTYwIDQxNiwxNDYgNDQ5LDEzMiA0ODgsMTI1IDUzMywxMjUgNTY5LDEyNSA2MDQsMTMzIDYzOSwxNDggNjczLDE2MyA3MDQsMTg4IDczMSwyMjEgNzU4LDI1NCA3ODAsMjk3IDc5NywzNTAgODE0LDQwMyA4MjIsNDY2IDgyMiw1NDEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iZiIgaG9yaXotYWR2LXg9IjU1NyIgZD0iTSAzNjEsOTUxIEwgMzYxLDAgMTgxLDAgMTgxLDk1MSAyOSw5NTEgMjksMTA4MiAxODEsMTA4MiAxODEsMTIwNCBDIDE4MSwxMjQzIDE4NSwxMjgwIDE5MiwxMzE0IDE5OSwxMzQ3IDIxMywxMzc3IDIzMywxNDAyIDI1MiwxNDI3IDI3OSwxNDQ2IDMxMywxNDYxIDM0NywxNDc1IDM5MSwxNDgyIDQ0NSwxNDgyIDQ2NiwxNDgyIDQ4OSwxNDgxIDUxMiwxNDc5IDUzNSwxNDc3IDU1NSwxNDc0IDU3MiwxNDcwIEwgNTcyLDEzMzMgQyA1NjEsMTMzNSA1NDgsMTMzNyA1MzMsMTMzOSA1MTgsMTM0MCA1MDQsMTM0MSA0OTIsMTM0MSA0NjUsMTM0MSA0NDQsMTMzNyA0MjcsMTMzMCA0MTAsMTMyMyAzOTYsMTMxMiAzODcsMTI5OSAzNzcsMTI4NSAzNzAsMTI2OCAzNjcsMTI0OCAzNjMsMTIyOCAzNjEsMTIwNSAzNjEsMTE3OSBMIDM2MSwxMDgyIDU3MiwxMDgyIDU3Miw5NTEgMzYxLDk1MSBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJlIiBob3Jpei1hZHYteD0iOTgwIiBkPSJNIDI3Niw1MDMgQyAyNzYsNDQ2IDI4MiwzOTQgMjk0LDM0NyAzMDUsMjk5IDMyMywyNTggMzQ4LDIyNCAzNzIsMTg5IDQwMywxNjMgNDQxLDE0NCA0NzksMTI1IDUyNSwxMTUgNTc4LDExNSA2NTYsMTE1IDcxOSwxMzEgNzY2LDE2MiA4MTMsMTkzIDg0NCwyMzMgODYxLDI4MSBMIDEwMTksMjM2IEMgMTAwOCwyMDYgOTkyLDE3NiA5NzIsMTQ2IDk1MSwxMTUgOTI0LDg4IDg5MCw2NCA4NTYsMzkgODE0LDE5IDc2Myw0IDcxMiwtMTIgNjUwLC0yMCA1NzgsLTIwIDQxOCwtMjAgMjk2LDI4IDIxMywxMjMgMTI5LDIxOCA4NywzNjAgODcsNTQ4IDg3LDY0OSAxMDAsNzM1IDEyNSw4MDYgMTUwLDg3NiAxODUsOTMzIDIyOSw5NzcgMjczLDEwMjEgMzI0LDEwNTMgMzgzLDEwNzMgNDQyLDEwOTIgNTA0LDExMDIgNTcxLDExMDIgNjYyLDExMDIgNzM4LDEwODcgNzk5LDEwNTggODYwLDEwMjkgOTA5LDk4OCA5NDYsOTM3IDk4Myw4ODUgMTAwOSw4MjQgMTAyNSw3NTQgMTA0MCw2ODQgMTA0OCw2MDggMTA0OCw1MjcgTCAxMDQ4LDUwMyAyNzYsNTAzIFogTSA4NjIsNjQxIEMgODUyLDc1NSA4MjMsODM4IDc3NSw4OTEgNzI3LDk0MyA2NTgsOTY5IDU2OCw5NjkgNTM4LDk2OSA1MDcsOTY0IDQ3NCw5NTUgNDQxLDk0NSA0MTAsOTI4IDM4Miw5MDMgMzU0LDg3OCAzMzAsODQ1IDMxMSw4MDMgMjkyLDc2MCAyODEsNzA2IDI3OCw2NDEgTCA4NjIsNjQxIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImQiIGhvcml6LWFkdi14PSI5MjciIGQ9Ik0gODIxLDE3NCBDIDc4OCwxMDUgNzQ0LDU1IDY4OSwyNSA2MzQsLTUgNTY1LC0yMCA0ODQsLTIwIDM0NywtMjAgMjQ3LDI2IDE4MywxMTggMTE4LDIxMCA4NiwzNDkgODYsNTM2IDg2LDkxMyAyMTksMTEwMiA0ODQsMTEwMiA1NjYsMTEwMiA2MzQsMTA4NyA2ODksMTA1NyA3NDQsMTAyNyA3ODgsOTc5IDgyMSw5MTQgTCA4MjMsOTE0IEMgODIzLDkyMSA4MjMsOTMxIDgyMyw5NDYgODIyLDk2MCA4MjIsOTc1IDgyMiw5OTEgODIxLDEwMDYgODIxLDEwMjEgODIxLDEwMzUgODIxLDEwNDkgODIxLDEwNTkgODIxLDEwNjUgTCA4MjEsMTQ4NCAxMDAxLDE0ODQgMTAwMSwyMjMgQyAxMDAxLDE5NyAxMDAxLDE3MiAxMDAyLDE0OCAxMDAyLDEyNCAxMDAyLDEwMiAxMDAzLDgyIDEwMDQsNjIgMTAwNCw0NSAxMDA1LDMxIDEwMDYsMTYgMTAwNiw2IDEwMDcsMCBMIDgzNSwwIEMgODM0LDcgODMzLDE2IDgzMiwyOSA4MzEsNDEgODMwLDU1IDgyOSw3MSA4MjgsODcgODI3LDEwNCA4MjYsMTIyIDgyNSwxMzkgODI1LDE1NyA4MjUsMTc0IEwgODIxLDE3NCBaIE0gMjc1LDU0MiBDIDI3NSw0NjcgMjgwLDQwMyAyODksMzUwIDI5OCwyOTcgMzEzLDI1MyAzMzQsMjE5IDM1NSwxODQgMzgxLDE1OSA0MTMsMTQzIDQ0NSwxMjcgNDg0LDExOSA1MzAsMTE5IDU3NywxMTkgNjE5LDEyNyA2NTYsMTQyIDY5MiwxNTcgNzIyLDE4MiA3NDcsMjE3IDc3MSwyNTEgNzg5LDI5NiA4MDIsMzUxIDgxNSw0MDYgODIxLDQ3NCA4MjEsNTU0IDgyMSw2MzEgODE1LDY5NiA4MDIsNzQ5IDc4OSw4MDIgNzcxLDg0NCA3NDYsODc3IDcyMSw5MTAgNjkxLDkzMyA2NTYsOTQ4IDYyMCw5NjIgNTc5LDk2OSA1MzIsOTY5IDQ4OCw5NjkgNDUwLDk2MSA0MTgsOTQ2IDM4Niw5MzEgMzU5LDkwNiAzMzgsODcyIDMxNyw4MzggMzAxLDc5NCAyOTEsNzQwIDI4MCw2ODUgMjc1LDYxOSAyNzUsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImMiIGhvcml6LWFkdi14PSI5MDEiIGQ9Ik0gMjc1LDU0NiBDIDI3NSw0ODQgMjgwLDQyNyAyODksMzc1IDI5OCwzMjMgMzEzLDI3OCAzMzQsMjQxIDM1NSwyMDMgMzg0LDE3NCA0MTksMTUzIDQ1NCwxMzIgNDk3LDEyMiA1NDgsMTIyIDYxMiwxMjIgNjY2LDEzOSA3MDksMTczIDc1MiwyMDYgNzc4LDI1OCA3ODgsMzI4IEwgOTcwLDMyOCBDIDk2NCwyODMgOTUxLDIzOSA5MzEsMTk3IDkxMSwxNTUgODg0LDExOCA4NTAsODYgODE1LDU0IDc3MywyOCA3MjQsOSA2NzUsLTEwIDYxOCwtMjAgNTUzLC0yMCA0NjgsLTIwIDM5NiwtNiAzMzcsMjMgMjc4LDUyIDIzMCw5MSAxOTMsMTQyIDE1NiwxOTIgMTI5LDI1MSAxMTIsMzIwIDk1LDM4OCA4Nyw0NjIgODcsNTQyIDg3LDYxNSA5Myw2NzkgMTA1LDczNSAxMTcsNzkwIDEzNCw4MzkgMTU2LDg4MSAxNzcsOTIyIDIwMyw5NTcgMjMyLDk4NiAyNjEsMTAxNCAyOTMsMTAzNyAzMjgsMTA1NCAzNjIsMTA3MSAzOTgsMTA4MyA0MzYsMTA5MSA0NzQsMTA5OCA1MTIsMTEwMiA1NTEsMTEwMiA2MTIsMTEwMiA2NjYsMTA5NCA3MTMsMTA3NyA3NjAsMTA2MCA4MDEsMTAzOCA4MzYsMTAwOSA4NzAsOTgwIDg5OCw5NDUgOTE5LDkwNiA5NDAsODY3IDk1NSw4MjQgOTY0LDc3OSBMIDc3OSw3NjUgQyA3NzAsODI1IDc0Niw4NzMgNzA4LDkwOCA2NzAsOTQzIDYxNiw5NjEgNTQ2LDk2MSA0OTUsOTYxIDQ1Miw5NTMgNDE4LDkzNiAzODMsOTE5IDM1NSw4OTMgMzM0LDg1OSAzMTMsODI0IDI5OCw3ODEgMjg5LDcyOSAyODAsNjc3IDI3NSw2MTYgMjc1LDU0NiBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJiIiBob3Jpei1hZHYteD0iOTUzIiBkPSJNIDEwNTMsNTQ2IEMgMTA1MywxNjkgOTIwLC0yMCA2NTUsLTIwIDU3MywtMjAgNTA1LC01IDQ1MSwyNSAzOTYsNTQgMzUyLDEwMiAzMTgsMTY4IEwgMzE2LDE2OCBDIDMxNiwxNTEgMzE2LDEzMyAzMTUsMTE0IDMxNCw5NSAzMTMsNzggMzEyLDYyIDMxMSw0NiAzMTAsMzIgMzA5LDIxIDMwOCwxMCAzMDcsMyAzMDYsMCBMIDEzMiwwIEMgMTMzLDYgMTMzLDE2IDEzNCwzMSAxMzUsNDUgMTM1LDYyIDEzNiw4MiAxMzcsMTAyIDEzNywxMjQgMTM4LDE0OCAxMzgsMTcyIDEzOCwxOTcgMTM4LDIyMyBMIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCwxMDYxIEMgMzE4LDEwNDEgMzE4LDEwMjIgMzE4LDEwMDQgMzE3LDk4NSAzMTcsOTY5IDMxNiw5NTUgMzE1LDkzOCAzMTUsOTIzIDMxNCw5MDggTCAzMTgsOTA4IEMgMzUxLDk3NyAzOTYsMTAyNyA0NTEsMTA1NyA1MDYsMTA4NyA1NzQsMTEwMiA2NTUsMTEwMiA3OTIsMTEwMiA4OTIsMTA1NiA5NTcsOTY0IDEwMjEsODcyIDEwNTMsNzMzIDEwNTMsNTQ2IFogTSA4NjQsNTQwIEMgODY0LDYxNSA4NTksNjc5IDg1MCw3MzIgODQxLDc4NSA4MjYsODI5IDgwNSw4NjQgNzg0LDg5OCA3NTgsOTIzIDcyNiw5MzkgNjk0LDk1NSA2NTUsOTYzIDYwOSw5NjMgNTYyLDk2MyA1MjAsOTU1IDQ4NCw5NDAgNDQ3LDkyNSA0MTcsOTAwIDM5Myw4NjYgMzY4LDgzMiAzNTAsNzg3IDMzNyw3MzIgMzI0LDY3NyAzMTgsNjA5IDMxOCw1MjkgMzE4LDQ1MiAzMjQsMzg3IDMzNywzMzQgMzUwLDI4MSAzNjgsMjM5IDM5MywyMDYgNDE3LDE3MyA0NDcsMTQ5IDQ4MywxMzUgNTE5LDEyMCA1NjAsMTEzIDYwNywxMTMgNjUxLDExMyA2ODksMTIxIDcyMSwxMzYgNzUzLDE1MSA3ODAsMTc2IDgwMSwyMTAgODIyLDI0NCA4MzgsMjg4IDg0OSwzNDMgODU5LDM5NyA4NjQsNDYzIDg2NCw1NDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iYSIgaG9yaXotYWR2LXg9IjEwNjAiIGQ9Ik0gNDE0LC0yMCBDIDMwNSwtMjAgMjI0LDkgMTY5LDY2IDExNCwxMjQgODcsMjAzIDg3LDMwMyA4NywzNzUgMTAxLDQzNCAxMjgsNDgwIDE1NSw1MjYgMTkwLDU2MiAyMzQsNTg4IDI3Nyw2MTQgMzI3LDYzMiAzODMsNjQyIDQzOSw2NTIgNDk2LDY1NyA1NTQsNjU3IEwgNzk3LDY1NyA3OTcsNzE3IEMgNzk3LDc2MiA3OTIsODAwIDc4Myw4MzIgNzc0LDg2MyA3NTksODg5IDc0MCw5MDggNzIxLDkyOCA2OTcsOTQyIDY2OCw5NTEgNjM5LDk2MCA2MDQsOTY1IDU2NSw5NjUgNTMwLDk2NSA0OTksOTYzIDQ3MSw5NTggNDQzLDk1MyA0MTksOTQ0IDM5OCw5MzEgMzc3LDkxOCAzNjEsOTAwIDM0OCw4NzggMzM1LDg1NSAzMjcsODI3IDMyMyw3OTMgTCAxMzUsODEwIEMgMTQyLDg1MyAxNTQsODkyIDE3Myw5MjggMTkyLDk2MyAyMTgsOTk0IDI1MywxMDIwIDI4NywxMDQ2IDMzMCwxMDY2IDM4MiwxMDgxIDQzMywxMDk1IDQ5NiwxMTAyIDU2OSwxMTAyIDcwNSwxMTAyIDgwNywxMDcxIDg3NiwxMDA5IDk0NSw5NDYgOTc5LDg1NiA5NzksNzM4IEwgOTc5LDI3MiBDIDk3OSwyMTkgOTg2LDE3OSAxMDAwLDE1MiAxMDE0LDEyNSAxMDQxLDExMSAxMDgwLDExMSAxMDkwLDExMSAxMTAwLDExMiAxMTEwLDExMyAxMTIwLDExNCAxMTMwLDExNiAxMTM5LDExOCBMIDExMzksNiBDIDExMTYsMSAxMDk0LC0zIDEwNzIsLTYgMTA0OSwtOSAxMDI1LC0xMCAxMDAwLC0xMCA5NjYsLTEwIDkzNywtNSA5MTMsNCA4ODgsMTMgODY4LDI2IDg1Myw0NSA4MzgsNjMgODI2LDg2IDgxOCwxMTMgODEwLDE0MCA4MDUsMTcxIDgwMywyMDcgTCA3OTcsMjA3IEMgNzc4LDE3MiA3NTcsMTQxIDczNCwxMTMgNzExLDg1IDY4NCw2MSA2NTMsNDIgNjIyLDIyIDU4OCw3IDU0OSwtNCA1MTAsLTE1IDQ2NSwtMjAgNDE0LC0yMCBaIE0gNDU1LDExNSBDIDUxMiwxMTUgNTYzLDEyNSA2MDYsMTQ2IDY0OSwxNjcgNjg0LDE5NCA3MTMsMjI2IDc0MSwyNTkgNzYyLDI5NCA3NzYsMzMyIDc5MCwzNzEgNzk3LDQwOCA3OTcsNDQzIEwgNzk3LDUzMSA2MDAsNTMxIEMgNTU2LDUzMSA1MTQsNTI4IDQ3NSw1MjIgNDM1LDUxNyA0MDAsNTA2IDM3MCw0ODkgMzQwLDQ3MiAzMTYsNDQ5IDI5OSw0MTggMjgxLDM4OCAyNzIsMzQ5IDI3MiwzMDAgMjcyLDI0MSAyODgsMTk1IDMyMCwxNjMgMzUxLDEzMSAzOTYsMTE1IDQ1NSwxMTUgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iUyIgaG9yaXotYWR2LXg9IjExOTIiIGQ9Ik0gMTI3MiwzODkgQyAxMjcyLDMzMCAxMjYxLDI3NSAxMjM4LDIyNSAxMjE1LDE3NSAxMTc5LDEzMiAxMTMxLDk2IDEwODMsNTkgMTAyMywzMSA5NTAsMTEgODc3LC0xMCA3OTAsLTIwIDY5MCwtMjAgNTE1LC0yMCAzNzgsMTEgMjgwLDcyIDE4MiwxMzMgMTIwLDIyMiA5MywzMzggTCAyNzgsMzc1IEMgMjg3LDMzOCAzMDIsMzA1IDMyMSwyNzUgMzQwLDI0NSAzNjcsMjE5IDQwMCwxOTggNDMzLDE3NiA0NzMsMTU5IDUyMiwxNDcgNTcxLDEzNSA2MjksMTI5IDY5NywxMjkgNzU0LDEyOSA4MDYsMTM0IDg1MywxNDQgOTAwLDE1MyA5NDEsMTY4IDk3NSwxODggMTAwOSwyMDggMTAzNiwyMzQgMTA1NSwyNjYgMTA3NCwyOTcgMTA4MywzMzUgMTA4MywzNzkgMTA4Myw0MjUgMTA3Myw0NjIgMTA1Miw0OTEgMTAzMSw1MjAgMTAwMSw1NDMgOTYzLDU2MiA5MjUsNTgxIDg4MCw1OTYgODI3LDYwOSA3NzQsNjIyIDcxNiw2MzUgNjUyLDY1MCA2MTMsNjU5IDU3Myw2NjggNTM0LDY3OSA0OTQsNjg5IDQ1Niw3MDEgNDIwLDcxNiAzODMsNzMwIDM0OSw3NDcgMzE3LDc2NiAyODUsNzg1IDI1Nyw4MDkgMjM0LDgzNiAyMTEsODYzIDE5Miw4OTQgMTc5LDkzMCAxNjYsOTY1IDE1OSwxMDA2IDE1OSwxMDUzIDE1OSwxMTIwIDE3MywxMTc3IDIwMCwxMjI1IDIyNywxMjcyIDI2NCwxMzExIDMxMiwxMzQyIDM2MCwxMzczIDQxNywxMzk1IDQ4MiwxNDA5IDU0NywxNDIzIDYxOCwxNDMwIDY5NCwxNDMwIDc4MSwxNDMwIDg1NiwxNDIzIDkxOCwxNDEwIDk4MCwxMzk2IDEwMzIsMTM3NSAxMDc1LDEzNDggMTExOCwxMzIxIDExNTIsMTI4NyAxMTc4LDEyNDcgMTIwMywxMjA2IDEyMjQsMTE1OSAxMjM5LDExMDYgTCAxMDUxLDEwNzMgQyAxMDQyLDExMDcgMTAyOCwxMTM3IDEwMTEsMTE2NCA5OTMsMTE5MSA5NzAsMTIxMyA5NDEsMTIzMSA5MTIsMTI0OSA4NzgsMTI2MyA4MzcsMTI3MiA3OTYsMTI4MSA3NDcsMTI4NiA2OTIsMTI4NiA2MjcsMTI4NiA1NzIsMTI4MCA1MjgsMTI2OSA0ODMsMTI1NyA0NDgsMTI0MSA0MjEsMTIyMSAzOTQsMTIwMSAzNzQsMTE3OCAzNjMsMTE1MSAzNTEsMTEyNCAzNDUsMTA5NCAzNDUsMTA2MyAzNDUsMTAyMSAzNTYsOTg3IDM3Nyw5NjAgMzk4LDkzMyA0MjYsOTEwIDQ2Miw4OTIgNDk4LDg3NCA1NDAsODU5IDU4Nyw4NDcgNjM0LDgzNSA2ODUsODIzIDczOCw4MTEgNzgxLDgwMSA4MjUsNzkxIDg2OCw3ODEgOTExLDc3MCA5NTIsNzU4IDk5MSw3NDQgMTAzMCw3MjkgMTA2Nyw3MTIgMTEwMiw2OTMgMTEzNiw2NzQgMTE2Niw2NTAgMTE5MSw2MjIgMTIxNiw1OTQgMTIzNiw1NjEgMTI1MSw1MjMgMTI2NSw0ODUgMTI3Miw0NDAgMTI3MiwzODkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iTyIgaG9yaXotYWR2LXg9IjE0MzAiIGQ9Ik0gMTQ5NSw3MTEgQyAxNDk1LDYwMSAxNDc5LDUwMSAxNDQ4LDQxMSAxNDE2LDMyMSAxMzcwLDI0NCAxMzEwLDE4MCAxMjUwLDExNiAxMTc3LDY3IDEwOTAsMzIgMTAwMywtMyA5MDUsLTIwIDc5NSwtMjAgNjc5LC0yMCA1NzcsLTIgNDkwLDM1IDQwMyw3MSAzMzAsMTIyIDI3MiwxODcgMjE0LDI1MiAxNzAsMzI5IDE0MSw0MTggMTEyLDUwNyA5Nyw2MDUgOTcsNzExIDk3LDgyMSAxMTIsOTIwIDE0MywxMDA5IDE3NCwxMDk4IDIxOSwxMTczIDI3OCwxMjM2IDMzNywxMjk4IDQxMSwxMzQ2IDQ5OCwxMzgwIDU4NSwxNDEzIDY4NCwxNDMwIDc5NywxNDMwIDkwOSwxNDMwIDEwMDksMTQxMyAxMDk2LDEzNzkgMTE4MywxMzQ1IDEyNTYsMTI5NyAxMzE1LDEyMzQgMTM3NCwxMTcxIDE0MTgsMTA5NiAxNDQ5LDEwMDcgMTQ4MCw5MTggMTQ5NSw4MjAgMTQ5NSw3MTEgWiBNIDEzMDAsNzExIEMgMTMwMCw3OTYgMTI4OSw4NzMgMTI2OCw5NDIgMTI0NiwxMDExIDEyMTQsMTA3MSAxMTcyLDExMjAgMTEyOSwxMTY5IDEwNzcsMTIwNyAxMDE0LDEyMzQgOTUxLDEyNjEgODc5LDEyNzQgNzk3LDEyNzQgNzEzLDEyNzQgNjM5LDEyNjEgNTc2LDEyMzQgNTEzLDEyMDcgNDYwLDExNjkgNDE4LDExMjAgMzc1LDEwNzEgMzQ0LDEwMTEgMzIzLDk0MiAzMDIsODczIDI5MSw3OTYgMjkxLDcxMSAyOTEsNjI2IDMwMiw1NDkgMzI0LDQ3OSAzNDUsNDA4IDM3NywzNDggNDIwLDI5NyA0NjIsMjQ2IDUxNSwyMDYgNTc4LDE3OCA2NDEsMTQ5IDcxMywxMzUgNzk1LDEzNSA4ODMsMTM1IDk1OSwxNDkgMTAyMywxNzggMTA4NiwyMDcgMTEzOSwyNDcgMTE4MCwyOTggMTIyMSwzNDkgMTI1MSw0MDkgMTI3MSw0ODAgMTI5MCw1NTEgMTMwMCw2MjggMTMwMCw3MTEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iQyIgaG9yaXotYWR2LXg9IjEzMjQiIGQ9Ik0gNzkyLDEyNzQgQyA3MTIsMTI3NCA2NDEsMTI2MSA1ODAsMTIzNCA1MTgsMTIwNyA0NjYsMTE2OSA0MjUsMTEyMCAzODMsMTA3MSAzNTEsMTAxMSAzMzAsOTQyIDMwOSw4NzMgMjk4LDc5NiAyOTgsNzExIDI5OCw2MjYgMzEwLDU0OSAzMzMsNDc5IDM1Niw0MDggMzg5LDM0OCA0MzIsMjk3IDQ3NSwyNDYgNTI3LDIwNyA1OTAsMTc5IDY1MiwxNTEgNzIyLDEzNyA4MDAsMTM3IDg1NSwxMzcgOTA1LDE0NCA5NTAsMTU5IDk5NSwxNzMgMTAzNSwxOTMgMTA3MiwyMTkgMTEwOCwyNDUgMTE0MCwyNzYgMTE2OSwzMTIgMTE5OCwzNDcgMTIyMywzODcgMTI0NSw0MzAgTCAxNDAxLDM1MiBDIDEzNzYsMjk5IDEzNDQsMjUwIDEzMDcsMjA1IDEyNzAsMTYwIDEyMjYsMTIwIDExNzYsODcgMTEyNSw1NCAxMDY4LDI4IDEwMDUsOSA5NDEsLTEwIDg3MCwtMjAgNzkxLC0yMCA2NzcsLTIwIDU3NywtMiA0OTIsMzUgNDA2LDcxIDMzNCwxMjIgMjc3LDE4NyAyMTksMjUyIDE3NiwzMjkgMTQ3LDQxOCAxMTgsNTA3IDEwNCw2MDUgMTA0LDcxMSAxMDQsODIxIDExOSw5MjAgMTUwLDEwMDkgMTgwLDEwOTggMjI0LDExNzMgMjgzLDEyMzYgMzQxLDEyOTggNDEzLDEzNDYgNDk4LDEzODAgNTgzLDE0MTMgNjgxLDE0MzAgNzkwLDE0MzAgOTQwLDE0MzAgMTA2NSwxNDAxIDExNjYsMTM0MiAxMjY3LDEyODMgMTM0MSwxMTk2IDEzODgsMTA4MSBMIDEyMDcsMTAyMSBDIDExOTQsMTA1NCAxMTc2LDEwODYgMTE1MywxMTE3IDExMzAsMTE0NyAxMTAyLDExNzQgMTA2OCwxMTk3IDEwMzQsMTIyMCA5OTQsMTIzOSA5NDksMTI1MyA5MDMsMTI2NyA4NTEsMTI3NCA3OTIsMTI3NCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSIgIiBob3Jpei1hZHYteD0iNTU2Ii8+CiAgPC9mb250PgogPC9kZWZzPgogPGRlZnMgY2xhc3M9IlRleHRTaGFwZUluZGV4Ij4KICA8ZyBvb286c2xpZGU9ImlkMSIgb29vOmlkLWxpc3Q9ImlkMyBpZDQgaWQ1IGlkNiBpZDcgaWQ4IGlkOSBpZDEwIGlkMTEgaWQxMiBpZDEzIGlkMTQgaWQxNSBpZDE2IGlkMTcgaWQxOCBpZDE5Ii8+CiA8L2RlZnM+CiA8ZGVmcyBjbGFzcz0iRW1iZWRkZWRCdWxsZXRDaGFycyI+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDU3MzU2KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gNTgwLDExNDEgTCAxMTYzLDU3MSA1ODAsMCAtNCw1NzEgNTgwLDExNDEgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoNTczNTQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSA4LDExMjggTCAxMTM3LDExMjggMTEzNywwIDgsMCA4LDExMjggWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAxNDYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAxNzQsMCBMIDYwMiw3MzkgMTc0LDE0ODEgMTQ1Niw3MzkgMTc0LDAgWiBNIDEzNTgsNzM5IEwgMzA5LDEzNDYgNjU5LDczOSAxMzU4LDczOSBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSgxMDEzMikiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIDIwMTUsNzM5IEwgMTI3NiwwIDcxNywwIDEyNjAsNTQzIDE3NCw1NDMgMTc0LDkzNiAxMjYwLDkzNiA3MTcsMTQ4MSAxMjc0LDE0ODEgMjAxNSw3MzkgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDcpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAwLC0yIEMgLTcsMTQgLTE2LDI3IC0yNSwzNyBMIDM1Niw1NjcgQyAyNjIsODIzIDIxNSw5NTIgMjE1LDk1NCAyMTUsOTc5IDIyOCw5OTIgMjU1LDk5MiAyNjQsOTkyIDI3Niw5OTAgMjg5LDk4NyAzMTAsOTkxIDMzMSw5OTkgMzU0LDEwMTIgTCAzODEsOTk5IDQ5Miw3NDggNzcyLDEwNDkgODM2LDEwMjQgODYwLDEwNDkgQyA4ODEsMTAzOSA5MDEsMTAyNSA5MjIsMTAwNiA4ODYsOTM3IDgzNSw4NjMgNzcwLDc4NCA3NjksNzgzIDcxMCw3MTYgNTk0LDU4NCBMIDc3NCwyMjMgQyA3NzQsMTk2IDc1MywxNjggNzExLDEzOSBMIDcyNywxMTkgQyA3MTcsOTAgNjk5LDc2IDY3Miw3NiA2NDEsNzYgNTcwLDE3OCA0NTcsMzgxIEwgMTY0LC03NiBDIDE0MiwtMTEwIDExMSwtMTI3IDcyLC0xMjcgMzAsLTEyNyA5LC0xMTAgOCwtNzYgMSwtNjcgLTIsLTUyIC0yLC0zMiAtMiwtMjMgLTEsLTEzIDAsLTIgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAyODUsLTMzIEMgMTgyLC0zMyAxMTEsMzAgNzQsMTU2IDUyLDIyOCA0MSwzMzMgNDEsNDcxIDQxLDU0OSA1NSw2MTYgODIsNjcyIDExNiw3NDMgMTY5LDc3OCAyNDAsNzc4IDI5Myw3NzggMzI4LDc0NyAzNDYsNjg0IEwgMzY5LDUwOCBDIDM3Nyw0NDQgMzk3LDQxMSA0MjgsNDEwIEwgMTE2MywxMTE2IEMgMTE3NCwxMTI3IDExOTYsMTEzMyAxMjI5LDExMzMgMTI3MSwxMTMzIDEyOTIsMTExOCAxMjkyLDEwODcgTCAxMjkyLDk2NSBDIDEyOTIsOTI5IDEyODIsOTAxIDEyNjIsODgxIEwgNDQyLDQ3IEMgMzkwLC02IDMzOCwtMzMgMjg1LC0zMyBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSg5Njc5KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gODEzLDAgQyA2MzIsMCA0ODksNTQgMzgzLDE2MSAyNzYsMjY4IDIyMyw0MTEgMjIzLDU5MiAyMjMsNzczIDI3Niw5MTYgMzgzLDEwMjMgNDg5LDExMzAgNjMyLDExODQgODEzLDExODQgOTkyLDExODQgMTEzNiwxMTMwIDEyNDUsMTAyMyAxMzUzLDkxNiAxNDA3LDc3MiAxNDA3LDU5MiAxNDA3LDQxMiAxMzUzLDI2OCAxMjQ1LDE2MSAxMTM2LDU0IDk5MiwwIDgxMywwIFoiLz4KICA8L2c+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDgyMjYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAzNDYsNDU3IEMgMjczLDQ1NyAyMDksNDgzIDE1NSw1MzUgMTAxLDU4NiA3NCw2NDkgNzQsNzIzIDc0LDc5NiAxMDEsODU5IDE1NSw5MTEgMjA5LDk2MyAyNzMsOTg5IDM0Niw5ODkgNDE5LDk4OSA0ODAsOTYzIDUzMSw5MTAgNTgyLDg1OSA2MDgsNzk2IDYwOCw3MjMgNjA4LDY0OCA1ODMsNTg2IDUzMiw1MzUgNDgyLDQ4MyA0MjAsNDU3IDM0Niw0NTcgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoODIxMSkiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIC00LDQ1OSBMIDExMzUsNDU5IDExMzUsNjA2IC00LDYwNiAtNCw0NTkgWiIvPgogIDwvZz4KIDwvZGVmcz4KIDxkZWZzIGNsYXNzPSJUZXh0RW1iZWRkZWRCaXRtYXBzIi8+CiA8Zz4KICA8ZyBpZD0iaWQyIiBjbGFzcz0iTWFzdGVyX1NsaWRlIj4KICAgPGcgaWQ9ImJnLWlkMiIgY2xhc3M9IkJhY2tncm91bmQiLz4KICAgPGcgaWQ9ImJvLWlkMiIgY2xhc3M9IkJhY2tncm91bmRPYmplY3RzIi8+CiAgPC9nPgogPC9nPgogPGcgY2xhc3M9IlNsaWRlR3JvdXAiPgogIDxnPgogICA8ZyBpZD0iaWQxIiBjbGFzcz0iU2xpZGUiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSI+CiAgICA8ZyBjbGFzcz0iUGFnZSI+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMyI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MCw3MDAwIEwgNzAwMCw3MDAwIDcwMDAsMzAwMCA5OTAwLDMwMDAgOTkwMCw3MDAwIDg0NTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTIwNTAsNzAwMCBMIDEwMTAwLDcwMDAgMTAxMDAsMzAwMCAxNDAwMCwzMDAwIDE0MDAwLDcwMDAgMTIwNTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkVsbGlwc2VTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDUiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDg5OTksMzMwMCBDIDkxMDUsMzMxMiA5MTk1LDMzODMgOTI4OCwzNTMxIDkzODcsMzY5MCA5NDU5LDM4ODkgOTUxNiw0MTY1IDk1NzQsNDQ0MSA5NjAwLDQ3MTIgOTYwMCw1MDMxIDk2MDAsNTM1MCA5NTc0LDU2MjEgOTUxNiw1ODk3IDk0NTksNjE3MyA5NDAyLDYzMjggOTMxOSw2NDc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiIGQ9Ik0gOTE0MSw2NzAxIEwgOTQwNSw2NTI2IDkyNDgsNjQwMyA5MTQxLDY3MDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5FbGxpcHNlU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ2Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDc5NCw2NzEwIEMgMTA3NDgsNjY2OSAxMDcxMCw2NjE4IDEwNjY4LDY1NDAgMTA1ODMsNjM4MCAxMDUyMSw2MTgxIDEwNDcyLDU5MDUgMTA0MjIsNTYyOCAxMDQwMCw1MzU2IDEwNDAwLDUwMzYgMTA0MDAsNDcxNiAxMDQyMiw0NDQ0IDEwNDcyLDQxNjggMTA1MjEsMzg5MSAxMDU4MywzNjkyIDEwNjY4LDM1MzIgMTA3NDgsMzM4MyAxMDY5MCwzNDkyIDEwNzAxLDM0NzQiLz4KICAgICAgIDxwYXRoIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSIgZD0iTSAxMDkxNiwzMzAwIEwgMTA2MjIsMzQxNiAxMDc1MCwzNTY5IDEwOTE2LDMzMDAgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDciPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4OTksNjkwMCBDIDk5NTUsNjkwMCA5OTk5LDY5NDMgOTk5OSw2OTk5IDk5OTksNzA1NSA5OTU1LDcwOTkgOTg5OSw3MDk5IDk4NDMsNzA5OSA5ODAwLDcwNTUgOTgwMCw2OTk5IDk4MDAsNjk0MyA5ODQzLDY5MDAgOTg5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODAwLDY5MDAgTCA5ODAwLDY5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAxLDcxMDEgTCAxMDAwMSw3MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ4Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDA5OSwyOTAwIEMgMTAxNTUsMjkwMCAxMDE5OSwyOTQzIDEwMTk5LDI5OTkgMTAxOTksMzA1NSAxMDE1NSwzMDk5IDEwMDk5LDMwOTkgMTAwNDMsMzA5OSAxMDAwMCwzMDU1IDEwMDAwLDI5OTkgMTAwMDAsMjk0MyAxMDA0MywyOTAwIDEwMDk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAwLDI5MDAgTCAxMDAwMCwyOTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMSwzMTAxIEwgMTAyMDEsMzEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkOSI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTg5OSwyOTAwIEMgOTk1NSwyOTAwIDk5OTksMjk0MyA5OTk5LDI5OTkgOTk5OSwzMDU1IDk5NTUsMzA5OSA5ODk5LDMwOTkgOTg0MywzMDk5IDk4MDAsMzA1NSA5ODAwLDI5OTkgOTgwMCwyOTQzIDk4NDMsMjkwMCA5ODk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4MDAsMjkwMCBMIDk4MDAsMjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDEsMzEwMSBMIDEwMDAxLDMxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEwIj4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODk5LDQ5MDAgQyA5OTU1LDQ5MDAgOTk5OSw0OTQzIDk5OTksNDk5OSA5OTk5LDUwNTUgOTk1NSw1MDk5IDk4OTksNTA5OSA5ODQzLDUwOTkgOTgwMCw1MDU1IDk4MDAsNDk5OSA5ODAwLDQ5NDMgOTg0Myw0OTAwIDk4OTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTgwMCw0OTAwIEwgOTgwMCw0OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMSw1MTAxIEwgMTAwMDEsNTEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTEiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDk5LDQ5MDAgQyAxMDE1NSw0OTAwIDEwMTk5LDQ5NDMgMTAxOTksNDk5OSAxMDE5OSw1MDU1IDEwMTU1LDUwOTkgMTAwOTksNTA5OSAxMDA0Myw1MDk5IDEwMDAwLDUwNTUgMTAwMDAsNDk5OSAxMDAwMCw0OTQzIDEwMDQzLDQ5MDAgMTAwOTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDAsNDkwMCBMIDEwMDAwLDQ5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjAxLDUxMDEgTCAxMDIwMSw1MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxMiI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwOTksNjkwMCBDIDEwMTU1LDY5MDAgMTAxOTksNjk0MyAxMDE5OSw2OTk5IDEwMTk5LDcwNTUgMTAxNTUsNzA5OSAxMDA5OSw3MDk5IDEwMDQzLDcwOTkgMTAwMDAsNzA1NSAxMDAwMCw2OTk5IDEwMDAwLDY5NDMgMTAwNDMsNjkwMCAxMDA5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMCw2OTAwIEwgMTAwMDAsNjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAyMDEsNzEwMSBMIDEwMjAxLDcxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEzIj4KICAgICAgIDxwYXRoIGZpbGw9InJnYigyNTUsMjU1LDI1NSkiIHN0cm9rZT0ibm9uZSIgZD0iTSA1MTAwLDUyMDAgTCAzNTAwLDUyMDAgMzUwMCwzMDAwIDY3MDAsMzAwMCA2NzAwLDUyMDAgNTEwMCw1MjAwIFoiLz4KICAgICAgIDx0ZXh0IGNsYXNzPSJUZXh0U2hhcGUiPjx0c3BhbiBjbGFzcz0iVGV4dFBhcmFncmFwaCIgZm9udC1mYW1pbHk9IkxpYmVyYXRpb24gU2Fucywgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNTNweCIgZm9udC13ZWlnaHQ9IjQwMCI+PHRzcGFuIGNsYXNzPSJUZXh0UG9zaXRpb24iIHg9IjM3NTAiIHk9IjM0MzMiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPlN1YmRpdmlzaW9uIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iMzgyNyI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+cG9pbnRzIG5lZWQgdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI0MjIxIj48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5sYW5kIG9uIHRoZSBzYW1lIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iNDYxNSI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+bG9jYXRpb24gdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI1MDA5Ij48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5wcmV2ZW50IGNyYWNraW5nPC90c3Bhbj48L3RzcGFuPjwvdHNwYW4+PC90ZXh0PgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5MaW5lU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjYwMCw0MjAwIEwgNjY1MSw0MjEzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjcwMyw0MjI3IEwgNjc1NCw0MjQwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjgwNiw0MjUzIEwgNjg1Nyw0MjY2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjkwOCw0MjgwIEwgNjk2MCw0MjkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzAxMSw0MzA2IEwgNzA2Myw0MzE5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzExNCw0MzMzIEwgNzE2NSw0MzQ2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzIxNyw0MzU5IEwgNzI2OCw0MzcyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzMyMCw0Mzg2IEwgNzM3MSw0Mzk5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzQyMyw0NDEyIEwgNzQ3NCw0NDI2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzUyNSw0NDM5IEwgNzU3Nyw0NDUyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzYyOCw0NDY1IEwgNzY4MCw0NDc5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzczMSw0NDkyIEwgNzc4Miw0NTA1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzgzNCw0NTE4IEwgNzg4NSw0NTMyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzkzNyw0NTQ1IEwgNzk4OCw0NTU4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODAzOSw0NTcxIEwgODA5MSw0NTg1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODE0Miw0NTk4IEwgODE5NCw0NjExIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODI0NSw0NjI1IEwgODI5Niw0NjM4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODM0OCw0NjUxIEwgODM5OSw0NjY0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MSw0Njc4IEwgODUwMiw0NjkxIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODU1Myw0NzA0IEwgODYwNSw0NzE3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODY1Niw0NzMxIEwgODcwOCw0NzQ0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODc1OSw0NzU3IEwgODgxMSw0NzcwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODg2Miw0Nzg0IEwgODkxMyw0Nzk3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODk2NSw0ODEwIEwgOTAxNiw0ODI0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTA2OCw0ODM3IEwgOTExOSw0ODUwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTE3MCw0ODYzIEwgOTIyMiw0ODc3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTI3Myw0ODkwIEwgOTMyNSw0OTAzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTM3Niw0OTE2IEwgOTQyNyw0OTMwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTQ3OSw0OTQzIEwgOTUzMCw0OTU2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTU4Miw0OTY5IEwgOTYzMyw0OTgzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTY4NCw0OTk2IEwgOTcwMCw1MDAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTUiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNjUwLDI3MDAgTCAxMDcwMCwyNzAwIDEwNzAwLDE1MDAgMTQ2MDAsMTUwMCAxNDYwMCwyNzAwIDEyNjUwLDI3MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTA5NTAiIHk9IjIwMjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMDk1MCIgeT0iMjQxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTYiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyODUwLDg1MDAgTCAxMDkwMCw4NTAwIDEwOTAwLDczMDAgMTQ4MDAsNzMwMCAxNDgwMCw4NTAwIDEyODUwLDg1MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9Ijc4MjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iODIxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTciPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNDAwLDUyMDAgTCAxMDkwMCw1MjAwIDEwOTAwLDMzMDAgMTM5MDAsMzMwMCAxMzkwMCw1MjAwIDEyNDAwLDUyMDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjM3ODAiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPk9wcG9zaW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQxNzQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmRpcmVjdGlvbnMgb2YgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iNDU2OCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+ZWRnZSB3YWxraW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQ5NjIiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmZvciBzdWJkaXZpc2lvbjwvdHNwYW4+PC90c3Bhbj48L3RzcGFuPjwvdGV4dD4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuTGluZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTgiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMzAwLDI5MDAgTCAxMDM0MSwyODY3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzODMsMjgzNCBMIDEwNDI0LDI4MDEiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ2NiwyNzY3IEwgMTA1MDcsMjczNCIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ5LDI3MDEgTCAxMDU5MCwyNjY4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsMjYzNSBMIDEwNjczLDI2MDIiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxNSwyNTY4IEwgMTA3NTYsMjUzNSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNzk3LDI1MDIgTCAxMDgwMCwyNTAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkxpbmVTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDE5Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMCw3MTAwIEwgMTAyNDMsNzEzMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjg2LDcxNjIgTCAxMDMzMCw3MTkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzNzMsNzIyMyBMIDEwNDE2LDcyNTQiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ1OSw3Mjg1IEwgMTA1MDIsNzMxNiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ2LDczNDcgTCAxMDU4OSw3Mzc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsNzQwOSBMIDEwNjc1LDc0MzkiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxOCw3NDcwIEwgMTA3NjIsNzUwMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwODA1LDc1MzIgTCAxMDg0OCw3NTYzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA4OTEsNzU5NCBMIDEwOTAwLDc2MDAiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgPC9nPgogIDwvZz4KIDwvZz4KPC9zdmc+" alt="precise">
+</div>
+</div>
+<div class="paragraph">
+<p>As stated in &#8220;<a href="#evaluation-of-expressions">Evaluation of Expressions</a>&#8221;,
+the compiler may transform expressions even if this changes the resulting
+value.
+Without any qualifiers, implementations are permitted to perform
+optimizations that effectively modify the order or number of operations used
+to evaluate an expression, even if those optimizations may produce slightly
+different results relative to unoptimized code.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>precise</strong> qualifier ensures that operations contributing to a
+variable&#8217;s value are done in their stated order and with operator consistency.
+The order is determined by operator precedence and parenthesis, as described in
+&#8220;<a href="#operators">Operators</a>&#8221;.
+Operator consistency means for each particular operator, for example the
+multiply operator (<strong>*</strong>), its operation is always computed with the same
+precision.
+Specifically, values computed by compiler-generated code must adhere to the
+following identities:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>a + b = b + a</p>
+</li>
+<li>
+<p>a * b = b * a</p>
+</li>
+<li>
+<p>a * b + c * d = b * a + c* d = d * c + b * a = &lt;any other mathematically
+valid combination&gt;</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>While the following are prevented:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>a + (b + c) is not allowed to become (a + b) + c</p>
+</li>
+<li>
+<p>a * (b * c) is not allowed to become (a * b) * c</p>
+</li>
+<li>
+<p>a * b + c is not allowed to become a single operation <strong>fma</strong>(a, b, c)</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Where <em>a</em>, <em>b</em>, <em>c</em>, and <em>d</em>, are scalars or vectors, not matrices.
+(Matrix multiplication generally does not commute.) It is the shader
+writer&#8217;s responsibility to express the computation in terms of these rules
+and the compiler&#8217;s responsibility to follow these rules.
+See the description of <em>gl_TessCoord</em> for the rules the tessellation stages
+are responsible for following, which in conjunction with the above allow
+avoiding cracking when subdividing.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precise out vec4 position;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>declares that operations used to produce the value of <em>position</em> must be
+performed in exactly the order specified in the source code and with all
+operators being treated consistently.
+As with the <strong>invariant</strong> qualifier (see &#8220;<a href="#the-invariant-qualifier">The
+Invariant Qualifier</a>&#8221;), the <strong>precise</strong> qualifier may be used to qualify a
+built-in or previously declared user-defined variable as being precise:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec3 Color;
+precise Color; <span class="comment">// make existing Color be precise</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When applied to a block, a structure type, or a variable of structure type,
+<strong>precise</strong> applies to each contained member, recursively.</p>
+</div>
+<div class="paragraph">
+<p>This qualifier will affect the evaluation of an r-value in a particular
+function if and only if the result is eventually consumed in the same
+function by an l-value qualified as <strong>precise</strong>.
+Any other expressions within a function are not affected, including return
+values and output parameters not declared as <strong>precise</strong> but that are
+eventually consumed outside the function by a variable qualified as
+<strong>precise</strong>. Unaffected expressions also include the controlling expressions
+in selection and iteration statements and the condition in ternary
+operators (<strong>?:</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Some examples of the use of <strong>precise</strong>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 a, b, c, d;
+precise out vec4 v;
+
+<span class="predefined-type">float</span> func(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h)
+{
+    <span class="keyword">return</span> (e*f) + (g*h); <span class="comment">// no constraint on order or operator consistency</span>
+}
+
+<span class="predefined-type">float</span> func2(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h)
+{
+    precise <span class="predefined-type">float</span> result = (e*f) + (g*h); <span class="comment">// ensures same precision for the two multiplies</span>
+    <span class="keyword">return</span> result;
+}
+
+<span class="predefined-type">float</span> func3(<span class="predefined-type">float</span> i, <span class="predefined-type">float</span> j, precise out <span class="predefined-type">float</span> k)
+{
+    k = i * i + j;        <span class="comment">// precise, due to &lt;k&gt; declaration</span>
+}
+
+<span class="directive">void</span> main()
+{
+    vec3 r = vec3(a * b);             <span class="comment">// precise, used to compute v.xyz</span>
+    vec3 s = vec3(c * d);             <span class="comment">// precise, used to compute v.xyz</span>
+    v.xyz = r + s;                    <span class="comment">// precise</span>
+    v.w = (a.w * b.w) + (c.w * d.w);  <span class="comment">// precise</span>
+    v.x = func(a.x, b.x, c.x, d.x);   <span class="comment">// values computed in func() are NOT precise</span>
+    v.x = func2(a.x, b.x, c.x, d.x);  <span class="comment">// precise!</span>
+    func3(a.x * b.x, c.x * d.x, v.x); <span class="comment">// precise!</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if an output from one shader stage matches
+an input of the next stage, the <strong>precise</strong> qualifier need not match between
+the input and the output.</p>
+</div>
+<div class="paragraph">
+<p>All constant expressions are evaluated as if <strong>precise</strong> was present, whether
+or not it is present.
+However, as described in &#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;,
+there is no requirement that a compile-time constant expression evaluates to
+the same value as a corresponding non-constant expression.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="memory-qualifiers">4.10. Memory Qualifiers</h3>
+<div class="paragraph">
+<p>Shader storage blocks, variables declared within shader storage blocks and
+variables declared as image types (the basic opaque types with &#8220;<strong>image</strong>&#8221;
+in their keyword), can be further qualified with one or more of the
+following memory qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>coherent</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where reads and writes are coherent with
+                reads and writes from other shader invocations</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>volatile</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable whose underlying value may be changed at any
+                point during shader execution by some source other than the
+                current shader invocation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>restrict</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where use of that variable is the only way
+                to read and write the underlying memory in the relevant
+                shader stage</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>readonly</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to read the underlying
+                memory, but cannot be used to write the underlying memory</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>writeonly</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to write the underlying
+                memory, but cannot be used to read the underlying memory</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>coherent</strong> qualifier
+are performed coherently with accesses to the same location from other
+shader invocations.</p>
+</div>
+<div class="paragraph">
+<p>As described in section
+7.11
+&#8220;Shader Memory Access&#8221; of the
+<a href="#references">OpenGL ES Specification</a>, shader memory reads and writes complete in a
+largely undefined order.
+The built-in function <strong>memoryBarrier</strong>() can be used if needed to guarantee
+the completion and relative ordering of memory accesses performed by a
+single shader invocation.</p>
+</div>
+<div class="paragraph">
+<p>When accessing memory using variables not declared as <strong>coherent</strong>, the memory
+accessed by a shader may be cached by the implementation to service future
+accesses to the same address.
+Memory stores may be cached in such a way that the values written may not be
+visible to other shader invocations accessing the same memory.
+The implementation may cache the values fetched by memory reads and return
+the same values to any shader invocation accessing the same memory, even if
+the underlying memory has been modified since the first memory read.
+While variables not declared as <strong>coherent</strong> may not be useful for
+communicating between shader invocations, using non-coherent accesses may
+result in higher performance.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>volatile</strong> qualifier
+must treat the underlying memory as though it could be read or written at
+any point during shader execution by some source other than the executing
+shader invocation.
+When a volatile variable is read, its value must be re-fetched from the
+underlying memory, even if the shader invocation performing the read had
+previously fetched its value from the same memory.
+When a volatile variable is written, its value must be written to the
+underlying memory, even if the compiler can conclusively determine that its
+value will be overwritten by a subsequent write.
+Since the external source reading or writing a <strong>volatile</strong> variable may be
+another shader invocation, variables declared as <strong>volatile</strong> are
+automatically treated as coherent.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>restrict</strong> qualifier
+may be compiled assuming that the variable used to perform the memory access
+is the only way to access the underlying memory using the shader stage in
+question.
+This allows the compiler to coalesce or reorder loads and stores using
+<strong>restrict</strong>-qualified image variables in ways that wouldn&#8217;t be permitted
+for image variables not so qualified, because the compiler can assume that
+the underlying image won&#8217;t be read or written by other code.
+Applications are responsible for ensuring that image memory referenced by
+variables qualified with <strong>restrict</strong> will not be referenced using other
+variables in the same scope; otherwise, accesses to <strong>restrict</strong>-qualified
+variables will have undefined results.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>readonly</strong> qualifier
+may only read the underlying memory, which is treated as read-only memory
+and cannot be written to.
+It is an error to pass an image variable qualified with
+<strong>readonly</strong> to <strong>imageStore</strong>() or other built-in functions that modify image
+memory.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>writeonly</strong> qualifier
+may only write the underlying memory; the underlying memory cannot be read.
+It is an error to pass an image variable qualified with
+<strong>writeonly</strong> to <strong>imageLoad</strong>() or other built-in functions that read image
+memory.</p>
+</div>
+<div class="paragraph">
+<p>A variable could be qualified as both <strong>readonly</strong> and <strong>writeonly</strong>, disallowing
+both read and write. Such variables can still be used with some queries, for
+example <strong>imageSize</strong>() and <strong>.length</strong>().</p>
+</div>
+<div class="paragraph">
+<p>Except for image variables qualified with the format qualifiers <strong>r32f</strong>,
+<strong>r32i</strong>, and <strong>r32ui</strong>, image variables must specify a memory qualifier
+(<strong>readonly</strong>, <strong>writeonly</strong>, or both).</p>
+</div>
+<div class="paragraph">
+<p>The memory qualifiers <strong>coherent</strong>, <strong>volatile</strong>, <strong>restrict</strong>, <strong>readonly</strong>, and
+<strong>writeonly</strong> may be used in the declaration of buffer variables (i.e.,
+members of shader storage blocks).
+When a buffer variable is declared with a memory qualifier, the behavior
+specified for memory accesses involving image variables described above
+applies identically to memory accesses involving that buffer variable.
+It is a compile-time error to assign to a buffer variable qualified with
+<strong>readonly</strong> or to read from a buffer variable qualified with <strong>writeonly</strong>.
+The combination <strong>readonly</strong> <strong>writeonly</strong> is allowed.</p>
+</div>
+<div class="paragraph">
+<p>Additionally, memory qualifiers may be used at the block-level declaration
+of a shader storage block, including the combination <strong>readonly</strong> <strong>writeonly</strong>.
+When a block declaration is qualified with a memory qualifier, it is as if
+all of its members were declared with the same memory qualifier.
+For example, the block declaration</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">coherent buffer Block {
+    readonly vec4 member1;
+    vec4 member2;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">buffer Block {
+    coherent readonly vec4 member1;
+    coherent vec4 member2;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Memory qualifiers are only supported in the declarations of image variables,
+buffer variables, and shader storage blocks; it is an error to use such
+qualifiers in any other declarations.</p>
+</div>
+<div class="paragraph">
+<p>When calling user-defined functions, variables qualified with <strong>coherent</strong>,
+<strong>volatile</strong>, <strong>readonly</strong>, or <strong>writeonly</strong> may not be passed to functions whose
+formal parameters lack such qualifiers.
+(See &#8220;<a href="#function-definitions">Function Definitions</a>&#8221; for more detail on
+function calling.) It is legal to have any additional memory qualifiers on a
+formal parameter, but only <strong>restrict</strong> can be taken away from a calling
+argument, by a formal parameter that lacks the <strong>restrict</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When a built-in function is called, the code generated is to be based on the
+actual qualification of the calling argument, not on the list of memory
+qualifiers specified on the formal parameter in the prototype.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 funcA(restrict image2D a) { ... }
+vec4 funcB(image2D a) { ... }
+layout(rgba32f) uniform image2D img1;
+layout(rgba32f) coherent uniform image2D img2;
+
+funcA(img1);        <span class="comment">// OK, adding &quot;restrict&quot; is allowed</span>
+funcB(img2);        <span class="comment">// illegal, stripping &quot;coherent&quot; is not</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Layout qualifiers cannot be used on formal function parameters, and layout
+qualification is not included in parameter matching.</p>
+</div>
+<div class="paragraph">
+<p>Note that the use of <strong>const</strong> in an image variable declaration is qualifying
+the const-ness of the variable being declared, not the image it refers to.
+The qualifier <strong>readonly</strong> qualifies the image memory (as accessed through
+that variable) while <strong>const</strong> qualifies the variable itself.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="order-of-qualification">4.11. Order and Repetition of Qualification</h3>
+<div class="paragraph">
+<p>When multiple qualifiers are present in a declaration, they may appear in
+any order, but they must all appear before the type.
+The <strong>layout</strong> qualifier is the only qualifier that can appear more than once.
+Further, a declaration can have at most one storage qualifier, at most one
+auxiliary storage qualifier, and at most one interpolation qualifier.
+Multiple memory qualifiers can be used.
+Any violation of these rules will cause a compile-time error.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="empty-declarations">4.12. Empty Declarations</h3>
+<div class="paragraph">
+<p><em>Empty declarations</em> are declarations without a variable name, meaning no
+object is instantiated by the declaration.
+Generally, empty declarations are allowed.
+Some are useful when declaring structures, while many others have no effect.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>;               <span class="comment">// No effect</span>
+<span class="keyword">struct</span> S {<span class="predefined-type">int</span> x;}; <span class="comment">// Defines a struct S</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The combinations of qualifiers that cause compile-time or link-time errors
+are the same whether or not the declaration is empty, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant in <span class="predefined-type">float</span> x; <span class="comment">// Error. An input cannot be invariant.</span>
+invariant in <span class="predefined-type">float</span>;   <span class="comment">// Error even though no variable is declared.</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="operators-and-expressions">5. Operators and Expressions</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="operators">5.1. Operators</h3>
+<div class="paragraph">
+<p>The OpenGL ES Shading Language has the following operators.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Precedence</th>
+<th class="tableblock halign-left valign-top">Operator Class</th>
+<th class="tableblock halign-left valign-top">Operators</th>
+<th class="tableblock halign-left valign-top">Associativity</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">array subscript<br>
+                 function call and constructor structure<br>
+                 field or method selector, swizzle<br>
+                 post fix increment and decrement</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ ]<br>
+                                                  ( )<br>
+                                                  .<br>
+                                                  ++ --</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">prefix increment and decrement<br>
+                 unary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">++ --<br>
+                                                  + - ~ !</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;&lt; &gt;&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt; &gt; &lt;= &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">12</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">13</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">14</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">selection</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">? :</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">16</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Assignment<br>
+                 arithmetic assignments</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">=<br>
+                                                  += -=<br>
+                                                  *= /=<br>
+                                                  %= &lt;&lt;= &gt;&gt;=<br>
+                                                  &amp;= ^= |=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">17 (lowest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">sequence</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">,</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>There is no address-of operator nor a dereference operator.
+There is no typecast operator; constructors are used instead.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="array-operations">5.2. Array Operations</h3>
+<div class="paragraph">
+<p>These are now described in &#8220;<a href="#structure-and-array-operations">Structure and
+Array Operations</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="function-calls">5.3. Function Calls</h3>
+<div class="paragraph">
+<p>If a function returns a value, then a call to that function may be used as
+an expression, whose type will be the type that was used to declare or
+define the function.</p>
+</div>
+<div class="paragraph">
+<p>Function definitions and calling conventions are discussed in
+&#8220;<a href="#function-definitions">Function Definitions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="constructors">5.4. Constructors</h3>
+<div class="paragraph">
+<p>Constructors use the function call syntax, where the function name is a
+type, and the call makes an object of that type.
+Constructors are used the same way in both initializers and expressions.
+(See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for details.)
+The parameters are used to initialize the constructed value.
+Constructors can be used to request a data type conversion to change from
+one scalar type to another scalar type, or to build larger types out of
+smaller types, or to reduce a larger type to a smaller type.</p>
+</div>
+<div class="paragraph">
+<p>In general, constructors are not built-in functions with predetermined
+prototypes.
+For arrays and structures, there must be exactly one argument in the
+constructor for each element or member.
+For the other types, the arguments must provide a sufficient number of
+components to perform the initialization, and it is an error to
+include so many arguments that they cannot all be used.
+Detailed rules follow.
+The prototypes actually listed below are merely a subset of examples.</p>
+</div>
+<div class="sect3">
+<h4 id="conversion-and-scalar-constructors">5.4.1. Conversion and Scalar Constructors</h4>
+<div class="paragraph">
+<p>Converting between scalar types is done as the following prototypes
+indicate:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>(uint)     <span class="comment">// converts an unsigned integer to a signed integer</span>
+<span class="predefined-type">int</span>(<span class="predefined-type">bool</span>)     <span class="comment">// converts a Boolean value to an int</span>
+<span class="predefined-type">int</span>(<span class="predefined-type">float</span>)    <span class="comment">// converts a float value to an int</span>
+uint(<span class="predefined-type">int</span>)     <span class="comment">// converts a signed integer value to an unsigned integer</span>
+uint(<span class="predefined-type">bool</span>)    <span class="comment">// converts a Boolean value to an unsigned integer</span>
+uint(<span class="predefined-type">float</span>)   <span class="comment">// converts a float value to an unsigned integer</span>
+<span class="predefined-type">bool</span>(<span class="predefined-type">int</span>)     <span class="comment">// converts a signed integer value to a Boolean</span>
+<span class="predefined-type">bool</span>(uint)    <span class="comment">// converts an unsigned integer value to a Boolean value</span>
+<span class="predefined-type">bool</span>(<span class="predefined-type">float</span>)   <span class="comment">// converts a float value to a Boolean</span>
+<span class="predefined-type">float</span>(<span class="predefined-type">int</span>)    <span class="comment">// converts a signed integer value to a float</span>
+<span class="predefined-type">float</span>(uint)   <span class="comment">// converts an unsigned integer value to a float value</span>
+<span class="predefined-type">float</span>(<span class="predefined-type">bool</span>)   <span class="comment">// converts a Boolean value to a float</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When constructors are used to convert a floating-point type to an integer
+type, the fractional part of the floating-point value is dropped.
+It is undefined to convert a negative floating-point value to an <strong>uint</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Integer values having more bits of precision than a single-precision
+floating-point mantissa will lose precision when converted to <strong>float</strong>.</p>
+</div>
+<div class="paragraph">
+<p>When a constructor is used to convert any integer or floating-point type to
+a <strong>bool</strong>, 0 and 0.0 are converted to <strong>false</strong>, and non-zero values are
+converted to <strong>true</strong>.
+When a constructor is used to convert a <strong>bool</strong> to any integer or
+floating-point type, <strong>false</strong> is converted to 0 or 0.0, and <strong>true</strong> is
+converted to 1 or 1.0.</p>
+</div>
+<div class="paragraph">
+<p>The constructor <strong>int</strong>(<strong>uint</strong>) preserves the bit pattern in the argument,
+which will change the argument&#8217;s value if its sign bit is set.
+The constructor <strong>uint</strong>(<strong>int</strong>) preserves the bit pattern in the argument,
+which will change its value if it is negative.</p>
+</div>
+<div class="paragraph">
+<p>Identity constructors, like <strong>float</strong>(<strong>float</strong>) are also legal, but of little
+use.</p>
+</div>
+<div class="paragraph">
+<p>Scalar constructors with non-scalar parameters can be used to take the first
+element from a non-scalar.
+For example, the constructor <strong>float</strong>(<strong>vec3</strong>) will select the first component
+of the <strong>vec3</strong> parameter.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="vector-and-matrix-constructors">5.4.2. Vector and Matrix Constructors</h4>
+<div class="paragraph">
+<p>Constructors can be used to create vectors or matrices from a set of
+scalars, vectors, or matrices.
+This includes the ability to shorten vectors.</p>
+</div>
+<div class="paragraph">
+<p>If there is a single scalar parameter to a vector constructor, it is used to
+initialize all components of the constructed vector to that scalar&#8217;s value.
+If there is a single scalar parameter to a matrix constructor, it is used to
+initialize all the components on the matrix&#8217;s diagonal, with the remaining
+components initialized to 0.0.</p>
+</div>
+<div class="paragraph">
+<p>If a vector is constructed from multiple scalars, one or more vectors, or
+one or more matrices, or a mixture of these, the vector&#8217;s components will be
+constructed in order from the components of the arguments.
+The arguments will be consumed left to right, and each argument will have
+all its components consumed, in order, before any components from the next
+argument are consumed.
+Similarly for constructing a matrix from multiple scalars or vectors, or a
+mixture of these.
+Matrix components will be constructed and consumed in column major order.
+In these cases, there must be enough components provided in the arguments to
+provide an initializer for every component in the constructed value.
+It is an error to provide extra arguments beyond this last used
+argument.</p>
+</div>
+<div class="paragraph">
+<p>If a matrix is constructed from a matrix, then each component (column <em>i</em>,
+row <em>j</em>) in the result that has a corresponding component (column <em>i</em>, row
+<em>j</em>) in the argument will be initialized from there.
+All other components will be initialized to the identity matrix.
+If a matrix argument is given to a matrix constructor, it is
+an error to have any other arguments.</p>
+</div>
+<div class="paragraph">
+<p>If the basic type (<strong>bool</strong>, <strong>int</strong>,
+or <strong>float</strong>)
+of a parameter to a
+constructor does not match the basic type of the object being constructed,
+the scalar construction rules (above) are used to convert the parameters.</p>
+</div>
+<div class="paragraph">
+<p>Some useful vector constructors are as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3(<span class="predefined-type">float</span>)          <span class="comment">// initializes each component of the vec3 with the float</span>
+vec4(ivec4)          <span class="comment">// makes a vec4 with component-wise conversion</span>
+vec4(mat2)           <span class="comment">// the vec4 is column 0 followed by column 1</span>
+vec2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>)   <span class="comment">// initializes a vec2 with 2 floats</span>
+ivec3(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">int</span>) <span class="comment">// initializes an ivec3 with 3 ints</span>
+bvec4(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>) <span class="comment">// uses 4 Boolean conversions</span>
+vec2(vec3)           <span class="comment">// drops the third component of a vec3</span>
+vec3(vec4)           <span class="comment">// drops the fourth component of a vec4</span>
+vec3(vec2, <span class="predefined-type">float</span>)    <span class="comment">// vec3.x = vec2.x, vec3.y = vec2.y, vec3.z = float</span>
+vec3(<span class="predefined-type">float</span>, vec2)    <span class="comment">// vec3.x = float, vec3.y = vec2.x, vec3.z = vec2.y</span>
+vec4(vec3, <span class="predefined-type">float</span>)
+vec4(<span class="predefined-type">float</span>, vec3)
+vec4(vec2, vec2)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Some examples of these are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 color = vec4(<span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>);
+vec4 rgba = vec4(<span class="float">1</span><span class="float">.0</span>);      <span class="comment">// sets each component to 1.0</span>
+vec3 rgb = vec3(color);     <span class="comment">// drop the 4th component</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To initialize the diagonal of a matrix with all other elements set to zero:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2(<span class="predefined-type">float</span>)
+mat3(<span class="predefined-type">float</span>)
+mat4(<span class="predefined-type">float</span>)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>That is, <em>result[i][j]</em> is set to the <em>float</em> argument for all \(i
+= j\) and set to 0 for all \(i \neq j\).</p>
+</div>
+<div class="paragraph">
+<p>To initialize a matrix by specifying vectors or scalars, the components are
+assigned to the matrix elements in column-major order.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2(vec2, vec2);                 <span class="comment">// one column per argument</span>
+mat3(vec3, vec3, vec3);           <span class="comment">// one column per argument</span>
+mat4(vec4, vec4, vec4, vec4);     <span class="comment">// one column per argument</span>
+mat3x2(vec2, vec2, vec2);         <span class="comment">// one column per argument</span>
+mat2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>,                <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>);               <span class="comment">// second column</span>
+mat3(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,         <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,         <span class="comment">// second column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>);        <span class="comment">// third column</span>
+mat4(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// second column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// third column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>); <span class="comment">// fourth column</span>
+mat2x3(vec2, <span class="predefined-type">float</span>,               <span class="comment">// first column</span>
+       vec2, <span class="predefined-type">float</span>);              <span class="comment">// second column</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A wide range of other possibilities exist, to construct a matrix from
+vectors and scalars, as long as enough components are present to initialize
+the matrix.
+To construct a matrix from a matrix:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat3x3(mat4x4); <span class="comment">// takes the upper-left 3x3 of the mat4x4</span>
+mat2x3(mat4x2); <span class="comment">// takes the upper-left 2x2 of the mat4x4, last row is 0,0</span>
+mat4x4(mat3x3); <span class="comment">// puts the mat3x3 in the upper-left, sets the lower right</span>
+                <span class="comment">// component to 1, and the rest to 0</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="structure-constructors">5.4.3. Structure Constructors</h4>
+<div class="paragraph">
+<p>Once a structure is defined, and its type is given a name, a constructor is
+available with the same name to construct instances of that structure.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light {
+    <span class="predefined-type">float</span> intensity;
+    vec3 position;
+};
+
+light lightVar = light(<span class="float">3</span><span class="float">.0</span>, vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>));</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The arguments to the constructor will be used to set the structure&#8217;s
+members, in order, using one argument per member.
+Each argument must be the same type as the member it
+sets.</p>
+</div>
+<div class="paragraph">
+<p>Structure constructors can be used as initializers or in expressions.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="array-constructors">5.4.4. Array Constructors</h4>
+<div class="paragraph">
+<p>Array types can also be used as constructor names, which can then be used in
+expressions or initializers.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> <span class="predefined-type">float</span> c[<span class="integer">3</span>] = <span class="predefined-type">float</span>[<span class="integer">3</span>](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+<span class="directive">const</span> <span class="predefined-type">float</span> d[<span class="integer">3</span>] = <span class="predefined-type">float</span>[](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+
+<span class="predefined-type">float</span> g;
+...
+<span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](g, <span class="integer">1</span>, g, <span class="float">2</span><span class="float">.3</span>, g);
+<span class="predefined-type">float</span> b[<span class="integer">3</span>];
+
+b = <span class="predefined-type">float</span>[<span class="integer">3</span>](g, g + <span class="float">1</span><span class="float">.0</span>, g + <span class="float">2</span><span class="float">.0</span>);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There must be exactly the same number of arguments as the size of the array
+being constructed.
+If no size is present in the constructor, then the array is explicitly sized
+to the number of arguments provided.
+The arguments are assigned in order, starting at element 0, to the elements
+of the constructed array.
+Each argument must be the same type as the element type of the
+array.</p>
+</div>
+<div class="paragraph">
+<p>Arrays of arrays are similarly constructed, and the size for any dimension
+is <strong class="purple">optional</strong></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 b[<span class="integer">2</span>] = ...;
+vec4[<span class="integer">3</span>][<span class="integer">2</span>](b, b, b);    <span class="comment">// constructor</span>
+vec4[][<span class="integer">2</span>](b, b, b);     <span class="comment">// constructor, valid, size deduced</span>
+vec4[<span class="integer">3</span>][](b, b, b);     <span class="comment">// constructor, valid, size deduced</span>
+vec4[][](b, b, b);      <span class="comment">// constructor, valid, both sizes deduced</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="vector-components">5.5. Vector Components</h3>
+<div class="paragraph">
+<p>The names of the components of a vector
+are denoted by a single letter.
+As a notational convenience, several letters are associated with each
+component based on common usage of position, color or texture coordinate
+vectors.
+The individual components can be selected by following the variable name
+with period (<strong>.</strong>) and then the component name.</p>
+</div>
+<div class="paragraph">
+<p>The component names supported are:</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ x, y, z, w }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent points or normals</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ r, g, b, a }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent colors</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ s, t, p, q }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent texture coordinates</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The component names <em>x</em>, <em>r</em>, and <em>s</em> are, for example, synonyms for the
+same (first) component in a vector.</p>
+</div>
+<div class="paragraph">
+<p>Note that the third component of the texture coordinate set, <em>r</em> in
+OpenGL ES, has been renamed <em>p</em> so as to avoid the confusion with <em>r</em> (for
+red) in a color.</p>
+</div>
+<div class="paragraph">
+<p>Accessing components beyond those declared for the type is
+an error so, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec2 pos;
+pos.x       <span class="comment">// is legal</span>
+pos.z       <span class="comment">// is illegal</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The component selection syntax allows multiple components to be selected by
+appending their names (from the same name set) after the period (<strong>.</strong>).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 v4;
+v4.rgba;    <span class="comment">// is a vec4 and the same as just using v4,</span>
+v4.rgb;     <span class="comment">// is a vec3,</span>
+v4.b;       <span class="comment">// is a float,</span>
+v4.xy;      <span class="comment">// is a vec2,</span>
+v4.xgba;    <span class="comment">// is illegal - the component names do not come from the same set</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>No more than 4 components can be selected.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 v4;
+v4.xyzwxy;      <span class="comment">// is illegal since it has 6 components</span>
+(v4.xyzwxy).xy; <span class="comment">// is illegal since the intermediate value has 6</span>
+components</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The order of the components can be different to swizzle them, or replicated:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);
+vec4 swiz = pos.wzyx;   <span class="comment">// swiz = (4.0, 3.0, 2.0, 1.0)</span>
+vec4 dup = pos.xxyy;    <span class="comment">// dup = (1.0, 1.0, 2.0, 2.0)</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This notation is more concise than the constructor syntax.
+To form an r-value, it can be applied to any expression that results in a
+vector r-value.</p>
+</div>
+<div class="paragraph">
+<p>The component group notation can occur on the left hand side of an
+expression.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);
+pos.xw = vec2(<span class="float">5</span><span class="float">.0</span>, <span class="float">6</span><span class="float">.0</span>);        <span class="comment">// pos = (5.0, 2.0, 3.0, 6.0)</span>
+pos.wx = vec2(<span class="float">7</span><span class="float">.0</span>, <span class="float">8</span><span class="float">.0</span>);        <span class="comment">// pos = (8.0, 2.0, 3.0, 7.0)</span>
+pos.xx = vec2(<span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);        <span class="comment">// illegal - 'x' used twice</span>
+pos.xy = vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>);   <span class="comment">// illegal - mismatch between vec2 and vec3</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To form an l-value, swizzling must further be applied to an l-value and
+contain no duplicate components. It results in an l-value of scalar or
+vector type, depending on number of components specified.</p>
+</div>
+<div class="paragraph">
+<p>Array subscripting syntax can also be applied to vectors (but not to
+scalars) to provide numeric indexing.
+So in</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><em>pos[2]</em> refers to the third element of <em>pos</em> and is equivalent to <em>pos.z</em>.
+This allows variable indexing into a vector, as well as a generic way of
+accessing components.
+Any integer expression can be used as the subscript.
+The first component is at index zero.
+Reading from or writing to a vector using a constant integral expression
+with a value that is negative or greater than or equal to the size of the
+vector results in an error.
+When indexing with non-constant expressions, behavior is undefined if the
+index is negative, or greater than or equal to the size of the vector.</p>
+</div>
+<div class="paragraph">
+<p>Note that scalars are not considered to be single-component vectors and
+therefore the use of component selection operators on scalars is illegal.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="matrix-components">5.6. Matrix Components</h3>
+<div class="paragraph">
+<p>The components of a matrix can be accessed using array subscripting syntax.
+Applying a single subscript to a matrix treats the matrix as an array of
+column vectors, and selects a single column, whose type is a vector of the
+same size as the (column size of the) matrix.
+The leftmost column is column 0.
+A second subscript would then operate on the resulting vector, as defined
+earlier for vectors.
+Hence, two subscripts select a column and then a row.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat4 m;
+m[<span class="integer">1</span>] = vec4(<span class="float">2</span><span class="float">.0</span>);   <span class="comment">// sets the second column to all 2.0</span>
+m[<span class="integer">0</span>][<span class="integer">0</span>] = <span class="float">1</span><span class="float">.0</span>;      <span class="comment">// sets the upper left element to 1.0</span>
+m[<span class="integer">2</span>][<span class="integer">3</span>] = <span class="float">2</span><span class="float">.0</span>;      <span class="comment">// sets the 4th element of the third column to 2.0</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Behavior is undefined when accessing a component outside the bounds of a
+matrix with a non-constant expression.
+It is an error to access a matrix with a constant expression
+that is outside the bounds of the matrix.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="structure-and-array-operations">5.7. Structure and Array Operations</h3>
+<div class="paragraph">
+<p>The members of a structure and the <strong>length</strong>() method of an array are
+selected using the period (<strong>.</strong>).</p>
+</div>
+<div class="paragraph">
+<p>In total, only the following operators are allowed to operate on arrays and
+structures as whole entities:</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">field selector</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>.</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>==</strong> <strong>!=</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">assignment</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>=</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Ternary operator</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>?:</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Sequence operator</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>,</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">indexing (arrays only)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>[</strong> <strong>]</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The equality operators and assignment operator are only allowed if the two
+operands are same size and type.
+The operands cannot contain any opaque types.
+Structure types must be of the same declared structure.
+Both array operands must be
+compile-time
+sized.
+When using the equality operators, two structures are equal if and only if
+all the members are component-wise equal, and two arrays are equal if and
+only if all the elements are element-wise equal.</p>
+</div>
+<div class="paragraph">
+<p>Array elements are accessed using the array subscript operator (<strong>[ ]</strong>).
+An example of accessing an array element is</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">diffuseColor += lightIntensity[<span class="integer">3</span>] * NdotL;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Array indices start at zero.
+Array elements are accessed using an expression whose type is <strong>int</strong> or
+<strong>uint</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Behavior is undefined if a shader subscripts an array with an index less
+than 0 or greater than or equal to the size the array was declared with.</p>
+</div>
+<div class="paragraph">
+<p>Arrays can also be accessed with the method operator (<strong>.</strong>) and the <strong>length</strong>
+method to query the size of the array:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">lightIntensity.length() <span class="comment">// return the size of the array</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="assignments">5.8. Assignments</h3>
+<div class="paragraph">
+<p>Assignments of values to variable names are done with the assignment
+operator (<strong>=</strong>):</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue-expression</em> = <em>rvalue-expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The <em>lvalue-expression</em> evaluates to an l-value.
+The assignment operator stores the value of <em>rvalue-expression</em> into the
+l-value and returns an r-value with the type and precision of
+<em>lvalue-expression</em>.
+The <em>lvalue-expression</em> and <em>rvalue-expression</em> must have the same
+type.
+Any type-conversions must be specified explicitly via constructors.
+It is an error if the l-value is not writable.
+Variables that are built-in types, entire structures or arrays, structure
+members, l-values with the field selector (<strong>.</strong>) applied to select components
+or swizzles without repeated fields, l-values within parentheses, and
+l-values dereferenced with the array subscript operator (<strong>[ ]</strong>) are all
+l-values.
+Other binary or unary expressions, function names, swizzles with repeated
+fields, and constants cannot be l-values.
+The ternary operator (<strong>?:</strong>) is also not allowed as an l-value.
+Using an incorrect expression as an l-value results in an error.</p>
+</div>
+<div class="paragraph">
+<p>Expressions on the left of an assignment are evaluated before expressions on
+the right of the assignment.</p>
+</div>
+<div class="paragraph">
+<p>The other assignment operators are</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>add into (<strong>+=</strong>)</p>
+</li>
+<li>
+<p>subtract from (<strong>-=</strong>)</p>
+</li>
+<li>
+<p>multiply into (<strong>*=</strong>)</p>
+</li>
+<li>
+<p>divide into (<strong>/=</strong>)</p>
+</li>
+<li>
+<p>modulus into (<strong>%=</strong>)</p>
+</li>
+<li>
+<p>left shift by (<strong>&lt;&lt;=</strong>)</p>
+</li>
+<li>
+<p>right shift by (<strong>&gt;&gt;=</strong>)</p>
+</li>
+<li>
+<p>and into (<strong>&amp;=</strong>)</p>
+</li>
+<li>
+<p>inclusive-or into (<strong>|=</strong>)</p>
+</li>
+<li>
+<p>exclusive-or into (<strong>^=</strong>)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>where the general expression</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue</em> <em>op</em>= <em>expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue</em> = <em>lvalue</em> <em>op</em> <em>expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>where <em>lvalue</em> is the value returned by <em>lvalue-expression</em>, <em>op</em> is as
+described below, and the <em>lvalue-expression</em> and <em>expression</em> must satisfy
+the semantic requirements of both <em>op</em> and equals (<strong>=</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Reading a variable before writing (or initializing) it is legal, however the
+value is undefined.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="expressions">5.9. Expressions</h3>
+<div class="paragraph">
+<p>Expressions in the shading language are built from the following:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Constants of type <strong>bool</strong>, all integral types, all floating-point types,
+all vector types, and all matrix types.</p>
+</li>
+<li>
+<p>Constructors of all types.</p>
+</li>
+<li>
+<p>Variable names of all types.</p>
+</li>
+<li>
+<p>Arrays with the length method applied.</p>
+</li>
+<li>
+<p>Subscripted arrays.</p>
+</li>
+<li>
+<p>Function calls that return values.
+In some cases, function calls returning <strong>void</strong> are also allowed in
+expressions as specified below.</p>
+</li>
+<li>
+<p>Component field selectors and array subscript results.</p>
+</li>
+<li>
+<p>Parenthesized expressions.
+Any expression, including expressions with void type can be
+parenthesized.
+Parentheses can be used to group operations.
+Operations within parentheses are done before operations across
+parentheses.</p>
+</li>
+<li>
+<p>The arithmetic binary operators add (<strong>+</strong>), subtract (<strong>-</strong>), multiply
+(<strong>*</strong>), and divide (<strong>/</strong>) operate on integer and floating-point scalars,
+vectors, and matrices.
+If the operands are integral types, they must both be signed or both be
+unsigned.
+All arithmetic binary operators result in the same fundamental type
+(signed integer, unsigned integer, or floating-point) as the operands
+they operate on.
+The following cases are valid</p>
+<div class="ulist">
+<ul>
+<li>
+<p>The two operands are scalars.
+In this case the operation is applied, resulting in a scalar.</p>
+</li>
+<li>
+<p>One operand is a scalar, and the other is a vector or matrix.
+In this case, the scalar operation is applied independently to each
+component of the vector or matrix, resulting in the same size vector or
+matrix.</p>
+</li>
+<li>
+<p>The two operands are vectors of the same size.
+In this case, the operation is done component-wise resulting in the
+same size vector.</p>
+</li>
+<li>
+<p>The operator is add (<strong>+</strong>), subtract (<strong>-</strong>), or divide (<strong>/</strong>), and the
+operands are matrices with the same number of rows and the same number
+of columns.
+In this case, the operation is done component-wise resulting in the
+same size matrix.</p>
+</li>
+<li>
+<p>The operator is multiply (<strong>*</strong>), where both operands are matrices or one
+operand is a vector and the other a matrix.
+A right vector operand is treated as a column vector and a left vector
+operand as a row vector.
+In all these cases, it is required that the number of columns of the
+left operand is equal to the number of rows of the right operand.
+Then, the multiply (<strong>*</strong>) operation does a linear algebraic multiply,
+yielding an object that has the same number of rows as the left operand
+and the same number of columns as the right operand.
+&#8220;<a href="#vector-and-matrix-operations">Vector and Matrix Operations</a>&#8221;
+explains in more detail how vectors and matrices are operated on.</p>
+<div class="openblock">
+<div class="content">
+<div class="paragraph">
+<p>All other cases result in an error.</p>
+</div>
+<div class="paragraph">
+<p>Use the built-in functions <strong>dot</strong>, <strong>cross</strong>, <strong>matrixCompMult</strong>, and
+<strong>outerProduct</strong>, to get, respectively, vector dot product, vector cross
+product, matrix component-wise multiplication, and the matrix product of a
+column vector times a row vector.</p>
+</div>
+</div>
+</div>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>The operator modulus (<strong>%</strong>) operates on signed or unsigned integers or
+integer vectors.
+The operand types must both be signed or both be unsigned.
+The operands cannot be vectors of differing size; this is
+an error.
+If one operand is a scalar and the other vector, then the scalar is
+applied component-wise to the vector, resulting in the same type as the
+vector.
+If both are vectors of the same size, the result is computed
+component-wise.
+The resulting value is undefined for any component computed with a
+second operand that is zero, while results for other components with
+non-zero second operands remain defined.
+If both operands are non-negative, then the remainder is non-negative.
+Results are undefined if one or both operands are negative.
+The operator modulus (<strong>%</strong>) is not defined for any other data types
+(non-integer types).</p>
+</li>
+<li>
+<p>The arithmetic unary operators negate (<strong>-</strong>), post- and pre-increment and
+decrement (<strong>--</strong> and <strong>++</strong>) operate on integer or floating-point values
+(including vectors and matrices).
+All unary operators work component-wise on their operands.
+These result with the same type they operated on.
+For post- and pre-increment and decrement, the expression must be a writable
+l-value.
+Pre-increment and pre-decrement add or subtract 1 or 1.0 to the contents
+of the expression they operate on, and the value of the pre-increment or
+pre-decrement expression is the resulting value of that modification.
+Post-increment and post-decrement expressions add or subtract 1 or 1.0
+to the contents of the expression they operate on, but the resulting
+expression has the expression&#8217;s value before the post-increment or
+post-decrement was executed.</p>
+</li>
+<li>
+<p>The relational operators greater than (<strong>&gt;</strong>), less than (<strong>&lt;</strong>), greater
+than or equal (<strong>&gt;=</strong>), and less than or equal (<strong>&lt;=</strong>) operate only on
+scalar integer and scalar floating-point expressions.
+The result is scalar Boolean.
+The types of the operands must match.
+To do component-wise relational comparisons on vectors, use the built-in
+functions <strong>lessThan</strong>, <strong>lessThanEqual</strong>, <strong>greaterThan</strong>, and
+<strong>greaterThanEqual.</strong></p>
+</li>
+<li>
+<p>The equality operators <strong>equal</strong> (<strong>==</strong>), and not equal (<strong>!=</strong>) operate on
+all types except opaque types.
+They result in a scalar Boolean.
+The types of the operands must match.
+For vectors, matrices, structures, and arrays, all components, members,
+or elements of one operand must equal the corresponding components,
+members, or elements in the other operand for the operands to be
+considered equal.
+To get a vector of component-wise equality results for vectors, use the
+built-in functions <strong>equal</strong> and <strong>notEqual</strong>.</p>
+</li>
+<li>
+<p>The logical binary operators and (<strong>&amp;&amp;</strong>), or (<strong>||</strong>), and exclusive or
+(<strong>^^</strong>) operate only on two Boolean expressions and result in a Boolean
+expression.
+And (<strong>&amp;&amp;</strong>) will only evaluate the right hand operand if the left hand
+operand evaluated to <strong>true</strong>.
+Or (<strong>||</strong>) will only evaluate the right hand operand if the left hand
+operand evaluated to <strong>false</strong>.
+Exclusive or (<strong>^^</strong>) will always evaluate both operands.</p>
+</li>
+<li>
+<p>The logical unary operator not (<strong>!</strong>).
+It operates only on a Boolean expression and results in a Boolean
+expression.
+To operate on a vector, use the built-in function <strong>not</strong>.</p>
+</li>
+<li>
+<p>The sequence (<strong>,</strong>) operator that operates on expressions by returning
+the type and value of the right-most expression in a comma separated
+list of expressions.
+All expressions are evaluated, in order, from left to right.
+The operands to the sequence operator may have <strong>void</strong> type.</p>
+</li>
+<li>
+<p>The ternary selection operator (<strong>?:</strong>).
+It operates on three expressions (<em>exp1</em> <strong>?</strong> <em>exp2</em> <strong>:</strong> <em>exp3</em>).
+This operator evaluates the first expression, which must result in a
+scalar Boolean.
+If the result is true, it selects to evaluate the second expression,
+otherwise it selects to evaluate the third expression.
+Only one of the second and third expressions is evaluated.
+The second and third expressions can be any type, including <strong>void</strong>, as
+long their types match.
+This resulting matching type is the type of the entire expression.</p>
+</li>
+<li>
+<p>The one&#8217;s complement operator (<strong>~</strong>).
+The operand must be of type signed or unsigned integer or integer
+vector, and the result is the one&#8217;s complement of its operand; each bit
+of each component is complemented, including any sign bits.</p>
+</li>
+<li>
+<p>The shift operators (<strong>&lt;&lt;</strong>) and (<strong>&gt;&gt;</strong>).
+For both operators, the operands must be signed or unsigned integers or
+integer vectors.
+One operand can be signed while the other is unsigned.
+In all cases, the resulting type will be the same type as the left
+operand.
+If the first operand is a scalar, the second operand has to be a scalar
+as well.
+If the first operand is a vector, the second operand must be a scalar or
+a vector with the same size as the first operand, and the result is
+computed component-wise.
+The result is undefined if the right operand is negative, or greater
+than or equal to the number of bits in the left expression&#8217;s base type.
+The value of E1 &lt;&lt; E2 is E1 (interpreted as a bit pattern) left-shifted
+by E2 bits.
+The value of E1 &gt;&gt; E2 is E1 right-shifted by E2 bit positions.
+If E1 is a signed integer, the right-shift will extend the sign bit.
+If E1 is an unsigned integer, the right-shift will zero-extend.</p>
+</li>
+<li>
+<p>The bitwise operators and (<strong>&amp;</strong>), exclusive-or (<strong>^</strong>), and inclusive-or
+(<strong>|</strong>).
+The operands must be of type signed or unsigned integers or integer
+vectors.
+The operands cannot be vectors of differing size; this is an error.
+If one operand is a scalar and the other a vector, the scalar is applied
+component-wise to the vector, resulting in the same type as the vector.
+The fundamental types of the operands (signed or unsigned) must match,
+and will be the resulting fundamental type.
+For and (<strong>&amp;</strong>), the result is the bitwise-and function of the operands.
+For exclusive-or (<strong>^</strong>), the result is the bitwise exclusive-or function
+of the operands.
+For inclusive-or (<strong>|</strong>), the result is the bitwise inclusive-or function
+of the operands.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>For a complete specification of the syntax of expressions, see
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="vector-and-matrix-operations">5.10. Vector and Matrix Operations</h3>
+<div class="paragraph">
+<p>With a few exceptions, operations are component-wise.
+Usually, when an operator operates on a vector or matrix, it is operating
+independently on each component of the vector or matrix, in a component-wise
+fashion.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u;
+<span class="predefined-type">float</span> f;
+v = u + f;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will be equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">v.x = u.x + f;
+v.y = u.y + f;
+v.z = u.z + f;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u, w;
+w = v + u;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will be equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">w.x = v.x + u.x;
+w.y = v.y + u.y;
+w.z = v.z + u.z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and likewise for most operators and all integer and floating-point vector
+and matrix types.
+The exceptions are matrix multiplied by vector, vector multiplied by matrix,
+and matrix multiplied by matrix.
+These do not operate component-wise, but rather perform the correct linear
+algebraic multiply.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u;
+mat3 m;
+u = v * m;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u.x = dot(v, m[<span class="integer">0</span>]); <span class="comment">// m[0] is the left column of m</span>
+u.y = dot(v, m[<span class="integer">1</span>]); <span class="comment">// dot(a,b) is the inner (dot) product of a and b</span>
+u.z = dot(v, m[<span class="integer">2</span>]);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u = m * v;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u.x = m[<span class="integer">0</span>].x * v.x + m[<span class="integer">1</span>].x * v.y + m[<span class="integer">2</span>].x * v.z;
+u.y = m[<span class="integer">0</span>].y * v.x + m[<span class="integer">1</span>].y * v.y + m[<span class="integer">2</span>].y * v.z;
+u.z = m[<span class="integer">0</span>].z * v.x + m[<span class="integer">1</span>].z * v.y + m[<span class="integer">2</span>].z * v.z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat3 m, n, r;
+r = m * n;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">r[<span class="integer">0</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">2</span>].z;
+r[<span class="integer">0</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">2</span>].z;
+r[<span class="integer">0</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">2</span>].z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and similarly for other sizes of vectors and matrices.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="evaluation-of-expressions">5.11. Evaluation of Expressions</h3>
+<div class="paragraph">
+<p>In general expressions must be evaluated in the order specified by the
+precedence of operations and may only be regrouped if the result is the same or
+where the result is undefined.
+No other transforms may be applied that affect the result of an operation.
+GLSL ES relaxes these requirements for scalar operations in the following
+ways:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Addition and multiplication are assumed to be associative.</p>
+</li>
+<li>
+<p>Multiplication is assumed to be distributive over addition.
+Therefore expressions may be expanded and re-factored.</p>
+</li>
+<li>
+<p>Floating-point division may be replaced by reciprocal and
+multiplication.</p>
+</li>
+<li>
+<p>Multiplication may be replaced by repeated addition.</p>
+</li>
+<li>
+<p>Within the constraints of invariance (where applicable), the precision
+used may vary.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>These rules also apply to the built-in functions.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="statements-and-structure">6. Statements and Structure</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The fundamental building blocks of the OpenGL ES Shading Language are:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>statements and declarations</p>
+</li>
+<li>
+<p>function definitions</p>
+</li>
+<li>
+<p>selection (<strong>if</strong>-<strong>else</strong> and <strong>switch</strong>-<strong>case</strong>-<strong>default</strong>)</p>
+</li>
+<li>
+<p>iteration (<strong>for</strong>, <strong>while</strong>, and <strong>do</strong>-<strong>while</strong>)</p>
+</li>
+<li>
+<p>jumps (<strong>discard</strong>, <strong>return</strong>, <strong>break</strong>, and <strong>continue</strong>)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The overall structure of a shader is as follows</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>translation-unit</em> : </dt>
+<dd>
+<p><em>global-declaration</em><br>
+<em>translation-unit</em> <em>global-declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>global-declaration</em> : </dt>
+<dd>
+<p><em>function-definition</em><br>
+<em>declaration</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>That is, a shader is a sequence of declarations and function bodies.
+Function bodies are defined as</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function-definition</em> : </dt>
+<dd>
+<p><em>function-prototype</em> <strong>{</strong> <em>statement-list</em> <strong>}</strong></p>
+</dd>
+<dt class="hdlist1"><em>statement-list</em> : </dt>
+<dd>
+<p><em>statement</em><br>
+<em>statement-list</em> <em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>statement</em> : </dt>
+<dd>
+<p><em>compound-statement</em><br>
+<em>simple-statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Curly braces are used to group sequences of statements into compound
+statements.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>compound-statement</em> : </dt>
+<dd>
+<p><strong>{</strong> <em>statement-list</em> <strong>}</strong></p>
+</dd>
+<dt class="hdlist1"><em>simple-statement</em> : </dt>
+<dd>
+<p><em>declaration-statement</em><br>
+<em>expression-statement</em><br>
+<em>selection-statement</em><br>
+<em>iteration-statement</em><br>
+<em>jump-statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Simple declaration, expression, and jump statements end in a semi-colon.</p>
+</div>
+<div class="paragraph">
+<p>This above is slightly simplified, and the complete grammar specified in
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; should be used as
+the definitive specification.</p>
+</div>
+<div class="paragraph">
+<p>Declarations and expressions have already been discussed.</p>
+</div>
+<div class="sect2">
+<h3 id="function-definitions">6.1. Function Definitions</h3>
+<div class="paragraph">
+<p>As indicated by the grammar above, a valid shader is a sequence of global
+declarations and function definitions.
+A function is declared as the following example shows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// prototype</span>
+returnType functionName (type0 arg0, type1 arg1, ..., typen argn);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and a function is defined like</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// definition</span>
+returnType functionName (type0 arg0, type1 arg1, ..., typen argn)
+{
+    <span class="comment">// do some computation</span>
+    <span class="keyword">return</span> returnValue;
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>returnType</em> must be present and cannot be void, or:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> functionName (type0 arg0, type1 arg1, ..., typen argn)
+{
+    <span class="comment">// do some computation</span>
+    <span class="keyword">return</span>; <span class="comment">// optional</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each of the <em>typeN</em> must include a type and can optionally include a
+parameter qualifier and/or <strong>const</strong>.</p>
+</div>
+<div class="paragraph">
+<p>A function is called by using its name followed by a list of arguments in
+parentheses.</p>
+</div>
+<div class="paragraph">
+<p>Arrays are allowed as arguments and as the return type.
+In both cases, the array must be
+compile-time
+sized.
+An array is passed or returned by using just its name, without brackets, and
+the size of the array must match the size specified in the function&#8217;s
+declaration.</p>
+</div>
+<div class="paragraph">
+<p>Structures are also allowed as argument types.
+The return type can also be a structure.</p>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for the
+definitive reference on the syntax to declare and define functions.</p>
+</div>
+<div class="paragraph">
+<p>All functions must be either declared with a prototype or defined with a
+body before they are called.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> myfunc (<span class="predefined-type">float</span> f,      <span class="comment">// f is an input parameter</span>
+              out <span class="predefined-type">float</span> g); <span class="comment">// g is an output parameter</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Functions that return no value must be declared as <strong>void</strong>.
+A <strong>void</strong> function can only use <strong>return</strong> without a return argument, even if
+the return argument has <strong>void</strong> type.
+Return statements only accept values:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> func1() { }
+<span class="directive">void</span> func2() { <span class="keyword">return</span> func1(); } <span class="comment">// illegal return statement</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Only a precision qualifier is allowed on the return type of a function.
+Formal parameters can have parameter, precision, and memory qualifiers, but
+no other qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Functions that accept no input arguments need not use <strong>void</strong> in the argument
+list because prototypes (or definitions) are required and therefore there is
+no ambiguity when an empty argument list &#8220;( )&#8221; is declared.
+The idiom &#8220;(<strong>void</strong>)&#8221; as a parameter list is provided for convenience.</p>
+</div>
+<div class="paragraph">
+<p>Function names can be overloaded.
+The same function name can be used for multiple functions, as long as the
+parameter types differ.
+If a function name is declared twice with the same parameter types, then the
+return types and all qualifiers must also match, and it is the same function
+being declared.
+When function calls are resolved, an exact type match for all the arguments
+is required.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 f(in vec4 x, out vec4 y);
+vec4 f(in vec4 x, out uvec4 y);      <span class="comment">// allowed, different argument type</span>
+<span class="predefined-type">int</span> f(in vec4 x, out vec4 y);        <span class="comment">// error, only return type differs</span>
+vec4 f(in vec4 x, in vec4 y);        <span class="comment">// error, only qualifier differs</span>
+vec4 f(<span class="directive">const</span> in vec4 x, out vec4 y); <span class="comment">// error, only qualifier differs</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Calling the first two functions above with the following argument types
+yields</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">f(vec4, vec4)   <span class="comment">// exact match of vec4 f(in vec4 x, out vec4 y)</span>
+f(vec4, uvec4)  <span class="comment">// exact match of vec4 f(in vec4 x, out uvec4 y)</span>
+f(ivec4, vec4)  <span class="comment">// error, no exact match.</span>
+f(ivec4, uvec4) <span class="comment">// error, no exact match.</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>User-defined functions can have multiple declarations, but only one
+definition.</p>
+</div>
+<div class="paragraph">
+<p>A shader cannot redefine or overload built-in functions.</p>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> is used as the entry point to a shader executable.
+All shaders must define a function named <em>main</em>.
+This function takes no arguments, returns no value, and must be declared as
+type <strong>void</strong>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> main()
+{
+    ...
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> can contain uses of <strong>return</strong>.
+See &#8220;<a href="#jumps">Jumps</a>&#8221; for more details.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error to declare or define a function
+<strong>main</strong> with any other parameters or return type.</p>
+</div>
+<div class="sect3">
+<h4 id="function-calling-conventions">6.1.1. Function Calling Conventions</h4>
+<div class="paragraph">
+<p>Functions are called by value-return.
+This means input arguments are copied into the function at call time, and
+output arguments are copied back to the caller before function exit.
+Because the function works with local copies of parameters, there are no
+issues regarding aliasing of variables within a function.
+To control what parameters are copied in and/or out through a function
+definition or declaration:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The keyword <strong>in</strong> is used as a qualifier to denote a parameter is to be
+copied in, but not copied out.</p>
+</li>
+<li>
+<p>The keyword <strong>out</strong> is used as a qualifier to denote a parameter is to be
+copied out, but not copied in.
+This should be used whenever possible to avoid unnecessarily copying
+parameters in.</p>
+</li>
+<li>
+<p>The keyword <strong>inout</strong> is used as a qualifier to denote the parameter is to
+be both copied in and copied out.
+It means the same thing as specifying both <strong>in</strong> and <strong>out</strong>.</p>
+</li>
+<li>
+<p>A function parameter declared with no such qualifier means the same
+thing as specifying <strong>in</strong>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>All arguments are evaluated at call time, exactly once, in order, from left
+to right.
+Evaluation of an <strong>in</strong> parameter results in a value that is copied to the
+formal parameter.
+Evaluation of an <strong>out</strong> parameter results in an l-value that is used to copy
+out a value when the function returns.
+Evaluation of an <strong>inout</strong> parameter results in both a value and an l-value;
+the value is copied to the formal parameter at call time and the l-value is
+used to copy out a value when the function returns.</p>
+</div>
+<div class="paragraph">
+<p>The order in which output parameters are copied back to the caller is
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>In a function, writing to an input-only parameter is allowed.
+Only the function&#8217;s copy is modified.
+This can be prevented by declaring a parameter with the <strong>const</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When calling a function, expressions that do not evaluate to l-values cannot
+be passed to parameters declared as <strong>out</strong> or <strong>inout</strong>, or an error
+results.</p>
+</div>
+<div class="paragraph">
+<p>Only precision qualifiers are allowed on the return type of a function.</p>
+</div>
+<div class="paragraph">
+<p>The syntax for function prototypes can be informally expressed as:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function_prototype</em> : </dt>
+<dd>
+<p>[ <em>type_qualifier</em> ] <em>type_specifier</em> <em>IDENTIFIER</em> <em>LEFT_PAREN</em>
+<em>parameter_declaration</em> , <em>parameter_declaration</em> , &#8230;&#8203;
+, <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_declaration</em> : </dt>
+<dd>
+<p>[ <em>type_qualifier</em> ] <em>type_specifier</em> [ <em>IDENTIFIER</em> [ <em>array_specifier</em>
+] ]</p>
+</dd>
+<dt class="hdlist1"><em>type_qualifier</em> : </dt>
+<dd>
+<p><em>single_type_qualifier</em> , <em>single_type_qualifier</em> , &#8230;&#8203;</p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The qualifiers allowed on formal parameters are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>empty</em><br>
+<strong>const</strong><br>
+<strong>in</strong><br>
+<strong>out</strong><br>
+<strong>inout</strong><br>
+<strong>precise</strong><br>
+<em>memory-qualifier</em><br>
+<em>precision-qualifier</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>const</strong> qualifier cannot be used with <strong>out</strong> or <strong>inout</strong>, or
+an error results.
+The above is used both for function declarations (i.e., prototypes) and for
+function definitions.
+Hence, function definitions can have unnamed arguments.</p>
+</div>
+<div class="paragraph">
+<p>Static, and hence dynamic recursion, are not allowed.
+Static recursion is present if the static function-call graph of a program
+contains cycles.
+Dynamic recursion occurs if at any time control flow has entered but not
+exited a single function more than once.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="selection">6.2. Selection</h3>
+<div class="paragraph">
+<p>Conditional control flow in the shading language is done by either <strong>if</strong>,
+<strong>if</strong>-<strong>else</strong>, or <strong>switch</strong> statements:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>selection-statement</em> : </dt>
+<dd>
+<p><strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em><br>
+<strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em> <strong>else</strong> <em>statement</em><br>
+<strong>switch</strong> <strong>(</strong> <em>init-expression</em> <strong>)</strong> <strong>{</strong> <em>switch-statement-list<sub>opt</sub></em> <strong>}</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Where <em>switch-statement-list</em> is a nested scope containing a list of zero or
+more <em>switch-statement</em> and other statements defined by the language, where
+<em>switch-statement</em> adds some forms of labels.
+That is</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>switch-statement-list</em> : </dt>
+<dd>
+<p><em>switch-statement</em><br>
+<em>switch-statement-list</em> <em>switch-statement</em></p>
+</dd>
+<dt class="hdlist1"><em>switch-statement</em> : </dt>
+<dd>
+<p><strong>case</strong> <em>constant-expression</em> <strong>:</strong><br>
+<strong>default</strong> <strong>:</strong> <em>statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Note the above grammar&#8217;s purpose is to aid discussion in this section; the
+normative grammar is in &#8220;<a href="#shading-language-grammar">Shading Language
+Grammar</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>If an <strong>if</strong>-expression evaluates to <strong>true</strong>, then the first <em>statement</em> is
+executed.
+If it evaluates to <strong>false</strong> and there is an <strong>else</strong> part then the second
+<em>statement</em> is executed.</p>
+</div>
+<div class="paragraph">
+<p>Any expression whose type evaluates to a Boolean can be used as the
+conditional expression <em>bool-expression</em>.
+Vector types are not accepted as the expression to <strong>if</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Conditionals can be nested.</p>
+</div>
+<div class="paragraph">
+<p>The type of <em>init-expression</em> in a <strong>switch</strong> statement must be a scalar
+integer.
+The type of <em>init-expression</em> must match the type of the <strong>case</strong> labels
+within each <strong>switch</strong> statement.
+Either signed integers or unsigned integers are allowed but there is no
+implicit type conversion between the two.
+If a <strong>case</strong> label has a <em>constant-expression</em> of equal value to
+<em>init-expression</em>, execution will continue after that label.
+Otherwise, if there is a <strong>default</strong> label, execution will continue after that
+label.
+Otherwise, execution skips the rest of the switch statement.
+It is an error to have more than one <strong>default</strong> or a replicated
+<em>constant-expression</em>.
+A <strong>break</strong> statement not nested in a loop or other switch statement (either
+not nested or nested only in <strong>if</strong> or <strong>if</strong>-<strong>else</strong> statements) will also skip
+the rest of the switch statement.
+Fall through labels are allowed, but it is an error to have no
+statement between a label and the end of the switch statement.
+No statements are allowed in a switch statement before the first <strong>case</strong>
+statement.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>case</strong> and <strong>default</strong> labels can only appear within a <strong>switch</strong> statement.
+No <strong>case</strong> or <strong>default</strong> labels can be nested inside other statements or
+compound statements within their corresponding <strong>switch</strong>.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="iteration">6.3. Iteration</h3>
+<div class="paragraph">
+<p>For, while, and do loops are allowed as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> (init-expression; condition-expression; loop-expression)
+    sub-statement
+<span class="keyword">while</span> (condition-expression)
+    sub-statement
+<span class="keyword">do</span>
+    statement
+<span class="keyword">while</span> (condition-expression)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for the
+definitive specification of loops.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>for</strong> loop first evaluates the <em>init-expression</em>, then the
+<em>condition-expression</em>.
+If the <em>condition-expression</em> evaluates to <strong>true</strong>, then the body of the loop
+is executed.
+After the body is executed, a <strong>for</strong> loop will then evaluate the
+<em>loop-expression</em>, and then loop back to evaluate the
+<em>condition-expression</em>, repeating until the <em>condition-expression</em> evaluates
+to <strong>false</strong>.
+The loop is then exited, skipping its body and skipping its
+<em>loop-expression</em>.
+Variables modified by the <em>loop-expression</em> maintain their value after the
+loop is exited, provided they are still in scope.
+Variables declared in <em>init-expression</em> or <em>condition-expression</em> are only
+in scope until the end of the sub-statement of the <strong>for</strong> loop.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>while</strong> loop first evaluates the <em>condition-expression</em>.
+If <strong>true</strong>, then the body is executed.
+This is then repeated, until the <em>condition-expression</em> evaluates to
+<strong>false</strong>, exiting the loop and skipping its body.
+Variables declared in the <em>condition-expression</em> are only in scope until the
+end of the sub-statement of the <strong>while</strong> loop.</p>
+</div>
+<div class="paragraph">
+<p>For both <strong>for</strong> and <strong>while</strong> loops, the sub-statement does not introduce a new
+scope for variable names, so the following has a redeclaration error:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> (<span class="predefined-type">int</span> i = <span class="integer">0</span>; i &lt; <span class="integer">10</span>; i++) +
+{
+    <span class="predefined-type">int</span> i; <span class="comment">// redeclaration error +</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>do</strong>-<strong>while</strong> loop first executes the body, then executes the
+<em>condition-expression</em>.
+This is repeated until <em>condition-expression</em> evaluates to <strong>false</strong>, and then
+the loop is exited.</p>
+</div>
+<div class="paragraph">
+<p>Expressions for <em>condition-expression</em> must evaluate to a Boolean.</p>
+</div>
+<div class="paragraph">
+<p>Both the <em>condition-expression</em> and the <em>init-expression</em> can declare and
+initialize a variable, except in the <strong>do</strong>-<strong>while</strong> loop, which cannot declare
+a variable in its <em>condition-expression</em>.
+The variable&#8217;s scope lasts only until the end of the sub-statement that
+forms the body of the loop.</p>
+</div>
+<div class="paragraph">
+<p>Loops can be nested.</p>
+</div>
+<div class="paragraph">
+<p>Non-terminating loops are allowed.
+The consequences of very long or non-terminating loops are platform
+dependent.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="jumps">6.4. Jumps</h3>
+<div class="paragraph">
+<p>These are the jumps:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>jump_statement</em> : </dt>
+<dd>
+<p><strong>continue</strong> <strong>;</strong><br>
+<strong>break</strong> <strong>;</strong><br>
+<strong>return</strong> <strong>;</strong><br>
+<strong>return</strong> <em>expression</em> <strong>;</strong><br>
+<strong>discard</strong> <strong>;</strong> // in the fragment shader language only</p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>There is no &#8220;goto&#8221; or other non-structured flow of control.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>continue</strong> jump is used only in loops.
+It skips the remainder of the body of the inner-most loop of which it is
+inside.
+For <strong>while</strong> and <strong>do</strong>-<strong>while</strong> loops, this jump is to the next evaluation of
+the loop <em>condition-expression</em> from which the loop continues as previously
+defined.
+For <strong>for</strong> loops, the jump is to the <em>loop-expression</em>, followed by the
+<em>condition-expression</em>.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>break</strong> jump can also be used only in loops and <strong>switch</strong> statements.
+It is simply an immediate exit of the inner-most loop or <strong>switch</strong> statements
+containing the <strong>break</strong>.
+No further execution of <em>condition-expression</em>, <em>loop-expression</em>, or
+<em>switch-statement</em> is done.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>discard</strong> keyword is only allowed within fragment shaders.
+It can be used within a fragment shader to abandon the operation on the
+current fragment.
+This keyword causes the fragment to be discarded and no updates to any
+buffers will occur.
+Any prior writes to other buffers such as shader storage buffers are
+unaffected.
+Control flow exits the shader, and subsequent implicit or explicit
+derivatives are undefined when this control flow is non-uniform (meaning
+different fragments within the primitive take different control paths).
+It would typically be used within a conditional statement, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">if</span> (intensity &lt; <span class="float">0</span><span class="float">.0</span>)
+    discard;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A fragment shader may test a fragment&#8217;s alpha value and discard the fragment
+based on that test.
+However, it should be noted that coverage testing occurs after the fragment
+shader runs, and the coverage test can change the alpha value.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>return</strong> jump causes immediate exit of the current function.
+If it has <em>expression</em> then that is the return value for the function.</p>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> can use <strong>return</strong>.
+This simply causes <em>main</em> to exit in the same way as when the end of the
+function had been reached.
+It does not imply a use of <strong>discard</strong> in a fragment shader.
+Using <strong>return</strong> in <em>main</em> before defining outputs will have the same behavior
+as reaching the end of <em>main</em> before defining outputs.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="built-in-variables">7. Built-In Variables</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="built-in-language-variables">7.1. Built-In Language Variables</h3>
+<div class="paragraph">
+<p>Some OpenGL ES operations occur in fixed functionality and need to provide
+values to or receive values from shader executables.
+Shaders communicate with fixed-function OpenGL ES pipeline stages, and
+optionally with other shader executables, through the use of built-in input
+and output variables.</p>
+</div>
+<div class="sect3">
+<h4 id="vertex-shader-special-variables">7.1.1. Vertex Shader Special Variables</h4>
+<div class="paragraph">
+<p>The built-in vertex shader variables are intrinsically declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in highp <span class="predefined-type">int</span> gl_VertexID;
+in highp <span class="predefined-type">int</span> gl_InstanceID;
+
+out gl_PerVertex {
+    out highp vec4 gl_Position;
+    out highp <span class="predefined-type">float</span> gl_PointSize;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_Position</em> is intended for writing the homogeneous vertex
+position.
+It can be written at any time during shader execution.
+This value will be used by primitive assembly, clipping, culling, and other
+fixed functionality operations, if present, that operate on primitives after
+vertex processing has occurred.
+Its value is undefined after the vertex processing stage if the vertex
+shader executable does not write <em>gl_Position</em>.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_PointSize</em> is intended for a shader to write the size of
+the point to be rasterized.
+It is measured in pixels.
+If <em>gl_PointSize</em> is not written to, its value is undefined in subsequent
+pipe stages.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_VertexID</em> is a vertex shader input variable that holds an
+integer index for the vertex, as defined under &#8220;Shader Inputs&#8221; in section
+11.1.3.9 &#8220;Shader Inputs&#8221; of the <a href="#references">OpenGL ES Specification</a>.
+While the variable <em>gl_VertexID</em> is always present, its value is not always
+defined.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_InstanceID</em> is a vertex shader input variable that holds
+the instance number of the current primitive in an instanced draw call (see
+&#8220;Shader Inputs&#8221; in section 11.1.3.9 &#8220;Shader Inputs&#8221; of the
+<a href="#references">OpenGL ES Specification</a>).
+If the current primitive does not come from an instanced draw call, the
+value of <em>gl_InstanceID</em> is zero.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="tessellation-control-shader-special-variables">7.1.2. Tessellation Control Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the tessellation control shader, built-in variables are intrinsically
+declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    highp vec4 gl_Position;
+} gl_in[gl_MaxPatchVertices];
+
+in highp <span class="predefined-type">int</span> gl_PatchVerticesIn;
+in highp <span class="predefined-type">int</span> gl_PrimitiveID;
+in highp <span class="predefined-type">int</span> gl_InvocationID;
+
+out gl_PerVertex {
+    highp vec4 gl_Position;
+} gl_out[];
+
+patch out highp <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>];
+patch out highp <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>];
+patch out highp vec4 gl_BoundingBox[<span class="integer">2</span>];</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-input-variables">Tessellation Control Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> contains the output written in the previous shader stage to
+<em>gl_Position</em>.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PatchVerticesIn</em> contains the number of vertices in the input patch
+being processed by the shader.
+A single shader can read patches of differing sizes, so the value of
+<em>gl_PatchVerticesIn</em> may differ between patches.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveID</em> contains the number of primitives processed by the shader
+since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_InvocationID</em> contains the number of the output patch vertex assigned to
+the tessellation control shader invocation.
+It is assigned integer values in the range [0, N-1], where N is the number
+of output patch vertices per primitive.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-output-variables">Tessellation Control Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> is used in the same fashion as the corresponding output
+variable in the vertex shader.</p>
+</div>
+<div class="paragraph">
+<p>The values written to <em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are
+assigned to the corresponding outer and inner tessellation levels of the
+output patch.
+They are used by the tessellation primitive generator to control primitive
+tessellation and may be read by tessellation evaluation shaders.</p>
+</div>
+<div class="paragraph">
+<p>The values written to <em>gl_BoundingBox</em> specify the minimum and maximum
+clip-space extents of a bounding box containing all primitives generated
+from the patch by the primitive generator, geometry shader, and clipping.
+Fragments may or may not be generated for portions of these primitives
+that extend outside the window-coordinate projection of this bounding
+box.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="tessellation-evaluation-shader-special-variables">7.1.3. Tessellation Evaluation Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the tessellation evaluation shader, built-in variables are intrinsically
+declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    highp vec4 gl_Position;
+} gl_in[gl_MaxPatchVertices];
+
+in highp <span class="predefined-type">int</span> gl_PatchVerticesIn;
+in highp <span class="predefined-type">int</span> gl_PrimitiveID;
+in highp vec3 gl_TessCoord;
+patch in highp <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>];
+patch in highp <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>];
+
+out gl_PerVertex {
+    highp vec4 gl_Position;
+};</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-input-variables">Tessellation Evaluation Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> contains the output written in the previous shader stage to
+<em>gl_Position</em>.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PatchVerticesIn</em> and <em>gl_PrimitiveID</em> are defined in the same fashion as
+the corresponding input variables in the tessellation control shader.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_TessCoord</em> specifies a three-component <em>(u,v,w)</em> vector identifying the
+position of the vertex being processed by the shader relative to the
+primitive being tessellated.
+Its values will obey the properties</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_TessCoord.x == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.x) <span class="comment">// two operations performed</span>
+gl_TessCoord.y == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.y) <span class="comment">// two operations performed</span>
+gl_TessCoord.z == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.z) <span class="comment">// two operations performed</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>to aid in replicating subdivision computations.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are filled with the
+corresponding outputs written by the active tessellation control shader.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-output-variables">Tessellation Evaluation Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> is used in the same fashion as the corresponding output
+variable in the vertex shader.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="geometry-shader-special-variables">7.1.4. Geometry Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the geometry shader, built-in variables are intrinsically declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    highp vec4 gl_Position;
+} gl_in[];
+
+in highp <span class="predefined-type">int</span> gl_PrimitiveIDIn;
+in highp <span class="predefined-type">int</span> gl_InvocationID;
+
+out gl_PerVertex {
+    highp vec4 gl_Position;
+};
+
+out highp <span class="predefined-type">int</span> gl_PrimitiveID;
+out highp <span class="predefined-type">int</span> gl_Layer;</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-input-variables">Geometry Shader Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> contains the output written in the previous shader stage to
+<em>gl_Position</em>.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveIDIn</em> contains the number of primitives processed by the shader
+since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_InvocationID</em> contains the invocation number assigned to the geometry
+shader invocation.
+It is assigned integer values in the range [0, N-1], where N is the number
+of geometry shader invocations per primitive.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-output-variables">Geometry Shader Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em> is used in the same fashion as the corresponding output
+variable in the vertex shader.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveID</em> is filled with a single integer that serves as a primitive
+identifier to the fragment shader.
+This is then available to fragment shaders, which will select the written
+primitive ID from the provoking vertex of the primitive being shaded.
+If a fragment shader using <em>gl_PrimitiveID</em> is active and a geometry shader
+is also active, the geometry shader must write to <em>gl_PrimitiveID</em> or the
+fragment shader input <em>gl_PrimitiveID</em> is undefined.
+See section 11.3.4.4 &#8220;Geometry Shader Outputs&#8221; of the
+<a href="#references">OpenGL ES Specification</a> for more information.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_Layer</em> is used to select a specific layer (or face and layer of a cube
+map) of a multi-layer framebuffer attachment.
+The actual layer used will come from one of the vertices in the primitive
+being shaded.
+Which vertex the layer comes from is determined as discussed in section
+11.3.4.4 of the <a href="#references">OpenGL ES Specification</a>
+but may be undefined, so it is best to write the same layer value for all
+vertices of a primitive.
+If a shader statically assigns a value to <em>gl_Layer</em>, layered rendering mode
+is enabled.
+See section 11.3.4.4 &#8220;Geometry Shader Outputs&#8221; and section 9.8 &#8220;Layered
+Framebuffers&#8221; of the <a href="#references">OpenGL ES Specification</a> for more information.
+If a shader statically assigns a value to <em>gl_Layer</em>, and there is an
+execution path through the shader that does not set <em>gl_Layer</em>, then the
+value of <em>gl_Layer</em> is undefined for executions of the shader that take that
+path.</p>
+</div>
+<div class="paragraph">
+<p>The output variable <em>gl_Layer</em> takes on a special value when used with an
+array of cube map textures.
+Instead of only referring to the layer, it is used to select a cube map face
+and a layer.
+Setting <em>gl_Layer</em> to the value <em>layer*6+face</em> will render to face <em>face</em> of
+the cube defined in layer <em>layer</em>.
+The face values are defined in table 8.25 of the <a href="#references">OpenGL ES Specification</a>,
+but repeated below for clarity.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Face Value</th>
+<th class="tableblock halign-left valign-top">Resulting Target</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Y</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Y</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Z</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Z</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>For example, to render to the positive <em>y</em> cube map face located in the 5th
+layer of the cube map array, <em>gl_Layer</em> should be set to <em>5 * 6 + 2</em>.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="fragment-shader-special-variables">7.1.5. Fragment Shader Special Variables</h4>
+<div class="paragraph">
+<p>The built-in special variables that are accessible from a fragment shader
+are intrinsically declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in highp vec4 gl_FragCoord;
+in <span class="predefined-type">bool</span> gl_FrontFacing;
+out highp <span class="predefined-type">float</span> gl_FragDepth;
+in mediump vec2 gl_PointCoord;
+in <span class="predefined-type">bool</span> gl_HelperInvocation;
+in highp <span class="predefined-type">int</span> gl_PrimitiveID;
+in highp <span class="predefined-type">int</span> gl_Layer;
+in lowp <span class="predefined-type">int</span> gl_SampleID;
+in mediump vec2 gl_SamplePosition;
+in highp <span class="predefined-type">int</span> gl_SampleMaskIn[(gl_MaxSamples+<span class="integer">31</span>)/<span class="integer">32</span>];
+out highp <span class="predefined-type">int</span> gl_SampleMask[(gl_MaxSamples+<span class="integer">31</span>)/<span class="integer">32</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The output of the fragment shader executable is processed by the fixed
+function operations at the back end of the OpenGL ES pipeline.</p>
+</div>
+<div class="paragraph">
+<p>The fixed functionality computed depth for a fragment may be obtained by
+reading <em>gl_FragCoord.z</em>, described below.</p>
+</div>
+<div class="paragraph">
+<p>Writing to <em>gl_FragDepth</em> will establish the depth value for the fragment
+being processed.
+If depth buffering is enabled, and no shader writes <em>gl_FragDepth</em>, then the
+fixed function value for depth will be used as the fragment&#8217;s depth value.
+If a shader statically assigns a value to <em>gl_FragDepth</em>, and there is an
+execution path through the shader that does not set <em>gl_FragDepth</em>, then the
+value of the fragment&#8217;s depth may be undefined for executions of the shader
+that take that path.
+That is, if the set of linked fragment shaders statically contain a write to
+<em>gl_FragDepth</em>, then it is responsible for always writing it.</p>
+</div>
+<div class="paragraph">
+<p>If a shader executes the <strong>discard</strong> keyword, the fragment is discarded, and
+the values of any user-defined fragment outputs, <em>gl_FragDepth</em>, and
+<em>gl_SampleMask</em> become irrelevant.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_FragCoord</em> is available as an input variable from within
+fragment shaders and it holds the window relative coordinates (<em>x</em>, <em>y</em>,
+<em>z</em>, <em>1/w</em>) values for the fragment.
+If multi-sampling, this value can be for any location within the pixel, or
+one of the fragment samples.
+The use of <strong>centroid</strong> does not further restrict this value to be inside the
+current primitive.
+This value is the result of the fixed functionality that interpolates
+primitives after vertex processing to generate fragments.
+The <em>z</em> component is the depth value that would be used for the fragment&#8217;s
+depth if no shader contained any writes to <em>gl_FragDepth</em>.
+This is useful for invariance if a shader conditionally computes
+<em>gl_FragDepth</em> but otherwise wants the fixed functionality fragment depth.</p>
+</div>
+<div class="paragraph">
+<p>Fragment shaders have access to the input built-in variable
+<em>gl_FrontFacing</em>, whose value is <strong>true</strong> if the fragment belongs to a
+front-facing primitive.
+One use of this is to emulate two-sided lighting by selecting one of two
+colors calculated by a vertex or geometry shader.</p>
+</div>
+<div class="paragraph">
+<p>The values in <em>gl_PointCoord</em> are two-dimensional coordinates indicating
+where within a point primitive the current fragment is located, when point
+sprites are enabled.
+They range from 0.0 to 1.0 across the point.
+If the current primitive is not a point, or if point sprites are not
+enabled, then the values read from <em>gl_PointCoord</em> are undefined.</p>
+</div>
+<div class="paragraph">
+<p>For both the input array <em>gl_SampleMaskIn[]</em> and the output array
+<em>gl_SampleMask[]</em>, bit <em>B</em> of mask <em>M</em> (<em>gl_SampleMaskIn[M]</em> or
+<em>gl_SampleMask[M]</em>) corresponds to sample <em>32*M+B</em>.
+These arrays have <strong>ceil</strong>(<em>s</em>/32) elements, where <em>s</em> is the maximum number
+of color samples supported by the implementation.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SampleMaskIn</em> indicates the set of samples covered by
+the primitive generating the fragment during multisample rasterization.
+It has a sample bit set if and only if the sample is considered covered for
+this fragment shader invocation.</p>
+</div>
+<div class="paragraph">
+<p>The output array <em>gl_SampleMask[]</em> sets the sample mask for the fragment
+being processed.
+Coverage for the current fragment will become the logical AND of the
+coverage mask and the output <em>gl_SampleMask</em>.
+This array must be sized in the fragment shader either implicitly or
+explicitly, to be no larger than the implementation-dependent maximum
+sample-mask (as an array of 32bit elements), determined by the maximum
+number of samples..
+If the fragment shader statically assigns a value to <em>gl_SampleMask</em>, the
+sample mask will be undefined for any array elements of any fragment shader
+invocations that fail to assign a value.
+If a shader does not statically assign a value to <em>gl_SampleMask</em>, the
+sample mask has no effect on the processing of a fragment.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SampleID</em> is filled with the sample number of the
+sample currently being processed.
+This variable is in the range <em>0</em> to <em>gl_NumSamples-1</em>, where
+<em>gl_NumSamples</em> is the total number of samples in the framebuffer, or 1 if
+rendering to a non-multisample framebuffer.
+Any static use of this variable in a fragment shader causes the entire
+shader to be evaluated per-sample.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SamplePosition</em> contains the position of the current
+sample within the multisample draw buffer.
+The <em>x</em> and <em>y</em> components of <em>gl_SamplePosition</em> contain the sub-pixel
+coordinate of the current sample and will have values in the range 0.0 to
+1.0.
+Any static use of this variable in a fragment shader causes the entire
+shader to be evaluated per sample.</p>
+</div>
+<div class="paragraph">
+<p>The value <em>gl_HelperInvocation</em> is <strong>true</strong> if the fragment shader invocation
+is considered a <em>helper invocation</em> and is <strong>false</strong> otherwise.
+A helper invocation is a fragment shader invocation that is created solely
+for the purposes of evaluating derivatives for use in non-helper fragment
+shader invocations.
+Such derivatives are computed implicitly in the built-in function
+<strong>texture</strong>() (see &#8220;<a href="#texture-functions">Texture Functions</a>&#8221;), and
+explicitly in the derivative functions in
+&#8220;<a href="#derivative-functions">Derivative Functions</a>&#8221;, for example <strong>dFdx</strong>() and
+<strong>dFdy</strong>().</p>
+</div>
+<div class="paragraph">
+<p>Fragment shader helper invocations execute the same shader code as
+non-helper invocations, but will not have side effects that modify the
+framebuffer or other shader-accessible memory.
+In particular:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Fragments corresponding to helper invocations are discarded when shader
+execution is complete, without updating the framebuffer.</p>
+</li>
+<li>
+<p>Stores to image and buffer variables performed by helper invocations
+have no effect on the underlying image or buffer memory.</p>
+</li>
+<li>
+<p>Atomic operations to image, buffer, or atomic counter variables
+performed by helper invocations have no effect on the underlying image
+or buffer memory.
+The values returned by such atomic operations are undefined.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Helper invocations may be generated for pixels not covered by a primitive
+being rendered.
+While fragment shader inputs qualified with <strong>centroid</strong> are normally required
+to be sampled in the intersection of the pixel and the primitive, the
+requirement is ignored for such pixels since there is no intersection
+between the pixel and primitive.</p>
+</div>
+<div class="paragraph">
+<p>Helper invocations may also be generated for fragments that are covered by a
+primitive being rendered when the fragment is killed by early fragment tests
+(using the <strong>early_fragment_tests</strong> qualifier) or where the implementation is
+able to determine that executing the fragment shader would have no effect
+other than assisting in computing derivatives for other fragment shader
+invocations.</p>
+</div>
+<div class="paragraph">
+<p>The set of helper invocations generated when processing any set of
+primitives is implementation-dependent.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_PrimitiveID</em> is filled with the value written to the
+<em>gl_PrimitiveID</em> geometry shader output, if a geometry shader is present.
+Otherwise, it is filled with the number of primitives processed by the
+shader since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_Layer</em> is filled with the value written to the
+<em>gl_Layer</em> geometry shader output, if a geometry shader is present.
+If the geometry stage does not dynamically assign a value to <em>gl_Layer</em>, the
+value of <em>gl_Layer</em> in the fragment stage will be undefined.
+If the geometry stage makes no static assignment to <em>gl_Layer</em>, the input
+value in the fragment stage will be zero.
+Otherwise, the fragment stage will read the same value written by the
+geometry stage, even if that value is out of range.
+If a fragment shader contains a static access to <em>gl_Layer</em>, it will count
+against the implementation defined limit for the maximum number of inputs to
+the fragment stage.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="compute-shader-special-variables">7.1.6. Compute Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the compute shader, built-in variables are declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// workgroup dimensions</span>
+in uvec3 gl_NumWorkGroups;
+<span class="directive">const</span> uvec3 gl_WorkGroupSize;
+
+<span class="comment">// workgroup and invocation IDs</span>
+in uvec3 gl_WorkGroupID;
+in uvec3 gl_LocalInvocationID;
+
+<span class="comment">// derived variables</span>
+in uvec3 gl_GlobalInvocationID;
+in uint gl_LocalInvocationIndex;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_NumWorkGroups</em> is a compute-shader input variable
+containing the number of workgroups in each dimension of the dispatch that
+will execute the compute shader.
+Its content is equal to the values specified in the <em>num_groups_x</em>,
+<em>num_groups_y</em>, and <em>num_groups_z</em> parameters passed to the
+<em>DispatchCompute</em> API entry point.</p>
+</div>
+<div class="paragraph">
+<p>The built-in constant <em>gl_WorkGroupSize</em> is a compute-shader constant
+containing the workgroup size of the shader.
+The size of the workgroup in the <em>X</em>, <em>Y</em>, and <em>Z</em> dimensions is stored in
+the <em>x</em>, <em>y</em>, and <em>z</em> components.
+The constants values in <em>gl_WorkGroupSize</em> will match those specified in the
+required <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> layout
+qualifiers for the current shader.
+This is a constant so that it can be used to size arrays of memory that can
+be shared within the workgroup.
+It is a compile-time error to use <em>gl_WorkGroupSize</em> in a shader that does
+not declare a fixed workgroup size, or before that shader has declared a
+fixed workgroup size, using <strong>local_size_x</strong>, <strong>local_size_y</strong>, and
+<strong>local_size_z</strong>.</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_WorkGroupID</em> is a compute-shader input variable
+containing the three-dimensional index of the workgroup that the
+current invocation is executing in.
+The possible values range across the parameters passed into
+<em>DispatchCompute</em>, i.e., from (0, 0, 0) to (<em>gl_NumWorkGroups.x</em> - 1,
+<em>gl_NumWorkGroups.y</em> - 1, <em>gl_NumWorkGroups.z</em> -1).</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_LocalInvocationID</em> is a compute-shader input
+variable containing the three-dimensional index of the current work item
+within the workgroup.
+The possible values for this variable range across the workgroup
+size, i.e., (0,0,0) to (<em>gl_WorkGroupSize.x</em> - 1, <em>gl_WorkGroupSize.y</em> - 1,
+<em>gl_WorkGroupSize.z</em> - 1).</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_GlobalInvocationID</em> is a compute shader input
+variable containing the global index of the current work item.
+This value uniquely identifies this invocation from all other invocations
+across all workgroups initiated by the current <em>DispatchCompute</em> call.
+This is computed as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_GlobalInvocationID =
+    gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_LocalInvocationIndex</em> is a compute shader input
+variable that contains the one-dimensional representation of the
+<em>gl_LocalInvocationID</em>.
+This is computed as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_LocalInvocationIndex =
+    gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
+    gl_LocalInvocationID.y * gl_WorkGroupSize.x +
+    gl_LocalInvocationID.x;</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="built-in-constants">7.2. Built-In Constants</h3>
+<div class="paragraph">
+<p>The following built-in constants are provided to all shaders.
+The actual values used are implementation-dependent, but must be at least
+the value shown.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span>
+<span class="comment">// Implementation-dependent constants. The example values below</span>
+<span class="comment">// are the minimum values allowed for these maximums.</span>
+<span class="comment">//</span></code></pre>
+</div>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAttribs = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexUniformVectors = <span class="integer">256</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexOutputVectors = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxVertexAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlInputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlOutputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlTotalOutputComponents = <span class="integer">2048</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessPatchComponents = <span class="integer">120</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxPatchVertices = <span class="integer">32</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessGenLevel = <span class="integer">64</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationInputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationOutputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryInputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryOutputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryOutputVertices = <span class="integer">256</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryTotalOutputComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentInputVectors = <span class="integer">15</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentImageUniforms = <span class="integer">4</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentUniformVectors = <span class="integer">256</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounterBuffers = <span class="integer">1</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxDrawBuffers = <span class="integer">4</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MinProgramTexelOffset = -<span class="integer">8</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxProgramTexelOffset = <span class="integer">7</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxImageUnits = <span class="integer">4</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxSamples = <span class="integer">4</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeImageUniforms = <span class="integer">4</span>;
+<span class="directive">const</span> highp ivec3 gl_MaxComputeWorkGroupCount = ivec3(<span class="integer">65535</span>, <span class="integer">65535</span>, <span class="integer">65535</span>);
+<span class="directive">const</span> highp ivec3 gl_MaxComputeWorkGroupSize = ivec3(<span class="integer">128</span>, <span class="integer">128</span>, <span class="integer">64</span>);
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxComputeAtomicCounterBuffers = <span class="integer">1</span>;
+
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedTextureImageUnits = <span class="integer">96</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedImageUniforms = <span class="integer">4</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedShaderOutputResources = <span class="integer">4</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounterBuffers = <span class="integer">1</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxAtomicCounterBindings = <span class="integer">1</span>;
+<span class="directive">const</span> mediump <span class="predefined-type">int</span> gl_MaxAtomicCounterBufferSize = <span class="integer">32</span>;</code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="built-in-uniform-state">7.3. Built-In Uniform State</h3>
+<div class="paragraph">
+<p>As an aid to accessing OpenGL ES processing state, the following uniform
+variables are built into the OpenGL ES Shading Language.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span>
+<span class="comment">// Depth range in window coordinates,</span>
+<span class="comment">// section 12.5.1 &quot;Controlling the Viewport&quot; in the</span>
+<span class="comment">// OpenGL ES Specification.</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_DepthRangeParameters {
+    highp <span class="predefined-type">float</span> near; <span class="comment">// n</span>
+    highp <span class="predefined-type">float</span> far;  <span class="comment">// f</span>
+    highp <span class="predefined-type">float</span> diff; <span class="comment">// f - n</span>
+};
+uniform gl_DepthRangeParameters gl_DepthRange;
+uniform lowp <span class="predefined-type">int</span> gl_NumSamples;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These variables are only guaranteed to be available in the fragment stage.
+In other stages, their presence and function is implementation-defined.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="redeclaring-built-in-blocks">7.4. Redeclaring Built-In Blocks</h3>
+<div class="paragraph">
+<p>The <em>gl_PerVertex</em> block can be redeclared in a shader to explicitly
+indicate what subset of the fixed pipeline interface will be used.
+This is necessary to establish the interface between multiple programs.</p>
+</div>
+<div class="paragraph">
+<p>If the <em>gl_PerVertex</em> block is not redefined in a given program, the
+intrinsically declared definition of that block is used for the program
+interface.</p>
+</div>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out gl_PerVertex {
+    highp vec4 gl_Position; <span class="comment">// will use gl_Position</span>
+    highp vec4 t;           <span class="comment">// error, only gl_PerVertex members allowed</span>
+}; <span class="comment">// no other members of gl_PerVertex will be used</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This establishes the output interface the shader will use with the
+subsequent pipeline stage.
+It must be a subset of the built-in members of <em>gl_PerVertex</em>.
+Such a redeclaration can also add the <strong>invariant</strong> qualifier and
+interpolation qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Other layout qualifiers, like <strong>location</strong>, cannot be added to such a
+redeclaration, unless specifically stated.</p>
+</div>
+<div class="paragraph">
+<p>If a built-in interface block is redeclared, it must appear in the shader
+before any use of any member included in the built-in declaration, or a
+compile-time error will result.
+It is also a compile-time error to redeclare the block more than once or to
+redeclare a built-in block and then use a member from that built-in block
+that was not included in the redeclaration.
+Also, if a built-in interface block is redeclared, no member of the built-in
+declaration can be redeclared outside the block redeclaration.
+If multiple shaders using members of a built-in block belonging to the same
+interface are linked together in the same program, they must all redeclare
+the built-in block in the same way, as described in
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221; for interface block matching, or a
+link-time error will result.
+It will also be a link-time error if some shaders in a program redeclare a
+specific built-in interface block while another shader in that program does
+not redeclare that interface block yet still uses a member of that interface
+block.
+If a built-in block interface is formed across shaders in different
+programs, the shaders must all redeclare the built-in block in the same way
+(as described for a single program), or the values passed along the
+interface are undefined.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="built-in-functions">8. Built-In Functions</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The OpenGL ES Shading Language defines an assortment of built-in convenience functions for
+scalar and vector operations.
+Many of these built-in functions can be used in more than one type of
+shader, but some are intended to provide a direct mapping to hardware and so
+are available only for a specific type of shader.</p>
+</div>
+<div class="paragraph">
+<p>The built-in functions basically fall into three categories:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>They expose some necessary hardware functionality in a convenient way
+such as accessing a texture map.
+There is no way in the language for these functions to be emulated by a
+shader.</p>
+</li>
+<li>
+<p>They represent a trivial operation (clamp, mix, etc.) that is very
+simple for the user to write, but they are very common and may have
+direct hardware support.
+It is a very hard problem for the compiler to map expressions to complex
+assembler instructions.</p>
+</li>
+<li>
+<p>They represent an operation graphics hardware is likely to accelerate at
+some point.
+The trigonometry functions fall into this category.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Many of the functions are similar to the same named ones in common C
+libraries, but they support vector input as well as the more traditional
+scalar input.</p>
+</div>
+<div class="paragraph">
+<p>Applications should be encouraged to use the built-in functions rather than
+do the equivalent computations in their own shader code since the built-in
+functions are assumed to be optimal (e.g. perhaps supported directly in
+hardware).</p>
+</div>
+<div class="paragraph">
+<p>When the built-in functions are specified below, where the input arguments
+(and corresponding output) can be <strong>float</strong>, <strong>vec2</strong>, <strong>vec3</strong>, or <strong>vec4</strong>,
+<em>genFType</em> is used as the argument.
+Where the input arguments (and corresponding output) can be <strong>int</strong>, <strong>ivec2</strong>,
+<strong>ivec3</strong>, or <strong>ivec4</strong>, <em>genIType</em> is used as the argument.
+Where the input arguments (and corresponding output) can be <strong>uint</strong>, <strong>uvec2</strong>,
+<strong>uvec3</strong>, or <strong>uvec4</strong>, <em>genUType</em> is used as the argument.
+Where the input arguments (or corresponding output) can be <strong>bool</strong>, <strong>bvec2</strong>,
+<strong>bvec3</strong>, or <strong>bvec4</strong>, <em>genBType</em> is used as the argument.
+For any specific use of a function, the actual types substituted for
+<em>genFType</em>, <em>genIType</em>, <em>genUType</em>, or <em>genBType</em> have to have the same
+number of components for all arguments and for the return type.
+Similarly, <em>mat</em> is used for any matrix basic
+type.</p>
+</div>
+<div class="paragraph">
+<p>Built-in functions have an effective precision qualification.
+This qualification cannot be set explicitly and may be different from the
+precision qualification of the result.</p>
+</div>
+<div class="paragraph">
+<p>The precision qualification of the operation of a built-in function is based
+on the precision qualification of its formal parameters and actual
+parameters (input arguments): When a formal parameter specifies a precision
+qualifier, that is used, otherwise, the precision qualification of the
+actual (calling) argument is used.
+The highest precision of these will be the precision of the operation of the
+built-in function.
+Generally, this is applied across all arguments to a built-in function, with
+the exceptions being:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>bitfieldExtract</strong> and <strong>bitfieldInsert</strong> ignore the <em>offset</em> and <em>bits</em>
+arguments.</p>
+</li>
+<li>
+<p><strong>interpolateAt</strong> functions only look at the <em>interpolant</em> argument.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The precision qualification of the result of a built-in function is
+determined in one of the following ways:</p>
+</div>
+<div class="paragraph">
+<p>For the texture sampling, image load and image store functions, the
+precision of the return type matches the precision of the sampler type:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform lowp sampler2D sampler;
+highp vec2 coord;
+...
+lowp vec4 col = texture (sampler, coord); <span class="comment">// texture() returns lowp</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Otherwise:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>For prototypes that do not specify a resulting precision qualifier, the
+precision will be the same as the precision of the operation (as defined
+earlier).</p>
+</li>
+<li>
+<p>For prototypes that do specify a resulting precision qualifier, the
+specified precision qualifier is the precision qualification of the
+result.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Where the built-in functions in the following sections specify an equation,
+the entire equation will be evaluated at the operation&#8217;s precision.
+This may lead to underflow or overflow in the result, even when the correct
+result could be represented in the operation precision.</p>
+</div>
+<div class="sect2">
+<h3 id="angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</h3>
+<div class="paragraph">
+<p>Function parameters specified as <em>angle</em> are assumed to be in units of
+radians.
+In no case will any of these functions result in a divide by zero error.
+If the divisor of a ratio is 0, then results will be undefined.</p>
+</div>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>radians</strong>(genFType <em>degrees</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>degrees</em> to radians, i.e.,
+      <span class="eq">(π / 180) · degrees</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>degrees</strong>(genFType <em>radians</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>radians</em> to degrees, i.e.,
+      <span class="eq">(180 / π) · radians</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sin</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric sine function.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cos</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric cosine function.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tan</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric tangent.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asin</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc sine.
+      Returns an angle whose sine is <em>x</em>.
+      The range of values returned by this function is
+      <span class="eq">[-π / 2, π / 2]</span>.
+      Results are undefined if <span class="eq">|x| &gt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acos</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc cosine.
+      Returns an angle whose cosine is <em>x</em>.
+      The range of values returned by this function is <span class="eq">[0,π]</span>.
+      Results are undefined if <span class="eq">|x| &gt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y</em>, genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent.
+      Returns an angle whose tangent is <span class="eq">y / x</span>.
+      The signs of <em>x</em> and <em>y</em> are used to determine what quadrant the angle
+      is in.
+      The range of values returned by this function is <span class="eq">[-π, π</span>.
+      Results are undefined if <em>x</em> and <em>y</em> are both 0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y_over_x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent.
+      Returns an angle whose tangent is <em>y_over_x</em>.
+      The range of values returned by this function is
+      <span class="eq">[-π / 2, π / 2]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sinh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic sine function <span class="eq">(e<sup>x</sup> - e<sup>-x</sup>) / 2</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cosh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic cosine function <span class="eq">(e<sup>x</sup> + e<sup>-x</sup>) / 2</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tanh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic tangent function <span class="eq">sinh(x) / cosh(x)</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asinh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic sine; returns the inverse of <strong>sinh</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acosh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic cosine; returns the non-negative inverse of <strong>cosh</strong>.
+      Results are undefined if <span class="eq">x &lt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atanh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic tangent; returns the inverse of <strong>tanh</strong>.
+      Results are undefined if <span class="eq">x ≥ 1</span>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="exponential-functions">8.2. Exponential Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>pow</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> raised to the <em>y</em> power, i.e., <span class="eq">x<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x &lt; 0</span>.
+      Results are undefined if <span class="eq">x = 0</span> and <span class="eq">y ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural exponentiation of <em>x</em>, i.e., <span class="eq">e<sup>x</sup></span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural logarithm of <em>x</em>, i.e., returns the value <em>y</em>
+      which satisfies the equation <span class="eq">x = e<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp2</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 2 raised to the <em>x</em> power, i.e., <span class="eq">2<sup>x</sup></span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log2</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the base 2 logarithm of <em>x</em>, i.e., returns the value <em>y</em> which
+      satisfies the equation <span class="eq">x = 2<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sqrt</strong>(genFType <em>x</em>)<br>
+  genDType <strong>sqrt</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">sqrt(x)</span>.
+      Results are undefined if <span class="eq">x &lt; 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>inversesqrt</strong>(genFType <em>x</em>)<br>
+  genDType <strong>inversesqrt</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">1 / sqrt(x)</span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="common-functions">8.3. Common Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>abs</strong>(genFType <em>x</em>)<br>
+  genIType <strong>abs</strong>(genIType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> if <span class="eq">x ≥ 0</span>; otherwise it returns -<em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sign</strong>(genFType <em>x</em>)<br>
+  genIType <strong>sign</strong>(genIType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 1.0 if <em>x</em> &gt; 0, 0.0 if <em>x</em> = 0, or -1.0 if <em>x</em> &lt; 0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>floor</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is less than or
+      equal to <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>trunc</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em> whose absolute
+      value is not larger than the absolute value of <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>round</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>.
+      The fraction 0.5 will round in a direction chosen by the
+      implementation, presumably the direction that is fastest.
+      This includes the possibility that <strong>round</strong>(<em>x</em>) returns the same value
+      as <strong>roundEven</strong>(<em>x</em>) for all values of <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>roundEven</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>.
+      A fractional part of 0.5 will round toward the nearest even integer.
+      (Both 3.5 and 4.5 for x will return 4.0.)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ceil</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is greater than or
+      equal to <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fract</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> - <strong>floor</strong>(<em>x</em>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mod</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genFType <strong>mod</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Modulus.
+      Returns <span class="eq">x - y · <strong>floor</strong>(x / y)</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>modf</strong>(genFType <em>x</em>, out genFType <em>i</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the fractional part of <em>x</em> and sets <em>i</em> to the integer part (as
+      a whole number floating-point value).
+      Both the return value and the output parameter will have the same sign
+      as <em>x</em>.
+      If <em>x</em> has the value +/- Inf, the return value should be NaN and must
+      be either NaN or 0.0.
+      For <strong>highp</strong> non-constant expressions, the value returned must be
+      consistent.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>min</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  genFType <strong>min</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genIType <strong>min</strong>(genIType <em>x</em>, genIType <em>y</em>)<br>
+  genIType <strong>min</strong>(genIType <em>x</em>, int <em>y</em>)<br>
+  genUType <strong>min</strong>(genUType <em>x</em>, genUType <em>y</em>)<br>
+  genUType <strong>min</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>y</em> &lt; <em>x;</em> otherwise it returns <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>max</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  genFType <strong>max</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genIType <strong>max</strong>(genIType <em>x</em>, genIType <em>y</em>)<br>
+  genIType <strong>max</strong>(genIType <em>x</em>, int <em>y</em>)<br>
+  genUType <strong>max</strong>(genUType <em>x</em>, genUType <em>y</em>)<br>
+  genUType <strong>max</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>x</em> &lt; <em>y;</em> otherwise it returns <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>clamp</strong>(genFType <em>x</em>, genFType <em>minVal</em>, genFType <em>maxVal</em>)<br>
+  genFType <strong>clamp</strong>(genFType <em>x</em>, float <em>minVal</em>, float <em>maxVal</em>)<br>
+  genIType <strong>clamp</strong>(genIType <em>x</em>, genIType <em>minVal</em>, genIType <em>maxVal</em>)<br>
+  genIType <strong>clamp</strong>(genIType <em>x</em>, int <em>minVal</em>, int <em>maxVal</em>)<br>
+  genUType <strong>clamp</strong>(genUType <em>x</em>, genUType <em>minVal</em>, genUType <em>maxVal</em>)<br>
+  genUType <strong>clamp</strong>(genUType <em>x</em>, uint <em>minVal</em>, uint <em>maxVal</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>min</strong>(<strong>max</strong>(<em>x</em>, <em>minVal</em>), <em>maxVal</em>).
+      Results are undefined if <em>minVal</em> &gt; <em>maxVal</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType <em>a</em>)<br>
+  genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, float <em>a</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the linear blend of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">x · (1 - a) + y · a</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>,  genBType <em>a</em>)<br>
+  genIType <strong>mix</strong>(genIType <em>x</em>, genIType <em>y</em>, genBType <em>a</em>)<br>
+  genUType <strong>mix</strong>(genUType <em>x</em>, genUType <em>y</em>, genBType <em>a</em>)<br>
+  genBType <strong>mix</strong>(genBType <em>x</em>, genBType <em>y</em>, genBType <em>a</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Selects which vector each returned component comes from.
+      For a component of <em>a</em> that is <strong>false</strong>, the corresponding component of
+      <em>x</em> is returned.
+      For a component of <em>a</em> that is <strong>true</strong>, the corresponding component of
+      <em>y</em> is returned.
+      Components of <em>x</em> and <em>y</em> that are not selected are allowed to be
+      invalid floating-point values and will have no effect on the results.
+      Thus, this provides different functionality than, for example,<br>
+      genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType(<em>a</em>))<br>
+      where <em>a</em> is a Boolean vector.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>step</strong>(genFType <em>edge</em>, genFType <em>x</em>)<br>
+  genFType <strong>step</strong>(float <em>edge</em>, genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 0.0 if <em>x</em> &lt; <em>edge;</em> otherwise it returns 1.0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>smoothstep</strong>(genFType <em>edge0</em>, genFType <em>edge1</em>, genFType <em>x</em>)<br>
+  genFType <strong>smoothstep</strong>(float <em>edge0</em>, float <em>edge1</em>, genFType <em>x</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns 0.0 if <span class="eq">x ≤ edge0</span> and 1.0 if <span class="eq">x ≥ edge1</span>, and
+      performs smooth Hermite interpolation between 0 and 1 when <span class="eq">edge0
+      &lt; x &lt; edge1</span>.
+      This is useful in cases where you would want a threshold function with
+      a smooth transition.
+      This is equivalent to:</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">genFType t;
+t = clamp ((x - edge0) / (edge1 - edge0), <span class="integer">0</span>, <span class="integer">1</span>);
+<span class="keyword">return</span> t * t * (<span class="integer">3</span> - <span class="integer">2</span> * t);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>(And similarly for doubles.) Results are undefined if <span class="eq">edge0 ≥
+edge1</span>.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isnan</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a NaN.
+      Returns <strong>false</strong> otherwise.
+      Always returns <strong>false</strong> if NaNs are not implemented.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isinf</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a positive infinity or negative infinity.
+      Returns <strong>false</strong> otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>floatBitsToInt</strong>(highp genFType <em>value</em>)<br>
+  genUType <strong>floatBitsToUint</strong>(highp genFType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a signed or unsigned integer value representing the encoding
+      of a floating-point value.
+      The <strong>float</strong> value&#8217;s bit-level representation is preserved.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>intBitsToFloat</strong>(highp genIType <em>value</em>)<br>
+  genFType <strong>uintBitsToFloat</strong>(highp genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a floating-point value corresponding to a signed or unsigned
+      integer encoding of a floating-point value.
+      If an Inf or NaN is passed in, it will not signal, and the resulting
+      floating-point value is unspecified.
+      Otherwise, the bit-level representation is preserved.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fma</strong>(genFType <em>a</em>, genFType <em>b</em>, genFType <em>c</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Computes and returns <span class="eq">a * b + c</span>.
+      In uses where the return value is eventually consumed by a variable
+      declared as <strong>precise</strong>:</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p><strong>fma</strong>() is considered a single operation, whereas the expression &#8220;a * b
++ c&#8221; consumed by a variable declared <strong>precise</strong> is considered two
+operations.</p>
+</li>
+<li>
+<p>The precision of <strong>fma</strong>() can differ from the precision of the expression
+&#8220;a * b + c&#8221;.</p>
+</li>
+<li>
+<p><strong>fma</strong>() will be computed with the same precision as any other <strong>fma</strong>()
+consumed by a precise variable, giving invariant results for the same
+input values of <em>a</em>, <em>b</em>, and <em>c</em>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Otherwise, in the absence of <strong>precise</strong> consumption, there are no special
+constraints on the number of operations or difference in precision between
+<strong>fma</strong>() and the expression &#8220;_a_ * <em>b</em> + <em>c</em>&#8221;.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>frexp</strong>(highp genFType <em>x</em>, out highp genIType <em>exp</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Splits <em>x</em> into a floating-point significand in the range
+      <span class="eq">[0.5,1.0]</span>, and an integral exponent of two, such that</p>
+<p class="tableblock">      <span class="eq">x = significant · 2<sup>exponent</sup></span></p>
+<p class="tableblock">      The significand is returned by the function and the exponent is
+      returned in the parameter <em>exp</em>.
+      For a floating-point value of zero, the significand and exponent are
+      both zero.</p>
+<p class="tableblock">      If an implementation supports signed zero, an input value of minus
+      zero should return a significand of minus zero.
+      For a floating-point value that is an infinity or is not a number, the
+      results are undefined.</p>
+<p class="tableblock">      If the input <em>x</em> is a vector, this operation is performed in a
+      component-wise manner; the value returned by the function and the
+      value written to <em>exp</em> are vectors with the same number of components
+      as <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ldexp</strong>(highp genFType <em>x</em>, highp genIType <em>exp</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Builds a floating-point number from <em>x</em> and the corresponding integral
+      exponent of two in <em>exp</em>, returning:</p>
+<p class="tableblock">      <span class="eq">significand · 2<sup>exponent</sup></span></p>
+<p class="tableblock">      If this product is too large to be represented in the floating-point
+      type, the result is undefined.</p>
+<p class="tableblock">      If <em>exp</em> is greater than +128, the value returned is undefined.
+      If <em>exp</em> is less than -126, the value returned may be flushed to zero.
+      Additionally, splitting the value into a significand and exponent
+      using <strong>frexp</strong>() and then reconstructing a floating-point value using
+      <strong>ldexp</strong>() should yield the original input for zero and all finite
+      non-denormalized values.<br>
+      If the input <em>x</em> is a vector, this operation is performed in a
+      component-wise manner; the value passed in <em>exp</em> and returned by the
+      function are vectors with the same number of components as <em>x</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</h3>
+<div class="paragraph">
+<p>These functions do not operate component-wise, rather, as described in each
+case.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>packUnorm2x16</strong>(vec2 <em>v</em>)<br>
+  highp uint <strong>packSnorm2x16</strong>(vec2 <em>v</em>)<br>
+  highp uint <strong>packUnorm4x8</strong>(vec4 <em>v</em>)<br>
+  highp uint <strong>packSnorm4x8</strong>(vec4 <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">First, converts each component of the normalized floating-point value
+      <em>v</em> into 16-bit (<strong>2x16</strong>) or 8-bit (<strong>4x8</strong>) integer values.
+      Then, the results are packed into the returned 32-bit unsigned
+      integer.</p>
+<p class="tableblock">      The conversion for component <em>c</em> of <em>v</em> to fixed point is done as
+      follows:</p>
+<p class="tableblock">      <strong>packUnorm2x16</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 65535.0)<br>
+      <strong>packSnorm2x16:</strong> <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 32767.0)<br>
+      <strong>packUnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 255.0)<br>
+      <strong>packSnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 127.0)</p>
+<p class="tableblock">      The first component of the vector will be written to the least
+      significant bits of the output; the last component will be written to
+      the most significant bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp vec2 <strong>unpackUnorm2x16</strong>(highp uint <em>p</em>)<br>
+  highp vec2 <strong>unpackSnorm2x16</strong>(highp uint <em>p</em>)<br>
+  mediump vec4 <strong>unpackUnorm4x8</strong>(highp uint <em>p</em>)<br>
+  mediump vec4 <strong>unpackSnorm4x8</strong>(highp uint <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">First, unpacks a single 32-bit unsigned integer <em>p</em> into a pair of
+      16-bit unsigned integers, a pair of 16-bit signed integers, four 8-bit
+      unsigned integers, or four 8-bit signed integers, respectively.
+      Then, each component is converted to a normalized floating-point value
+      to generate the returned two- or four-component vector.</p>
+<p class="tableblock">      The conversion for unpacked fixed-point value <em>f</em> to floating-point is
+      done as follows:</p>
+<p class="tableblock">      <strong>unpackUnorm2x16</strong>: <em>f</em> / 65535.0<br>
+      <strong>unpackSnorm2x16</strong>: <strong>clamp</strong>(<em>f</em> / 32767.0, -1, +1)<br>
+      <strong>unpackUnorm4x8</strong>: <em>f</em> / 255.0<br>
+      <strong>unpackSnorm4x8</strong>: <strong>clamp</strong>(<em>f</em> / 127.0, -1, +1)</p>
+<p class="tableblock">      The first component of the returned vector will be extracted from the
+      least significant bits of the input; the last component will be
+      extracted from the most significant bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>packHalf2x16</strong>(vec2 <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns an unsigned integer obtained by converting the components of a
+      two-component floating-point vector to the 16-bit floating-point
+      representation found in the <a href="#references">OpenGL ES Specification</a>, and
+      then packing these two 16-bit integers into a 32-bit unsigned integer.</p>
+<p class="tableblock">      The first vector component specifies the 16 least-significant bits of
+      the result; the second component specifies the 16 most-significant
+      bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mediump vec2 <strong>unpackHalf2x16</strong>(highp uint <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a two-component floating-point vector with components obtained
+      by unpacking a 32-bit unsigned integer into a pair of 16-bit values,
+      interpreting those values as 16-bit floating-point numbers according
+      to the <a href="#references">OpenGL ES Specification</a>, and converting them to
+      32-bit floating-point values.</p>
+<p class="tableblock">      The first component of the vector is obtained from the 16
+      least-significant bits of <em>v</em>; the second component is obtained from
+      the 16 most-significant bits of <em>v</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="geometric-functions">8.5. Geometric Functions</h3>
+<div class="paragraph">
+<p>These operate on vectors as vectors, not component-wise.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>length</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the length of vector <em>x</em>, i.e.,
+      <span class="eq">sqrt( x<sub>0</sub><sup>2</sup> + x<sub>1</sub><sup>2</sup> + &#8230;&#8203; )</span>.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>distance</strong>(genFType <em>p0</em>, genFType <em>p1</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the distance between <em>p0</em> and <em>p1</em>, i.e.,
+      <strong>length</strong>(<em>p0</em> - <em>p1</em>)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>dot</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dot product of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">x<sub>0</sub> · y<sub>0</sub> + x<sub>1</sub> · y<sub>1</sub> + &#8230;&#8203;</span></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec3 <strong>cross</strong>(vec3 <em>x</em>, vec3 <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the cross product of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">(x<sub>1</sub> · y<sub>2</sub> - y<sub>1</sub> · x<sub>2</sub>,
+            x<sub>2</sub> · y<sub>0</sub> - y<sub>2</sub> · x<sub>0</sub>,
+            x<sub>0</sub> · y<sub>1</sub> - y<sub>0</sub> · x<sub>1</sub>)</span>.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>normalize</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a vector in the same direction as <em>x</em> but with a length of 1,
+      i.e. <em>x</em> / <strong>length</strong>(x).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>faceforward</strong>(genFType <em>N</em>, genFType <em>I</em>, genFType <em>Nref</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">If <strong>dot</strong>(<em>Nref</em>, <em>I</em>) &lt; 0 return <em>N</em>, otherwise return -<em>N</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>reflect</strong>(genFType <em>I</em>, genFType <em>N</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">For the incident vector <em>I</em> and surface orientation <em>N</em>, returns the
+      reflection direction: <span class="eq">I - 2 · <strong>dot</strong>(N, I) · N</span>.
+      <em>N</em> must already be normalized in order to achieve the desired result.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>refract</strong>(genFType <em>I</em>, genFType <em>N</em>, float <em>eta</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>For the incident vector <em>I</em> and surface normal <em>N</em>, and the ratio of
+      indices of refraction <em>eta</em>, return the refraction vector.
+      The result is computed by the <a href="#refraction-equation">refraction
+      equation</a> shown below.</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>The input parameters for the incident vector _I_ and the surface
+normal _N_ must already be normalized to get the desired results.</pre>
+</div>
+</div></div></td>
+</tr>
+</tbody>
+</table>
+<div class="sect3">
+<h4 id="refraction-equation">8.5.1. Refraction Equation</h4>
+<div class="stemblock">
+<div class="content">
+\[k = 1.0 - eta * eta * (1.0 - \textbf{dot}(N,I) \cdot \textbf{dot}(N,I))\]
+</div>
+</div>
+<div class="stemblock">
+<div class="content">
+\[\begin{aligned}
+result &amp;=
+  \begin{cases}
+    genFType(0.0), &amp; k &lt; 0.0 \\
+    eta * I - (eta * \textbf{dot}(N,I) + \sqrt { k }) * N, &amp; \textbf{otherwise}
+  \end{cases}
+\end{aligned}\]
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="matrix-functions">8.6. Matrix Functions</h3>
+<div class="paragraph">
+<p>For each of the following built-in matrix functions, there is both a
+single-precision floating-point version, where all arguments and return
+values are single precision, and a double-precision floating-point version,
+where all arguments and return values are double precision.
+Only the single-precision floating-point version is shown.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat <strong>matrixCompMult</strong>(mat <em>x</em>, mat <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply matrix <em>x</em> by matrix <em>y</em> component-wise, i.e., result[i][j]
+      is the scalar product of <em>x</em>[i][j] and <em>y</em>[i][j].<br></p>
+<p class="tableblock">      Note: to get linear algebraic matrix multiplication, use the multiply
+      operator (<strong>*</strong>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec2 <em>r</em>)<br>
+  mat3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec3 <em>r</em>)<br>
+  mat4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec4 <em>r</em>)<br>
+  mat2x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec2 <em>r</em>)<br>
+  mat3x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec3 <em>r</em>)<br>
+  mat2x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec2 <em>r</em>)<br>
+  mat4x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec4 <em>r</em>)<br>
+  mat3x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec3 <em>r</em>)<br>
+  mat4x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec4 <em>r</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Treats the first parameter <em>c</em> as a column vector (matrix with one
+      column) and the second parameter <em>r</em> as a row vector (matrix with one
+      row) and does a linear algebraic matrix multiply <em>c</em> * <em>r</em>, yielding a
+      matrix whose number of rows is the number of components in <em>c</em> and
+      whose number of columns is the number of components in <em>r</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>transpose</strong>(mat2 <em>m</em>)<br>
+  mat3 <strong>transpose</strong>(mat3 <em>m</em>)<br>
+  mat4 <strong>transpose</strong>(mat4 <em>m</em>)<br>
+  mat2x3 <strong>transpose</strong>(mat3x2 <em>m</em>)<br>
+  mat3x2 <strong>transpose</strong>(mat2x3 <em>m</em>)<br>
+  mat2x4 <strong>transpose</strong>(mat4x2 <em>m</em>)<br>
+  mat4x2 <strong>transpose</strong>(mat2x4 <em>m</em>)<br>
+  mat3x4 <strong>transpose</strong>(mat4x3 <em>m</em>)<br>
+  mat4x3 <strong>transpose</strong>(mat3x4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the transpose of <em>m</em>.
+      The input matrix <em>m</em> is not modified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>determinant</strong>(mat2 <em>m</em>)<br>
+  float <strong>determinant</strong>(mat3 <em>m</em>)<br>
+  float <strong>determinant</strong>(mat4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the determinant of <em>m</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>inverse</strong>(mat2 <em>m</em>)<br>
+  mat3 <strong>inverse</strong>(mat3 <em>m</em>)<br>
+  mat4 <strong>inverse</strong>(mat4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the inverse of <em>m</em>.
+      The input matrix <em>m</em> is not modified.
+      The values in the returned matrix are undefined if <em>m</em> is singular or
+      poorly-conditioned (nearly singular).</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="vector-relational-functions">8.7. Vector Relational Functions</h3>
+<div class="paragraph">
+<p>Relational and equality operators (<strong>&lt;</strong>, <strong>&lt;=</strong>, <strong>&gt;</strong>, <strong>&gt;=</strong>, <strong>==</strong>, <strong>!=</strong>) are
+defined to operate on scalars and produce scalar Boolean results.
+For vector results, use the following built-in functions.
+Below, the following placeholders are used for the listed specific types:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Placeholder</th>
+<th class="tableblock halign-left valign-top">Specific Types Allowed</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec2, bvec3, bvec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">ivec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">ivec2, ivec3, ivec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uvec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uvec2, uvec3, uvec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec2, vec3, vec4</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>In all cases, the sizes of all the input and return vectors for any
+particular call must match.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThan</strong>(vec x, vec y)<br>
+  bvec <strong>lessThan</strong>(ivec x, ivec y)<br>
+  bvec <strong>lessThan</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x &lt; y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThanEqual</strong>(vec x, vec y)<br>
+  bvec <strong>lessThanEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>lessThanEqual</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≤ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThan</strong>(vec x, vec y)<br>
+  bvec <strong>greaterThan</strong>(ivec x, ivec y)<br>
+  bvec <strong>greaterThan</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x &gt; y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThanEqual</strong>(vec x, vec y)<br>
+  bvec <strong>greaterThanEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>greaterThanEqual</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≥ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>equal</strong>(vec x, vec y)<br>
+  bvec <strong>equal</strong>(ivec x, ivec y)<br>
+  bvec <strong>equal</strong>(uvec x, uvec y)<br>
+  bvec <strong>equal</strong>(bvec x, bvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x == y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>notEqual</strong>(vec x, vec y)<br>
+  bvec <strong>notEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>notEqual</strong>(uvec x, uvec y)<br>
+  bvec <strong>notEqual</strong>(bvec x, bvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≠ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>any</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if any component of <em>x</em> is <strong>true</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>all</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> only if all components of <em>x</em> are <strong>true</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>not</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise logical complement of <em>x</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="integer-functions">8.8. Integer Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.
+The notation [<em>a</em>, <em>b</em>] means the set of bits from bit-number <em>a</em> through
+bit-number <em>b</em>, inclusive.
+The lowest-order bit is bit 0.
+&#8220;Bit number&#8221; will always refer to counting up from the lowest-order bit as
+bit 0.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>uaddCarry</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out lowp genUType <em>carry</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Adds 32-bit unsigned integers <em>x</em> and <em>y</em>, returning the sum modulo
+      2<sup>32</sup>.
+      The value <em>carry</em> is set to zero if the sum was less than 2<sup>32</sup>, or
+      one otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>usubBorrow</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out lowp genUType <em>borrow</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Subtracts the 32-bit unsigned integer <em>y</em> from <em>x</em>, returning the
+      difference if non-negative, or 2<sup>32</sup> plus the difference otherwise.
+      The value <em>borrow</em> is set to zero if <span class="eq">x ≥ y</span>, or one
+      otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>umulExtended</strong>(highp genUType <em>x</em>, highp genUType <em>y</em>, out highp genUType <em>msb</em>, out highp genUType <em>lsb</em>)<br>
+  void <strong>imulExtended</strong>(highp genIType <em>x</em>, highp genIType <em>y</em>, out highp genIType <em>msb</em>, out highp genIType <em>lsb</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Multiplies 32-bit unsigned or signed integers <em>x</em> and <em>y</em>, producing a
+      64-bit result.
+      The 32 least-significant bits are returned in <em>lsb</em>.
+      The 32 most-significant bits are returned in <em>msb</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldExtract</strong>(genIType <em>value</em>, int <em>offset</em>, int <em>bits</em>)<br>
+  genUType <strong>bitfieldExtract</strong>(genUType <em>value</em>, int <em>offset</em>, int <em>bits</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Extracts bits <span class="eq">[offset, offset + bits - 1]</span> from <em>value</em>,
+      returning them in the least significant bits of the result.<br></p>
+<p class="tableblock">      For unsigned data types, the most significant bits of the result will
+      be set to zero.
+      For signed data types, the most significant bits will be set to the
+      value of bit <span class="eq">offset + bits - 1</span>.<br></p>
+<p class="tableblock">      If <em>bits</em> is zero, the result will be zero.
+      The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if
+      the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used
+      to store the operand.
+      Note that for vector versions of <strong>bitfieldExtract</strong>(), a single pair of
+      <em>offset</em> and <em>bits</em> values is shared for all components.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldInsert</strong>(genIType <em>base</em>, genIType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)<br>
+  genUType <strong>bitfieldInsert</strong>(genUType <em>base</em>, genUType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inserts the <em>bits</em> least significant bits of <em>insert</em> into <em>base</em>.</p>
+<p class="tableblock">      The result will have bits <span class="eq">[offset, offset + bits - 1]</span> taken from
+      bits <span class="eq">[0, bits - 1]</span> of <em>insert</em>, and all other bits taken
+      directly from the corresponding bits of <em>base</em>.
+      If <em>bits</em> is zero, the result will simply be <em>base</em>.
+      The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if
+      the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used
+      to store the operand.<br>
+      Note that for vector versions of <strong>bitfieldInsert</strong>(), a single pair of
+      <em>offset</em> and <em>bits</em> values is shared for all components.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldReverse</strong>(highp genIType <em>value</em>)<br>
+  genUType <strong>bitfieldReverse</strong>(highp genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Reverses the bits of <em>value</em>.
+      The bit numbered <em>n</em> of the result will be taken from bit <span class="eq">(bits -
+      1) - n</span> of <em>value</em>, where <em>bits</em> is the total number of bits used to
+      represent <em>value</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>bitCount</strong>(genIType <em>value</em>)<br>
+  lowp genIType <strong>bitCount</strong>(genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of one bits in the binary representation of
+      <em>value</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>findLSB</strong>(genIType <em>value</em>)<br>
+  lowp genIType <strong>findLSB</strong>(genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the least significant one bit in the binary
+      representation of <em>value</em>.
+      If <em>value</em> is zero, -1 will be returned.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">lowp genIType <strong>findMSB</strong>(highp genIType <em>value</em>)<br>
+  lowp genIType <strong>findMSB</strong>(highp genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the most significant bit in the binary
+      representation of <em>value</em>.</p>
+<p class="tableblock">      For positive integers, the result will be the bit number of the most
+      significant one bit.
+      For negative integers, the result will be the bit number of the most
+      significant zero bit.
+      For a <em>value</em> of zero or negative one, -1 will be returned.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="texture-functions">8.9. Texture Functions</h3>
+<div class="paragraph">
+<p>Texture lookup functions are available in all shading stages.
+However, level-of-detail is implicitly computed only for fragment shaders.
+Other shaders operate as though the base level-of-detail were computed as
+zero.
+The functions in the table below provide access to textures through
+samplers, as set up through the OpenGL ES API.
+Texture properties such as size, pixel format, number of dimensions,
+filtering method, number of mipmap levels, depth comparison, and so on are
+also defined by OpenGL ES API calls.
+Such properties are taken into account as the texture is accessed via the
+built-in functions defined below.</p>
+</div>
+<div class="paragraph">
+<p>Texture data can be stored by the GL as single-precision floating-point,
+unsigned normalized integer, unsigned integer or signed integer data.
+This is determined by the type of the internal format of the texture.</p>
+</div>
+<div class="paragraph">
+<p>Texture lookup functions are provided that can return their result as
+floating-point, unsigned integer or signed integer, depending on the sampler
+type passed to the lookup function.
+Care must be taken to use the right sampler type for texture access.
+The following table lists the supported combinations of sampler types and
+texture internal formats.
+Blank entries are unsupported.
+Doing a texture lookup will return undefined values for unsupported
+combinations.</p>
+</div>
+<div class="paragraph">
+<p>For depth/stencil textures, the internal texture format is determined by the
+component being accessed as set through the OpenGL ES API.
+When the depth/stencil texture mode is set to DEPTH_COMPONENT, the internal
+format of the depth component should be used.
+When the depth/stencil texture mode is set to STENCIL_INDEX, the internal format
+of the stencil component should be used.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Internal Texture Format</th>
+<th class="tableblock halign-left valign-top">Floating-Point Sampler Types</th>
+<th class="tableblock halign-left valign-top">Signed Integer Sampler Types</th>
+<th class="tableblock halign-left valign-top">Unsigned Integer Sampler Types</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Floating-point</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Normalized Integer</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Signed Integer</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Unsigned Integer</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>If an integer sampler type is used, the result of a texture lookup is an
+<strong>ivec4</strong>.
+If an unsigned integer sampler type is used, the result of a texture lookup
+is a <strong>uvec4</strong>.
+If a floating-point sampler type is used, the result of a texture lookup is
+a <strong>vec4</strong>.</p>
+</div>
+<div class="paragraph">
+<p>In the prototypes below, the &#8220;_g_&#8221; in the return type &#8220;_gvec4_&#8221; is used
+as a placeholder for nothing, &#8220;_i_&#8221;, or &#8220;_u_&#8221; making a return type of
+<strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong>.
+In these cases, the sampler argument type also starts with &#8220;_g_&#8221;,
+indicating the same substitution done on the return type; it is either a
+floating-point, signed integer, or unsigned integer sampler, matching the
+basic type of the return type, as described above.</p>
+</div>
+<div class="paragraph">
+<p>For shadow forms (the sampler parameter is a shadow-type), a depth
+comparison lookup on the depth texture bound to <em>sampler</em> is done as
+described in section
+8.20
+&#8220;Texture Comparison Modes&#8221; of the
+<a href="#references">OpenGL ES Specification</a>.
+See the table below for which component specifies <em>D<sub>ref</sub></em>.
+The texture bound to <em>sampler</em> must be a depth texture, or results are
+undefined.
+If a non-shadow texture call is made to a sampler that represents a depth
+texture with depth comparisons turned on, then results are undefined.
+If a shadow texture call is made to a sampler that represents a depth
+texture with depth comparisons turned off, then results are undefined.
+If a shadow texture call is made to a sampler that does not represent a
+depth texture, then results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>In all functions below, the <em>bias</em> parameter is optional for fragment
+shaders.
+The <em>bias</em> parameter is not accepted in any other shader stage.
+For a fragment shader, if <em>bias</em> is present, it is added to the implicit
+level-of-detail prior to performing the texture access operation.
+No <em>bias</em> or <em>lod</em> parameters for
+multisample textures, or texture buffers
+are supported because mipmaps are not allowed for these types of textures.</p>
+</div>
+<div class="paragraph">
+<p>The implicit level-of-detail is selected as follows: For a texture that is
+not mipmapped, the texture is used directly.
+If it is mipmapped and running in a fragment shader, the level-of-detail
+computed by the implementation is used to do the texture lookup.
+If it is mipmapped and running in a non-fragment shader, then the base
+texture is used.</p>
+</div>
+<div class="paragraph">
+<p>Some texture functions (non-&#8220;<strong>Lod</strong>&#8221; and non-&#8220;<strong>Grad</strong>&#8221; versions) may
+require implicit derivatives.
+Implicit derivatives are undefined within non-uniform control flow and for
+non-fragment shader texture fetches.</p>
+</div>
+<div class="paragraph">
+<p>For <strong>Cube</strong> forms, the direction of <em>P</em> is used to select which face to do a
+2-dimensional texture lookup in, as described in section 8.13 &#8220;Cube Map
+Texture Selection&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>For <strong>Array</strong> forms, the array layer used will be</p>
+</div>
+<div class="paragraph">
+<p>\(\max(0,\min(d-1,\left\lfloor layer + 0.5\right\rfloor))\)</p>
+</div>
+<div class="paragraph">
+<p>where <em>d</em> is the depth of the texture array and <em>layer</em> comes from the
+component indicated in the tables below.</p>
+</div>
+<div class="sect3">
+<h4 id="texture-query-functions">8.9.1. Texture Query Functions</h4>
+<div class="paragraph">
+<p>The <strong>textureSize</strong> functions query the dimensions of a specific texture level
+for a sampler.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp ivec2 <strong>textureSize</strong>(gsampler2D <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec3 <strong>textureSize</strong>(gsampler3D <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec2 <strong>textureSize</strong>(gsamplerCube <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec2 <strong>textureSize</strong>(sampler2DShadow <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec2 <strong>textureSize</strong>(samplerCubeShadow <em>sampler</em>, int <em>lod</em>)
+  highp ivec3 <strong>textureSize</strong>(gsamplerCubeArray <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec3 <strong>textureSize</strong>(samplerCubeArrayShadow <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec3 <strong>textureSize</strong>(gsampler2DArray <em>sampler</em>, int <em>lod</em>)<br>
+  highp ivec3 <strong>textureSize</strong>(sampler2DArrayShadow <em>sampler</em>, int <em>lod</em>)<br>
+  highp int <strong>textureSize</strong>(gsamplerBuffer <em>sampler</em>)<br>
+  highp ivec2 <strong>textureSize</strong>(gsampler2DMS <em>sampler</em>)<br>
+  highp ivec3 <strong>textureSize</strong>(gsampler2DMSArray <em>sampler</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of level <em>lod</em> (if present) for the texture
+      bound to <em>sampler</em>, as described in section
+      8.11 &#8220;Texture Queries&#8221; of the <a href="#references">OpenGL ES Specification</a>.<br>
+      The components in the return value are filled in, in order, with the
+      width, height, and depth of the texture.</p>
+<p class="tableblock">      For the array forms, the last component of the return value is the
+      number of layers in the texture array, or the number of cubes in the
+      texture cube map array.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="texel-lookup-functions">8.9.2. Texel Lookup Functions</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texture</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>[, float <em>bias</em>] )<br>
+  float <strong>texture</strong>(sampler2DShadow <em>sampler</em>, <em>vec3 _P</em> [, float <em>bias</em>])<br>
+  float <strong>texture</strong>(samplerCubeShadow <em>sampler</em>, <em>vec4 _P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  float <strong>texture</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>)<br>
+  float <strong>texture</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>compare</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Use the texture coordinate <em>P</em> to do a texture lookup in the texture
+      currently bound to <em>sampler</em>.</p>
+<p class="tableblock">      For shadow forms: When <em>compare</em> is present, it is used as <em>D<sub>ref</sub></em>
+      and the array layer comes from the last component of <em>P</em>.
+      When <em>compare</em> is not present, the last component of <em>P</em> is used as
+      <em>D<sub>ref</sub></em> and the array layer comes from the second to last component
+      of <em>P</em>.</p>
+<p class="tableblock">      For non-shadow forms: the array layer comes from the last component of
+      <em>P</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  float <strong>textureProj</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with projection.
+      The texture coordinates consumed from <em>P</em>, not including the last
+      component of <em>P</em>, are divided by the last component of <em>P</em> to
+      form projected coordinates <em>P'</em>.
+      The resulting third component of <em>P</em> in the shadow forms is used as
+      <em>D<sub>ref</sub></em>.
+      The third component of <em>P</em> is ignored when <em>sampler</em> has type
+      <strong>gsampler2D</strong> and <em>P</em> has type <strong>vec4</strong>.
+      After these values are computed, texture lookup proceeds as in
+      <strong>texture</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLod</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureLod</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Do a texture lookup as in <strong>texture</strong> but with explicit level-of-detail;
+      <em>lod</em> specifies <span class="eq">λ<sub>base</sub>]</span> and sets the partial derivatives
+      as follows:<br>
+      (See section 8.14 &#8220;Texture Minification&#8221; and equations 8.4-8.6 of
+      the <a href="#references">OpenGL ES Specification</a>.)<br>
+     <br>
+      <span class="eq">∂u / ∂x =
+           ∂v / ∂x =
+           ∂w / ∂x = 0</span>
+     <br>
+      <span class="eq">∂u / ∂y =
+           ∂v / ∂y =
+           ∂w / ∂y = 0</span></p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup as in <strong>texture</strong> but with <em>offset</em> added to the
+      <span class="eq">(u,v,w)</span> texel coordinates before looking up each texel.
+      The offset value must be a constant expression.
+      A limited range of offset values are supported; the minimum and
+      maximum offset values are implementation-dependent and given by
+      <em>gl_MinProgramTexelOffset</em> and <em>gl_MaxProgramTexelOffset</em>,
+      respectively.</p>
+<p class="tableblock">      Note that <em>offset</em> does not apply to the layer coordinate for texture
+      arrays.
+      This is explained in detail in section 8.14.2 &#8220;Coordinate Wrapping
+      and Texel Selection&#8221; of the <a href="#references">OpenGL ES Specification</a>, where <em>offset</em>
+      is <span class="eq">(δ<sub>u</sub>, δ<sub>v</sub>, δ<sub>w</sub>)</span>.<br>
+      Note that texel offsets are also not supported for cube maps.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetch</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>)
+  gvec4 <strong>texelFetch</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsamplerBuffer <em>sampler</em>, int <em>P</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2DMS <em>sampler</em>, ivec2 <em>P</em>, int <em>sample</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2DMSArray <em>sampler</em>, ivec3 <em>P</em>, int <em>sample</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Use integer texture coordinate <em>P</em> to lookup a single texel from
+      <em>sampler</em>.
+      The array layer comes from the last component of <em>P</em> for the array
+      forms.
+      The level-of-detail <em>lod</em> (if present) is as described in sections
+      11.1.3.2 &#8220;Texel Fetches&#8221; and 8.14.1 &#8220;Scale Factor and Level of
+      Detail&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetchOffset</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec3 <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Fetch a single texel as in <strong>texelFetch</strong>, offset by <em>offset</em> as
+      described in <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureProjOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup as described in <strong>textureProj</strong>, offset
+      by <em>offset</em> as described in <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLodOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureLodOffset</strong>(sampler2DShadow <em>sampler</em>,  <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset texture lookup with explicit level-of-detail.
+      See <strong>textureLod</strong> and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureProjLod</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup with explicit level-of-detail.
+      See <strong>textureProj</strong> and <strong>textureLod</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureProjLodOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset projective texture lookup with explicit level-of-detail.
+      See <strong>textureProj</strong>, <strong>textureLod</strong>, and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGrad</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler3D <em>sampler</em>,  <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(samplerCubeShadow <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Do a texture lookup as in <strong>texture</strong> but with <a href="#explicit-gradients">explicit gradients</a> as shown below.
+      The partial derivatives of <em>P</em> are with respect to window <em>x</em> and
+      window <em>y</em>.
+      For the cube version, the partial derivatives of <em>P</em> are assumed to be
+      in the coordinate system used before texture coordinates are projected
+      onto the appropriate cube face.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGradOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with both explicit gradient and offset, as
+      described in <strong>textureGrad</strong> and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  float <strong>textureProjGrad</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup both projectively, as described in <strong>textureProj</strong>,
+      and with explicit gradient as described in <strong>textureGrad</strong>.
+      The partial derivatives <em>dPdx</em> and <em>dPdy</em> are assumed to be already
+      projected.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureProjGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup projectively and with explicit gradient as
+      described in <strong>textureProjGrad</strong>, as well as with offset, as described in
+      <strong>textureOffset</strong>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="explicit-gradients">8.9.3. Explicit Gradients</h4>
+<div class="paragraph">
+<p>In the <strong>textureGrad</strong> functions described above, explicit gradients control
+texture lookups as follows:</p>
+</div>
+<div class="stemblock">
+<div class="content">
+\[\begin{aligned}
+  \frac{\partial{s}}{\partial{x}} &amp; = \frac{\partial{P.s}}{\partial{x}} \\[0.8em]
+  \frac{\partial{s}}{\partial{y}} &amp; = \frac{\partial{P.s}}{\partial{y}} \\[0.8em]
+  \frac{\partial{t}}{\partial{x}} &amp; = \frac{\partial{P.t}}{\partial{x}} \\[0.8em]
+  \frac{\partial{t}}{\partial{y}} &amp; = \frac{\partial{P.t}}{\partial{y}} \\[0.8em]
+  \frac{\partial{r}}{\partial{x}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for 2D} \\[0.8em]
+      \frac{\partial{P.p}}{\partial{x}}, &amp; \text{cube, other}
+    \end{cases} \\[2.5em]
+  \frac{\partial{r}}{\partial{y}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for 2D} \\[0.8em]
+      \frac{\partial{P.p}}{\partial{y}}, &amp; \text{cube, other}
+    \end{cases}
+\end{aligned}\]
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="texture-gather-functions">8.9.4. Texture Gather Functions</h4>
+<div class="paragraph">
+<p>The texture gather functions take components of a single floating-point
+vector operand as a texture coordinate, determine a set of four texels to
+sample from the base level-of-detail of the specified texture image, and
+return one component from each texel in a four-component result vector.</p>
+</div>
+<div class="paragraph">
+<p>When performing a texture gather operation, the minification and
+magnification filters are ignored, and the rules for LINEAR filtering in the
+<a href="#references">OpenGL ES Specification</a> are applied to the base level of the texture image
+to identify the four texels <em>i<sub>0</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, and <em>i<sub>0</sub>
+j<sub>0</sub></em>.
+The texels are then converted to texture base colors (<em>R<sub>s</sub></em>, <em>G<sub>s</sub></em>,
+<em>B<sub>s</sub></em>, <em>A<sub>s</sub></em>) according to table 15.1, followed by application of the
+texture swizzle as described in section 15.2.1 &#8220;Texture Access&#8221; of the
+<a href="#references">OpenGL ES Specification</a>.
+A four-component vector is assembled by taking the selected component from
+each of the post-swizzled texture source colors in the order (<em>i<sub>0</sub> j<sub>1</sub></em>,
+<em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, <em>i<sub>0</sub> j<sub>0</sub></em>).</p>
+</div>
+<div class="paragraph">
+<p>The selected component is identified by the optional <em>comp</em> argument, where
+the values zero, one, two, and three identify the <em>R<sub>s</sub></em>, <em>G<sub>s</sub></em>, <em>B<sub>s</sub></em>, or
+<em>A<sub>s</sub></em> component, respectively.
+If <em>comp</em> is omitted, it is treated as identifying the <em>R<sub>s</sub></em> component.</p>
+</div>
+<div class="paragraph">
+<p>Incomplete textures (see section 8.16 &#8220;Texture Completeness&#8221; of the
+<a href="#references">OpenGL ES Specification</a>) return a texture source color of (0,0,0,1) for all
+four source texels.</p>
+</div>
+<div class="paragraph">
+<p>For texture gather functions using a shadow sampler type, each of the four
+texel lookups perform a depth comparison against the depth reference value
+passed in (<em>refZ</em>), and returns the result of that comparison in the
+appropriate component of the result vector.</p>
+</div>
+<div class="paragraph">
+<p>As with other texture lookup functions, the results of a texture gather are
+undefined for shadow samplers if the texture referenced is not a depth
+texture or has depth comparisons disabled; or for non-shadow samplers if the
+texture referenced is a depth texture with depth comparisons enabled.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>textureGatherOffset</strong> built-in functions from the OpenGL ES Shading Language return a vector
+derived from sampling four texels in the image array of level <em>level<sub>base</sub></em>.
+For each of the four texel offsets specified by the <em>offsets</em> argument, the
+rules for the LINEAR minification filter are applied to identify a 2 ×
+2 texel footprint, from which the single texel T<sub>i0j0</sub> is selected.
+A four-component vector is then assembled by taking a single component from
+each of the four T<sub>i0j0</sub> texels in the same manner as for the
+<strong>textureGather</strong> function.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGather</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>[, int <em>comp</em>])<br>
+  vec4 <strong>textureGather</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(samplerCubeShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>refZ</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the value<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4(Sample_i0_j1(P, base).comp,
+     Sample_i1_j1(P, base).comp,
+     Sample_i1_j0(P, base).comp,
+     Sample_i0_j0(P, base).comp)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If specified, the value of <em>comp</em> must be a constant integer expression with
+a value of 0, 1, 2, or 3, identifying the <em>x</em>, <em>y</em>, <em>z</em>, or <em>w</em>
+post-swizzled component of the four-component vector lookup result for each
+texel, respectively.
+If <em>comp</em> is not specified, it is treated as 0, selecting the <em>x</em> component
+of each texel to generate the result.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em>, [ int <em>comp</em>])<br>
+  gvec4 <strong>textureGatherOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [ int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffset</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br>
+  vec4 <strong>textureGatherOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Perform a texture gather operation as in <strong>textureGather</strong> by <em>offset</em>
+      as described in <strong>textureOffset</strong> except that the <em>offset</em> can be
+      variable (non constant) and the implementation-dependent minimum and
+      maximum offset values are given by MIN_PROGRAM_TEXTURE_GATHER_OFFSET
+      and MAX_PROGRAM_TEXTURE_GATHER_OFFSET, respectively.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffsets</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offsets</em>[4] [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGatherOffsets</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offsets</em>[4]   [, int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffsets</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br>
+  vec4 <strong>textureGatherOffsets</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Operate identically to <strong>textureGatherOffset</strong> except that <em>offsets</em> is
+      used to determine the location of the four texels to sample.
+      Each of the four texels is obtained by applying the corresponding
+      offset in <em>offsets</em> as a (<em>u</em>, <em>v</em>) coordinate offset to <em>P</em>,
+      identifying the four-texel LINEAR footprint, and then selecting the
+      texel <em>i<sub>0</sub> j<sub>0</sub></em> of that footprint.
+      The specified values in <em>offsets</em> must be constant integral
+      expressions.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="atomic-counter-functions">8.10. Atomic Counter Functions</h3>
+<div class="paragraph">
+<p>The atomic-counter operations in this section operate atomically with
+respect to each other.
+They are atomic for any single counter, meaning any of these operations on a
+specific counter in one shader instantiation will be indivisible by any of
+these operations on the same counter from another shader instantiation.
+There is no guarantee that these operations are atomic with respect to other
+forms of access to the counter or that they are serialized when applied to
+separate counters.
+Such cases would require additional use of fences, barriers, or other forms
+of synchronization, if atomicity or serialization is desired.</p>
+</div>
+<div class="paragraph">
+<p>The underlying counter is a 32-bit unsigned integer.
+The result of operations will wrap to [0, 2<sup>32</sup>-1].</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterIncrement</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>increments the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the increment operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterDecrement</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>decrements the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns the value resulting from the decrement operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounter</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the counter value for <em>c</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="atomic-memory-functions">8.11. Atomic Memory Functions</h3>
+<div class="paragraph">
+<p>Atomic memory functions perform atomic operations on an individual signed or
+unsigned integer stored in buffer object or shared variable storage.
+All of the atomic memory operations read a value from memory, compute a new
+value using one of the operations described below, write the new value to
+memory, and return the original value read.
+The contents of the memory being updated by the atomic operation are
+guaranteed not to be modified by any other assignment or atomic memory
+function in any shader invocation between the time the original value is
+read and the time the new value is written.</p>
+</div>
+<div class="paragraph">
+<p>Atomic memory functions are supported only for a limited set of variables.
+A shader will fail to compile if the value passed to the <em>mem</em> argument of
+an atomic memory function does not correspond to a buffer or shared
+variable.
+It is acceptable to pass an element of an array or a single component of a
+vector to the <em>mem</em> argument of an atomic memory function, as long as the
+underlying array or vector is a buffer or shared variable.</p>
+</div>
+<div class="paragraph">
+<p>All the built-in functions in this section accept arguments with
+combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification,
+despite not having them listed in the prototypes.
+The atomic operation will operate as required by the calling argument&#8217;s
+memory qualification, not by the built-in function&#8217;s formal parameter memory
+qualification.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAdd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicAdd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents
+      <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMin</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicMin</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and
+      the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMax</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicMax</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value of <em>data</em> and
+      the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAnd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicAnd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of
+      <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicOr</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicOr</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of
+      <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicXor</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicXor</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the
+      value of <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicExchange</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicExchange</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCompSwap</strong>(inout uint <em>mem</em>, uint <em>compare</em>, uint <em>data</em>)<br>
+  int <strong>atomicCompSwap</strong>(inout int <em>mem</em>, int <em>compare</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of <em>mem</em>.
+      If the values are equal, the new value is given by <em>data</em>; otherwise,
+      it is taken from the original contents of <em>mem</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="image-functions">8.12. Image Functions</h3>
+<div class="paragraph">
+<p>Variables using one of the image basic types may be used by the built-in
+shader image memory functions defined in this section to read and write
+individual texels of a texture.
+Each image variable references an image unit, which has a texture image
+attached.</p>
+</div>
+<div class="paragraph">
+<p>When image memory functions below access memory, an individual texel in the
+image is identified using an (<em>i</em>), (<em>i, j</em>), or (<em>i, j, k</em>) coordinate
+corresponding to the values of <em>P</em>.
+The coordinates
+are used to select an individual texel in the manner described in section
+8.22
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>Loads and stores support float, integer, and unsigned integer types.
+The data types below starting &#8220;_gimage_&#8221; serve as placeholders meaning
+types starting either &#8220;<strong>image</strong>&#8221;, &#8220;<strong>iimage</strong>&#8221;, or &#8220;<strong>uimage</strong>&#8221; in the same
+way as <em>gvec</em> or <em>gsampler</em> in earlier sections.</p>
+</div>
+<div class="paragraph">
+<p>The <em>IMAGE_PARAMS</em> in the prototypes below is a placeholder representing
+18
+separate functions, each for a different type of image variable.
+The <em>IMAGE_PARAMS</em> placeholder is replaced by one of the following parameter
+lists:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2D <em>image</em>, ivec2 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage3D <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageCube <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageBuffer <em>image</em>, int <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2DArray <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageCubeArray <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>where each of the lines represents one of three different image variable
+types, and <em>image</em>,
+<em>P</em>
+specify the individual texel to operate on.
+The method for identifying the individual texel operated on from <em>image</em>,
+<em>P</em>,
+and the method for reading and writing the texel are specified in section
+8.22
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL ES Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>The atomic functions perform operations on individual texels or samples of
+an image variable.
+Atomic memory operations read a value from the selected texel, compute a new
+value using one of the operations described below, write the new value to
+the selected texel, and return the original value read.
+The contents of the texel being updated by the atomic operation are
+guaranteed not to be modified by any other image store or atomic function
+between the time the original value is read and the time the new value is
+written.</p>
+</div>
+<div class="paragraph">
+<p>Atomic memory operations are supported on only a subset of all image
+variable types; <em>image</em> must be either:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>a signed integer image variable (type starts &#8220;<strong>iimage</strong>&#8221;) and a format
+qualifier of <strong>r32i</strong>, used with a <em>data</em> argument of type <strong>int</strong>, or</p>
+</li>
+<li>
+<p>an unsigned integer image variable (type starts &#8220;<strong>uimage</strong>&#8221;) and a
+format qualifier of <strong>r32ui</strong>, used with a <em>data</em> argument of type <strong>uint</strong>,
+or</p>
+</li>
+<li>
+<p>a float image variable (type starts &#8220;<strong>image</strong>&#8221;) and a format qualifier
+of <strong>r32f</strong>, used with a <em>data</em> argument of type <strong>float</strong>
+(<strong>imageAtomicExchange</strong> only).</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>All the built-in functions in this section accept arguments with
+combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification,
+despite not having them listed in the prototypes.
+The image operation will operate as required by the calling argument&#8217;s
+memory qualification, not by the built-in function&#8217;s formal parameter memory
+qualification.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp ivec2 <strong>imageSize</strong>(readonly writeonly gimage2D <em>image</em>)<br>
+  highp ivec3 <strong>imageSize</strong>(readonly writeonly gimage3D <em>image</em>)<br>
+  highp ivec2 <strong>imageSize</strong>(readonly writeonly gimageCube <em>image</em>)<br>
+  highp ivec3 <strong>imageSize</strong>(readonly writeonly gimageCubeArray <em>image</em>)<br>
+  highp ivec3 <strong>imageSize</strong>(readonly writeonly gimage2DArray <em>image</em>)<br>
+  highp   int <strong>imageSize</strong>(readonly writeonly gimageBuffer <em>image</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of the image or images bound to <em>image</em>.
+      For arrayed images, the last component of the return value will hold
+      the size of the array.
+      Cube images only return the dimensions of one face, and the number of
+      cubes in the cube map array, if arrayed.<br>
+      Note: The qualification <strong>readonly writeonly</strong> accepts a variable
+      qualified with <strong>readonly</strong>, <strong>writeonly</strong>, both, or neither.
+      It means the formal argument will be used for neither reading nor
+      writing to the underlying memory.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp gvec4 <strong>imageLoad</strong>(readonly <em>IMAGE_PARAMS</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Loads the texel at the coordinate <em>P</em> from the image unit <em>image</em> (in
+      <em>IMAGE_PARAMS</em>).
+      When <em>image</em> and <em>P</em>
+      identify a valid texel, the bits used to represent the selected texel in
+      memory are converted to a <strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong> in the manner
+      described in section
+8.23
+      &#8220;Texture Image Loads and Stores&#8221; of the
+      <a href="#references">OpenGL ES Specification</a> and returned.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>imageStore</strong>(writeonly <em>IMAGE_PARAMS</em>, gvec4 <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Stores <em>data</em> into the texel at the coordinate <em>P</em> from the image
+      specified by <em>image</em>.
+      When <em>image</em> and <em>P</em>
+      identify a valid texel, the bits used to represent <em>data</em> are converted
+      to the format of the image unit in the manner described in section
+8.23
+      &#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL ES Specification</a>
+      and stored to the specified texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents of
+      the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and
+      the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value <em>data</em> and the
+      contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of
+      <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of
+      <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the
+      value of <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)<br>
+  highp float <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, float <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">highp uint <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, uint <em>compare</em>, uint <em>data</em>)<br>
+  highp int <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, int <em>compare</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of the selected
+      texel.
+      If the values are equal, the new value is given by <em>data</em>; otherwise,
+      it is taken from the original value loaded from the texel.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="geometry-shader-functions">8.13. Geometry Shader Functions</h3>
+<div class="paragraph">
+<p>These functions are only available in geometry shaders.
+They are described in more depth following the table.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EmitVertex</strong>()<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Emits the current values of output variables to the current output
+      primitive.
+      On return from this call, the values of output variables are
+      undefined.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EndPrimitive</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Completes the current output primitive and starts a new one.
+      No vertex is emitted.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The function <strong>EmitVertex</strong>() specifies that a vertex is completed.
+A vertex is added to the current output primitive using the current values
+of all built-in and user-defined output variables.
+The values of all output variables are undefined after a call to
+<strong>EmitVertex</strong>().
+If a geometry shader invocation has emitted more vertices than permitted by
+the output layout qualifier <strong>max_vertices</strong>, the results of calling
+<strong>EmitVertex</strong>() are undefined.</p>
+</div>
+<div class="paragraph">
+<p>The function <strong>EndPrimitive</strong>() specifies that the current output primitive is
+completed and a new output primitive (of the same type) will be started by
+any subsequent <strong>EmitVertex</strong>().
+This function does not emit a vertex.
+If the output layout is declared to be <strong>points</strong>, calling <strong>EndPrimitive</strong>() is
+optional.</p>
+</div>
+<div class="paragraph">
+<p>A geometry shader starts with an output primitive containing no vertices.
+When a geometry shader terminates, the current output primitive is
+automatically completed.
+It is not necessary to call <strong>EndPrimitive</strong>() if the geometry shader writes
+only a single primitive.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="fragment-processing-functions">8.14. Fragment Processing Functions</h3>
+<div class="paragraph">
+<p>Fragment processing functions are only available in fragment shaders.</p>
+</div>
+<div class="sect3">
+<h4 id="derivative-functions">8.14.1. Derivative Functions</h4>
+<div class="paragraph">
+<p>Derivatives may be computationally expensive and/or numerically unstable.
+Therefore, an OpenGL ES implementation may approximate the true derivatives
+by using a fast but not entirely accurate derivative computation.
+Derivatives are undefined within non-uniform control flow.</p>
+</div>
+<div class="paragraph">
+<p>The expected behavior of a derivative is specified using forward/backward
+differencing.</p>
+</div>
+<div class="paragraph">
+<p>Forward differencing:</p>
+</div>
+<div class="paragraph">
+<p>\(F(x+dx) - F(x) \sim dFdx(x) \cdot dx (1a)\)</p>
+</div>
+<div class="paragraph">
+<p>\(dFdx(x) \sim \frac{F(x+dx) - F(x)}{dx} (1b)\)</p>
+</div>
+<div class="paragraph">
+<p>Backward differencing:</p>
+</div>
+<div class="paragraph">
+<p>\(F(x-dx) - F(x) \sim -dFdx(x) \cdot dx (2a)\)</p>
+</div>
+<div class="paragraph">
+<p>\(dFdx(x) \sim \frac{F(x) - F(x-dx)}{dx} (2b)\)</p>
+</div>
+<div class="paragraph">
+<p>With single-sample rasterization, \(dx \leq 1.0\) in equations 1b
+and 2b.
+For multisample rasterization, \(dx &lt; 2.0\) in equations 1b and 2b.</p>
+</div>
+<div class="paragraph">
+<p>\(dFdy\) is approximated similarly, with <em>y</em> replacing <em>x</em>.</p>
+</div>
+<div class="paragraph">
+<p>An OpenGL ES implementation may use the above or other methods to perform
+the calculation, subject to the following conditions:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>The method may use piecewise linear approximations.
+Such linear approximations imply that higher order derivatives,
+<strong>dFdx</strong>(<strong>dFdx</strong>(<em>x</em>)) and above, are undefined.</p>
+</li>
+<li>
+<p>The method may assume that the function evaluated is continuous.
+Therefore derivatives within the body of a non-uniform conditional are
+undefined.</p>
+</li>
+<li>
+<p>The method may differ per fragment, subject to the constraint that the
+method may vary by window coordinates, not screen coordinates.
+The invariance requirement described in section 13.2 &#8220;Invariance&#8221; of
+the <a href="#references">OpenGL ES Specification</a>, is relaxed for derivative calculations,
+because the method may be a function of fragment location.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Other properties that are desirable, but not required, are:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Functions should be evaluated within the interior of a primitive
+(interpolated, not extrapolated).</p>
+</li>
+<li>
+<p>Functions for <strong>dFdx</strong> should be evaluated while holding <em>y</em> constant.
+Functions for <strong>dFdy</strong> should be evaluated while holding <em>x</em> constant.
+However, mixed higher order derivatives, like <strong>dFdx</strong>(<strong>dFdy</strong>(<em>y</em>)) and
+<strong>dFdy</strong>(<strong>dFdx</strong>(<em>x</em>)) are undefined.</p>
+</li>
+<li>
+<p>Derivatives of constant arguments should be 0.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>In some implementations, varying degrees of derivative accuracy may be
+obtained by providing GL hints (see section 19.1 &#8220;Hints&#8221; of the
+<a href="#references">OpenGL ES Specification</a>), allowing a user to make an image quality versus
+speed trade off.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdx</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the derivative in x using local differencing for the input
+      argument <em>p</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdy</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the derivative in y using local differencing for the input
+      argument <em>p</em>.<br>
+      <br>
+      These two functions are commonly used to estimate the filter width used
+      to anti-alias procedural textures. We are assuming that the expression
+      is being evaluated in parallel on a SIMD array so that at any given
+      point in time the value of the function is known at the grid points
+      represented by the SIMD array. Local differencing between SIMD array
+      elements can therefore be used to derive <strong>dFdx</strong>, <strong>dFdy</strong>, etc.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fwidth</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the sum of the absolute derivative in x and y using local
+      differencing for the input argument <em>p</em>, i.e., <strong>abs</strong>(<strong>dFdx</strong>(<em>p</em>))
+      + <strong>abs</strong>(<strong>dFdy</strong>(<em>p</em>));</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="interpolation-functions">8.14.2. Interpolation Functions</h4>
+<div class="paragraph">
+<p>Built-in interpolation functions are available to compute an interpolated
+value of a fragment shader input variable at a shader-specified (<em>x</em>, <em>y</em>)
+location.
+A separate (<em>x</em>, <em>y</em>) location may be used for each invocation of the
+built-in function, and those locations may differ from the default (<em>x</em>,
+<em>y</em>) location used to produce the default value of the input.
+For the <strong>interpolateAt*</strong> functions, the call will return a precision
+qualification matching the precision of the <em>interpolant</em> argument to the
+function call.</p>
+</div>
+<div class="paragraph">
+<p>For all of the interpolation functions, <em>interpolant</em> must be an l-value
+from an <strong>in</strong> declaration;
+this can be either a variable, or an array element.
+Component selection operators (e.g. <strong>.xy</strong>) may not be used when specifying <em>interpolant</em>.</p>
+</div>
+<div class="paragraph">
+<p>If <em>interpolant</em> is declared with the <strong>flat</strong> qualifier, the interpolated
+value will have the same value everywhere for a single primitive, so the
+location used for interpolation has no effect and the functions just return
+that same value.
+If <em>interpolant</em> is declared with the <strong>centroid</strong> qualifier, the value
+returned by <strong>interpolateAtSample</strong>() and <strong>interpolateAtOffset</strong>() will be
+evaluated at the specified location, ignoring the location normally used
+with the <strong>centroid</strong> qualifier.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtCentroid</strong>(float <em>interpolant</em>)<br>
+  vec2 <strong>interpolateAtCentroid</strong>(vec2 <em>interpolant</em>)<br>
+  vec3 <strong>interpolateAtCentroid</strong>(vec3 <em>interpolant</em>)<br>
+  vec4 <strong>interpolateAtCentroid</strong>(vec4 <em>interpolant</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> sampled at a location
+      inside both the pixel and the primitive being processed.
+      The value obtained would be the same value assigned to the input
+      variable if declared with the <strong>centroid</strong> qualifier.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtSample</strong>(float <em>interpolant</em>, int <em>sample</em>)<br>
+  vec2 <strong>interpolateAtSample</strong>(vec2 <em>interpolant</em>, int <em>sample</em>)<br>
+  vec3 <strong>interpolateAtSample</strong>(vec3 <em>interpolant</em>, int <em>sample</em>)<br>
+  vec4 <strong>interpolateAtSample</strong>(vec4 <em>interpolant</em>, int <em>sample</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable at the location
+      of sample number <em>sample</em>.
+      If multisample buffers are not available, the input variable will be
+      evaluated at the center of the pixel.
+      If sample <em>sample</em> does not exist, the position used to interpolate
+      the input variable is undefined.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtOffset</strong>(float <em>interpolant</em>, vec2 offset)<br>
+  vec2 <strong>interpolateAtOffset</strong>(vec2 <em>interpolant</em>, vec2 offset)<br>
+  vec3 <strong>interpolateAtOffset</strong>(vec3 <em>interpolant</em>, vec2 offset)<br>
+  vec4 <strong>interpolateAtOffset</strong>(vec4 <em>interpolant</em>, vec2 offset)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable sampled at an
+      offset from the center of the pixel specified by <em>offset</em>.
+      The two floating-point components of <em>offset</em>, give the offset in
+      pixels in the <em>x</em> and <em>y</em> directions, respectively.<br>
+      An offset of (0, 0) identifies the center of the pixel.
+      The range and granularity of offsets supported by this function is
+      implementation-dependent.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="shader-invocation-control-functions">8.15. Shader Invocation Control Functions</h3>
+<div class="paragraph">
+<p>The shader invocation control function is only available in tessellation
+control and compute shaders.
+It is used to control the relative execution order of multiple shader
+invocations used to process a patch (in the case of tessellation control
+shaders) or a workgroup (in the case of compute shaders), which are
+otherwise executed with an undefined relative order.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>barrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">For any given static instance of <strong>barrier</strong>(), all tessellation control
+      shader invocations for a single input patch must enter it before any
+      will be allowed to continue beyond it, or all compute shader
+      invocations for a single workgroup must enter it before any will
+      continue beyond it.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The function <strong>barrier</strong>() provides a partially defined order of execution
+between shader invocations.
+The ensures that, for some types of memory accesses, values written by one
+invocation prior to a given static instance of <strong>barrier</strong>() can be safely read
+by other invocations after their call to the same static instance <strong>barrier</strong>().
+Because invocations may execute in an undefined order between these barrier
+calls, the values of a per-vertex or per-patch output variable for tessellation
+control shaders, or the values of <strong>shared</strong> variables for compute shaders will be
+undefined in a number of cases enumerated in
+&#8220;<a href="#output-variables">Output Variables</a>&#8221; (for tessellation control shaders)
+and &#8220;<a href="#shared-variables">Shared Variables</a>&#8221; (for compute shaders).</p>
+</div>
+<div class="paragraph">
+<p>For tessellation control shaders, the <strong>barrier</strong>() function may only be
+placed inside the function <strong>main</strong>() of the shader and may not be called
+within any control flow.
+Barriers are also disallowed after a return statement in the function
+<strong>main</strong>().
+Any such misplaced barriers result in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>A <strong>barrier</strong>() affects control flow but only synchronizes memory accesses
+to <strong>shared</strong> variables and tessellation control output variables.
+For other memory accesses, it does not ensure that values written by one invocation
+prior to a given static instance of <strong>barrier</strong>() can be safely read by other
+invocations after their call to the same static instance of <strong>barrier</strong>().
+To achieve this requires the use of both <strong>barrier</strong>() and a memory barrier.</p>
+</div>
+<div class="paragraph">
+<p>For compute shaders, the <strong>barrier</strong>() function may be placed within control
+flow, but that control flow must be uniform control flow.
+That is, all the controlling expressions that lead to execution of the
+barrier must be dynamically uniform expressions.
+This ensures that if any shader invocation enters a conditional statement,
+then all invocations will enter it.
+While compilers are encouraged to give warnings if they can detect this
+might not happen, compilers cannot completely determine this.
+Hence, it is the author&#8217;s responsibility to ensure <strong>barrier</strong>() only exists
+inside uniform control flow.
+Otherwise, some shader invocations will stall indefinitely, waiting for a
+barrier that is never reached by other invocations.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="shader-memory-control-functions">8.16. Shader Memory Control Functions</h3>
+<div class="paragraph">
+<p>Within a single shader invocation, the visibility and order of writes made
+by that invocation are well-defined.
+However, the relative order of reads and writes to a single shared memory
+address from multiple separate shader invocations is largely undefined.
+Additionally, the order of accesses to multiple memory addresses performed
+by a single shader invocation, as observed by other shader invocations, is
+also undefined.</p>
+</div>
+<div class="paragraph">
+<p>The following built-in functions can be used to control the ordering of
+reads and writes:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions issued by a single shader
+      invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierAtomicCounter</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of accesses to atomic-counter variables issued by
+      a single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierBuffer</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to buffer variables issued
+      within a single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierShared</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to shared variables issued
+      within a single shader invocation, as viewed by other invocations in
+      the same workgroup.<br>
+      Only available in compute shaders.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierImage</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to images issued within a
+      single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>groupMemoryBarrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of all memory transactions issued within a single
+      shader invocation, as viewed by other invocations in the same workgroup.<br>
+      Only available in compute shaders.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The memory barrier built-in functions can be used to order reads and writes
+to variables stored in memory accessible to other shader invocations.
+When called, these functions will wait for the completion of all reads and
+writes previously performed by the caller that access selected variable
+types, and then return with no other effect.
+The built-in functions <strong>memoryBarrierAtomicCounter</strong>(),
+<strong>memoryBarrierBuffer</strong>(), <strong>memoryBarrierImage</strong>(), and <strong>memoryBarrierShared</strong>()
+wait for the completion of accesses to atomic counter, buffer, image, and
+shared variables, respectively.
+The built-in functions <strong>memoryBarrier</strong>() and <strong>groupMemoryBarrier</strong>() wait for
+the completion of accesses to all of the above variable types.
+The functions <strong>memoryBarrierShared</strong>() and <strong>groupMemoryBarrier</strong>() are
+available only in compute shaders; the other functions are available in all
+shader types.</p>
+</div>
+<div class="paragraph">
+<p>When these functions return, the effects of any memory stores performed
+using coherent variables prior to the call will be visible to any
+future<sup>1</sup> coherent access to the same memory performed by any other shader
+invocation.
+In particular, the values written this way in one shader stage are
+guaranteed to be visible to coherent memory accesses performed by shader
+invocations in subsequent stages when those invocations were triggered by
+the execution of the original shader invocation (e.g. fragment shader
+invocations for a primitive resulting from a particular geometry
+shader invocation).</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">1</dt>
+<dd>
+<p>An access is only a <em>future</em> access if a <em>happens-before</em> relation can
+be established between the store and the load.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Additionally, memory barrier functions order stores performed by the calling
+invocation, as observed by other shader invocations.
+Without memory barriers, if one shader invocation performs two stores to
+coherent variables, a second shader invocation might see the values written
+by the second store prior to seeing those written by the first.
+However, if the first shader invocation calls a memory barrier function
+between the two stores, selected other shader invocations will never see the
+results of the second store before seeing those of the first.
+When using the functions <strong>groupMemoryBarrier</strong>() or <strong>memoryBarrierShared</strong>(),
+this ordering guarantee applies only to other shader invocations in the same
+compute shader workgroup; all other memory barrier functions provide the
+guarantee to all other shader invocations.
+No memory barrier is required to guarantee the order of memory stores as
+observed by the invocation performing the stores; an invocation reading from
+a variable that it previously wrote will always see the most recently
+written value unless another shader invocation also wrote to the same
+memory.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="shader-interface-matching">9. Shader Interface Matching</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>As described in chapter 7 of the <a href="#references">OpenGL ES Specification</a>, shaders may be
+linked together to form a <em>program object</em> before being bound to the
+pipeline or may be linked and bound individually as <em>separable program
+objects</em>.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="title">Note</div>
+<div class="paragraph">
+<p>These were previously known as separate shader objects (SSOs) but the
+mechanism has been extended to support future versions of the specification
+that have more than two shader stages.
+It allows a subset of the shaders to be linked together.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>Within a <em>program object</em> or a <em>separable program object</em>, qualifiers for
+matching variables must themselves match according to the rules specified in
+this section.
+There are also matching rules for qualifiers of matching variables between
+separable program objects but only for variables across an input/output
+boundary between shader stages.
+For other shader interface variables such as uniforms, each program object
+or separable program object has its own name space and so the same name can
+refer to multiple independent variables.
+Consequently, there are no matching rules for qualifiers in these cases.</p>
+</div>
+<div class="sect2">
+<h3 id="input-output-matching-by-name-in-linked-programs">9.1. Input Output Matching by Name in Linked Programs</h3>
+<div class="paragraph">
+<p>When linking shaders, the type of declared vertex outputs and fragment
+inputs with the same name must match, otherwise the link command will fail.
+Only those fragment inputs statically used (i.e. read) in the fragment
+shader must be declared as outputs in the vertex shader; declaring
+superfluous vertex shader outputs is permissible.</p>
+</div>
+<div class="paragraph">
+<p>The following table summarizes the rules for matching shader outputs to
+shader inputs in consecutive stages when shaders are linked together.</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+<col>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top" colspan="2" rowspan="2"><p class="tableblock">Treatment of Mismatched Input Variables</p></td>
+<td class="tableblock halign-left valign-top" colspan="3"><p class="tableblock">Consuming Shader (input variables)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared but no Static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared and Static Use</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="3"><p class="tableblock">Generating Shader (output variables)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">error</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declares; no static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are undefined)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declares and static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are potentially undefined)</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>See &#8220;<a href="#static-use">Static Use</a>&#8221; for the definition of <em>static use</em>.</p>
+</div>
+<div class="paragraph">
+<p>The precision of a vertex output does not need to match the precision of the
+corresponding fragment input.
+The minimum precision at which vertex outputs are interpolated is the
+minimum of the vertex output precision and the fragment input precision,
+with the exception that for <strong>highp</strong>, implementations do not have to support
+full IEEE 754 precision.</p>
+</div>
+<div class="paragraph">
+<p>The precision of values exported to a transform feedback buffer is the
+precision of the outputs of the vertex shader.
+However, they are converted to <strong>highp</strong> format before being written.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="matching-of-qualifiers">9.2. Matching of Qualifiers</h3>
+<div class="paragraph">
+<p>The following tables summarize the requirements for matching of qualifiers.
+It applies whenever there are two or more matching variables in a shader
+interface.</p>
+</div>
+<div class="paragraph">
+<p>Notes:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><em>Yes</em> means the qualifiers must match.</p>
+</li>
+<li>
+<p><em>No</em> means the qualifiers do not need to match.</p>
+</li>
+<li>
+<p><em>Consistent</em> means qualifiers may be missing from a subset of
+declarations but they cannot conflict</p>
+</li>
+<li>
+<p>If there are conflicting qualifiers, only the last of these is
+significant.</p>
+</li>
+<li>
+<p>Matching is based only on the resulting qualification, not on the
+presence or otherwise of qualifiers.</p>
+</li>
+<li>
+<p>The rules apply to all declared variables, irrespective of whether they
+are statically used, with the exception of inputs and outputs when
+shaders are linked (see
+&#8220;<a href="#input-output-matching-by-name-in-linked-programs">Input Output
+Matching by Name in Linked Programs</a>&#8221;).</p>
+</li>
+<li>
+<p>Errors are generated for any conflicts.</p>
+</li>
+</ol>
+</div>
+<div class="sect3">
+<h4 id="linked-shaders">9.2.1. Linked Shaders</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier Class</th>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top"><strong>in</strong>/<strong>out</strong></th>
+<th class="tableblock halign-left valign-top">Default Uniforms</th>
+<th class="tableblock halign-left valign-top"><strong>uniform</strong> Block</th>
+<th class="tableblock halign-left valign-top"><strong>buffer</strong> Block</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Storage<sup>1</sup></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong><br>
+                    <strong>out</strong><br>
+                    <strong>uniform</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">Auxiliary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong><br>
+                    <strong>sample</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="5"><p class="tableblock">Layout</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes<sup>2</sup></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Consistent</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Block layout<sup>3,4</sup></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Consistent</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">format</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Interpolation</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong><br>
+                    <strong>flat</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Precision</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong><br>
+                    <strong>mediump</strong><br>
+                    <strong>highp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Variance</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invariant</strong><br>
+                    <strong>precise</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Memory</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">all</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+</tbody>
+</table>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">1</dt>
+<dd>
+<p>Storage qualifiers determine <em>when</em> variables match rather than being
+<em>required</em> to match for matching variables.
+Note also that each shader interface has a separate name space so for
+example, it is possible to use the same name for a vertex output and
+fragment uniform.</p>
+</dd>
+<dt class="hdlist1">2</dt>
+<dd>
+<p>If present, the <strong>location</strong> qualifier determines the matching of inputs
+and outputs.
+See section 7.4.1 &#8220;Shader interface Matching&#8221; of the
+<a href="#references">OpenGL ES Specification</a> for details.]</p>
+</dd>
+<dt class="hdlist1">3</dt>
+<dd>
+<p>The <strong>row_major</strong> and <strong>column_major</strong> layout qualifiers do not need to
+match when applied to non-matrix types.</p>
+</dd>
+<dt class="hdlist1">4</dt>
+<dd>
+<p>In cases where a layout qualifier overrides a previous layout qualifier
+or a default, only the resulting qualification must match.</p>
+</dd>
+</dl>
+</div>
+</div>
+<div class="sect3">
+<h4 id="separable-programs">9.2.2. Separable Programs</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 33.3333%;">
+<col style="width: 33.3334%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier Class</th>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top"><strong>in</strong>/<strong>out</strong></th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Storage</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong><br>
+                    <strong>out</strong><br>
+                    <strong>uniform</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">Auxiliary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong><br>
+                    <strong>sample</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="5"><p class="tableblock">Layout</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Block layout</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">format</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Interpolation</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong><br>
+                    <strong>flat</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Precision</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong><br>
+                    <strong>mediump</strong><br>
+                    <strong>highp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Yes</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Variance</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invariant</strong><br>
+                    <strong>precise</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Memory</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">all</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">N/A</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="shading-language-grammar">10. Shading Language Grammar</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The grammar is fed from the output of lexical analysis.
+The tokens returned from lexical analysis are</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">CONST BOOL FLOAT INT UINT
+
+BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4
+
+MAT2 MAT3 MAT4 CENTROID IN OUT INOUT
+
+UNIFORM PATCH SAMPLE BUFFER SHARED
+
+COHERENT VOLATILE RESTRICT READONLY WRITEONLY
+
+FLAT SMOOTH LAYOUT
+
+MAT2X2 MAT2X3 MAT2X4
+
+MAT3X2 MAT3X3 MAT3X4
+
+MAT4X2 MAT4X3 MAT4X4
+
+
+
+
+
+ATOMIC_UINT
+
+SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER2DSHADOW
+
+SAMPLERCUBESHADOW SAMPLER2DARRAY SAMPLER2DARRAYSHADOW
+
+ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
+
+USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY
+
+
+
+
+
+
+SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER
+
+SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW
+
+ISAMPLERCUBEARRAY USAMPLERCUBEARRAY
+
+SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
+
+SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
+
+IMAGE2D IIMAGE2D UIMAGE2D
+
+IMAGE3D IIMAGE3D UIMAGE3D
+
+IMAGECUBE IIMAGECUBE UIMAGECUBE
+
+IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER
+
+IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY
+
+IMAGECUBEARRAY IIMAGECUBEARRAY UIMAGECUBEARRAY
+
+
+
+
+
+
+STRUCT VOID
+
+WHILE BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+
+IDENTIFIER TYPE_NAME
+
+FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT
+
+FIELD_SELECTION
+
+LEFT_OP RIGHT_OP
+
+INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+
+AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+
+MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+
+SUB_ASSIGN
+
+LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+
+COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+
+LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+INVARIANT PRECISE
+
+HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The following describes the grammar for the OpenGL ES Shading Language in terms of the above
+tokens.
+The starting rule is <em>translation_unit</em>.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>variable_identifier</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em></p>
+</dd>
+<dt class="hdlist1"><em>primary_expression</em> : </dt>
+<dd>
+<p><em>variable_identifier</em><br>
+<em>INTCONSTANT</em><br>
+<em>UINTCONSTANT</em><br>
+<em>FLOATCONSTANT</em><br>
+<em>BOOLCONSTANT</em><br>
+<em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>postfix_expression</em> : </dt>
+<dd>
+<p><em>primary_expression</em><br>
+<em>postfix_expression</em> <em>LEFT_BRACKET</em> <em>integer_expression</em> <em>RIGHT_BRACKET</em><br>
+<em>function_call</em><br>
+<em>postfix_expression</em> <em>DOT</em> <em>FIELD_SELECTION</em><br>
+<em>postfix_expression</em> <em>INC_OP</em><br>
+<em>postfix_expression</em> <em>DEC_OP</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>FIELD_SELECTION includes members in structures, component selection for
+vectors and the 'length' identifier for the length() method</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>integer_expression</em> : </dt>
+<dd>
+<p><em>expression</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call</em> : </dt>
+<dd>
+<p><em>function_call_or_method</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_or_method</em> : </dt>
+<dd>
+<p><em>function_call_generic</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_generic</em> : </dt>
+<dd>
+<p><em>function_call_header_with_parameters</em> <em>RIGHT_PAREN</em><br>
+<em>function_call_header_no_parameters</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header_no_parameters</em> : </dt>
+<dd>
+<p><em>function_call_header</em> <em>VOID</em><br>
+<em>function_call_header</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header_with_parameters</em> : </dt>
+<dd>
+<p><em>function_call_header</em> <em>assignment_expression</em><br>
+<em>function_call_header_with_parameters</em> <em>COMMA</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header</em> : </dt>
+<dd>
+<p><em>function_identifier</em> <em>LEFT_PAREN</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: Constructors look like functions, but lexical analysis
+recognized most of them as keywords.
+They are now recognized through <em>type_specifier</em>.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Methods (<strong>.length</strong>) and identifiers are recognized through
+<em>postfix_expression</em>.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function_identifier</em> : </dt>
+<dd>
+<p><em>type_specifier</em><br>
+<em>postfix_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>unary_expression</em> : </dt>
+<dd>
+<p><em>postfix_expression</em><br>
+<em>INC_OP</em> <em>unary_expression</em><br>
+<em>DEC_OP</em> <em>unary_expression</em><br>
+<em>unary_operator</em> <em>unary_expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No traditional style type casts.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>unary_operator</em> : </dt>
+<dd>
+<p><em>PLUS</em><br>
+<em>DASH</em><br>
+<em>BANG</em><br>
+<em>TILDE</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No '*' or '&amp;' unary ops.
+Pointers are not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>multiplicative_expression</em> : </dt>
+<dd>
+<p><em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>STAR</em> <em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>SLASH</em> <em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>PERCENT</em> <em>unary_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>additive_expression</em> : </dt>
+<dd>
+<p><em>multiplicative_expression</em><br>
+<em>additive_expression</em> <em>PLUS</em> <em>multiplicative_expression</em><br>
+<em>additive_expression</em> <em>DASH</em> <em>multiplicative_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>shift_expression</em> : </dt>
+<dd>
+<p><em>additive_expression</em><br>
+<em>shift_expression</em> <em>LEFT_OP</em> <em>additive_expression</em><br>
+<em>shift_expression</em> <em>RIGHT_OP</em> <em>additive_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>relational_expression</em> : </dt>
+<dd>
+<p><em>shift_expression</em><br>
+<em>relational_expression</em> <em>LEFT_ANGLE</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>RIGHT_ANGLE</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>LE_OP</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>GE_OP</em> <em>shift_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>equality_expression</em> : </dt>
+<dd>
+<p><em>relational_expression</em><br>
+<em>equality_expression</em> <em>EQ_OP</em> <em>relational_expression</em><br>
+<em>equality_expression</em> <em>NE_OP</em> <em>relational_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>and_expression</em> : </dt>
+<dd>
+<p><em>equality_expression</em><br>
+<em>and_expression</em> <em>AMPERSAND</em> <em>equality_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>exclusive_or_expression</em> : </dt>
+<dd>
+<p><em>and_expression</em><br>
+<em>exclusive_or_expression</em> <em>CARET</em> <em>and_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>inclusive_or_expression</em> : </dt>
+<dd>
+<p><em>exclusive_or_expression</em><br>
+<em>inclusive_or_expression</em> <em>VERTICAL_BAR</em> <em>exclusive_or_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_and_expression</em> : </dt>
+<dd>
+<p><em>inclusive_or_expression</em><br>
+<em>logical_and_expression</em> <em>AND_OP</em> <em>inclusive_or_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_xor_expression</em> : </dt>
+<dd>
+<p><em>logical_and_expression</em><br>
+<em>logical_xor_expression</em> <em>XOR_OP</em> <em>logical_and_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_or_expression</em> : </dt>
+<dd>
+<p><em>logical_xor_expression</em><br>
+<em>logical_or_expression</em> <em>OR_OP</em> <em>logical_xor_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>conditional_expression</em> : </dt>
+<dd>
+<p><em>logical_or_expression</em><br>
+<em>logical_or_expression</em> <em>QUESTION</em> <em>expression</em> <em>COLON</em>
+<em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>assignment_expression</em> : </dt>
+<dd>
+<p><em>conditional_expression</em><br>
+<em>unary_expression</em> <em>assignment_operator</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>assignment_operator</em> : </dt>
+<dd>
+<p><em>EQUAL</em><br>
+<em>MUL_ASSIGN</em><br>
+<em>DIV_ASSIGN</em><br>
+<em>MOD_ASSIGN</em><br>
+<em>ADD_ASSIGN</em><br>
+<em>SUB_ASSIGN</em><br>
+<em>LEFT_ASSIGN</em><br>
+<em>RIGHT_ASSIGN</em><br>
+<em>AND_ASSIGN</em><br>
+<em>XOR_ASSIGN</em><br>
+<em>OR_ASSIGN</em></p>
+</dd>
+<dt class="hdlist1"><em>expression</em> : </dt>
+<dd>
+<p><em>assignment_expression</em><br>
+<em>expression</em> <em>COMMA</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>constant_expression</em> : </dt>
+<dd>
+<p><em>conditional_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>declaration</em> : </dt>
+<dd>
+<p><em>function_prototype</em> <em>SEMICOLON</em><br>
+<em>init_declarator_list</em> <em>SEMICOLON</em><br>
+<em>PRECISION</em> <em>precision_qualifier</em> <em>type_specifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>identifier_list</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>identifier_list</em> : </dt>
+<dd>
+<p><em>COMMA</em> <em>IDENTIFIER</em><br>
+<em>identifier_list</em> <em>COMMA</em> <em>IDENTIFIER</em></p>
+</dd>
+<dt class="hdlist1"><em>function_prototype</em> : </dt>
+<dd>
+<p><em>function_declarator</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>function_declarator</em> : </dt>
+<dd>
+<p><em>function_header</em><br>
+<em>function_header_with_parameters</em></p>
+</dd>
+<dt class="hdlist1"><em>function_header_with_parameters</em> : </dt>
+<dd>
+<p><em>function_header</em> <em>parameter_declaration</em><br>
+<em>function_header_with_parameters</em> <em>COMMA</em> <em>parameter_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>function_header</em> : </dt>
+<dd>
+<p><em>fully_specified_type</em> <em>IDENTIFIER</em> <em>LEFT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_declarator</em> : </dt>
+<dd>
+<p><em>type_specifier</em> <em>IDENTIFIER</em><br>
+<em>type_specifier</em> <em>IDENTIFIER</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_declaration</em> : </dt>
+<dd>
+<p><em>type_qualifier</em> <em>parameter_declarator</em><br>
+<em>parameter_declarator</em><br>
+<em>type_qualifier</em> <em>parameter_type_specifier</em><br>
+<em>parameter_type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_type_specifier</em> : </dt>
+<dd>
+<p><em>type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>init_declarator_list</em> : </dt>
+<dd>
+<p><em>single_declaration</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em>
+<em>initializer</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+<dt class="hdlist1"><em>single_declaration</em> : </dt>
+<dd>
+<p><em>fully_specified_type</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em>
+<em>initializer</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No 'enum', or 'typedef'.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>fully_specified_type</em> : </dt>
+<dd>
+<p><em>type_specifier</em><br>
+<em>type_qualifier</em> <em>type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>invariant_qualifier</em> : </dt>
+<dd>
+<p><em>INVARIANT</em></p>
+</dd>
+<dt class="hdlist1"><em>interpolation_qualifier</em> : </dt>
+<dd>
+<p><em>SMOOTH</em><br>
+<em>FLAT</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier</em> : </dt>
+<dd>
+<p><em>LAYOUT</em> <em>LEFT_PAREN</em> <em>layout_qualifier_id_list</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier_id_list</em> : </dt>
+<dd>
+<p><em>layout_qualifier_id</em><br>
+<em>layout_qualifier_id_list</em> <em>COMMA</em> <em>layout_qualifier_id</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier_id</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em><br>
+<em>IDENTIFIER</em> <em>EQUAL</em> <em>INTCONSTANT</em><br>
+<em>IDENTIFIER</em> <em>EQUAL</em> <em>UINTCONSTANT</em><br>
+<em>SHARED</em></p>
+</dd>
+<dt class="hdlist1"><em>precise_qualifier</em> : </dt>
+<dd>
+<p><em>PRECISE</em></p>
+</dd>
+<dt class="hdlist1"><em>type_qualifier</em> : </dt>
+<dd>
+<p><em>single_type_qualifier</em><br>
+<em>type_qualifier</em> <em>single_type_qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>single_type_qualifier</em> : </dt>
+<dd>
+<p><em>storage_qualifier</em><br>
+<em>layout_qualifier</em><br>
+<em>precision_qualifier</em><br>
+<em>interpolation_qualifier</em><br>
+<em>invariant_qualifier</em><br>
+<em>precise_qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>storage_qualifier</em> : </dt>
+<dd>
+<p><em>CONST</em><br>
+<em>IN</em><br>
+<em>OUT</em><br>
+<em>INOUT</em><br>
+<em>CENTROID</em><br>
+<em>PATCH</em><br>
+<em>SAMPLE</em><br>
+<em>UNIFORM</em><br>
+<em>BUFFER</em><br>
+<em>SHARED</em><br>
+<em>COHERENT</em><br>
+<em>VOLATILE</em><br>
+<em>RESTRICT</em><br>
+<em>READONLY</em><br>
+<em>WRITEONLY</em></p>
+</dd>
+<dt class="hdlist1"><em>type_specifier</em> : </dt>
+<dd>
+<p><em>type_specifier_nonarray</em><br>
+<em>type_specifier_nonarray</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>array_specifier</em> : </dt>
+<dd>
+<p><em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br>
+<em>LEFT_BRACKET</em> <em>constant_expression</em> <em>RIGHT_BRACKET</em><br>
+<em>array_specifier</em> <em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br>
+<em>array_specifier</em> <em>LEFT_BRACKET</em> <em>constant_expression</em> <em>RIGHT_BRACKET</em></p>
+</dd>
+<dt class="hdlist1"><em>type_specifier_nonarray</em> : </dt>
+<dd>
+<p><em>VOID</em><br>
+<em>FLOAT</em><br>
+<em>INT</em><br>
+<em>UINT</em><br>
+<em>BOOL</em><br>
+<em>VEC2</em><br>
+<em>VEC3</em><br>
+<em>VEC4</em><br>
+<em>BVEC2</em><br>
+<em>BVEC3</em><br>
+<em>BVEC4</em><br>
+<em>IVEC2</em><br>
+<em>IVEC3</em><br>
+<em>IVEC4</em><br>
+<em>UVEC2</em><br>
+<em>UVEC3</em><br>
+<em>UVEC4</em><br>
+<em>MAT2</em><br>
+<em>MAT3</em><br>
+<em>MAT4</em><br>
+<em>MAT2X2</em><br>
+<em>MAT2X3</em><br>
+<em>MAT2X4</em><br>
+<em>MAT3X2</em><br>
+<em>MAT3X3</em><br>
+<em>MAT3X4</em><br>
+<em>MAT4X2</em><br>
+<em>MAT4X3</em><br>
+<em>MAT4X4</em><br>
+<em>ATOMIC_UINT</em><br>
+<em>SAMPLER2D</em><br>
+<em>SAMPLER3D</em><br>
+<em>SAMPLERCUBE</em><br>
+<em>SAMPLER2DSHADOW</em><br>
+<em>SAMPLERCUBESHADOW</em><br>
+<em>SAMPLER2DARRAY</em><br>
+<em>SAMPLER2DARRAYSHADOW</em><br>
+<em>SAMPLERCUBEARRAY</em><br>
+<em>SAMPLERCUBEARRAYSHADOW</em><br>
+<em>ISAMPLER2D</em><br>
+<em>ISAMPLER3D</em><br>
+<em>ISAMPLERCUBE</em><br>
+<em>ISAMPLER2DARRAY</em><br>
+<em>ISAMPLERCUBEARRAY</em><br>
+<em>USAMPLER2D</em><br>
+<em>USAMPLER3D</em><br>
+<em>USAMPLERCUBE</em><br>
+<em>USAMPLER2DARRAY</em><br>
+<em>USAMPLERCUBEARRAY</em><br>
+<em>SAMPLERBUFFER</em><br>
+<em>ISAMPLERBUFFER</em><br>
+<em>USAMPLERBUFFER</em><br>
+<em>SAMPLER2DMS</em><br>
+<em>ISAMPLER2DMS</em><br>
+<em>USAMPLER2DMS</em><br>
+<em>SAMPLER2DMSARRAY</em><br>
+<em>ISAMPLER2DMSARRAY</em><br>
+<em>USAMPLER2DMSARRAY</em><br>
+<em>IMAGE2D</em><br>
+<em>IIMAGE2D</em><br>
+<em>UIMAGE2D</em><br>
+<em>IMAGE3D</em><br>
+<em>IIMAGE3D</em><br>
+<em>UIMAGE3D</em><br>
+<em>IMAGECUBE</em><br>
+<em>IIMAGECUBE</em><br>
+<em>UIMAGECUBE</em><br>
+<em>IMAGEBUFFER</em><br>
+<em>IIMAGEBUFFER</em><br>
+<em>UIMAGEBUFFER</em><br>
+<em>IMAGE2DARRAY</em><br>
+<em>IIMAGE2DARRAY</em><br>
+<em>UIMAGE2DARRAY</em><br>
+<em>IMAGECUBEARRAY</em><br>
+<em>IIMAGECUBEARRAY</em><br>
+<em>UIMAGECUBEARRAY</em><br>
+<em>struct_specifier</em><br>
+<em>TYPE_NAME</em></p>
+</dd>
+<dt class="hdlist1"><em>precision_qualifier</em> : </dt>
+<dd>
+<p><em>HIGH_PRECISION</em><br>
+<em>MEDIUM_PRECISION</em><br>
+<em>LOW_PRECISION</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_specifier</em> : </dt>
+<dd>
+<p><em>STRUCT</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em><br>
+<em>STRUCT</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declaration_list</em> : </dt>
+<dd>
+<p><em>struct_declaration</em><br>
+<em>struct_declaration_list</em> <em>struct_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declaration</em> : </dt>
+<dd>
+<p><em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declarator_list</em> : </dt>
+<dd>
+<p><em>struct_declarator</em><br>
+<em>struct_declarator_list</em> <em>COMMA</em> <em>struct_declarator</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declarator</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em><br>
+<em>IDENTIFIER</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>initializer</em> : </dt>
+<dd>
+<p><em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>declaration_statement</em> : </dt>
+<dd>
+<p><em>declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>statement</em> : </dt>
+<dd>
+<p><em>compound_statement</em><br>
+<em>simple_statement</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: labeled statements for SWITCH only; 'goto' is not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>simple_statement</em> : </dt>
+<dd>
+<p><em>declaration_statement</em><br>
+<em>expression_statement</em><br>
+<em>selection_statement</em><br>
+<em>switch_statement</em><br>
+<em>case_label</em><br>
+<em>iteration_statement</em><br>
+<em>jump_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>compound_statement</em> : </dt>
+<dd>
+<p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br>
+<em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>statement_no_new_scope</em> : </dt>
+<dd>
+<p><em>compound_statement_no_new_scope</em><br>
+<em>simple_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>compound_statement_no_new_scope</em> : </dt>
+<dd>
+<p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br>
+<em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>statement_list</em> : </dt>
+<dd>
+<p><em>statement</em><br>
+<em>statement_list</em> <em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>expression_statement</em> : </dt>
+<dd>
+<p><em>SEMICOLON</em><br>
+<em>expression</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>selection_statement</em> : </dt>
+<dd>
+<p><em>IF</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>selection_rest_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>selection_rest_statement</em> : </dt>
+<dd>
+<p><em>statement</em> <em>ELSE</em> <em>statement</em><br>
+<em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>condition</em> : </dt>
+<dd>
+<p><em>expression</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+<dt class="hdlist1"><em>switch_statement</em> : </dt>
+<dd>
+<p><em>SWITCH</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>LEFT_BRACE</em>
+<em>switch_statement_list</em><br>
+<em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>switch_statement_list</em> : </dt>
+<dd>
+<p>/* <em>nothing</em> */<br>
+<em>statement_list</em></p>
+</dd>
+<dt class="hdlist1"><em>case_label</em> : </dt>
+<dd>
+<p><em>CASE</em> <em>expression</em> <em>COLON</em><br>
+<em>DEFAULT</em> <em>COLON</em></p>
+</dd>
+<dt class="hdlist1"><em>iteration_statement</em> : </dt>
+<dd>
+<p><em>WHILE</em> <em>LEFT_PAREN</em> <em>condition</em> <em>RIGHT_PAREN</em> <em>statement_no_new_scope</em><br>
+<em>DO</em> <em>statement</em> <em>WHILE</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em>
+<em>SEMICOLON</em><br>
+<em>FOR</em> <em>LEFT_PAREN</em> <em>for_init_statement</em> <em>for_rest_statement</em>
+<em>RIGHT_PAREN</em> <em>statement_no_new_scope</em></p>
+</dd>
+<dt class="hdlist1"><em>for_init_statement</em> : </dt>
+<dd>
+<p><em>expression_statement</em><br>
+<em>declaration_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>conditionopt</em> : </dt>
+<dd>
+<p><em>condition</em><br>
+/* <em>empty</em> */</p>
+</dd>
+<dt class="hdlist1"><em>for_rest_statement</em> : </dt>
+<dd>
+<p><em>conditionopt</em> <em>SEMICOLON</em><br>
+<em>conditionopt</em> <em>SEMICOLON</em> <em>expression</em></p>
+</dd>
+<dt class="hdlist1"><em>jump_statement</em> : </dt>
+<dd>
+<p><em>CONTINUE</em> <em>SEMICOLON</em><br>
+<em>BREAK</em> <em>SEMICOLON</em><br>
+<em>RETURN</em> <em>SEMICOLON</em><br>
+<em>RETURN</em> <em>expression</em> <em>SEMICOLON</em><br>
+<em>DISCARD</em> <em>SEMICOLON</em> // Fragment shader only.</p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No 'goto'.
+Gotos are not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>translation_unit</em> : </dt>
+<dd>
+<p><em>external_declaration</em><br>
+<em>translation_unit</em> <em>external_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>external_declaration</em> : </dt>
+<dd>
+<p><em>function_definition</em><br>
+<em>declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>function_definition</em> : </dt>
+<dd>
+<p><em>function_prototype</em> <em>compound_statement_no_new_scope</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>In general the above grammar describes a super set of the OpenGL ES Shading Language.
+Certain constructs that are valid purely in terms of the grammar are
+disallowed by statements elsewhere in this specification.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="counting-of-inputs-and-outputs">11. Counting of Inputs and Outputs</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This section applies to outputs from the last active vertex processing stage
+and inputs to the fragment stage.
+GLSL ES 3.20 specifies the storage available for such variables in terms of
+an array of 4-vectors.
+The assumption is that variables will be packed into these arrays without
+wasting space.
+This places significant burden on implementations since optimal packing is
+computationally intensive.
+Implementations may have more internal resources than exposed to the
+application and so avoid the need to perform packing but this is also
+considered an expensive solution.</p>
+</div>
+<div class="paragraph">
+<p>GLSL ES 3.20 therefore relaxes the requirements for packing by
+specifying a simpler algorithm that may be used.
+This algorithm specifies a minimum requirement for when a set of variables
+must be supported by an implementation.
+The implementation is allowed to support more than the minimum and so may
+use a more efficient algorithm and/or may support more registers than the
+virtual target machine.</p>
+</div>
+<div class="paragraph">
+<p>Outputs from the last active vertex stage and inputs to the fragment stage are
+counted separately.
+If statically used in the fragment shader, the built-in special variables
+(<em>gl_FragCoord</em>, <em>gl_FrontFacing</em> and <em>gl_PointCoord</em>) are included when
+calculating the storage requirements of fragment inputs.</p>
+</div>
+<div class="paragraph">
+<p>If the last active vertex-pipeline shader and fragment shader are linked
+together, inputs and outputs are only counted if they are statically used
+within the shader.
+If the shaders are each compiled into a separable program, all declared inputs
+and outputs are counted.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="title">Note</div>
+<div class="paragraph">
+<p>GLSL ES 3.20 does not require the implementation to remove
+outputs which are not statically used in the fragment shader.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>For the algorithm used, failing resource allocation for a variable must
+result in an error.</p>
+</div>
+<div class="paragraph">
+<p>The resource allocation of variables must succeed for all cases where the
+following packing algorithm succeeds:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The target architecture consists of a grid of registers, 16 rows by 4
+columns.
+Each register can contain a scalar value, i.e. a float, int or uint.</p>
+</li>
+<li>
+<p>Variables with an explicit location are allocated first.
+When attempting to allocate a location for other variables, if there is
+a conflict, the search moves to the next available free location.</p>
+</li>
+<li>
+<p>Structures are assumed to be flattened.
+Each data member is treated as if it were at global scope.</p>
+</li>
+<li>
+<p>Variables are packed into the registers one at a time so that they each
+occupy a contiguous sub-rectangle.
+No splitting of variables is permitted.</p>
+</li>
+<li>
+<p>The orientation of variables is fixed.
+Vectors always occupy registers in a single row.
+Elements of an array must be in different rows.
+E.g. <strong>vec4</strong> will always occupy one row; float[16] will occupy one
+column.
+Since it is not permitted to split a variable, large arrays e.g.
+float[32] will always fail with this algorithm.</p>
+</li>
+<li>
+<p>Non-square matrices of type <strong>matCxR</strong> consume the same space as a square
+matrix of type <strong>matN</strong> where N is the greater of C and R.
+Variables of type <strong>mat2</strong> occupies 2 complete rows.
+These rules allow implementations more flexibility in how variables are
+stored.
++ Other variables consume only the minimum space required.</p>
+</li>
+<li>
+<p>Arrays of size N are assumed to take N times the size of the base type.</p>
+</li>
+<li>
+<p>Variables are packed in the following order:</p>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><strong>mat4</strong> and arrays of <strong>mat4</strong>.</p>
+</li>
+<li>
+<p><strong>mat2</strong> and arrays of <strong>mat2</strong> (since they occupy full rows)</p>
+</li>
+<li>
+<p><strong>vec4</strong> and arrays of <strong>vec4</strong></p>
+</li>
+<li>
+<p><strong>mat3</strong> and arrays of <strong>mat3</strong></p>
+</li>
+<li>
+<p><strong>vec3</strong> and arrays of <strong>vec3</strong></p>
+</li>
+<li>
+<p><strong>vec2</strong> and arrays of <strong>vec2</strong></p>
+</li>
+<li>
+<p>Scalar types and arrays of scalar types</p>
+</li>
+</ol>
+</div>
+</li>
+<li>
+<p>For each of the above types, the arrays are processed in order of size,
+largest first.
+Arrays of size 1 and the base type are considered equivalent.
+The first type to be packed will be mat4[4], mat4[3], mat[2] followed by
+mat4, mat2[4]&#8230;&#8203;mat2[2], mat2, vec4[8], vec4[7],&#8230;&#8203;vec4[1], vec4,
+mat3[2], mat3 and so on.
+The last variables to be packed will be float (and float[1]).</p>
+</li>
+<li>
+<p>For 2,3 and 4 component variables packing is started using the 1<sup>st</sup>
+column of the 1<sup>st</sup> row.
+Variables are then allocated to successive rows, aligning them to the
+1<sup>st</sup> column.</p>
+</li>
+<li>
+<p>For 2 component variables, when there are no spare rows, the strategy is
+switched to using the highest numbered row and the lowest numbered
+column where the variable will fit.
+(In practice, this means they will be aligned to the x or z component.)
+Packing of any further 3 or 4 component variables will fail at this
+point.</p>
+</li>
+<li>
+<p>1 component variables (e.g. floats and arrays of floats) have their own
+packing rule.
+They are packed in order of size, largest first.
+Each variable is placed in the column that leaves the least amount of
+space in the column and aligned to the lowest available rows within that
+column.
+During this phase of packing, space will be available in up to 4
+columns.
+The space within each column is always contiguous in the case where no
+variables have explicit locations.</p>
+</li>
+<li>
+<p>For each type, variables with the 'smooth' property are packed first,
+followed by variables with the 'flat' property.</p>
+</li>
+<li>
+<p>Each row can contain either values with the 'smooth' property or the
+'flat' property but not both.
+If this situation is encountered during allocation, the algorithm skips
+the component location and continues with the next available location.
+These skipped locations may be used for other values later in the
+allocation process.</p>
+</li>
+<li>
+<p>There is no backtracking.
+Once a value is assigned a location, it cannot be changed, even if such
+a change is required for a successful allocation.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Example: pack the following types:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec4 a;     <span class="comment">// top left</span>
+out mat3 b;     <span class="comment">// align to left, lowest numbered rows</span>
+out mat2x3 c;   <span class="comment">// same size as mat3, align to left</span>
+out vec2 d[<span class="integer">6</span>];  <span class="comment">// align to left, lowest numbered rows</span>
+out vec2 e[<span class="integer">4</span>];  <span class="comment">// Cannot align to left so align to z column, highest</span>
+                <span class="comment">// numbered rows</span>
+out vec2 f;     <span class="comment">// Align to left, lowest numbered rows.</span>
+out <span class="predefined-type">float</span> g[<span class="integer">3</span>]  <span class="comment">// Column with minimum space</span>
+out <span class="predefined-type">float</span> h[<span class="integer">2</span>]; <span class="comment">// Column with minimum space (choice of 3, any</span>
+                <span class="comment">// can be used)</span>
+out <span class="predefined-type">float</span> i;    <span class="comment">// Column with minimum space</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In this example, the variables happen to be listed in the order in which
+they are packed.
+Packing is independent of the order of declaration.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 20%;">
+<col style="width: 20%;">
+<col style="width: 20%;">
+<col style="width: 20%;">
+<col style="width: 20%;">
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>x</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>y</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>z</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>w</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>a</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>b</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>c</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>g</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">12</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>d</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">13</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>f</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>f</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">14</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>h</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>i</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>h</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>e</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Some types e.g. mat4[8] will be too large to fit.
+These always fail with this algorithm.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="acknowledgments">12. Acknowledgments</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This specification is based on the work of those who contributed to past
+versions of the Open GL and Open GL ES Language Specifications and the
+following contributors to this version:</p>
+</div>
+<div class="paragraph">
+<p>Acorn Pooley, NVIDIA<br>
+Alberto Moreira, Qualcomm<br>
+Aleksandra Krstic, Qualcomm<br>
+Alon Or-bach, Nokia &amp; Samsung<br>
+Andrzej Kacprowski, Intel<br>
+Arzhange Safdarzadeh, Intel<br>
+Aske Simon Christensen, ARM<br>
+Avi Shapira, Graphic Remedy<br>
+Barthold Lichtenbelt, NVIDIA<br>
+Ben Bowman, Imagination Technologies<br>
+Ben Brierton, Broadcom<br>
+Benj Lipchak, Apple<br>
+Benson Tao, Vivante<br>
+Bill Licea-Kane, Qualcomm<br>
+Brent Insko, Intel<br>
+Brian Murray, Freescale<br>
+Bruce Merry, ARM<br>
+Carlos Santa, TI<br>
+Cass Everitt, Epic Games &amp; NVIDIA<br>
+Cemil Azizoglu, TI<br>
+Chang-Hyo Yu, Samsung<br>
+Chris Dodd, NVIDIA<br>
+Chris Knox, NVIDIA<br>
+Chris Tserng, TI<br>
+Clay Montgomery, TI<br>
+Daniel Kartch, NVIDIA<br>
+Daniel Koch, Transgaming&amp; NVIDIA<br>
+Daoxiang Gong, Imagination Technologies<br>
+Dave Shreiner, ARM<br>
+David Garcia, AMD<br>
+David Jarmon, Vivante<br>
+Derek Cornish, Epic Games<br>
+Dominick Witczak, Mobica<br>
+Eben Upton, Broadcom<br>
+Ed Plowman, ARM<br>
+Eisaku Ohbuchi, DMP<br>
+Elan Lennard, ARM<br>
+Erik Faye-Lund, ARM<br>
+Graham Connor, Imagination Technologies<br>
+Graham Sellers, AMD<br>
+Greg Roth, NVIDIA<br>
+Guillaume Portier, Hi Corporation<br>
+Guofang Jiao, Qualcomm<br>
+Hans-Martin Will, Vincent<br>
+Hwanyong Lee, Huone<br>
+I-Gene Leong, NVIDIA<br>
+Ian Romanick, Intel<br>
+Ian South-Dickinson, NVIDIA<br>
+Ilan Aelion-Exch, Samsung<br>
+Inkyun Lee, Huone<br>
+Jacob Strm, Ericsson<br>
+James Adams, Broadcom<br>
+James Jones, Imagination Technologies<br>
+James McCombe, Imagination Technologies<br>
+Jamie Gennis, Google<br>
+Jan-Harald Fredriksen, ARM<br>
+Jani Vaisanen, Nokia<br>
+Jarkko Kemppainen, Symbio<br>
+Jeff Bolz, NVIDIA<br>
+Jeff Leger, Qualcomm<br>
+Jeff Vigil, Qualcomm<br>
+Jeremy Sandmel, Apple<br>
+Jeremy Thorne, Broadcom<br>
+Jim Hauxwell, Broadcom<br>
+Jinsung Kim, Huone<br>
+Jiyoung Yoon, Huone<br>
+John Kessenich, Google<br>
+Jon Kennedy, 3DLabs<br>
+Jon Leech, Khronos<br>
+Jonathan Putsman, Imagination Technologies<br>
+Joohoon Lee, Samsung<br>
+JoukoKylmäoja, Symbio<br>
+Jrn Nystad, ARM<br>
+Jussi Rasanen, NVIDIA<br>
+Kalle Raita, drawElements<br>
+Kari Pulli, Nokia<br>
+Keith Whitwell, VMware<br>
+Kent Miller, Netlogic Microsystems<br>
+Kimmo Nikkanen, Nokia<br>
+Konsta Karsisto, Nokia<br>
+Krzysztof Kaminski, Intel<br>
+Larry Seiler, Intel<br>
+Lars Remes, Symbio<br>
+Lee Thomason, Adobe<br>
+Lefan Zhong, Vivante<br>
+Marcus Lorentzon, Ericsson<br>
+Mark Butler, Imagination Technologies<br>
+Mark Callow, Hi Corporation<br>
+Mark Cresswell, Broadcom<br>
+Mark Snyder, Alt Software<br>
+Mark Young, AMD<br>
+Mathieu Robart, STM<br>
+Matt Netsch, Qualcomm<br>
+Matt Russo, Matrox<br>
+Maurice Ribble, Qualcomm<br>
+Max Kazakov, DMP<br>
+Mika Pesonen, Nokia<br>
+Mike Cai, Vivante<br>
+Mike Weiblen, Zebra Imaging &amp; Qualcomm<br>
+Mila Smith, AMD<br>
+Nakhoon Baek, Kyungpook Univeristy<br>
+Nate Huang, NVIDIA<br>
+Neil Trevett, NVIDIA<br>
+Nelson Kidd, Intel<br>
+Nick Haemel, NVIDIA<br>
+Nick Penwarden, Epic Games<br>
+Niklas Smedberg, Epic Games<br>
+Nizar Romdan, ARM<br>
+Oliver Wohlmuth , Fujitsu<br>
+Pat Brown, NVIDIA<br>
+Paul Ruggieri, Qualcomm<br>
+Per Wennersten, Ericsson<br>
+Petri Talala, Symbio<br>
+Phil Huxley, ZiiLabs<br>
+Philip Hatcher, Freescale &amp; Intel<br>
+Piers Daniell, NVIDIA<br>
+Pyry Haulos, drawElements<br>
+Piotr Tomaszewski, Ericsson<br>
+Piotr Uminski, Intel<br>
+Rami Mayer, Samsung<br>
+Rauli Laatikainen, RightWare<br>
+Rob Barris, NVIDIA<br>
+Rob Simpson, Qualcomm<br>
+Roj Langhi, Vivante<br>
+Rune Holm, ARM<br>
+Sami Kyostila, Nokia<br>
+Sean Ellis, ARM<br>
+Shereef Shehata, TI<br>
+Sila Kayo, Nokia<br>
+Slawomir Cygan, Intel<br>
+Slawomir Grajewski, Intel<br>
+Steve Hill, STM &amp; Broadcom<br>
+Steven Olney, DMP<br>
+Suman Sharma, Intel<br>
+Tapani Palli, Nokia<br>
+Teemu Laakso, Symbio<br>
+Tero Karras, NVIDIA<br>
+Timo Suoranta, Imagination Technologies &amp; Broadcom<br>
+Tom Cooksey, ARM<br>
+Tom McReynolds, NVIDIA<br>
+Tom Olson, TI &amp; ARM<br>
+Tomi Aarnio, Nokia<br>
+Tommy Asano, Takumi<br>
+Wes Bang, Nokia<br>
+Yanjun Zhang, Vivante</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="references">13. Normative References</h2>
+<div class="sectionbody">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>International Standard ISO/IEC 14882:1998(E).
+Programming Languages - C++. Referenced for preprocessor only</p>
+</li>
+<li>
+<p>&#8220;OpenGL<sup>R</sup> ES, Version 3.2&#8221;,
+<a href="https://www.khronos.org/registry/OpenGL/index_es.php" class="bare">https://www.khronos.org/registry/OpenGL/index_es.php</a>, November 3, 2016.</p>
+</li>
+<li>
+<p>&#8220;The OpenGL<sup>R</sup> Graphics System: A Specification, Version 4.6 (Core
+Profile)&#8221;, <a href="https://www.khronos.org/registry/OpenGL/index_gl.php" class="bare">https://www.khronos.org/registry/OpenGL/index_gl.php</a>, June
+1, 2016.</p>
+</li>
+<li>
+<p>International Standard ISO/IEC 646:1991.
+Information technology - ISO 7-bit coded character set for information
+interchange</p>
+</li>
+<li>
+<p>The Unicode Standard Version 6.0 - Core Specification.</p>
+</li>
+<li>
+<p>IEEE 754-2008.
+<em>IEEE Standard for Floating-Point Arithmetic</em></p>
+</li>
+</ol>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Version 3.20.5<br>
+Last updated 2018-12-12 16:37:44 MST
+</div>
+</div>
+
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/specs/es/3.2/GLSL_ES_Specification_3.20.pdf b/specs/es/3.2/GLSL_ES_Specification_3.20.pdf
index 70434ce..c436090 100644
--- a/specs/es/3.2/GLSL_ES_Specification_3.20.pdf
+++ b/specs/es/3.2/GLSL_ES_Specification_3.20.pdf
Binary files differ
diff --git a/specs/es/3.2/es_spec_3.2.pdf b/specs/es/3.2/es_spec_3.2.pdf
index 93624e7..6c2b506 100644
--- a/specs/es/3.2/es_spec_3.2.pdf
+++ b/specs/es/3.2/es_spec_3.2.pdf
Binary files differ
diff --git a/specs/es/3.2/es_spec_3.2.withchanges.pdf b/specs/es/3.2/es_spec_3.2.withchanges.pdf
index 2d0ead6..04d5acc 100644
--- a/specs/es/3.2/es_spec_3.2.withchanges.pdf
+++ b/specs/es/3.2/es_spec_3.2.withchanges.pdf
Binary files differ
diff --git a/specs/es/3.2/katex/README.md b/specs/es/3.2/katex/README.md
new file mode 100644
index 0000000..5f8caa8
--- /dev/null
+++ b/specs/es/3.2/katex/README.md
@@ -0,0 +1,68 @@
+# [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX)
+
+[![Join the chat at https://gitter.im/Khan/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
+
+ * **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://jsperf.com/katex-vs-mathjax/).
+ * **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
+ * **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
+ * **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
+
+KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, and IE 8 - IE 11.  A list of supported  commands can be on the [wiki](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX).
+
+## Usage
+
+You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
+
+```html
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css">
+<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js"></script>
+```
+
+#### In-browser rendering
+
+Call `katex.render` with a TeX expression and a DOM element to render into:
+
+```js
+katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
+```
+
+If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
+
+#### Server side rendering or rendering to a string
+
+To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
+
+```js
+var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
+// '<span class="katex">...</span>'
+```
+
+Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
+
+#### Rendering options
+
+You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
+
+- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
+- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
+- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
+
+For example:
+
+```js
+katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true });
+```
+
+#### Automatic rendering of math on a page
+
+Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## License
+
+KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
diff --git a/specs/es/3.2/katex/contrib/auto-render.min.js b/specs/es/3.2/katex/contrib/auto-render.min.js
new file mode 100644
index 0000000..30cc312
--- /dev/null
+++ b/specs/es/3.2/katex/contrib/auto-render.min.js
@@ -0,0 +1 @@
+(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.renderMathInElement=e()}})(function(){var e,t,r;return function n(e,t,r){function a(o,l){if(!t[o]){if(!e[o]){var f=typeof require=="function"&&require;if(!l&&f)return f(o,!0);if(i)return i(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var s=t[o]={exports:{}};e[o][0].call(s.exports,function(t){var r=e[o][1][t];return a(r?r:t)},s,s.exports,n,e,t,r)}return t[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)a(r[o]);return a}({1:[function(e,t,r){var n=e("./splitAtDelimiters");var a=function(e,t){var r=[{type:"text",data:e}];for(var a=0;a<t.length;a++){var i=t[a];r=n(r,i.left,i.right,i.display||false)}return r};var i=function(e,t){var r=a(e,t);var n=document.createDocumentFragment();for(var i=0;i<r.length;i++){if(r[i].type==="text"){n.appendChild(document.createTextNode(r[i].data))}else{var o=document.createElement("span");var l=r[i].data;try{katex.render(l,o,{displayMode:r[i].display})}catch(f){if(!(f instanceof katex.ParseError)){throw f}console.error("KaTeX auto-render: Failed to parse `"+r[i].data+"` with ",f);n.appendChild(document.createTextNode(r[i].rawData));continue}n.appendChild(o)}}return n};var o=function(e,t,r){for(var n=0;n<e.childNodes.length;n++){var a=e.childNodes[n];if(a.nodeType===3){var l=i(a.textContent,t);n+=l.childNodes.length-1;e.replaceChild(l,a)}else if(a.nodeType===1){var f=r.indexOf(a.nodeName.toLowerCase())===-1;if(f){o(a,t,r)}}}};var l={delimiters:[{left:"$$",right:"$$",display:true},{left:"\\[",right:"\\]",display:true},{left:"\\(",right:"\\)",display:false}],ignoredTags:["script","noscript","style","textarea","pre","code"]};var f=function(e){var t;var r;for(var n=1,a=arguments.length;n<a;n++){t=arguments[n];for(r in t){if(Object.prototype.hasOwnProperty.call(t,r)){e[r]=t[r]}}}return e};var d=function(e,t){if(!e){throw new Error("No element provided to render")}t=f({},l,t);o(e,t.delimiters,t.ignoredTags)};t.exports=d},{"./splitAtDelimiters":2}],2:[function(e,t,r){var n=function(e,t,r){var n=r;var a=0;var i=e.length;while(n<t.length){var o=t[n];if(a<=0&&t.slice(n,n+i)===e){return n}else if(o==="\\"){n++}else if(o==="{"){a++}else if(o==="}"){a--}n++}return-1};var a=function(e,t,r,a){var i=[];for(var o=0;o<e.length;o++){if(e[o].type==="text"){var l=e[o].data;var f=true;var d=0;var s;s=l.indexOf(t);if(s!==-1){d=s;i.push({type:"text",data:l.slice(0,d)});f=false}while(true){if(f){s=l.indexOf(t,d);if(s===-1){break}i.push({type:"text",data:l.slice(d,s)});d=s}else{s=n(r,l,d+t.length);if(s===-1){break}i.push({type:"math",data:l.slice(d+t.length,s),rawData:l.slice(d,s+r.length),display:a});d=s+r.length}f=!f}i.push({type:"text",data:l.slice(d)})}else{i.push(e[o])}}return i};t.exports=a},{}]},{},[1])(1)});
diff --git a/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.eot
new file mode 100644
index 0000000..784276a
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.ttf
new file mode 100644
index 0000000..6f1e0be
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff
new file mode 100644
index 0000000..4dded47
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff2
new file mode 100644
index 0000000..ea81079
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_AMS-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.eot b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.eot
new file mode 100644
index 0000000..1a0db0c
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.ttf b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.ttf
new file mode 100644
index 0000000..b94907d
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff
new file mode 100644
index 0000000..799fa81
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff2
new file mode 100644
index 0000000..73bb542
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Bold.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.eot
new file mode 100644
index 0000000..6cc83d0
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.ttf
new file mode 100644
index 0000000..cf51e20
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff
new file mode 100644
index 0000000..f5e5c62
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff2
new file mode 100644
index 0000000..dd76d34
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Caligraphic-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.eot b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.eot
new file mode 100644
index 0000000..1960b10
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.ttf b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.ttf
new file mode 100644
index 0000000..7b0790f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff
new file mode 100644
index 0000000..dc32571
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff2
new file mode 100644
index 0000000..fdc4292
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Bold.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.eot
new file mode 100644
index 0000000..e4e7379
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.ttf
new file mode 100644
index 0000000..063bc02
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff
new file mode 100644
index 0000000..c4b18d8
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff2
new file mode 100644
index 0000000..4318d93
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Fraktur-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.eot b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.eot
new file mode 100644
index 0000000..80fbd02
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.ttf b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.ttf
new file mode 100644
index 0000000..8e10722
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff
new file mode 100644
index 0000000..43b361a
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff2
new file mode 100644
index 0000000..af57a96
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Bold.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.eot b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.eot
new file mode 100644
index 0000000..fc77016
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.ttf b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.ttf
new file mode 100644
index 0000000..d124495
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff
new file mode 100644
index 0000000..e623236
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff2
new file mode 100644
index 0000000..944e974
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Italic.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.eot
new file mode 100644
index 0000000..dc60c09
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.ttf
new file mode 100644
index 0000000..da5797f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff
new file mode 100644
index 0000000..37db672
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff2
new file mode 100644
index 0000000..4882042
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Main-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.eot b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.eot
new file mode 100644
index 0000000..52c8b8c
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.ttf b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.ttf
new file mode 100644
index 0000000..a8b527c
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff
new file mode 100644
index 0000000..8940e0b
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff2
new file mode 100644
index 0000000..15cf56d
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-BoldItalic.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.eot b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.eot
new file mode 100644
index 0000000..64c8992
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.ttf b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.ttf
new file mode 100644
index 0000000..06f39d3
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff
new file mode 100644
index 0000000..cf3b4b7
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff2
new file mode 100644
index 0000000..5f8c4bf
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Italic.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.eot
new file mode 100644
index 0000000..5521e6a
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.ttf
new file mode 100644
index 0000000..7312708
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff
new file mode 100644
index 0000000..0e2ebdf
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff2
new file mode 100644
index 0000000..ebe3d02
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Math-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.eot b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.eot
new file mode 100644
index 0000000..1660e76
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.ttf b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.ttf
new file mode 100644
index 0000000..dbeb7b9
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff
new file mode 100644
index 0000000..8f144a8
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff2 b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff2
new file mode 100644
index 0000000..329e855
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Bold.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.eot b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.eot
new file mode 100644
index 0000000..289ae3f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.ttf b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.ttf
new file mode 100644
index 0000000..b3a2f38
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff
new file mode 100644
index 0000000..bddf7ea
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff2 b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff2
new file mode 100644
index 0000000..5fa767b
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Italic.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.eot
new file mode 100644
index 0000000..1b38b98
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.ttf
new file mode 100644
index 0000000..e4712f8
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff
new file mode 100644
index 0000000..33be368
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff2
new file mode 100644
index 0000000..4fcb2e2
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_SansSerif-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.eot
new file mode 100644
index 0000000..7870d7f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.ttf
new file mode 100644
index 0000000..da4d113
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff
new file mode 100644
index 0000000..d6ae79f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff2
new file mode 100644
index 0000000..1b43deb
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Script-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.eot
new file mode 100644
index 0000000..29950f9
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.ttf
new file mode 100644
index 0000000..194466a
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff
new file mode 100644
index 0000000..237f271
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff2
new file mode 100644
index 0000000..39b6f8f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size1-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.eot
new file mode 100644
index 0000000..b8b0536
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.ttf
new file mode 100644
index 0000000..b41b66a
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff
new file mode 100644
index 0000000..4a30558
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff2
new file mode 100644
index 0000000..3facec1
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size2-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.eot
new file mode 100644
index 0000000..576b864
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.ttf
new file mode 100644
index 0000000..790ddbb
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff
new file mode 100644
index 0000000..3a6d062
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff2
new file mode 100644
index 0000000..2cffafe
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size3-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.eot
new file mode 100644
index 0000000..c2b045f
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.ttf
new file mode 100644
index 0000000..ce660aa
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff
new file mode 100644
index 0000000..7826c6c
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff2
new file mode 100644
index 0000000..c921898
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Size4-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.eot b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.eot
new file mode 100644
index 0000000..4c178f4
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.eot
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.ttf b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.ttf
new file mode 100644
index 0000000..b0427ad
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.ttf
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff
new file mode 100644
index 0000000..78e9904
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff
Binary files differ
diff --git a/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff2 b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff2
new file mode 100644
index 0000000..618de99
--- /dev/null
+++ b/specs/es/3.2/katex/fonts/KaTeX_Typewriter-Regular.woff2
Binary files differ
diff --git a/specs/es/3.2/katex/katex.css b/specs/es/3.2/katex/katex.css
new file mode 100644
index 0000000..ef0aa62
--- /dev/null
+++ b/specs/es/3.2/katex/katex.css
@@ -0,0 +1,976 @@
+@font-face {
+  font-family: 'KaTeX_AMS';
+  src: url('fonts/KaTeX_AMS-Regular.eot');
+  src: url('fonts/KaTeX_AMS-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_AMS-Regular.woff2') format('woff2'), url('fonts/KaTeX_AMS-Regular.woff') format('woff'), url('fonts/KaTeX_AMS-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Caligraphic';
+  src: url('fonts/KaTeX_Caligraphic-Bold.eot');
+  src: url('fonts/KaTeX_Caligraphic-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Caligraphic-Bold.woff2') format('woff2'), url('fonts/KaTeX_Caligraphic-Bold.woff') format('woff'), url('fonts/KaTeX_Caligraphic-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Caligraphic';
+  src: url('fonts/KaTeX_Caligraphic-Regular.eot');
+  src: url('fonts/KaTeX_Caligraphic-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Caligraphic-Regular.woff2') format('woff2'), url('fonts/KaTeX_Caligraphic-Regular.woff') format('woff'), url('fonts/KaTeX_Caligraphic-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Fraktur';
+  src: url('fonts/KaTeX_Fraktur-Bold.eot');
+  src: url('fonts/KaTeX_Fraktur-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Fraktur-Bold.woff2') format('woff2'), url('fonts/KaTeX_Fraktur-Bold.woff') format('woff'), url('fonts/KaTeX_Fraktur-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Fraktur';
+  src: url('fonts/KaTeX_Fraktur-Regular.eot');
+  src: url('fonts/KaTeX_Fraktur-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Fraktur-Regular.woff2') format('woff2'), url('fonts/KaTeX_Fraktur-Regular.woff') format('woff'), url('fonts/KaTeX_Fraktur-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Bold.eot');
+  src: url('fonts/KaTeX_Main-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Bold.woff2') format('woff2'), url('fonts/KaTeX_Main-Bold.woff') format('woff'), url('fonts/KaTeX_Main-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Italic.eot');
+  src: url('fonts/KaTeX_Main-Italic.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Italic.woff2') format('woff2'), url('fonts/KaTeX_Main-Italic.woff') format('woff'), url('fonts/KaTeX_Main-Italic.ttf') format('truetype');
+  font-weight: normal;
+  font-style: italic;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Regular.eot');
+  src: url('fonts/KaTeX_Main-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Regular.woff2') format('woff2'), url('fonts/KaTeX_Main-Regular.woff') format('woff'), url('fonts/KaTeX_Main-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Math';
+  src: url('fonts/KaTeX_Math-Italic.eot');
+  src: url('fonts/KaTeX_Math-Italic.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Math-Italic.woff2') format('woff2'), url('fonts/KaTeX_Math-Italic.woff') format('woff'), url('fonts/KaTeX_Math-Italic.ttf') format('truetype');
+  font-weight: normal;
+  font-style: italic;
+}
+@font-face {
+  font-family: 'KaTeX_SansSerif';
+  src: url('fonts/KaTeX_SansSerif-Regular.eot');
+  src: url('fonts/KaTeX_SansSerif-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_SansSerif-Regular.woff2') format('woff2'), url('fonts/KaTeX_SansSerif-Regular.woff') format('woff'), url('fonts/KaTeX_SansSerif-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Script';
+  src: url('fonts/KaTeX_Script-Regular.eot');
+  src: url('fonts/KaTeX_Script-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Script-Regular.woff2') format('woff2'), url('fonts/KaTeX_Script-Regular.woff') format('woff'), url('fonts/KaTeX_Script-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size1';
+  src: url('fonts/KaTeX_Size1-Regular.eot');
+  src: url('fonts/KaTeX_Size1-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size1-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size1-Regular.woff') format('woff'), url('fonts/KaTeX_Size1-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size2';
+  src: url('fonts/KaTeX_Size2-Regular.eot');
+  src: url('fonts/KaTeX_Size2-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size2-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size2-Regular.woff') format('woff'), url('fonts/KaTeX_Size2-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size3';
+  src: url('fonts/KaTeX_Size3-Regular.eot');
+  src: url('fonts/KaTeX_Size3-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size3-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size3-Regular.woff') format('woff'), url('fonts/KaTeX_Size3-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size4';
+  src: url('fonts/KaTeX_Size4-Regular.eot');
+  src: url('fonts/KaTeX_Size4-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size4-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size4-Regular.woff') format('woff'), url('fonts/KaTeX_Size4-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Typewriter';
+  src: url('fonts/KaTeX_Typewriter-Regular.eot');
+  src: url('fonts/KaTeX_Typewriter-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Typewriter-Regular.woff2') format('woff2'), url('fonts/KaTeX_Typewriter-Regular.woff') format('woff'), url('fonts/KaTeX_Typewriter-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+.katex-display {
+  display: block;
+  margin: 1em 0;
+  text-align: center;
+}
+.katex-display > .katex {
+  display: inline-block;
+  text-align: initial;
+}
+.katex {
+  font: normal 1.21em KaTeX_Main, Times New Roman, serif;
+  line-height: 1.2;
+  white-space: nowrap;
+  text-indent: 0;
+}
+.katex .katex-html {
+  display: inline-block;
+}
+.katex .katex-mathml {
+  position: absolute;
+  clip: rect(1px, 1px, 1px, 1px);
+  padding: 0;
+  border: 0;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+}
+.katex .base {
+  display: inline-block;
+}
+.katex .strut {
+  display: inline-block;
+}
+.katex .mathrm {
+  font-style: normal;
+}
+.katex .textit {
+  font-style: italic;
+}
+.katex .mathit {
+  font-family: KaTeX_Math;
+  font-style: italic;
+}
+.katex .mathbf {
+  font-family: KaTeX_Main;
+  font-weight: bold;
+}
+.katex .amsrm {
+  font-family: KaTeX_AMS;
+}
+.katex .mathbb {
+  font-family: KaTeX_AMS;
+}
+.katex .mathcal {
+  font-family: KaTeX_Caligraphic;
+}
+.katex .mathfrak {
+  font-family: KaTeX_Fraktur;
+}
+.katex .mathtt {
+  font-family: KaTeX_Typewriter;
+}
+.katex .mathscr {
+  font-family: KaTeX_Script;
+}
+.katex .mathsf {
+  font-family: KaTeX_SansSerif;
+}
+.katex .mainit {
+  font-family: KaTeX_Main;
+  font-style: italic;
+}
+.katex .mord + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mord + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .mord + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mord + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mord {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mop + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mbin + .mord {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .mop {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .mopen {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .minner {
+  margin-left: 0.22222em;
+}
+.katex .mrel + .mord {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .mop {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .mopen {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .minner {
+  margin-left: 0.27778em;
+}
+.katex .mclose + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mclose + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .mclose + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mclose + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mord {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mrel {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mopen {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mclose {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mpunct {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .minner {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mord {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mop {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .minner + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .minner + .mopen {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mpunct {
+  margin-left: 0.16667em;
+}
+.katex .minner + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mord.mtight {
+  margin-left: 0;
+}
+.katex .mop.mtight {
+  margin-left: 0;
+}
+.katex .mbin.mtight {
+  margin-left: 0;
+}
+.katex .mrel.mtight {
+  margin-left: 0;
+}
+.katex .mopen.mtight {
+  margin-left: 0;
+}
+.katex .mclose.mtight {
+  margin-left: 0;
+}
+.katex .mpunct.mtight {
+  margin-left: 0;
+}
+.katex .minner.mtight {
+  margin-left: 0;
+}
+.katex .mord + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mord.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mclose + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .reset-textstyle.textstyle {
+  font-size: 1em;
+}
+.katex .reset-textstyle.scriptstyle {
+  font-size: 0.7em;
+}
+.katex .reset-textstyle.scriptscriptstyle {
+  font-size: 0.5em;
+}
+.katex .reset-scriptstyle.textstyle {
+  font-size: 1.42857em;
+}
+.katex .reset-scriptstyle.scriptstyle {
+  font-size: 1em;
+}
+.katex .reset-scriptstyle.scriptscriptstyle {
+  font-size: 0.71429em;
+}
+.katex .reset-scriptscriptstyle.textstyle {
+  font-size: 2em;
+}
+.katex .reset-scriptscriptstyle.scriptstyle {
+  font-size: 1.4em;
+}
+.katex .reset-scriptscriptstyle.scriptscriptstyle {
+  font-size: 1em;
+}
+.katex .style-wrap {
+  position: relative;
+}
+.katex .vlist {
+  display: inline-block;
+}
+.katex .vlist > span {
+  display: block;
+  height: 0;
+  position: relative;
+}
+.katex .vlist > span > span {
+  display: inline-block;
+}
+.katex .vlist .baseline-fix {
+  display: inline-table;
+  table-layout: fixed;
+}
+.katex .msupsub {
+  text-align: left;
+}
+.katex .mfrac > span > span {
+  text-align: center;
+}
+.katex .mfrac .frac-line {
+  width: 100%;
+}
+.katex .mfrac .frac-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .mfrac .frac-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .mspace {
+  display: inline-block;
+}
+.katex .mspace.negativethinspace {
+  margin-left: -0.16667em;
+}
+.katex .mspace.thinspace {
+  width: 0.16667em;
+}
+.katex .mspace.negativemediumspace {
+  margin-left: -0.22222em;
+}
+.katex .mspace.mediumspace {
+  width: 0.22222em;
+}
+.katex .mspace.thickspace {
+  width: 0.27778em;
+}
+.katex .mspace.sixmuspace {
+  width: 0.333333em;
+}
+.katex .mspace.eightmuspace {
+  width: 0.444444em;
+}
+.katex .mspace.enspace {
+  width: 0.5em;
+}
+.katex .mspace.twelvemuspace {
+  width: 0.666667em;
+}
+.katex .mspace.quad {
+  width: 1em;
+}
+.katex .mspace.qquad {
+  width: 2em;
+}
+.katex .llap,
+.katex .rlap {
+  width: 0;
+  position: relative;
+}
+.katex .llap > .inner,
+.katex .rlap > .inner {
+  position: absolute;
+}
+.katex .llap > .fix,
+.katex .rlap > .fix {
+  display: inline-block;
+}
+.katex .llap > .inner {
+  right: 0;
+}
+.katex .rlap > .inner {
+  left: 0;
+}
+.katex .katex-logo .a {
+  font-size: 0.75em;
+  margin-left: -0.32em;
+  position: relative;
+  top: -0.2em;
+}
+.katex .katex-logo .t {
+  margin-left: -0.23em;
+}
+.katex .katex-logo .e {
+  margin-left: -0.1667em;
+  position: relative;
+  top: 0.2155em;
+}
+.katex .katex-logo .x {
+  margin-left: -0.125em;
+}
+.katex .rule {
+  display: inline-block;
+  border: solid 0;
+  position: relative;
+}
+.katex .overline .overline-line,
+.katex .underline .underline-line {
+  width: 100%;
+}
+.katex .overline .overline-line:before,
+.katex .underline .underline-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .overline .overline-line:after,
+.katex .underline .underline-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .sqrt > .sqrt-sign {
+  position: relative;
+}
+.katex .sqrt .sqrt-line {
+  width: 100%;
+}
+.katex .sqrt .sqrt-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .sqrt .sqrt-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .sqrt > .root {
+  margin-left: 0.27777778em;
+  margin-right: -0.55555556em;
+}
+.katex .sizing,
+.katex .fontsize-ensurer {
+  display: inline-block;
+}
+.katex .sizing.reset-size1.size1,
+.katex .fontsize-ensurer.reset-size1.size1 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size1.size2,
+.katex .fontsize-ensurer.reset-size1.size2 {
+  font-size: 1.4em;
+}
+.katex .sizing.reset-size1.size3,
+.katex .fontsize-ensurer.reset-size1.size3 {
+  font-size: 1.6em;
+}
+.katex .sizing.reset-size1.size4,
+.katex .fontsize-ensurer.reset-size1.size4 {
+  font-size: 1.8em;
+}
+.katex .sizing.reset-size1.size5,
+.katex .fontsize-ensurer.reset-size1.size5 {
+  font-size: 2em;
+}
+.katex .sizing.reset-size1.size6,
+.katex .fontsize-ensurer.reset-size1.size6 {
+  font-size: 2.4em;
+}
+.katex .sizing.reset-size1.size7,
+.katex .fontsize-ensurer.reset-size1.size7 {
+  font-size: 2.88em;
+}
+.katex .sizing.reset-size1.size8,
+.katex .fontsize-ensurer.reset-size1.size8 {
+  font-size: 3.46em;
+}
+.katex .sizing.reset-size1.size9,
+.katex .fontsize-ensurer.reset-size1.size9 {
+  font-size: 4.14em;
+}
+.katex .sizing.reset-size1.size10,
+.katex .fontsize-ensurer.reset-size1.size10 {
+  font-size: 4.98em;
+}
+.katex .sizing.reset-size2.size1,
+.katex .fontsize-ensurer.reset-size2.size1 {
+  font-size: 0.71428571em;
+}
+.katex .sizing.reset-size2.size2,
+.katex .fontsize-ensurer.reset-size2.size2 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size2.size3,
+.katex .fontsize-ensurer.reset-size2.size3 {
+  font-size: 1.14285714em;
+}
+.katex .sizing.reset-size2.size4,
+.katex .fontsize-ensurer.reset-size2.size4 {
+  font-size: 1.28571429em;
+}
+.katex .sizing.reset-size2.size5,
+.katex .fontsize-ensurer.reset-size2.size5 {
+  font-size: 1.42857143em;
+}
+.katex .sizing.reset-size2.size6,
+.katex .fontsize-ensurer.reset-size2.size6 {
+  font-size: 1.71428571em;
+}
+.katex .sizing.reset-size2.size7,
+.katex .fontsize-ensurer.reset-size2.size7 {
+  font-size: 2.05714286em;
+}
+.katex .sizing.reset-size2.size8,
+.katex .fontsize-ensurer.reset-size2.size8 {
+  font-size: 2.47142857em;
+}
+.katex .sizing.reset-size2.size9,
+.katex .fontsize-ensurer.reset-size2.size9 {
+  font-size: 2.95714286em;
+}
+.katex .sizing.reset-size2.size10,
+.katex .fontsize-ensurer.reset-size2.size10 {
+  font-size: 3.55714286em;
+}
+.katex .sizing.reset-size3.size1,
+.katex .fontsize-ensurer.reset-size3.size1 {
+  font-size: 0.625em;
+}
+.katex .sizing.reset-size3.size2,
+.katex .fontsize-ensurer.reset-size3.size2 {
+  font-size: 0.875em;
+}
+.katex .sizing.reset-size3.size3,
+.katex .fontsize-ensurer.reset-size3.size3 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size3.size4,
+.katex .fontsize-ensurer.reset-size3.size4 {
+  font-size: 1.125em;
+}
+.katex .sizing.reset-size3.size5,
+.katex .fontsize-ensurer.reset-size3.size5 {
+  font-size: 1.25em;
+}
+.katex .sizing.reset-size3.size6,
+.katex .fontsize-ensurer.reset-size3.size6 {
+  font-size: 1.5em;
+}
+.katex .sizing.reset-size3.size7,
+.katex .fontsize-ensurer.reset-size3.size7 {
+  font-size: 1.8em;
+}
+.katex .sizing.reset-size3.size8,
+.katex .fontsize-ensurer.reset-size3.size8 {
+  font-size: 2.1625em;
+}
+.katex .sizing.reset-size3.size9,
+.katex .fontsize-ensurer.reset-size3.size9 {
+  font-size: 2.5875em;
+}
+.katex .sizing.reset-size3.size10,
+.katex .fontsize-ensurer.reset-size3.size10 {
+  font-size: 3.1125em;
+}
+.katex .sizing.reset-size4.size1,
+.katex .fontsize-ensurer.reset-size4.size1 {
+  font-size: 0.55555556em;
+}
+.katex .sizing.reset-size4.size2,
+.katex .fontsize-ensurer.reset-size4.size2 {
+  font-size: 0.77777778em;
+}
+.katex .sizing.reset-size4.size3,
+.katex .fontsize-ensurer.reset-size4.size3 {
+  font-size: 0.88888889em;
+}
+.katex .sizing.reset-size4.size4,
+.katex .fontsize-ensurer.reset-size4.size4 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size4.size5,
+.katex .fontsize-ensurer.reset-size4.size5 {
+  font-size: 1.11111111em;
+}
+.katex .sizing.reset-size4.size6,
+.katex .fontsize-ensurer.reset-size4.size6 {
+  font-size: 1.33333333em;
+}
+.katex .sizing.reset-size4.size7,
+.katex .fontsize-ensurer.reset-size4.size7 {
+  font-size: 1.6em;
+}
+.katex .sizing.reset-size4.size8,
+.katex .fontsize-ensurer.reset-size4.size8 {
+  font-size: 1.92222222em;
+}
+.katex .sizing.reset-size4.size9,
+.katex .fontsize-ensurer.reset-size4.size9 {
+  font-size: 2.3em;
+}
+.katex .sizing.reset-size4.size10,
+.katex .fontsize-ensurer.reset-size4.size10 {
+  font-size: 2.76666667em;
+}
+.katex .sizing.reset-size5.size1,
+.katex .fontsize-ensurer.reset-size5.size1 {
+  font-size: 0.5em;
+}
+.katex .sizing.reset-size5.size2,
+.katex .fontsize-ensurer.reset-size5.size2 {
+  font-size: 0.7em;
+}
+.katex .sizing.reset-size5.size3,
+.katex .fontsize-ensurer.reset-size5.size3 {
+  font-size: 0.8em;
+}
+.katex .sizing.reset-size5.size4,
+.katex .fontsize-ensurer.reset-size5.size4 {
+  font-size: 0.9em;
+}
+.katex .sizing.reset-size5.size5,
+.katex .fontsize-ensurer.reset-size5.size5 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size5.size6,
+.katex .fontsize-ensurer.reset-size5.size6 {
+  font-size: 1.2em;
+}
+.katex .sizing.reset-size5.size7,
+.katex .fontsize-ensurer.reset-size5.size7 {
+  font-size: 1.44em;
+}
+.katex .sizing.reset-size5.size8,
+.katex .fontsize-ensurer.reset-size5.size8 {
+  font-size: 1.73em;
+}
+.katex .sizing.reset-size5.size9,
+.katex .fontsize-ensurer.reset-size5.size9 {
+  font-size: 2.07em;
+}
+.katex .sizing.reset-size5.size10,
+.katex .fontsize-ensurer.reset-size5.size10 {
+  font-size: 2.49em;
+}
+.katex .sizing.reset-size6.size1,
+.katex .fontsize-ensurer.reset-size6.size1 {
+  font-size: 0.41666667em;
+}
+.katex .sizing.reset-size6.size2,
+.katex .fontsize-ensurer.reset-size6.size2 {
+  font-size: 0.58333333em;
+}
+.katex .sizing.reset-size6.size3,
+.katex .fontsize-ensurer.reset-size6.size3 {
+  font-size: 0.66666667em;
+}
+.katex .sizing.reset-size6.size4,
+.katex .fontsize-ensurer.reset-size6.size4 {
+  font-size: 0.75em;
+}
+.katex .sizing.reset-size6.size5,
+.katex .fontsize-ensurer.reset-size6.size5 {
+  font-size: 0.83333333em;
+}
+.katex .sizing.reset-size6.size6,
+.katex .fontsize-ensurer.reset-size6.size6 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size6.size7,
+.katex .fontsize-ensurer.reset-size6.size7 {
+  font-size: 1.2em;
+}
+.katex .sizing.reset-size6.size8,
+.katex .fontsize-ensurer.reset-size6.size8 {
+  font-size: 1.44166667em;
+}
+.katex .sizing.reset-size6.size9,
+.katex .fontsize-ensurer.reset-size6.size9 {
+  font-size: 1.725em;
+}
+.katex .sizing.reset-size6.size10,
+.katex .fontsize-ensurer.reset-size6.size10 {
+  font-size: 2.075em;
+}
+.katex .sizing.reset-size7.size1,
+.katex .fontsize-ensurer.reset-size7.size1 {
+  font-size: 0.34722222em;
+}
+.katex .sizing.reset-size7.size2,
+.katex .fontsize-ensurer.reset-size7.size2 {
+  font-size: 0.48611111em;
+}
+.katex .sizing.reset-size7.size3,
+.katex .fontsize-ensurer.reset-size7.size3 {
+  font-size: 0.55555556em;
+}
+.katex .sizing.reset-size7.size4,
+.katex .fontsize-ensurer.reset-size7.size4 {
+  font-size: 0.625em;
+}
+.katex .sizing.reset-size7.size5,
+.katex .fontsize-ensurer.reset-size7.size5 {
+  font-size: 0.69444444em;
+}
+.katex .sizing.reset-size7.size6,
+.katex .fontsize-ensurer.reset-size7.size6 {
+  font-size: 0.83333333em;
+}
+.katex .sizing.reset-size7.size7,
+.katex .fontsize-ensurer.reset-size7.size7 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size7.size8,
+.katex .fontsize-ensurer.reset-size7.size8 {
+  font-size: 1.20138889em;
+}
+.katex .sizing.reset-size7.size9,
+.katex .fontsize-ensurer.reset-size7.size9 {
+  font-size: 1.4375em;
+}
+.katex .sizing.reset-size7.size10,
+.katex .fontsize-ensurer.reset-size7.size10 {
+  font-size: 1.72916667em;
+}
+.katex .sizing.reset-size8.size1,
+.katex .fontsize-ensurer.reset-size8.size1 {
+  font-size: 0.28901734em;
+}
+.katex .sizing.reset-size8.size2,
+.katex .fontsize-ensurer.reset-size8.size2 {
+  font-size: 0.40462428em;
+}
+.katex .sizing.reset-size8.size3,
+.katex .fontsize-ensurer.reset-size8.size3 {
+  font-size: 0.46242775em;
+}
+.katex .sizing.reset-size8.size4,
+.katex .fontsize-ensurer.reset-size8.size4 {
+  font-size: 0.52023121em;
+}
+.katex .sizing.reset-size8.size5,
+.katex .fontsize-ensurer.reset-size8.size5 {
+  font-size: 0.57803468em;
+}
+.katex .sizing.reset-size8.size6,
+.katex .fontsize-ensurer.reset-size8.size6 {
+  font-size: 0.69364162em;
+}
+.katex .sizing.reset-size8.size7,
+.katex .fontsize-ensurer.reset-size8.size7 {
+  font-size: 0.83236994em;
+}
+.katex .sizing.reset-size8.size8,
+.katex .fontsize-ensurer.reset-size8.size8 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size8.size9,
+.katex .fontsize-ensurer.reset-size8.size9 {
+  font-size: 1.19653179em;
+}
+.katex .sizing.reset-size8.size10,
+.katex .fontsize-ensurer.reset-size8.size10 {
+  font-size: 1.43930636em;
+}
+.katex .sizing.reset-size9.size1,
+.katex .fontsize-ensurer.reset-size9.size1 {
+  font-size: 0.24154589em;
+}
+.katex .sizing.reset-size9.size2,
+.katex .fontsize-ensurer.reset-size9.size2 {
+  font-size: 0.33816425em;
+}
+.katex .sizing.reset-size9.size3,
+.katex .fontsize-ensurer.reset-size9.size3 {
+  font-size: 0.38647343em;
+}
+.katex .sizing.reset-size9.size4,
+.katex .fontsize-ensurer.reset-size9.size4 {
+  font-size: 0.43478261em;
+}
+.katex .sizing.reset-size9.size5,
+.katex .fontsize-ensurer.reset-size9.size5 {
+  font-size: 0.48309179em;
+}
+.katex .sizing.reset-size9.size6,
+.katex .fontsize-ensurer.reset-size9.size6 {
+  font-size: 0.57971014em;
+}
+.katex .sizing.reset-size9.size7,
+.katex .fontsize-ensurer.reset-size9.size7 {
+  font-size: 0.69565217em;
+}
+.katex .sizing.reset-size9.size8,
+.katex .fontsize-ensurer.reset-size9.size8 {
+  font-size: 0.83574879em;
+}
+.katex .sizing.reset-size9.size9,
+.katex .fontsize-ensurer.reset-size9.size9 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size9.size10,
+.katex .fontsize-ensurer.reset-size9.size10 {
+  font-size: 1.20289855em;
+}
+.katex .sizing.reset-size10.size1,
+.katex .fontsize-ensurer.reset-size10.size1 {
+  font-size: 0.20080321em;
+}
+.katex .sizing.reset-size10.size2,
+.katex .fontsize-ensurer.reset-size10.size2 {
+  font-size: 0.2811245em;
+}
+.katex .sizing.reset-size10.size3,
+.katex .fontsize-ensurer.reset-size10.size3 {
+  font-size: 0.32128514em;
+}
+.katex .sizing.reset-size10.size4,
+.katex .fontsize-ensurer.reset-size10.size4 {
+  font-size: 0.36144578em;
+}
+.katex .sizing.reset-size10.size5,
+.katex .fontsize-ensurer.reset-size10.size5 {
+  font-size: 0.40160643em;
+}
+.katex .sizing.reset-size10.size6,
+.katex .fontsize-ensurer.reset-size10.size6 {
+  font-size: 0.48192771em;
+}
+.katex .sizing.reset-size10.size7,
+.katex .fontsize-ensurer.reset-size10.size7 {
+  font-size: 0.57831325em;
+}
+.katex .sizing.reset-size10.size8,
+.katex .fontsize-ensurer.reset-size10.size8 {
+  font-size: 0.69477912em;
+}
+.katex .sizing.reset-size10.size9,
+.katex .fontsize-ensurer.reset-size10.size9 {
+  font-size: 0.8313253em;
+}
+.katex .sizing.reset-size10.size10,
+.katex .fontsize-ensurer.reset-size10.size10 {
+  font-size: 1em;
+}
+.katex .delimsizing.size1 {
+  font-family: KaTeX_Size1;
+}
+.katex .delimsizing.size2 {
+  font-family: KaTeX_Size2;
+}
+.katex .delimsizing.size3 {
+  font-family: KaTeX_Size3;
+}
+.katex .delimsizing.size4 {
+  font-family: KaTeX_Size4;
+}
+.katex .delimsizing.mult .delim-size1 > span {
+  font-family: KaTeX_Size1;
+}
+.katex .delimsizing.mult .delim-size4 > span {
+  font-family: KaTeX_Size4;
+}
+.katex .nulldelimiter {
+  display: inline-block;
+  width: 0.12em;
+}
+.katex .op-symbol {
+  position: relative;
+}
+.katex .op-symbol.small-op {
+  font-family: KaTeX_Size1;
+}
+.katex .op-symbol.large-op {
+  font-family: KaTeX_Size2;
+}
+.katex .op-limits > .vlist > span {
+  text-align: center;
+}
+.katex .accent > .vlist > span {
+  text-align: center;
+}
+.katex .accent .accent-body > span {
+  width: 0;
+}
+.katex .accent .accent-body.accent-vec > span {
+  position: relative;
+  left: 0.326em;
+}
+.katex .mtable .vertical-separator {
+  display: inline-block;
+  margin: 0 -0.025em;
+  border-right: 0.05em solid black;
+}
+.katex .mtable .arraycolsep {
+  display: inline-block;
+}
+.katex .mtable .col-align-c > .vlist {
+  text-align: center;
+}
+.katex .mtable .col-align-l > .vlist {
+  text-align: left;
+}
+.katex .mtable .col-align-r > .vlist {
+  text-align: right;
+}
diff --git a/specs/es/3.2/katex/katex.js b/specs/es/3.2/katex/katex.js
new file mode 100644
index 0000000..e104be9
--- /dev/null
+++ b/specs/es/3.2/katex/katex.js
@@ -0,0 +1,9075 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.katex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This is the main entry point for KaTeX. Here, we expose functions for
+ * rendering expressions either to DOM nodes or to markup strings.
+ *
+ * We also expose the ParseError class to check if errors thrown from KaTeX are
+ * errors in the expression, or errors in javascript handling.
+ */
+
+var ParseError = require("./src/ParseError");
+var Settings = require("./src/Settings");
+
+var buildTree = require("./src/buildTree");
+var parseTree = require("./src/parseTree");
+var utils = require("./src/utils");
+
+/**
+ * Parse and build an expression, and place that expression in the DOM node
+ * given.
+ */
+var render = function(expression, baseNode, options) {
+    utils.clearNode(baseNode);
+
+    var settings = new Settings(options);
+
+    var tree = parseTree(expression, settings);
+    var node = buildTree(tree, expression, settings).toNode();
+
+    baseNode.appendChild(node);
+};
+
+// KaTeX's styles don't work properly in quirks mode. Print out an error, and
+// disable rendering.
+if (typeof document !== "undefined") {
+    if (document.compatMode !== "CSS1Compat") {
+        typeof console !== "undefined" && console.warn(
+            "Warning: KaTeX doesn't work in quirks mode. Make sure your " +
+                "website has a suitable doctype.");
+
+        render = function() {
+            throw new ParseError("KaTeX doesn't work in quirks mode.");
+        };
+    }
+}
+
+/**
+ * Parse and build an expression, and return the markup for that.
+ */
+var renderToString = function(expression, options) {
+    var settings = new Settings(options);
+
+    var tree = parseTree(expression, settings);
+    return buildTree(tree, expression, settings).toMarkup();
+};
+
+/**
+ * Parse an expression and return the parse tree.
+ */
+var generateParseTree = function(expression, options) {
+    var settings = new Settings(options);
+    return parseTree(expression, settings);
+};
+
+module.exports = {
+    render: render,
+    renderToString: renderToString,
+    /**
+     * NOTE: This method is not currently recommended for public use.
+     * The internal tree representation is unstable and is very likely
+     * to change. Use at your own risk.
+     */
+    __parse: generateParseTree,
+    ParseError: ParseError
+};
+
+},{"./src/ParseError":6,"./src/Settings":8,"./src/buildTree":13,"./src/parseTree":22,"./src/utils":25}],2:[function(require,module,exports){
+/** @flow */
+
+"use strict";
+
+function getRelocatable(re) {
+  // In the future, this could use a WeakMap instead of an expando.
+  if (!re.__matchAtRelocatable) {
+    // Disjunctions are the lowest-precedence operator, so we can make any
+    // pattern match the empty string by appending `|()` to it:
+    // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-patterns
+    var source = re.source + "|()";
+
+    // We always make the new regex global.
+    var flags = "g" + (re.ignoreCase ? "i" : "") + (re.multiline ? "m" : "") + (re.unicode ? "u" : "")
+    // sticky (/.../y) doesn't make sense in conjunction with our relocation
+    // logic, so we ignore it here.
+    ;
+
+    re.__matchAtRelocatable = new RegExp(source, flags);
+  }
+  return re.__matchAtRelocatable;
+}
+
+function matchAt(re, str, pos) {
+  if (re.global || re.sticky) {
+    throw new Error("matchAt(...): Only non-global regexes are supported");
+  }
+  var reloc = getRelocatable(re);
+  reloc.lastIndex = pos;
+  var match = reloc.exec(str);
+  // Last capturing group is our sentinel that indicates whether the regex
+  // matched at the given location.
+  if (match[match.length - 1] == null) {
+    // Original regex matched.
+    match.length = match.length - 1;
+    return match;
+  } else {
+    return null;
+  }
+}
+
+module.exports = matchAt;
+},{}],3:[function(require,module,exports){
+/**
+ * The Lexer class handles tokenizing the input in various ways. Since our
+ * parser expects us to be able to backtrack, the lexer allows lexing from any
+ * given starting point.
+ *
+ * Its main exposed function is the `lex` function, which takes a position to
+ * lex from and a type of token to lex. It defers to the appropriate `_innerLex`
+ * function.
+ *
+ * The various `_innerLex` functions perform the actual lexing of different
+ * kinds.
+ */
+
+var matchAt = require("match-at");
+
+var ParseError = require("./ParseError");
+
+// The main lexer class
+function Lexer(input) {
+    this.input = input;
+    this.pos = 0;
+}
+
+/**
+ * The resulting token returned from `lex`.
+ *
+ * It consists of the token text plus some position information.
+ * The position information is essentially a range in an input string,
+ * but instead of referencing the bare input string, we refer to the lexer.
+ * That way it is possible to attach extra metadata to the input string,
+ * like for example a file name or similar.
+ *
+ * The position information (all three parameters) is optional,
+ * so it is OK to construct synthetic tokens if appropriate.
+ * Not providing available position information may lead to
+ * degraded error reporting, though.
+ *
+ * @param {string}  text   the text of this token
+ * @param {number=} start  the start offset, zero-based inclusive
+ * @param {number=} end    the end offset, zero-based exclusive
+ * @param {Lexer=}  lexer  the lexer which in turn holds the input string
+ */
+function Token(text, start, end, lexer) {
+    this.text = text;
+    this.start = start;
+    this.end = end;
+    this.lexer = lexer;
+}
+
+/**
+ * Given a pair of tokens (this and endToken), compute a “Token” encompassing
+ * the whole input range enclosed by these two.
+ *
+ * @param {Token}  endToken  last token of the range, inclusive
+ * @param {string} text      the text of the newly constructed token
+ */
+Token.prototype.range = function(endToken, text) {
+    if (endToken.lexer !== this.lexer) {
+        return new Token(text); // sorry, no position information available
+    }
+    return new Token(text, this.start, endToken.end, this.lexer);
+};
+
+/* The following tokenRegex
+ * - matches typical whitespace (but not NBSP etc.) using its first group
+ * - does not match any control character \x00-\x1f except whitespace
+ * - does not match a bare backslash
+ * - matches any ASCII character except those just mentioned
+ * - does not match the BMP private use area \uE000-\uF8FF
+ * - does not match bare surrogate code units
+ * - matches any BMP character except for those just described
+ * - matches any valid Unicode surrogate pair
+ * - matches a backslash followed by one or more letters
+ * - matches a backslash followed by any BMP character, including newline
+ * Just because the Lexer matches something doesn't mean it's valid input:
+ * If there is no matching function or symbol definition, the Parser will
+ * still reject the input.
+ */
+var tokenRegex = new RegExp(
+    "([ \r\n\t]+)|" +                                 // whitespace
+    "([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" +  // single codepoint
+    "|[\uD800-\uDBFF][\uDC00-\uDFFF]" +               // surrogate pair
+    "|\\\\(?:[a-zA-Z]+|[^\uD800-\uDFFF])" +           // function name
+    ")"
+);
+
+/**
+ * This function lexes a single token.
+ */
+Lexer.prototype.lex = function() {
+    var input = this.input;
+    var pos = this.pos;
+    if (pos === input.length) {
+        return new Token("EOF", pos, pos, this);
+    }
+    var match = matchAt(tokenRegex, input, pos);
+    if (match === null) {
+        throw new ParseError(
+            "Unexpected character: '" + input[pos] + "'",
+            new Token(input[pos], pos, pos + 1, this));
+    }
+    var text = match[2] || " ";
+    var start = this.pos;
+    this.pos += match[0].length;
+    var end = this.pos;
+    return new Token(text, start, end, this);
+};
+
+module.exports = Lexer;
+
+},{"./ParseError":6,"match-at":2}],4:[function(require,module,exports){
+/**
+ * This file contains the “gullet” where macros are expanded
+ * until only non-macro tokens remain.
+ */
+
+var Lexer = require("./Lexer");
+
+function MacroExpander(input, macros) {
+    this.lexer = new Lexer(input);
+    this.macros = macros;
+    this.stack = []; // contains tokens in REVERSE order
+    this.discardedWhiteSpace = [];
+}
+
+/**
+ * Recursively expand first token, then return first non-expandable token.
+ */
+MacroExpander.prototype.nextToken = function() {
+    for (;;) {
+        if (this.stack.length === 0) {
+            this.stack.push(this.lexer.lex());
+        }
+        var topToken = this.stack.pop();
+        var name = topToken.text;
+        if (!(name.charAt(0) === "\\" && this.macros.hasOwnProperty(name))) {
+            return topToken;
+        }
+        var expansion = this.macros[name];
+        if (typeof expansion === "string") {
+            var bodyLexer = new Lexer(expansion);
+            expansion = [];
+            var tok = bodyLexer.lex();
+            while (tok.text !== "EOF") {
+                expansion.push(tok);
+                tok = bodyLexer.lex();
+            }
+            expansion.reverse(); // to fit in with stack using push and pop
+            this.macros[name] = expansion;
+        }
+        this.stack = this.stack.concat(expansion);
+    }
+};
+
+MacroExpander.prototype.get = function(ignoreSpace) {
+    this.discardedWhiteSpace = [];
+    var token = this.nextToken();
+    if (ignoreSpace) {
+        while (token.text === " ") {
+            this.discardedWhiteSpace.push(token);
+            token = this.nextToken();
+        }
+    }
+    return token;
+};
+
+/**
+ * Undo the effect of the preceding call to the get method.
+ * A call to this method MUST be immediately preceded and immediately followed
+ * by a call to get.  Only used during mode switching, i.e. after one token
+ * was got in the old mode but should get got again in a new mode
+ * with possibly different whitespace handling.
+ */
+MacroExpander.prototype.unget = function(token) {
+    this.stack.push(token);
+    while (this.discardedWhiteSpace.length !== 0) {
+        this.stack.push(this.discardedWhiteSpace.pop());
+    }
+};
+
+module.exports = MacroExpander;
+
+},{"./Lexer":3}],5:[function(require,module,exports){
+/**
+ * This file contains information about the options that the Parser carries
+ * around with it while parsing. Data is held in an `Options` object, and when
+ * recursing, a new `Options` object can be created with the `.with*` and
+ * `.reset` functions.
+ */
+
+/**
+ * This is the main options class. It contains the style, size, color, and font
+ * of the current parse level. It also contains the style and size of the parent
+ * parse level, so size changes can be handled efficiently.
+ *
+ * Each of the `.with*` and `.reset` functions passes its current style and size
+ * as the parentStyle and parentSize of the new options class, so parent
+ * handling is taken care of automatically.
+ */
+function Options(data) {
+    this.style = data.style;
+    this.color = data.color;
+    this.size = data.size;
+    this.phantom = data.phantom;
+    this.font = data.font;
+
+    if (data.parentStyle === undefined) {
+        this.parentStyle = data.style;
+    } else {
+        this.parentStyle = data.parentStyle;
+    }
+
+    if (data.parentSize === undefined) {
+        this.parentSize = data.size;
+    } else {
+        this.parentSize = data.parentSize;
+    }
+}
+
+/**
+ * Returns a new options object with the same properties as "this".  Properties
+ * from "extension" will be copied to the new options object.
+ */
+Options.prototype.extend = function(extension) {
+    var data = {
+        style: this.style,
+        size: this.size,
+        color: this.color,
+        parentStyle: this.style,
+        parentSize: this.size,
+        phantom: this.phantom,
+        font: this.font
+    };
+
+    for (var key in extension) {
+        if (extension.hasOwnProperty(key)) {
+            data[key] = extension[key];
+        }
+    }
+
+    return new Options(data);
+};
+
+/**
+ * Create a new options object with the given style.
+ */
+Options.prototype.withStyle = function(style) {
+    return this.extend({
+        style: style
+    });
+};
+
+/**
+ * Create a new options object with the given size.
+ */
+Options.prototype.withSize = function(size) {
+    return this.extend({
+        size: size
+    });
+};
+
+/**
+ * Create a new options object with the given color.
+ */
+Options.prototype.withColor = function(color) {
+    return this.extend({
+        color: color
+    });
+};
+
+/**
+ * Create a new options object with "phantom" set to true.
+ */
+Options.prototype.withPhantom = function() {
+    return this.extend({
+        phantom: true
+    });
+};
+
+/**
+ * Create a new options objects with the give font.
+ */
+Options.prototype.withFont = function(font) {
+    return this.extend({
+        font: font || this.font
+    });
+};
+
+/**
+ * Create a new options object with the same style, size, and color. This is
+ * used so that parent style and size changes are handled correctly.
+ */
+Options.prototype.reset = function() {
+    return this.extend({});
+};
+
+/**
+ * A map of color names to CSS colors.
+ * TODO(emily): Remove this when we have real macros
+ */
+var colorMap = {
+    "katex-blue": "#6495ed",
+    "katex-orange": "#ffa500",
+    "katex-pink": "#ff00af",
+    "katex-red": "#df0030",
+    "katex-green": "#28ae7b",
+    "katex-gray": "gray",
+    "katex-purple": "#9d38bd",
+    "katex-blueA": "#ccfaff",
+    "katex-blueB": "#80f6ff",
+    "katex-blueC": "#63d9ea",
+    "katex-blueD": "#11accd",
+    "katex-blueE": "#0c7f99",
+    "katex-tealA": "#94fff5",
+    "katex-tealB": "#26edd5",
+    "katex-tealC": "#01d1c1",
+    "katex-tealD": "#01a995",
+    "katex-tealE": "#208170",
+    "katex-greenA": "#b6ffb0",
+    "katex-greenB": "#8af281",
+    "katex-greenC": "#74cf70",
+    "katex-greenD": "#1fab54",
+    "katex-greenE": "#0d923f",
+    "katex-goldA": "#ffd0a9",
+    "katex-goldB": "#ffbb71",
+    "katex-goldC": "#ff9c39",
+    "katex-goldD": "#e07d10",
+    "katex-goldE": "#a75a05",
+    "katex-redA": "#fca9a9",
+    "katex-redB": "#ff8482",
+    "katex-redC": "#f9685d",
+    "katex-redD": "#e84d39",
+    "katex-redE": "#bc2612",
+    "katex-maroonA": "#ffbde0",
+    "katex-maroonB": "#ff92c6",
+    "katex-maroonC": "#ed5fa6",
+    "katex-maroonD": "#ca337c",
+    "katex-maroonE": "#9e034e",
+    "katex-purpleA": "#ddd7ff",
+    "katex-purpleB": "#c6b9fc",
+    "katex-purpleC": "#aa87ff",
+    "katex-purpleD": "#7854ab",
+    "katex-purpleE": "#543b78",
+    "katex-mintA": "#f5f9e8",
+    "katex-mintB": "#edf2df",
+    "katex-mintC": "#e0e5cc",
+    "katex-grayA": "#f6f7f7",
+    "katex-grayB": "#f0f1f2",
+    "katex-grayC": "#e3e5e6",
+    "katex-grayD": "#d6d8da",
+    "katex-grayE": "#babec2",
+    "katex-grayF": "#888d93",
+    "katex-grayG": "#626569",
+    "katex-grayH": "#3b3e40",
+    "katex-grayI": "#21242c",
+    "katex-kaBlue": "#314453",
+    "katex-kaGreen": "#71B307"
+};
+
+/**
+ * Gets the CSS color of the current options object, accounting for the
+ * `colorMap`.
+ */
+Options.prototype.getColor = function() {
+    if (this.phantom) {
+        return "transparent";
+    } else {
+        return colorMap[this.color] || this.color;
+    }
+};
+
+module.exports = Options;
+
+},{}],6:[function(require,module,exports){
+/**
+ * This is the ParseError class, which is the main error thrown by KaTeX
+ * functions when something has gone wrong. This is used to distinguish internal
+ * errors from errors in the expression that the user provided.
+ *
+ * If possible, a caller should provide a Token or ParseNode with information
+ * about where in the source string the problem occurred.
+ *
+ * @param {string} message  The error message
+ * @param {(Token|ParseNode)=} token  An object providing position information
+ */
+function ParseError(message, token) {
+    var error = "KaTeX parse error: " + message;
+    var start;
+    var end;
+
+    if (token && token.lexer && token.start <= token.end) {
+        // If we have the input and a position, make the error a bit fancier
+
+        // Get the input
+        var input = token.lexer.input;
+
+        // Prepend some information
+        start = token.start;
+        end = token.end;
+        if (start === input.length) {
+            error += " at end of input: ";
+        } else {
+            error += " at position " + (start + 1) + ": ";
+        }
+
+        // Underline token in question using combining underscores
+        var underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
+
+        // Extract some context from the input and add it to the error
+        var left;
+        if (start > 15) {
+            left = "…" + input.slice(start - 15, start);
+        } else {
+            left = input.slice(0, start);
+        }
+        var right;
+        if (end + 15 < input.length) {
+            right = input.slice(end, end + 15) + "…";
+        } else {
+            right = input.slice(end);
+        }
+        error += left + underlined + right;
+    }
+
+    // Some hackery to make ParseError a prototype of Error
+    // See http://stackoverflow.com/a/8460753
+    var self = new Error(error);
+    self.name = "ParseError";
+    self.__proto__ = ParseError.prototype;
+
+    self.position = start;
+    return self;
+}
+
+// More hackery
+ParseError.prototype.__proto__ = Error.prototype;
+
+module.exports = ParseError;
+
+},{}],7:[function(require,module,exports){
+/* eslint no-constant-condition:0 */
+var functions = require("./functions");
+var environments = require("./environments");
+var MacroExpander = require("./MacroExpander");
+var symbols = require("./symbols");
+var utils = require("./utils");
+var cjkRegex = require("./unicodeRegexes").cjkRegex;
+
+var parseData = require("./parseData");
+var ParseError = require("./ParseError");
+
+/**
+ * This file contains the parser used to parse out a TeX expression from the
+ * input. Since TeX isn't context-free, standard parsers don't work particularly
+ * well.
+ *
+ * The strategy of this parser is as such:
+ *
+ * The main functions (the `.parse...` ones) take a position in the current
+ * parse string to parse tokens from. The lexer (found in Lexer.js, stored at
+ * this.lexer) also supports pulling out tokens at arbitrary places. When
+ * individual tokens are needed at a position, the lexer is called to pull out a
+ * token, which is then used.
+ *
+ * The parser has a property called "mode" indicating the mode that
+ * the parser is currently in. Currently it has to be one of "math" or
+ * "text", which denotes whether the current environment is a math-y
+ * one or a text-y one (e.g. inside \text). Currently, this serves to
+ * limit the functions which can be used in text mode.
+ *
+ * The main functions then return an object which contains the useful data that
+ * was parsed at its given point, and a new position at the end of the parsed
+ * data. The main functions can call each other and continue the parsing by
+ * using the returned position as a new starting point.
+ *
+ * There are also extra `.handle...` functions, which pull out some reused
+ * functionality into self-contained functions.
+ *
+ * The earlier functions return ParseNodes.
+ * The later functions (which are called deeper in the parse) sometimes return
+ * ParseFuncOrArgument, which contain a ParseNode as well as some data about
+ * whether the parsed object is a function which is missing some arguments, or a
+ * standalone object which can be used as an argument to another function.
+ */
+
+/**
+ * Main Parser class
+ */
+function Parser(input, settings) {
+    // Create a new macro expander (gullet) and (indirectly via that) also a
+    // new lexer (mouth) for this parser (stomach, in the language of TeX)
+    this.gullet = new MacroExpander(input, settings.macros);
+    // Store the settings for use in parsing
+    this.settings = settings;
+    // Count leftright depth (for \middle errors)
+    this.leftrightDepth = 0;
+}
+
+var ParseNode = parseData.ParseNode;
+
+/**
+ * An initial function (without its arguments), or an argument to a function.
+ * The `result` argument should be a ParseNode.
+ */
+function ParseFuncOrArgument(result, isFunction, token) {
+    this.result = result;
+    // Is this a function (i.e. is it something defined in functions.js)?
+    this.isFunction = isFunction;
+    this.token = token;
+}
+
+/**
+ * Checks a result to make sure it has the right type, and throws an
+ * appropriate error otherwise.
+ *
+ * @param {boolean=} consume whether to consume the expected token,
+ *                           defaults to true
+ */
+Parser.prototype.expect = function(text, consume) {
+    if (this.nextToken.text !== text) {
+        throw new ParseError(
+            "Expected '" + text + "', got '" + this.nextToken.text + "'",
+            this.nextToken
+        );
+    }
+    if (consume !== false) {
+        this.consume();
+    }
+};
+
+/**
+ * Considers the current look ahead token as consumed,
+ * and fetches the one after that as the new look ahead.
+ */
+Parser.prototype.consume = function() {
+    this.nextToken = this.gullet.get(this.mode === "math");
+};
+
+Parser.prototype.switchMode = function(newMode) {
+    this.gullet.unget(this.nextToken);
+    this.mode = newMode;
+    this.consume();
+};
+
+/**
+ * Main parsing function, which parses an entire input.
+ *
+ * @return {?Array.<ParseNode>}
+ */
+Parser.prototype.parse = function() {
+    // Try to parse the input
+    this.mode = "math";
+    this.consume();
+    var parse = this.parseInput();
+    return parse;
+};
+
+/**
+ * Parses an entire input tree.
+ */
+Parser.prototype.parseInput = function() {
+    // Parse an expression
+    var expression = this.parseExpression(false);
+    // If we succeeded, make sure there's an EOF at the end
+    this.expect("EOF", false);
+    return expression;
+};
+
+var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
+
+/**
+ * Parses an "expression", which is a list of atoms.
+ *
+ * @param {boolean} breakOnInfix  Should the parsing stop when we hit infix
+ *                  nodes? This happens when functions have higher precendence
+ *                  than infix nodes in implicit parses.
+ *
+ * @param {?string} breakOnTokenText  The text of the token that the expression
+ *                  should end with, or `null` if something else should end the
+ *                  expression.
+ *
+ * @return {ParseNode}
+ */
+Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) {
+    var body = [];
+    // Keep adding atoms to the body until we can't parse any more atoms (either
+    // we reached the end, a }, or a \right)
+    while (true) {
+        var lex = this.nextToken;
+        if (endOfExpression.indexOf(lex.text) !== -1) {
+            break;
+        }
+        if (breakOnTokenText && lex.text === breakOnTokenText) {
+            break;
+        }
+        if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
+            break;
+        }
+        var atom = this.parseAtom();
+        if (!atom) {
+            if (!this.settings.throwOnError && lex.text[0] === "\\") {
+                var errorNode = this.handleUnsupportedCmd();
+                body.push(errorNode);
+                continue;
+            }
+
+            break;
+        }
+        body.push(atom);
+    }
+    return this.handleInfixNodes(body);
+};
+
+/**
+ * Rewrites infix operators such as \over with corresponding commands such
+ * as \frac.
+ *
+ * There can only be one infix operator per group.  If there's more than one
+ * then the expression is ambiguous.  This can be resolved by adding {}.
+ *
+ * @returns {Array}
+ */
+Parser.prototype.handleInfixNodes = function(body) {
+    var overIndex = -1;
+    var funcName;
+
+    for (var i = 0; i < body.length; i++) {
+        var node = body[i];
+        if (node.type === "infix") {
+            if (overIndex !== -1) {
+                throw new ParseError(
+                    "only one infix operator per group",
+                    node.value.token);
+            }
+            overIndex = i;
+            funcName = node.value.replaceWith;
+        }
+    }
+
+    if (overIndex !== -1) {
+        var numerNode;
+        var denomNode;
+
+        var numerBody = body.slice(0, overIndex);
+        var denomBody = body.slice(overIndex + 1);
+
+        if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
+            numerNode = numerBody[0];
+        } else {
+            numerNode = new ParseNode("ordgroup", numerBody, this.mode);
+        }
+
+        if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
+            denomNode = denomBody[0];
+        } else {
+            denomNode = new ParseNode("ordgroup", denomBody, this.mode);
+        }
+
+        var value = this.callFunction(
+            funcName, [numerNode, denomNode], null);
+        return [new ParseNode(value.type, value, this.mode)];
+    } else {
+        return body;
+    }
+};
+
+// The greediness of a superscript or subscript
+var SUPSUB_GREEDINESS = 1;
+
+/**
+ * Handle a subscript or superscript with nice errors.
+ */
+Parser.prototype.handleSupSubscript = function(name) {
+    var symbolToken = this.nextToken;
+    var symbol = symbolToken.text;
+    this.consume();
+    var group = this.parseGroup();
+
+    if (!group) {
+        if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") {
+            return this.handleUnsupportedCmd();
+        } else {
+            throw new ParseError(
+                "Expected group after '" + symbol + "'",
+                symbolToken
+            );
+        }
+    } else if (group.isFunction) {
+        // ^ and _ have a greediness, so handle interactions with functions'
+        // greediness
+        var funcGreediness = functions[group.result].greediness;
+        if (funcGreediness > SUPSUB_GREEDINESS) {
+            return this.parseFunction(group);
+        } else {
+            throw new ParseError(
+                "Got function '" + group.result + "' with no arguments " +
+                    "as " + name, symbolToken);
+        }
+    } else {
+        return group.result;
+    }
+};
+
+/**
+ * Converts the textual input of an unsupported command into a text node
+ * contained within a color node whose color is determined by errorColor
+ */
+Parser.prototype.handleUnsupportedCmd = function() {
+    var text = this.nextToken.text;
+    var textordArray = [];
+
+    for (var i = 0; i < text.length; i++) {
+        textordArray.push(new ParseNode("textord", text[i], "text"));
+    }
+
+    var textNode = new ParseNode(
+        "text",
+        {
+            body: textordArray,
+            type: "text"
+        },
+        this.mode);
+
+    var colorNode = new ParseNode(
+        "color",
+        {
+            color: this.settings.errorColor,
+            value: [textNode],
+            type: "color"
+        },
+        this.mode);
+
+    this.consume();
+    return colorNode;
+};
+
+/**
+ * Parses a group with optional super/subscripts.
+ *
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseAtom = function() {
+    // The body of an atom is an implicit group, so that things like
+    // \left(x\right)^2 work correctly.
+    var base = this.parseImplicitGroup();
+
+    // In text mode, we don't have superscripts or subscripts
+    if (this.mode === "text") {
+        return base;
+    }
+
+    // Note that base may be empty (i.e. null) at this point.
+
+    var superscript;
+    var subscript;
+    while (true) {
+        // Lex the first token
+        var lex = this.nextToken;
+
+        if (lex.text === "\\limits" || lex.text === "\\nolimits") {
+            // We got a limit control
+            if (!base || base.type !== "op") {
+                throw new ParseError(
+                    "Limit controls must follow a math operator",
+                    lex);
+            } else {
+                var limits = lex.text === "\\limits";
+                base.value.limits = limits;
+                base.value.alwaysHandleSupSub = true;
+            }
+            this.consume();
+        } else if (lex.text === "^") {
+            // We got a superscript start
+            if (superscript) {
+                throw new ParseError("Double superscript", lex);
+            }
+            superscript = this.handleSupSubscript("superscript");
+        } else if (lex.text === "_") {
+            // We got a subscript start
+            if (subscript) {
+                throw new ParseError("Double subscript", lex);
+            }
+            subscript = this.handleSupSubscript("subscript");
+        } else if (lex.text === "'") {
+            // We got a prime
+            var prime = new ParseNode("textord", "\\prime", this.mode);
+
+            // Many primes can be grouped together, so we handle this here
+            var primes = [prime];
+            this.consume();
+            // Keep lexing tokens until we get something that's not a prime
+            while (this.nextToken.text === "'") {
+                // For each one, add another prime to the list
+                primes.push(prime);
+                this.consume();
+            }
+            // Put them into an ordgroup as the superscript
+            superscript = new ParseNode("ordgroup", primes, this.mode);
+        } else {
+            // If it wasn't ^, _, or ', stop parsing super/subscripts
+            break;
+        }
+    }
+
+    if (superscript || subscript) {
+        // If we got either a superscript or subscript, create a supsub
+        return new ParseNode("supsub", {
+            base: base,
+            sup: superscript,
+            sub: subscript
+        }, this.mode);
+    } else {
+        // Otherwise return the original body
+        return base;
+    }
+};
+
+// A list of the size-changing functions, for use in parseImplicitGroup
+var sizeFuncs = [
+    "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
+    "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"
+];
+
+// A list of the style-changing functions, for use in parseImplicitGroup
+var styleFuncs = [
+    "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"
+];
+
+/**
+ * Parses an implicit group, which is a group that starts at the end of a
+ * specified, and ends right before a higher explicit group ends, or at EOL. It
+ * is used for functions that appear to affect the current style, like \Large or
+ * \textrm, where instead of keeping a style we just pretend that there is an
+ * implicit grouping after it until the end of the group. E.g.
+ *   small text {\Large large text} small text again
+ * It is also used for \left and \right to get the correct grouping.
+ *
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseImplicitGroup = function() {
+    var start = this.parseSymbol();
+
+    if (start == null) {
+        // If we didn't get anything we handle, fall back to parseFunction
+        return this.parseFunction();
+    }
+
+    var func = start.result;
+    var body;
+
+    if (func === "\\left") {
+        // If we see a left:
+        // Parse the entire left function (including the delimiter)
+        var left = this.parseFunction(start);
+        // Parse out the implicit body
+        ++this.leftrightDepth;
+        body = this.parseExpression(false);
+        --this.leftrightDepth;
+        // Check the next token
+        this.expect("\\right", false);
+        var right = this.parseFunction();
+        return new ParseNode("leftright", {
+            body: body,
+            left: left.value.value,
+            right: right.value.value
+        }, this.mode);
+    } else if (func === "\\begin") {
+        // begin...end is similar to left...right
+        var begin = this.parseFunction(start);
+        var envName = begin.value.name;
+        if (!environments.hasOwnProperty(envName)) {
+            throw new ParseError(
+                "No such environment: " + envName, begin.value.nameGroup);
+        }
+        // Build the environment object. Arguments and other information will
+        // be made available to the begin and end methods using properties.
+        var env = environments[envName];
+        var args = this.parseArguments("\\begin{" + envName + "}", env);
+        var context = {
+            mode: this.mode,
+            envName: envName,
+            parser: this,
+            positions: args.pop()
+        };
+        var result = env.handler(context, args);
+        this.expect("\\end", false);
+        var endNameToken = this.nextToken;
+        var end = this.parseFunction();
+        if (end.value.name !== envName) {
+            throw new ParseError(
+                "Mismatch: \\begin{" + envName + "} matched " +
+                "by \\end{" + end.value.name + "}",
+                endNameToken);
+        }
+        result.position = end.position;
+        return result;
+    } else if (utils.contains(sizeFuncs, func)) {
+        // If we see a sizing function, parse out the implict body
+        body = this.parseExpression(false);
+        return new ParseNode("sizing", {
+            // Figure out what size to use based on the list of functions above
+            size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
+            value: body
+        }, this.mode);
+    } else if (utils.contains(styleFuncs, func)) {
+        // If we see a styling function, parse out the implict body
+        body = this.parseExpression(true);
+        return new ParseNode("styling", {
+            // Figure out what style to use by pulling out the style from
+            // the function name
+            style: func.slice(1, func.length - 5),
+            value: body
+        }, this.mode);
+    } else {
+        // Defer to parseFunction if it's not a function we handle
+        return this.parseFunction(start);
+    }
+};
+
+/**
+ * Parses an entire function, including its base and all of its arguments.
+ * The base might either have been parsed already, in which case
+ * it is provided as an argument, or it's the next group in the input.
+ *
+ * @param {ParseFuncOrArgument=} baseGroup optional as described above
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseFunction = function(baseGroup) {
+    if (!baseGroup) {
+        baseGroup = this.parseGroup();
+    }
+
+    if (baseGroup) {
+        if (baseGroup.isFunction) {
+            var func = baseGroup.result;
+            var funcData = functions[func];
+            if (this.mode === "text" && !funcData.allowedInText) {
+                throw new ParseError(
+                    "Can't use function '" + func + "' in text mode",
+                    baseGroup.token);
+            }
+
+            var args = this.parseArguments(func, funcData);
+            var token = baseGroup.token;
+            var result = this.callFunction(func, args, args.pop(), token);
+            return new ParseNode(result.type, result, this.mode);
+        } else {
+            return baseGroup.result;
+        }
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Call a function handler with a suitable context and arguments.
+ */
+Parser.prototype.callFunction = function(name, args, positions, token) {
+    var context = {
+        funcName: name,
+        parser: this,
+        positions: positions,
+        token: token
+    };
+    return functions[name].handler(context, args);
+};
+
+/**
+ * Parses the arguments of a function or environment
+ *
+ * @param {string} func  "\name" or "\begin{name}"
+ * @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData
+ * @return the array of arguments, with the list of positions as last element
+ */
+Parser.prototype.parseArguments = function(func, funcData) {
+    var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
+    if (totalArgs === 0) {
+        return [[this.pos]];
+    }
+
+    var baseGreediness = funcData.greediness;
+    var positions = [this.pos];
+    var args = [];
+
+    for (var i = 0; i < totalArgs; i++) {
+        var nextToken = this.nextToken;
+        var argType = funcData.argTypes && funcData.argTypes[i];
+        var arg;
+        if (i < funcData.numOptionalArgs) {
+            if (argType) {
+                arg = this.parseGroupOfType(argType, true);
+            } else {
+                arg = this.parseGroup(true);
+            }
+            if (!arg) {
+                args.push(null);
+                positions.push(this.pos);
+                continue;
+            }
+        } else {
+            if (argType) {
+                arg = this.parseGroupOfType(argType);
+            } else {
+                arg = this.parseGroup();
+            }
+            if (!arg) {
+                if (!this.settings.throwOnError &&
+                    this.nextToken.text[0] === "\\") {
+                    arg = new ParseFuncOrArgument(
+                        this.handleUnsupportedCmd(this.nextToken.text),
+                        false);
+                } else {
+                    throw new ParseError(
+                        "Expected group after '" + func + "'", nextToken);
+                }
+            }
+        }
+        var argNode;
+        if (arg.isFunction) {
+            var argGreediness =
+                functions[arg.result].greediness;
+            if (argGreediness > baseGreediness) {
+                argNode = this.parseFunction(arg);
+            } else {
+                throw new ParseError(
+                    "Got function '" + arg.result + "' as " +
+                    "argument to '" + func + "'", nextToken);
+            }
+        } else {
+            argNode = arg.result;
+        }
+        args.push(argNode);
+        positions.push(this.pos);
+    }
+
+    args.push(positions);
+
+    return args;
+};
+
+
+/**
+ * Parses a group when the mode is changing.
+ *
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseGroupOfType = function(innerMode, optional) {
+    var outerMode = this.mode;
+    // Handle `original` argTypes
+    if (innerMode === "original") {
+        innerMode = outerMode;
+    }
+
+    if (innerMode === "color") {
+        return this.parseColorGroup(optional);
+    }
+    if (innerMode === "size") {
+        return this.parseSizeGroup(optional);
+    }
+
+    this.switchMode(innerMode);
+    if (innerMode === "text") {
+        // text mode is special because it should ignore the whitespace before
+        // it
+        while (this.nextToken.text === " ") {
+            this.consume();
+        }
+    }
+    // By the time we get here, innerMode is one of "text" or "math".
+    // We switch the mode of the parser, recurse, then restore the old mode.
+    var res = this.parseGroup(optional);
+    this.switchMode(outerMode);
+    return res;
+};
+
+/**
+ * Parses a group, essentially returning the string formed by the
+ * brace-enclosed tokens plus some position information.
+ *
+ * @param {string} modeName  Used to describe the mode in error messages
+ * @param {boolean=} optional  Whether the group is optional or required
+ */
+Parser.prototype.parseStringGroup = function(modeName, optional) {
+    if (optional && this.nextToken.text !== "[") {
+        return null;
+    }
+    var outerMode = this.mode;
+    this.mode = "text";
+    this.expect(optional ? "[" : "{");
+    var str = "";
+    var firstToken = this.nextToken;
+    var lastToken = firstToken;
+    while (this.nextToken.text !== (optional ? "]" : "}")) {
+        if (this.nextToken.text === "EOF") {
+            throw new ParseError(
+                "Unexpected end of input in " + modeName,
+                firstToken.range(this.nextToken, str));
+        }
+        lastToken = this.nextToken;
+        str += lastToken.text;
+        this.consume();
+    }
+    this.mode = outerMode;
+    this.expect(optional ? "]" : "}");
+    return firstToken.range(lastToken, str);
+};
+
+/**
+ * Parses a regex-delimited group: the largest sequence of tokens
+ * whose concatenated strings match `regex`. Returns the string
+ * formed by the tokens plus some position information.
+ *
+ * @param {RegExp} regex
+ * @param {string} modeName  Used to describe the mode in error messages
+ */
+Parser.prototype.parseRegexGroup = function(regex, modeName) {
+    var outerMode = this.mode;
+    this.mode = "text";
+    var firstToken = this.nextToken;
+    var lastToken = firstToken;
+    var str = "";
+    while (this.nextToken.text !== "EOF"
+           && regex.test(str + this.nextToken.text)) {
+        lastToken = this.nextToken;
+        str += lastToken.text;
+        this.consume();
+    }
+    if (str === "") {
+        throw new ParseError(
+            "Invalid " + modeName + ": '" + firstToken.text + "'",
+            firstToken);
+    }
+    this.mode = outerMode;
+    return firstToken.range(lastToken, str);
+};
+
+/**
+ * Parses a color description.
+ */
+Parser.prototype.parseColorGroup = function(optional) {
+    var res = this.parseStringGroup("color", optional);
+    if (!res) {
+        return null;
+    }
+    var match = (/^(#[a-z0-9]+|[a-z]+)$/i).exec(res.text);
+    if (!match) {
+        throw new ParseError("Invalid color: '" + res.text + "'", res);
+    }
+    return new ParseFuncOrArgument(
+        new ParseNode("color", match[0], this.mode),
+        false);
+};
+
+/**
+ * Parses a size specification, consisting of magnitude and unit.
+ */
+Parser.prototype.parseSizeGroup = function(optional) {
+    var res;
+    if (!optional && this.nextToken.text !== "{") {
+        res = this.parseRegexGroup(
+            /^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/, "size");
+    } else {
+        res = this.parseStringGroup("size", optional);
+    }
+    if (!res) {
+        return null;
+    }
+    var match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(res.text);
+    if (!match) {
+        throw new ParseError("Invalid size: '" + res.text + "'", res);
+    }
+    var data = {
+        number: +(match[1] + match[2]), // sign + magnitude, cast to number
+        unit: match[3]
+    };
+    if (data.unit !== "em" && data.unit !== "ex" && data.unit !== "mu") {
+        throw new ParseError("Invalid unit: '" + data.unit + "'", res);
+    }
+    return new ParseFuncOrArgument(
+        new ParseNode("color", data, this.mode),
+        false);
+};
+
+/**
+ * If the argument is false or absent, this parses an ordinary group,
+ * which is either a single nucleus (like "x") or an expression
+ * in braces (like "{x+y}").
+ * If the argument is true, it parses either a bracket-delimited expression
+ * (like "[x+y]") or returns null to indicate the absence of a
+ * bracket-enclosed group.
+ *
+ * @param {boolean=} optional  Whether the group is optional or required
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseGroup = function(optional) {
+    var firstToken = this.nextToken;
+    // Try to parse an open brace
+    if (this.nextToken.text === (optional ? "[" : "{")) {
+        // If we get a brace, parse an expression
+        this.consume();
+        var expression = this.parseExpression(false, optional ? "]" : null);
+        var lastToken = this.nextToken;
+        // Make sure we get a close brace
+        this.expect(optional ? "]" : "}");
+        if (this.mode === "text") {
+            this.formLigatures(expression);
+        }
+        return new ParseFuncOrArgument(
+            new ParseNode("ordgroup", expression, this.mode,
+                          firstToken, lastToken),
+            false);
+    } else {
+        // Otherwise, just return a nucleus, or nothing for an optional group
+        return optional ? null : this.parseSymbol();
+    }
+};
+
+/**
+ * Form ligature-like combinations of characters for text mode.
+ * This includes inputs like "--", "---", "``" and "''".
+ * The result will simply replace multiple textord nodes with a single
+ * character in each value by a single textord node having multiple
+ * characters in its value.  The representation is still ASCII source.
+ *
+ * @param {Array.<ParseNode>} group  the nodes of this group,
+ *                                   list will be moified in place
+ */
+Parser.prototype.formLigatures = function(group) {
+    var i;
+    var n = group.length - 1;
+    for (i = 0; i < n; ++i) {
+        var a = group[i];
+        var v = a.value;
+        if (v === "-" && group[i + 1].value === "-") {
+            if (i + 1 < n && group[i + 2].value === "-") {
+                group.splice(i, 3, new ParseNode(
+                    "textord", "---", "text", a, group[i + 2]));
+                n -= 2;
+            } else {
+                group.splice(i, 2, new ParseNode(
+                    "textord", "--", "text", a, group[i + 1]));
+                n -= 1;
+            }
+        }
+        if ((v === "'" || v === "`") && group[i + 1].value === v) {
+            group.splice(i, 2, new ParseNode(
+                "textord", v + v, "text", a, group[i + 1]));
+            n -= 1;
+        }
+    }
+};
+
+/**
+ * Parse a single symbol out of the string. Here, we handle both the functions
+ * we have defined, as well as the single character symbols
+ *
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseSymbol = function() {
+    var nucleus = this.nextToken;
+
+    if (functions[nucleus.text]) {
+        this.consume();
+        // If there exists a function with this name, we return the function and
+        // say that it is a function.
+        return new ParseFuncOrArgument(
+            nucleus.text,
+            true, nucleus);
+    } else if (symbols[this.mode][nucleus.text]) {
+        this.consume();
+        // Otherwise if this is a no-argument function, find the type it
+        // corresponds to in the symbols map
+        return new ParseFuncOrArgument(
+            new ParseNode(symbols[this.mode][nucleus.text].group,
+                          nucleus.text, this.mode, nucleus),
+            false, nucleus);
+    } else if (this.mode === "text" && cjkRegex.test(nucleus.text)) {
+        this.consume();
+        return new ParseFuncOrArgument(
+            new ParseNode("textord", nucleus.text, this.mode, nucleus),
+            false, nucleus);
+    } else {
+        return null;
+    }
+};
+
+Parser.prototype.ParseNode = ParseNode;
+
+module.exports = Parser;
+
+},{"./MacroExpander":4,"./ParseError":6,"./environments":16,"./functions":19,"./parseData":21,"./symbols":23,"./unicodeRegexes":24,"./utils":25}],8:[function(require,module,exports){
+/**
+ * This is a module for storing settings passed into KaTeX. It correctly handles
+ * default settings.
+ */
+
+/**
+ * Helper function for getting a default value if the value is undefined
+ */
+function get(option, defaultValue) {
+    return option === undefined ? defaultValue : option;
+}
+
+/**
+ * The main Settings object
+ *
+ * The current options stored are:
+ *  - displayMode: Whether the expression should be typeset by default in
+ *                 textstyle or displaystyle (default false)
+ */
+function Settings(options) {
+    // allow null options
+    options = options || {};
+    this.displayMode = get(options.displayMode, false);
+    this.throwOnError = get(options.throwOnError, true);
+    this.errorColor = get(options.errorColor, "#cc0000");
+    this.macros = options.macros || {};
+}
+
+module.exports = Settings;
+
+},{}],9:[function(require,module,exports){
+/**
+ * This file contains information and classes for the various kinds of styles
+ * used in TeX. It provides a generic `Style` class, which holds information
+ * about a specific style. It then provides instances of all the different kinds
+ * of styles possible, and provides functions to move between them and get
+ * information about them.
+ */
+
+var sigmas = require("./fontMetrics.js").sigmas;
+
+var metrics = [{}, {}, {}];
+var i;
+for (var key in sigmas) {
+    if (sigmas.hasOwnProperty(key)) {
+        for (i = 0; i < 3; i++) {
+            metrics[i][key] = sigmas[key][i];
+        }
+    }
+}
+for (i = 0; i < 3; i++) {
+    metrics[i].emPerEx = sigmas.xHeight[i] / sigmas.quad[i];
+}
+
+/**
+ * The main style class. Contains a unique id for the style, a size (which is
+ * the same for cramped and uncramped version of a style), a cramped flag, and a
+ * size multiplier, which gives the size difference between a style and
+ * textstyle.
+ */
+function Style(id, size, multiplier, cramped) {
+    this.id = id;
+    this.size = size;
+    this.cramped = cramped;
+    this.sizeMultiplier = multiplier;
+    this.metrics = metrics[size > 0 ? size - 1 : 0];
+}
+
+/**
+ * Get the style of a superscript given a base in the current style.
+ */
+Style.prototype.sup = function() {
+    return styles[sup[this.id]];
+};
+
+/**
+ * Get the style of a subscript given a base in the current style.
+ */
+Style.prototype.sub = function() {
+    return styles[sub[this.id]];
+};
+
+/**
+ * Get the style of a fraction numerator given the fraction in the current
+ * style.
+ */
+Style.prototype.fracNum = function() {
+    return styles[fracNum[this.id]];
+};
+
+/**
+ * Get the style of a fraction denominator given the fraction in the current
+ * style.
+ */
+Style.prototype.fracDen = function() {
+    return styles[fracDen[this.id]];
+};
+
+/**
+ * Get the cramped version of a style (in particular, cramping a cramped style
+ * doesn't change the style).
+ */
+Style.prototype.cramp = function() {
+    return styles[cramp[this.id]];
+};
+
+/**
+ * HTML class name, like "displaystyle cramped"
+ */
+Style.prototype.cls = function() {
+    return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped");
+};
+
+/**
+ * HTML Reset class name, like "reset-textstyle"
+ */
+Style.prototype.reset = function() {
+    return resetNames[this.size];
+};
+
+/**
+ * Return if this style is tightly spaced (scriptstyle/scriptscriptstyle)
+ */
+Style.prototype.isTight = function() {
+    return this.size >= 2;
+};
+
+// IDs of the different styles
+var D = 0;
+var Dc = 1;
+var T = 2;
+var Tc = 3;
+var S = 4;
+var Sc = 5;
+var SS = 6;
+var SSc = 7;
+
+// String names for the different sizes
+var sizeNames = [
+    "displaystyle textstyle",
+    "textstyle",
+    "scriptstyle",
+    "scriptscriptstyle"
+];
+
+// Reset names for the different sizes
+var resetNames = [
+    "reset-textstyle",
+    "reset-textstyle",
+    "reset-scriptstyle",
+    "reset-scriptscriptstyle"
+];
+
+// Instances of the different styles
+var styles = [
+    new Style(D, 0, 1.0, false),
+    new Style(Dc, 0, 1.0, true),
+    new Style(T, 1, 1.0, false),
+    new Style(Tc, 1, 1.0, true),
+    new Style(S, 2, 0.7, false),
+    new Style(Sc, 2, 0.7, true),
+    new Style(SS, 3, 0.5, false),
+    new Style(SSc, 3, 0.5, true)
+];
+
+// Lookup tables for switching from one style to another
+var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
+var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
+var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
+var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
+var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
+
+// We only export some of the styles. Also, we don't export the `Style` class so
+// no more styles can be generated.
+module.exports = {
+    DISPLAY: styles[D],
+    TEXT: styles[T],
+    SCRIPT: styles[S],
+    SCRIPTSCRIPT: styles[SS]
+};
+
+},{"./fontMetrics.js":17}],10:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This module contains general functions that can be used for building
+ * different kinds of domTree nodes in a consistent manner.
+ */
+
+var domTree = require("./domTree");
+var fontMetrics = require("./fontMetrics");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var greekCapitals = [
+    "\\Gamma",
+    "\\Delta",
+    "\\Theta",
+    "\\Lambda",
+    "\\Xi",
+    "\\Pi",
+    "\\Sigma",
+    "\\Upsilon",
+    "\\Phi",
+    "\\Psi",
+    "\\Omega"
+];
+
+// The following have to be loaded from Main-Italic font, using class mainit
+var mainitLetters = [
+    "\u0131",   // dotless i, \imath
+    "\u0237",   // dotless j, \jmath
+    "\u00a3"   // \pounds
+];
+
+/**
+ * Makes a symbolNode after translation via the list of symbols in symbols.js.
+ * Correctly pulls out metrics for the character, and optionally takes a list of
+ * classes to be attached to the node.
+ *
+ * TODO: make argument order closer to makeSpan
+ * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
+ * should if present come first in `classes`.
+ */
+var makeSymbol = function(value, fontFamily, mode, options, classes) {
+    // Replace the value with its replaced value from symbol.js
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var metrics = fontMetrics.getCharacterMetrics(value, fontFamily);
+
+    var symbolNode;
+    if (metrics) {
+        var italic = metrics.italic;
+        if (mode === "text") {
+            italic = 0;
+        }
+        symbolNode = new domTree.symbolNode(
+            value, metrics.height, metrics.depth, italic, metrics.skew,
+            classes);
+    } else {
+        // TODO(emily): Figure out a good way to only print this in development
+        typeof console !== "undefined" && console.warn(
+            "No character metrics for '" + value + "' in style '" +
+                fontFamily + "'");
+        symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
+    }
+
+    if (options) {
+        if (options.style.isTight()) {
+            symbolNode.classes.push("mtight");
+        }
+        if (options.getColor()) {
+            symbolNode.style.color = options.getColor();
+        }
+    }
+
+    return symbolNode;
+};
+
+/**
+ * Makes a symbol in Main-Regular or AMS-Regular.
+ * Used for rel, bin, open, close, inner, and punct.
+ */
+var mathsym = function(value, mode, options, classes) {
+    // Decide what font to render the symbol in by its entry in the symbols
+    // table.
+    // Have a special case for when the value = \ because the \ is used as a
+    // textord in unsupported command errors but cannot be parsed as a regular
+    // text ordinal and is therefore not present as a symbol in the symbols
+    // table for text
+    if (value === "\\" || symbols[mode][value].font === "main") {
+        return makeSymbol(value, "Main-Regular", mode, options, classes);
+    } else {
+        return makeSymbol(
+            value, "AMS-Regular", mode, options, classes.concat(["amsrm"]));
+    }
+};
+
+/**
+ * Makes a symbol in the default font for mathords and textords.
+ */
+var mathDefault = function(value, mode, options, classes, type) {
+    if (type === "mathord") {
+        return mathit(value, mode, options, classes);
+    } else if (type === "textord") {
+        return makeSymbol(
+            value, "Main-Regular", mode, options, classes.concat(["mathrm"]));
+    } else {
+        throw new Error("unexpected type: " + type + " in mathDefault");
+    }
+};
+
+/**
+ * Makes a symbol in the italic math font.
+ */
+var mathit = function(value, mode, options, classes) {
+    if (/[0-9]/.test(value.charAt(0)) ||
+            // glyphs for \imath and \jmath do not exist in Math-Italic so we
+            // need to use Main-Italic instead
+            utils.contains(mainitLetters, value) ||
+            utils.contains(greekCapitals, value)) {
+        return makeSymbol(
+            value, "Main-Italic", mode, options, classes.concat(["mainit"]));
+    } else {
+        return makeSymbol(
+            value, "Math-Italic", mode, options, classes.concat(["mathit"]));
+    }
+};
+
+/**
+ * Makes either a mathord or textord in the correct font and color.
+ */
+var makeOrd = function(group, options, type) {
+    var mode = group.mode;
+    var value = group.value;
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var classes = ["mord"];
+
+    var font = options.font;
+    if (font) {
+        if (font === "mathit" || utils.contains(mainitLetters, value)) {
+            return mathit(value, mode, options, classes);
+        } else {
+            var fontName = fontMap[font].fontName;
+            if (fontMetrics.getCharacterMetrics(value, fontName)) {
+                return makeSymbol(
+                    value, fontName, mode, options, classes.concat([font]));
+            } else {
+                return mathDefault(value, mode, options, classes, type);
+            }
+        }
+    } else {
+        return mathDefault(value, mode, options, classes, type);
+    }
+};
+
+/**
+ * Calculate the height, depth, and maxFontSize of an element based on its
+ * children.
+ */
+var sizeElementFromChildren = function(elem) {
+    var height = 0;
+    var depth = 0;
+    var maxFontSize = 0;
+
+    if (elem.children) {
+        for (var i = 0; i < elem.children.length; i++) {
+            if (elem.children[i].height > height) {
+                height = elem.children[i].height;
+            }
+            if (elem.children[i].depth > depth) {
+                depth = elem.children[i].depth;
+            }
+            if (elem.children[i].maxFontSize > maxFontSize) {
+                maxFontSize = elem.children[i].maxFontSize;
+            }
+        }
+    }
+
+    elem.height = height;
+    elem.depth = depth;
+    elem.maxFontSize = maxFontSize;
+};
+
+/**
+ * Makes a span with the given list of classes, list of children, and options.
+ *
+ * TODO: Ensure that `options` is always provided (currently some call sites
+ * don't pass it).
+ * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
+ * should if present come first in `classes`.
+ */
+var makeSpan = function(classes, children, options) {
+    var span = new domTree.span(classes, children, options);
+
+    sizeElementFromChildren(span);
+
+    return span;
+};
+
+/**
+ * Prepends the given children to the given span, updating height, depth, and
+ * maxFontSize.
+ */
+var prependChildren = function(span, children) {
+    span.children = children.concat(span.children);
+
+    sizeElementFromChildren(span);
+};
+
+/**
+ * Makes a document fragment with the given list of children.
+ */
+var makeFragment = function(children) {
+    var fragment = new domTree.documentFragment(children);
+
+    sizeElementFromChildren(fragment);
+
+    return fragment;
+};
+
+/**
+ * Makes an element placed in each of the vlist elements to ensure that each
+ * element has the same max font size. To do this, we create a zero-width space
+ * with the correct font size.
+ */
+var makeFontSizer = function(options, fontSize) {
+    var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
+    fontSizeInner.style.fontSize =
+        (fontSize / options.style.sizeMultiplier) + "em";
+
+    var fontSizer = makeSpan(
+        ["fontsize-ensurer", "reset-" + options.size, "size5"],
+        [fontSizeInner]);
+
+    return fontSizer;
+};
+
+/**
+ * Makes a vertical list by stacking elements and kerns on top of each other.
+ * Allows for many different ways of specifying the positioning method.
+ *
+ * Arguments:
+ *  - children: A list of child or kern nodes to be stacked on top of each other
+ *              (i.e. the first element will be at the bottom, and the last at
+ *              the top). Element nodes are specified as
+ *                {type: "elem", elem: node}
+ *              while kern nodes are specified as
+ *                {type: "kern", size: size}
+ *  - positionType: The method by which the vlist should be positioned. Valid
+ *                  values are:
+ *                   - "individualShift": The children list only contains elem
+ *                                        nodes, and each node contains an extra
+ *                                        "shift" value of how much it should be
+ *                                        shifted (note that shifting is always
+ *                                        moving downwards). positionData is
+ *                                        ignored.
+ *                   - "top": The positionData specifies the topmost point of
+ *                            the vlist (note this is expected to be a height,
+ *                            so positive values move up)
+ *                   - "bottom": The positionData specifies the bottommost point
+ *                               of the vlist (note this is expected to be a
+ *                               depth, so positive values move down
+ *                   - "shift": The vlist will be positioned such that its
+ *                              baseline is positionData away from the baseline
+ *                              of the first child. Positive values move
+ *                              downwards.
+ *                   - "firstBaseline": The vlist will be positioned such that
+ *                                      its baseline is aligned with the
+ *                                      baseline of the first child.
+ *                                      positionData is ignored. (this is
+ *                                      equivalent to "shift" with
+ *                                      positionData=0)
+ *  - positionData: Data used in different ways depending on positionType
+ *  - options: An Options object
+ *
+ */
+var makeVList = function(children, positionType, positionData, options) {
+    var depth;
+    var currPos;
+    var i;
+    if (positionType === "individualShift") {
+        var oldChildren = children;
+        children = [oldChildren[0]];
+
+        // Add in kerns to the list of children to get each element to be
+        // shifted to the correct specified shift
+        depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
+        currPos = depth;
+        for (i = 1; i < oldChildren.length; i++) {
+            var diff = -oldChildren[i].shift - currPos -
+                oldChildren[i].elem.depth;
+            var size = diff -
+                (oldChildren[i - 1].elem.height +
+                 oldChildren[i - 1].elem.depth);
+
+            currPos = currPos + diff;
+
+            children.push({type: "kern", size: size});
+            children.push(oldChildren[i]);
+        }
+    } else if (positionType === "top") {
+        // We always start at the bottom, so calculate the bottom by adding up
+        // all the sizes
+        var bottom = positionData;
+        for (i = 0; i < children.length; i++) {
+            if (children[i].type === "kern") {
+                bottom -= children[i].size;
+            } else {
+                bottom -= children[i].elem.height + children[i].elem.depth;
+            }
+        }
+        depth = bottom;
+    } else if (positionType === "bottom") {
+        depth = -positionData;
+    } else if (positionType === "shift") {
+        depth = -children[0].elem.depth - positionData;
+    } else if (positionType === "firstBaseline") {
+        depth = -children[0].elem.depth;
+    } else {
+        depth = 0;
+    }
+
+    // Make the fontSizer
+    var maxFontSize = 0;
+    for (i = 0; i < children.length; i++) {
+        if (children[i].type === "elem") {
+            maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
+        }
+    }
+    var fontSizer = makeFontSizer(options, maxFontSize);
+
+    // Create a new list of actual children at the correct offsets
+    var realChildren = [];
+    currPos = depth;
+    for (i = 0; i < children.length; i++) {
+        if (children[i].type === "kern") {
+            currPos += children[i].size;
+        } else {
+            var child = children[i].elem;
+
+            var shift = -child.depth - currPos;
+            currPos += child.height + child.depth;
+
+            var childWrap = makeSpan([], [fontSizer, child]);
+            childWrap.height -= shift;
+            childWrap.depth += shift;
+            childWrap.style.top = shift + "em";
+
+            realChildren.push(childWrap);
+        }
+    }
+
+    // Add in an element at the end with no offset to fix the calculation of
+    // baselines in some browsers (namely IE, sometimes safari)
+    var baselineFix = makeSpan(
+        ["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]);
+    realChildren.push(baselineFix);
+
+    var vlist = makeSpan(["vlist"], realChildren);
+    // Fix the final height and depth, in case there were kerns at the ends
+    // since the makeSpan calculation won't take that in to account.
+    vlist.height = Math.max(currPos, vlist.height);
+    vlist.depth = Math.max(-depth, vlist.depth);
+    return vlist;
+};
+
+// A table of size -> font size for the different sizing functions
+var sizingMultiplier = {
+    size1: 0.5,
+    size2: 0.7,
+    size3: 0.8,
+    size4: 0.9,
+    size5: 1.0,
+    size6: 1.2,
+    size7: 1.44,
+    size8: 1.73,
+    size9: 2.07,
+    size10: 2.49
+};
+
+// A map of spacing functions to their attributes, like size and corresponding
+// CSS class
+var spacingFunctions = {
+    "\\qquad": {
+        size: "2em",
+        className: "qquad"
+    },
+    "\\quad": {
+        size: "1em",
+        className: "quad"
+    },
+    "\\enspace": {
+        size: "0.5em",
+        className: "enspace"
+    },
+    "\\;": {
+        size: "0.277778em",
+        className: "thickspace"
+    },
+    "\\:": {
+        size: "0.22222em",
+        className: "mediumspace"
+    },
+    "\\,": {
+        size: "0.16667em",
+        className: "thinspace"
+    },
+    "\\!": {
+        size: "-0.16667em",
+        className: "negativethinspace"
+    }
+};
+
+/**
+ * Maps TeX font commands to objects containing:
+ * - variant: string used for "mathvariant" attribute in buildMathML.js
+ * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
+ */
+// A map between tex font commands an MathML mathvariant attribute values
+var fontMap = {
+    // styles
+    "mathbf": {
+        variant: "bold",
+        fontName: "Main-Bold"
+    },
+    "mathrm": {
+        variant: "normal",
+        fontName: "Main-Regular"
+    },
+    "textit": {
+        variant: "italic",
+        fontName: "Main-Italic"
+    },
+
+    // "mathit" is missing because it requires the use of two fonts: Main-Italic
+    // and Math-Italic.  This is handled by a special case in makeOrd which ends
+    // up calling mathit.
+
+    // families
+    "mathbb": {
+        variant: "double-struck",
+        fontName: "AMS-Regular"
+    },
+    "mathcal": {
+        variant: "script",
+        fontName: "Caligraphic-Regular"
+    },
+    "mathfrak": {
+        variant: "fraktur",
+        fontName: "Fraktur-Regular"
+    },
+    "mathscr": {
+        variant: "script",
+        fontName: "Script-Regular"
+    },
+    "mathsf": {
+        variant: "sans-serif",
+        fontName: "SansSerif-Regular"
+    },
+    "mathtt": {
+        variant: "monospace",
+        fontName: "Typewriter-Regular"
+    }
+};
+
+module.exports = {
+    fontMap: fontMap,
+    makeSymbol: makeSymbol,
+    mathsym: mathsym,
+    makeSpan: makeSpan,
+    makeFragment: makeFragment,
+    makeVList: makeVList,
+    makeOrd: makeOrd,
+    prependChildren: prependChildren,
+    sizingMultiplier: sizingMultiplier,
+    spacingFunctions: spacingFunctions
+};
+
+},{"./domTree":15,"./fontMetrics":17,"./symbols":23,"./utils":25}],11:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This file does the main work of building a domTree structure from a parse
+ * tree. The entry point is the `buildHTML` function, which takes a parse tree.
+ * Then, the buildExpression, buildGroup, and various groupTypes functions are
+ * called, to produce a final HTML tree.
+ */
+
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var buildCommon = require("./buildCommon");
+var delimiter = require("./delimiter");
+var domTree = require("./domTree");
+var fontMetrics = require("./fontMetrics");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+
+var isSpace = function(node) {
+    return node instanceof domTree.span && node.classes[0] === "mspace";
+};
+
+// Binary atoms (first class `mbin`) change into ordinary atoms (`mord`)
+// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6,
+// and the text before Rule 19.
+
+var isBin = function(node) {
+    return node && node.classes[0] === "mbin";
+};
+
+var isBinLeftCanceller = function(node, isRealGroup) {
+    // TODO: This code assumes that a node's math class is the first element
+    // of its `classes` array. A later cleanup should ensure this, for
+    // instance by changing the signature of `makeSpan`.
+    if (node) {
+        return utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"],
+                              node.classes[0]);
+    } else {
+        return isRealGroup;
+    }
+};
+
+var isBinRightCanceller = function(node, isRealGroup) {
+    if (node) {
+        return utils.contains(["mrel", "mclose", "mpunct"], node.classes[0]);
+    } else {
+        return isRealGroup;
+    }
+};
+
+/**
+ * Take a list of nodes, build them in order, and return a list of the built
+ * nodes. documentFragments are flattened into their contents, so the
+ * returned list contains no fragments. `isRealGroup` is true if `expression`
+ * is a real group (no atoms will be added on either side), as opposed to
+ * a partial group (e.g. one created by \color).
+ */
+var buildExpression = function(expression, options, isRealGroup) {
+    // Parse expressions into `groups`.
+    var groups = [];
+    for (var i = 0; i < expression.length; i++) {
+        var group = expression[i];
+        var output = buildGroup(group, options);
+        if (output instanceof domTree.documentFragment) {
+            Array.prototype.push.apply(groups, output.children);
+        } else {
+            groups.push(output);
+        }
+    }
+    // At this point `groups` consists entirely of `symbolNode`s and `span`s.
+
+    // Explicit spaces (e.g., \;, \,) should be ignored with respect to atom
+    // spacing (e.g., "add thick space between mord and mrel"). Since CSS
+    // adjacency rules implement atom spacing, spaces should be invisible to
+    // CSS. So we splice them out of `groups` and into the atoms themselves.
+    var spaces = null;
+    for (i = 0; i < groups.length; i++) {
+        if (isSpace(groups[i])) {
+            spaces = spaces || [];
+            spaces.push(groups[i]);
+            groups.splice(i, 1);
+            i--;
+        } else if (spaces) {
+            if (groups[i] instanceof domTree.symbolNode) {
+                groups[i] = makeSpan([].concat(groups[i].classes), [groups[i]]);
+            }
+            buildCommon.prependChildren(groups[i], spaces);
+            spaces = null;
+        }
+    }
+    if (spaces) {
+        Array.prototype.push.apply(groups, spaces);
+    }
+
+    // Binary operators change to ordinary symbols in some contexts.
+    for (i = 0; i < groups.length; i++) {
+        if (isBin(groups[i])
+            && (isBinLeftCanceller(groups[i - 1], isRealGroup)
+                || isBinRightCanceller(groups[i + 1], isRealGroup))) {
+            groups[i].classes[0] = "mord";
+        }
+    }
+
+    return groups;
+};
+
+// Return math atom class (mclass) of a domTree.
+var getTypeOfDomTree = function(node) {
+    if (node instanceof domTree.documentFragment) {
+        if (node.children.length) {
+            return getTypeOfDomTree(
+                node.children[node.children.length - 1]);
+        }
+    } else {
+        if (utils.contains(["mord", "mop", "mbin", "mrel", "mopen", "mclose",
+            "mpunct", "minner"], node.classes[0])) {
+            return node.classes[0];
+        }
+    }
+    return null;
+};
+
+/**
+ * Sometimes, groups perform special rules when they have superscripts or
+ * subscripts attached to them. This function lets the `supsub` group know that
+ * its inner element should handle the superscripts and subscripts instead of
+ * handling them itself.
+ */
+var shouldHandleSupSub = function(group, options) {
+    if (!group) {
+        return false;
+    } else if (group.type === "op") {
+        // Operators handle supsubs differently when they have limits
+        // (e.g. `\displaystyle\sum_2^3`)
+        return group.value.limits &&
+            (options.style.size === Style.DISPLAY.size ||
+            group.value.alwaysHandleSupSub);
+    } else if (group.type === "accent") {
+        return isCharacterBox(group.value.base);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Sometimes we want to pull out the innermost element of a group. In most
+ * cases, this will just be the group itself, but when ordgroups and colors have
+ * a single element, we want to pull that out.
+ */
+var getBaseElem = function(group) {
+    if (!group) {
+        return false;
+    } else if (group.type === "ordgroup") {
+        if (group.value.length === 1) {
+            return getBaseElem(group.value[0]);
+        } else {
+            return group;
+        }
+    } else if (group.type === "color") {
+        if (group.value.value.length === 1) {
+            return getBaseElem(group.value.value[0]);
+        } else {
+            return group;
+        }
+    } else if (group.type === "font") {
+        return getBaseElem(group.value.body);
+    } else {
+        return group;
+    }
+};
+
+/**
+ * TeXbook algorithms often reference "character boxes", which are simply groups
+ * with a single character in them. To decide if something is a character box,
+ * we find its innermost group, and see if it is a single character.
+ */
+var isCharacterBox = function(group) {
+    var baseElem = getBaseElem(group);
+
+    // These are all they types of groups which hold single characters
+    return baseElem.type === "mathord" ||
+        baseElem.type === "textord" ||
+        baseElem.type === "bin" ||
+        baseElem.type === "rel" ||
+        baseElem.type === "inner" ||
+        baseElem.type === "open" ||
+        baseElem.type === "close" ||
+        baseElem.type === "punct";
+};
+
+var makeNullDelimiter = function(options, classes) {
+    return makeSpan(classes.concat([
+        "sizing", "reset-" + options.size, "size5",
+        options.style.reset(), Style.TEXT.cls(),
+        "nulldelimiter"]));
+};
+
+/**
+ * This is a map of group types to the function used to handle that type.
+ * Simpler types come at the beginning, while complicated types come afterwards.
+ */
+var groupTypes = {};
+
+groupTypes.mathord = function(group, options) {
+    return buildCommon.makeOrd(group, options, "mathord");
+};
+
+groupTypes.textord = function(group, options) {
+    return buildCommon.makeOrd(group, options, "textord");
+};
+
+groupTypes.bin = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mbin"]);
+};
+
+groupTypes.rel = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mrel"]);
+};
+
+groupTypes.open = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mopen"]);
+};
+
+groupTypes.close = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mclose"]);
+};
+
+groupTypes.inner = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["minner"]);
+};
+
+groupTypes.punct = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mpunct"]);
+};
+
+groupTypes.ordgroup = function(group, options) {
+    return makeSpan(
+        ["mord", options.style.cls()],
+        buildExpression(group.value, options.reset(), true),
+        options
+    );
+};
+
+groupTypes.text = function(group, options) {
+    var newOptions = options.withFont(group.value.style);
+    var inner = buildExpression(group.value.body, newOptions, true);
+    for (var i = 0; i < inner.length - 1; i++) {
+        if (inner[i].tryCombine(inner[i + 1])) {
+            inner.splice(i + 1, 1);
+            i--;
+        }
+    }
+    return makeSpan(["mord", "text", newOptions.style.cls()],
+        inner, newOptions);
+};
+
+groupTypes.color = function(group, options) {
+    var elements = buildExpression(
+        group.value.value,
+        options.withColor(group.value.color),
+        false
+    );
+
+    // \color isn't supposed to affect the type of the elements it contains.
+    // To accomplish this, we wrap the results in a fragment, so the inner
+    // elements will be able to directly interact with their neighbors. For
+    // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
+    return new buildCommon.makeFragment(elements);
+};
+
+groupTypes.supsub = function(group, options) {
+    // Superscript and subscripts are handled in the TeXbook on page
+    // 445-446, rules 18(a-f).
+
+    // Here is where we defer to the inner group if it should handle
+    // superscripts and subscripts itself.
+    if (shouldHandleSupSub(group.value.base, options)) {
+        return groupTypes[group.value.base.type](group, options);
+    }
+
+    var base = buildGroup(group.value.base, options.reset());
+    var supmid;
+    var submid;
+    var sup;
+    var sub;
+
+    var style = options.style;
+    var newOptions;
+
+    if (group.value.sup) {
+        newOptions = options.withStyle(style.sup());
+        sup = buildGroup(group.value.sup, newOptions);
+        supmid = makeSpan([style.reset(), style.sup().cls()],
+            [sup], newOptions);
+    }
+
+    if (group.value.sub) {
+        newOptions = options.withStyle(style.sub());
+        sub = buildGroup(group.value.sub, newOptions);
+        submid = makeSpan([style.reset(), style.sub().cls()],
+            [sub], newOptions);
+    }
+
+    // Rule 18a
+    var supShift;
+    var subShift;
+    if (isCharacterBox(group.value.base)) {
+        supShift = 0;
+        subShift = 0;
+    } else {
+        supShift = base.height - style.metrics.supDrop;
+        subShift = base.depth + style.metrics.subDrop;
+    }
+
+    // Rule 18c
+    var minSupShift;
+    if (style === Style.DISPLAY) {
+        minSupShift = style.metrics.sup1;
+    } else if (style.cramped) {
+        minSupShift = style.metrics.sup3;
+    } else {
+        minSupShift = style.metrics.sup2;
+    }
+
+    // scriptspace is a font-size-independent size, so scale it
+    // appropriately
+    var multiplier = Style.TEXT.sizeMultiplier *
+            style.sizeMultiplier;
+    var scriptspace =
+        (0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
+
+    var supsub;
+    if (!group.value.sup) {
+        // Rule 18b
+        subShift = Math.max(
+            subShift, style.metrics.sub1,
+            sub.height - 0.8 * style.metrics.xHeight);
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: submid}
+        ], "shift", subShift, options);
+
+        supsub.children[0].style.marginRight = scriptspace;
+
+        // Subscripts shouldn't be shifted by the base's italic correction.
+        // Account for that by shifting the subscript back the appropriate
+        // amount. Note we only do this when the base is a single symbol.
+        if (base instanceof domTree.symbolNode) {
+            supsub.children[0].style.marginLeft = -base.italic + "em";
+        }
+    } else if (!group.value.sub) {
+        // Rule 18c, d
+        supShift = Math.max(supShift, minSupShift,
+            sup.depth + 0.25 * style.metrics.xHeight);
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: supmid}
+        ], "shift", -supShift, options);
+
+        supsub.children[0].style.marginRight = scriptspace;
+    } else {
+        supShift = Math.max(
+            supShift, minSupShift, sup.depth + 0.25 * style.metrics.xHeight);
+        subShift = Math.max(subShift, style.metrics.sub2);
+
+        var ruleWidth = fontMetrics.metrics.defaultRuleThickness;
+
+        // Rule 18e
+        if ((supShift - sup.depth) - (sub.height - subShift) <
+                4 * ruleWidth) {
+            subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height;
+            var psi = 0.8 * style.metrics.xHeight - (supShift - sup.depth);
+            if (psi > 0) {
+                supShift += psi;
+                subShift -= psi;
+            }
+        }
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: submid, shift: subShift},
+            {type: "elem", elem: supmid, shift: -supShift}
+        ], "individualShift", null, options);
+
+        // See comment above about subscripts not being shifted
+        if (base instanceof domTree.symbolNode) {
+            supsub.children[0].style.marginLeft = -base.italic + "em";
+        }
+
+        supsub.children[0].style.marginRight = scriptspace;
+        supsub.children[1].style.marginRight = scriptspace;
+    }
+
+    // We ensure to wrap the supsub vlist in a span.msupsub to reset text-align
+    var mclass = getTypeOfDomTree(base) || "mord";
+    return makeSpan([mclass],
+        [base, makeSpan(["msupsub"], [supsub])],
+        options);
+};
+
+groupTypes.genfrac = function(group, options) {
+    // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
+    // Figure out what style this fraction should be in based on the
+    // function used
+    var style = options.style;
+    if (group.value.size === "display") {
+        style = Style.DISPLAY;
+    } else if (group.value.size === "text") {
+        style = Style.TEXT;
+    }
+
+    var nstyle = style.fracNum();
+    var dstyle = style.fracDen();
+    var newOptions;
+
+    newOptions = options.withStyle(nstyle);
+    var numer = buildGroup(group.value.numer, newOptions);
+    var numerreset = makeSpan([style.reset(), nstyle.cls()],
+        [numer], newOptions);
+
+    newOptions = options.withStyle(dstyle);
+    var denom = buildGroup(group.value.denom, newOptions);
+    var denomreset = makeSpan([style.reset(), dstyle.cls()],
+        [denom], newOptions);
+
+    var ruleWidth;
+    if (group.value.hasBarLine) {
+        ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+            options.style.sizeMultiplier;
+    } else {
+        ruleWidth = 0;
+    }
+
+    // Rule 15b
+    var numShift;
+    var clearance;
+    var denomShift;
+    if (style.size === Style.DISPLAY.size) {
+        numShift = style.metrics.num1;
+        if (ruleWidth > 0) {
+            clearance = 3 * ruleWidth;
+        } else {
+            clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
+        }
+        denomShift = style.metrics.denom1;
+    } else {
+        if (ruleWidth > 0) {
+            numShift = style.metrics.num2;
+            clearance = ruleWidth;
+        } else {
+            numShift = style.metrics.num3;
+            clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
+        }
+        denomShift = style.metrics.denom2;
+    }
+
+    var frac;
+    if (ruleWidth === 0) {
+        // Rule 15c
+        var candidateClearance =
+            (numShift - numer.depth) - (denom.height - denomShift);
+        if (candidateClearance < clearance) {
+            numShift += 0.5 * (clearance - candidateClearance);
+            denomShift += 0.5 * (clearance - candidateClearance);
+        }
+
+        frac = buildCommon.makeVList([
+            {type: "elem", elem: denomreset, shift: denomShift},
+            {type: "elem", elem: numerreset, shift: -numShift}
+        ], "individualShift", null, options);
+    } else {
+        // Rule 15d
+        var axisHeight = style.metrics.axisHeight;
+
+        if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) <
+                clearance) {
+            numShift +=
+                clearance - ((numShift - numer.depth) -
+                             (axisHeight + 0.5 * ruleWidth));
+        }
+
+        if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) <
+                clearance) {
+            denomShift +=
+                clearance - ((axisHeight - 0.5 * ruleWidth) -
+                             (denom.height - denomShift));
+        }
+
+        var mid = makeSpan(
+            [options.style.reset(), Style.TEXT.cls(), "frac-line"]);
+        // Manually set the height of the line because its height is
+        // created in CSS
+        mid.height = ruleWidth;
+
+        var midShift = -(axisHeight - 0.5 * ruleWidth);
+
+        frac = buildCommon.makeVList([
+            {type: "elem", elem: denomreset, shift: denomShift},
+            {type: "elem", elem: mid,        shift: midShift},
+            {type: "elem", elem: numerreset, shift: -numShift}
+        ], "individualShift", null, options);
+    }
+
+    // Since we manually change the style sometimes (with \dfrac or \tfrac),
+    // account for the possible size change here.
+    frac.height *= style.sizeMultiplier / options.style.sizeMultiplier;
+    frac.depth *= style.sizeMultiplier / options.style.sizeMultiplier;
+
+    // Rule 15e
+    var delimSize;
+    if (style.size === Style.DISPLAY.size) {
+        delimSize = style.metrics.delim1;
+    } else {
+        delimSize = style.metrics.delim2;
+    }
+
+    var leftDelim;
+    var rightDelim;
+    if (group.value.leftDelim == null) {
+        leftDelim = makeNullDelimiter(options, ["mopen"]);
+    } else {
+        leftDelim = delimiter.customSizedDelim(
+            group.value.leftDelim, delimSize, true,
+            options.withStyle(style), group.mode, ["mopen"]);
+    }
+    if (group.value.rightDelim == null) {
+        rightDelim = makeNullDelimiter(options, ["mclose"]);
+    } else {
+        rightDelim = delimiter.customSizedDelim(
+            group.value.rightDelim, delimSize, true,
+            options.withStyle(style), group.mode, ["mclose"]);
+    }
+
+    return makeSpan(
+        ["mord", options.style.reset(), style.cls()],
+        [leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
+        options);
+};
+
+var calculateSize = function(sizeValue, style) {
+    var x = sizeValue.number;
+    if (sizeValue.unit === "ex") {
+        x *= style.metrics.emPerEx;
+    } else if (sizeValue.unit === "mu") {
+        x /= 18;
+    }
+    return x;
+};
+
+groupTypes.array = function(group, options) {
+    var r;
+    var c;
+    var nr = group.value.body.length;
+    var nc = 0;
+    var body = new Array(nr);
+
+    var style = options.style;
+
+    // Horizontal spacing
+    var pt = 1 / fontMetrics.metrics.ptPerEm;
+    var arraycolsep = 5 * pt; // \arraycolsep in article.cls
+
+    // Vertical spacing
+    var baselineskip = 12 * pt; // see size10.clo
+    // Default \arraystretch from lttab.dtx
+    // TODO(gagern): may get redefined once we have user-defined macros
+    var arraystretch = utils.deflt(group.value.arraystretch, 1);
+    var arrayskip = arraystretch * baselineskip;
+    var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
+    var arstrutDepth = 0.3 * arrayskip;  // \@arstrutbox in lttab.dtx
+
+    var totalHeight = 0;
+    for (r = 0; r < group.value.body.length; ++r) {
+        var inrow = group.value.body[r];
+        var height = arstrutHeight; // \@array adds an \@arstrut
+        var depth = arstrutDepth;   // to each tow (via the template)
+
+        if (nc < inrow.length) {
+            nc = inrow.length;
+        }
+
+        var outrow = new Array(inrow.length);
+        for (c = 0; c < inrow.length; ++c) {
+            var elt = buildGroup(inrow[c], options);
+            if (depth < elt.depth) {
+                depth = elt.depth;
+            }
+            if (height < elt.height) {
+                height = elt.height;
+            }
+            outrow[c] = elt;
+        }
+
+        var gap = 0;
+        if (group.value.rowGaps[r]) {
+            gap = calculateSize(group.value.rowGaps[r].value, style);
+            if (gap > 0) { // \@argarraycr
+                gap += arstrutDepth;
+                if (depth < gap) {
+                    depth = gap; // \@xargarraycr
+                }
+                gap = 0;
+            }
+        }
+
+        outrow.height = height;
+        outrow.depth = depth;
+        totalHeight += height;
+        outrow.pos = totalHeight;
+        totalHeight += depth + gap; // \@yargarraycr
+        body[r] = outrow;
+    }
+
+    var offset = totalHeight / 2 + style.metrics.axisHeight;
+    var colDescriptions = group.value.cols || [];
+    var cols = [];
+    var colSep;
+    var colDescrNum;
+    for (c = 0, colDescrNum = 0;
+         // Continue while either there are more columns or more column
+         // descriptions, so trailing separators don't get lost.
+         c < nc || colDescrNum < colDescriptions.length;
+         ++c, ++colDescrNum) {
+
+        var colDescr = colDescriptions[colDescrNum] || {};
+
+        var firstSeparator = true;
+        while (colDescr.type === "separator") {
+            // If there is more than one separator in a row, add a space
+            // between them.
+            if (!firstSeparator) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width =
+                    fontMetrics.metrics.doubleRuleSep + "em";
+                cols.push(colSep);
+            }
+
+            if (colDescr.separator === "|") {
+                var separator = makeSpan(
+                    ["vertical-separator"],
+                    []);
+                separator.style.height = totalHeight + "em";
+                separator.style.verticalAlign =
+                    -(totalHeight - offset) + "em";
+
+                cols.push(separator);
+            } else {
+                throw new ParseError(
+                    "Invalid separator type: " + colDescr.separator);
+            }
+
+            colDescrNum++;
+            colDescr = colDescriptions[colDescrNum] || {};
+            firstSeparator = false;
+        }
+
+        if (c >= nc) {
+            continue;
+        }
+
+        var sepwidth;
+        if (c > 0 || group.value.hskipBeforeAndAfter) {
+            sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
+            if (sepwidth !== 0) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width = sepwidth + "em";
+                cols.push(colSep);
+            }
+        }
+
+        var col = [];
+        for (r = 0; r < nr; ++r) {
+            var row = body[r];
+            var elem = row[c];
+            if (!elem) {
+                continue;
+            }
+            var shift = row.pos - offset;
+            elem.depth = row.depth;
+            elem.height = row.height;
+            col.push({type: "elem", elem: elem, shift: shift});
+        }
+
+        col = buildCommon.makeVList(col, "individualShift", null, options);
+        col = makeSpan(
+            ["col-align-" + (colDescr.align || "c")],
+            [col]);
+        cols.push(col);
+
+        if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
+            sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
+            if (sepwidth !== 0) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width = sepwidth + "em";
+                cols.push(colSep);
+            }
+        }
+    }
+    body = makeSpan(["mtable"], cols);
+    return makeSpan(["mord"], [body], options);
+};
+
+groupTypes.spacing = function(group, options) {
+    if (group.value === "\\ " || group.value === "\\space" ||
+        group.value === " " || group.value === "~") {
+        // Spaces are generated by adding an actual space. Each of these
+        // things has an entry in the symbols table, so these will be turned
+        // into appropriate outputs.
+        if (group.mode === "text") {
+            return buildCommon.makeOrd(group, options, "textord");
+        } else {
+            return makeSpan(["mspace"],
+                [buildCommon.mathsym(group.value, group.mode, options)],
+                options);
+        }
+    } else {
+        // Other kinds of spaces are of arbitrary width. We use CSS to
+        // generate these.
+        return makeSpan(
+            ["mspace",
+                buildCommon.spacingFunctions[group.value].className],
+            [], options);
+    }
+};
+
+groupTypes.llap = function(group, options) {
+    var inner = makeSpan(
+        ["inner"], [buildGroup(group.value.body, options.reset())]);
+    var fix = makeSpan(["fix"], []);
+    return makeSpan(
+        ["mord", "llap", options.style.cls()], [inner, fix], options);
+};
+
+groupTypes.rlap = function(group, options) {
+    var inner = makeSpan(
+        ["inner"], [buildGroup(group.value.body, options.reset())]);
+    var fix = makeSpan(["fix"], []);
+    return makeSpan(
+        ["mord", "rlap", options.style.cls()], [inner, fix], options);
+};
+
+groupTypes.op = function(group, options) {
+    // Operators are handled in the TeXbook pg. 443-444, rule 13(a).
+    var supGroup;
+    var subGroup;
+    var hasLimits = false;
+    if (group.type === "supsub") {
+        // If we have limits, supsub will pass us its group to handle. Pull
+        // out the superscript and subscript and set the group to the op in
+        // its base.
+        supGroup = group.value.sup;
+        subGroup = group.value.sub;
+        group = group.value.base;
+        hasLimits = true;
+    }
+
+    var style = options.style;
+
+    // Most operators have a large successor symbol, but these don't.
+    var noSuccessor = [
+        "\\smallint"
+    ];
+
+    var large = false;
+    if (style.size === Style.DISPLAY.size &&
+        group.value.symbol &&
+        !utils.contains(noSuccessor, group.value.body)) {
+
+        // Most symbol operators get larger in displaystyle (rule 13)
+        large = true;
+    }
+
+    var base;
+    var baseShift = 0;
+    var slant = 0;
+    if (group.value.symbol) {
+        // If this is a symbol, create the symbol.
+        var fontName = large ? "Size2-Regular" : "Size1-Regular";
+        base = buildCommon.makeSymbol(
+            group.value.body, fontName, "math", options,
+            ["mop", "op-symbol", large ? "large-op" : "small-op"]);
+
+        // Shift the symbol so its center lies on the axis (rule 13). It
+        // appears that our fonts have the centers of the symbols already
+        // almost on the axis, so these numbers are very small. Note we
+        // don't actually apply this here, but instead it is used either in
+        // the vlist creation or separately when there are no limits.
+        baseShift = (base.height - base.depth) / 2 -
+            style.metrics.axisHeight * style.sizeMultiplier;
+
+        // The slant of the symbol is just its italic correction.
+        slant = base.italic;
+    } else if (group.value.value) {
+        // If this is a list, compose that list.
+        var inner = buildExpression(group.value.value, options, true);
+
+        base = makeSpan(["mop"], inner, options);
+    } else {
+        // Otherwise, this is a text operator. Build the text from the
+        // operator's name.
+        // TODO(emily): Add a space in the middle of some of these
+        // operators, like \limsup
+        var output = [];
+        for (var i = 1; i < group.value.body.length; i++) {
+            output.push(buildCommon.mathsym(group.value.body[i], group.mode));
+        }
+        base = makeSpan(["mop"], output, options);
+    }
+
+    if (hasLimits) {
+        // IE 8 clips \int if it is in a display: inline-block. We wrap it
+        // in a new span so it is an inline, and works.
+        base = makeSpan([], [base]);
+
+        var supmid;
+        var supKern;
+        var submid;
+        var subKern;
+        var newOptions;
+        // We manually have to handle the superscripts and subscripts. This,
+        // aside from the kern calculations, is copied from supsub.
+        if (supGroup) {
+            newOptions = options.withStyle(style.sup());
+            var sup = buildGroup(supGroup, newOptions);
+            supmid = makeSpan([style.reset(), style.sup().cls()],
+                [sup], newOptions);
+
+            supKern = Math.max(
+                fontMetrics.metrics.bigOpSpacing1,
+                fontMetrics.metrics.bigOpSpacing3 - sup.depth);
+        }
+
+        if (subGroup) {
+            newOptions = options.withStyle(style.sub());
+            var sub = buildGroup(subGroup, newOptions);
+            submid = makeSpan([style.reset(), style.sub().cls()],
+                [sub], newOptions);
+
+            subKern = Math.max(
+                fontMetrics.metrics.bigOpSpacing2,
+                fontMetrics.metrics.bigOpSpacing4 - sub.height);
+        }
+
+        // Build the final group as a vlist of the possible subscript, base,
+        // and possible superscript.
+        var finalGroup;
+        var top;
+        var bottom;
+        if (!supGroup) {
+            top = base.height - baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
+                {type: "elem", elem: submid},
+                {type: "kern", size: subKern},
+                {type: "elem", elem: base}
+            ], "top", top, options);
+
+            // Here, we shift the limits by the slant of the symbol. Note
+            // that we are supposed to shift the limits by 1/2 of the slant,
+            // but since we are centering the limits adding a full slant of
+            // margin will shift by 1/2 that.
+            finalGroup.children[0].style.marginLeft = -slant + "em";
+        } else if (!subGroup) {
+            bottom = base.depth + baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "elem", elem: base},
+                {type: "kern", size: supKern},
+                {type: "elem", elem: supmid},
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}
+            ], "bottom", bottom, options);
+
+            // See comment above about slants
+            finalGroup.children[1].style.marginLeft = slant + "em";
+        } else if (!supGroup && !subGroup) {
+            // This case probably shouldn't occur (this would mean the
+            // supsub was sending us a group with no superscript or
+            // subscript) but be safe.
+            return base;
+        } else {
+            bottom = fontMetrics.metrics.bigOpSpacing5 +
+                submid.height + submid.depth +
+                subKern +
+                base.depth + baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
+                {type: "elem", elem: submid},
+                {type: "kern", size: subKern},
+                {type: "elem", elem: base},
+                {type: "kern", size: supKern},
+                {type: "elem", elem: supmid},
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}
+            ], "bottom", bottom, options);
+
+            // See comment above about slants
+            finalGroup.children[0].style.marginLeft = -slant + "em";
+            finalGroup.children[2].style.marginLeft = slant + "em";
+        }
+
+        return makeSpan(["mop", "op-limits"], [finalGroup], options);
+    } else {
+        if (group.value.symbol) {
+            base.style.top = baseShift + "em";
+        }
+
+        return base;
+    }
+};
+
+groupTypes.mod = function(group, options) {
+    var inner = [];
+
+    if (group.value.modType === "bmod") {
+        // “\nonscript\mskip-\medmuskip\mkern5mu”
+        if (!options.style.isTight()) {
+            inner.push(makeSpan(
+                ["mspace", "negativemediumspace"], [], options));
+        }
+        inner.push(makeSpan(["mspace", "thickspace"], [], options));
+    } else if (options.style.size === Style.DISPLAY.size) {
+        inner.push(makeSpan(["mspace", "quad"], [], options));
+    } else if (group.value.modType === "mod") {
+        inner.push(makeSpan(["mspace", "twelvemuspace"], [], options));
+    } else {
+        inner.push(makeSpan(["mspace", "eightmuspace"], [], options));
+    }
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(buildCommon.mathsym("(", group.mode));
+    }
+
+    if (group.value.modType !== "pod") {
+        var modInner = [
+            buildCommon.mathsym("m", group.mode),
+            buildCommon.mathsym("o", group.mode),
+            buildCommon.mathsym("d", group.mode)];
+        if (group.value.modType === "bmod") {
+            inner.push(makeSpan(["mbin"], modInner, options));
+            // “\mkern5mu\nonscript\mskip-\medmuskip”
+            inner.push(makeSpan(["mspace", "thickspace"], [], options));
+            if (!options.style.isTight()) {
+                inner.push(makeSpan(
+                    ["mspace", "negativemediumspace"], [], options));
+            }
+        } else {
+            Array.prototype.push.apply(inner, modInner);
+            inner.push(makeSpan(["mspace", "sixmuspace"], [], options));
+        }
+    }
+
+    if (group.value.value) {
+        Array.prototype.push.apply(inner,
+            buildExpression(group.value.value, options, false));
+    }
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(buildCommon.mathsym(")", group.mode));
+    }
+
+    return buildCommon.makeFragment(inner);
+};
+
+groupTypes.katex = function(group, options) {
+    // The KaTeX logo. The offsets for the K and a were chosen to look
+    // good, but the offsets for the T, E, and X were taken from the
+    // definition of \TeX in TeX (see TeXbook pg. 356)
+    var k = makeSpan(
+        ["k"], [buildCommon.mathsym("K", group.mode)], options);
+    var a = makeSpan(
+        ["a"], [buildCommon.mathsym("A", group.mode)], options);
+
+    a.height = (a.height + 0.2) * 0.75;
+    a.depth = (a.height - 0.2) * 0.75;
+
+    var t = makeSpan(
+        ["t"], [buildCommon.mathsym("T", group.mode)], options);
+    var e = makeSpan(
+        ["e"], [buildCommon.mathsym("E", group.mode)], options);
+
+    e.height = (e.height - 0.2155);
+    e.depth = (e.depth + 0.2155);
+
+    var x = makeSpan(
+        ["x"], [buildCommon.mathsym("X", group.mode)], options);
+
+    return makeSpan(
+        ["mord", "katex-logo"], [k, a, t, e, x], options);
+};
+
+groupTypes.overline = function(group, options) {
+    // Overlines are handled in the TeXbook pg 443, Rule 9.
+    var style = options.style;
+
+    // Build the inner group in the cramped style.
+    var innerGroup = buildGroup(group.value.body,
+            options.withStyle(style.cramp()));
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    // Create the line above the body
+    var line = makeSpan(
+        [style.reset(), Style.TEXT.cls(), "overline-line"]);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    // Generate the vlist, with the appropriate kerns
+    var vlist = buildCommon.makeVList([
+        {type: "elem", elem: innerGroup},
+        {type: "kern", size: 3 * ruleWidth},
+        {type: "elem", elem: line},
+        {type: "kern", size: ruleWidth}
+    ], "firstBaseline", null, options);
+
+    return makeSpan(["mord", "overline"], [vlist], options);
+};
+
+groupTypes.underline = function(group, options) {
+    // Underlines are handled in the TeXbook pg 443, Rule 10.
+    var style = options.style;
+
+    // Build the inner group.
+    var innerGroup = buildGroup(group.value.body, options);
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    // Create the line above the body
+    var line = makeSpan([style.reset(), Style.TEXT.cls(), "underline-line"]);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    // Generate the vlist, with the appropriate kerns
+    var vlist = buildCommon.makeVList([
+        {type: "kern", size: ruleWidth},
+        {type: "elem", elem: line},
+        {type: "kern", size: 3 * ruleWidth},
+        {type: "elem", elem: innerGroup}
+    ], "top", innerGroup.height, options);
+
+    return makeSpan(["mord", "underline"], [vlist], options);
+};
+
+groupTypes.sqrt = function(group, options) {
+    // Square roots are handled in the TeXbook pg. 443, Rule 11.
+    var style = options.style;
+
+    // First, we do the same steps as in overline to build the inner group
+    // and line
+    var inner = buildGroup(group.value.body, options.withStyle(style.cramp()));
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    var line = makeSpan(
+        [style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
+        options);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    var phi = ruleWidth;
+    if (style.id < Style.TEXT.id) {
+        phi = style.metrics.xHeight;
+    }
+
+    // Calculate the clearance between the body and line
+    var lineClearance = ruleWidth + phi / 4;
+
+    var innerHeight = (inner.height + inner.depth) * style.sizeMultiplier;
+    var minDelimiterHeight = innerHeight + lineClearance + ruleWidth;
+
+    // Create a \surd delimiter of the required minimum size
+    var delim = makeSpan(["sqrt-sign"], [
+        delimiter.customSizedDelim("\\surd", minDelimiterHeight,
+                                   false, options, group.mode)],
+                         options);
+
+    var delimDepth = (delim.height + delim.depth) - ruleWidth;
+
+    // Adjust the clearance based on the delimiter size
+    if (delimDepth > inner.height + inner.depth + lineClearance) {
+        lineClearance =
+            (lineClearance + delimDepth - inner.height - inner.depth) / 2;
+    }
+
+    // Shift the delimiter so that its top lines up with the top of the line
+    var delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height;
+    delim.style.top = delimShift + "em";
+    delim.height -= delimShift;
+    delim.depth += delimShift;
+
+    // We add a special case here, because even when `inner` is empty, we
+    // still get a line. So, we use a simple heuristic to decide if we
+    // should omit the body entirely. (note this doesn't work for something
+    // like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for
+    // it not to work.
+    var body;
+    if (inner.height === 0 && inner.depth === 0) {
+        body = makeSpan();
+    } else {
+        body = buildCommon.makeVList([
+            {type: "elem", elem: inner},
+            {type: "kern", size: lineClearance},
+            {type: "elem", elem: line},
+            {type: "kern", size: ruleWidth}
+        ], "firstBaseline", null, options);
+    }
+
+    if (!group.value.index) {
+        return makeSpan(["mord", "sqrt"], [delim, body], options);
+    } else {
+        // Handle the optional root index
+
+        // The index is always in scriptscript style
+        var newOptions = options.withStyle(Style.SCRIPTSCRIPT);
+        var root = buildGroup(group.value.index, newOptions);
+        var rootWrap = makeSpan(
+            [style.reset(), Style.SCRIPTSCRIPT.cls()],
+            [root],
+            newOptions);
+
+        // Figure out the height and depth of the inner part
+        var innerRootHeight = Math.max(delim.height, body.height);
+        var innerRootDepth = Math.max(delim.depth, body.depth);
+
+        // The amount the index is shifted by. This is taken from the TeX
+        // source, in the definition of `\r@@t`.
+        var toShift = 0.6 * (innerRootHeight - innerRootDepth);
+
+        // Build a VList with the superscript shifted up correctly
+        var rootVList = buildCommon.makeVList(
+            [{type: "elem", elem: rootWrap}],
+            "shift", -toShift, options);
+        // Add a class surrounding it so we can add on the appropriate
+        // kerning
+        var rootVListWrap = makeSpan(["root"], [rootVList]);
+
+        return makeSpan(["mord", "sqrt"],
+            [rootVListWrap, delim, body], options);
+    }
+};
+
+groupTypes.sizing = function(group, options) {
+    // Handle sizing operators like \Huge. Real TeX doesn't actually allow
+    // these functions inside of math expressions, so we do some special
+    // handling.
+    var inner = buildExpression(group.value.value,
+            options.withSize(group.value.size), false);
+
+    // Compute the correct maxFontSize.
+    var style = options.style;
+    var fontSize = buildCommon.sizingMultiplier[group.value.size];
+    fontSize = fontSize * style.sizeMultiplier;
+
+    // Add size-resetting classes to the inner list and set maxFontSize
+    // manually. Handle nested size changes.
+    for (var i = 0; i < inner.length; i++) {
+        var pos = utils.indexOf(inner[i].classes, "sizing");
+        if (pos < 0) {
+            inner[i].classes.push("sizing", "reset-" + options.size,
+                                  group.value.size, style.cls());
+            inner[i].maxFontSize = fontSize;
+        } else if (inner[i].classes[pos + 1] === "reset-" + group.value.size) {
+            // This is a nested size change: e.g., inner[i] is the "b" in
+            // `\Huge a \small b`. Override the old size (the `reset-` class)
+            // but not the new size.
+            inner[i].classes[pos + 1] = "reset-" + options.size;
+        }
+    }
+
+    return buildCommon.makeFragment(inner);
+};
+
+groupTypes.styling = function(group, options) {
+    // Style changes are handled in the TeXbook on pg. 442, Rule 3.
+
+    // Figure out what style we're changing to.
+    var styleMap = {
+        "display": Style.DISPLAY,
+        "text": Style.TEXT,
+        "script": Style.SCRIPT,
+        "scriptscript": Style.SCRIPTSCRIPT
+    };
+
+    var newStyle = styleMap[group.value.style];
+    var newOptions = options.withStyle(newStyle);
+
+    // Build the inner expression in the new style.
+    var inner = buildExpression(
+        group.value.value, newOptions, false);
+
+    // Add style-resetting classes to the inner list. Handle nested changes.
+    for (var i = 0; i < inner.length; i++) {
+        var pos = utils.indexOf(inner[i].classes, newStyle.reset());
+        if (pos < 0) {
+            inner[i].classes.push(options.style.reset(), newStyle.cls());
+        } else {
+            // This is a nested style change, as `\textstyle a\scriptstyle b`.
+            // Only override the old style (the reset class).
+            inner[i].classes[pos] = options.style.reset();
+        }
+    }
+
+    return new buildCommon.makeFragment(inner);
+};
+
+groupTypes.font = function(group, options) {
+    var font = group.value.font;
+    return buildGroup(group.value.body, options.withFont(font));
+};
+
+groupTypes.delimsizing = function(group, options) {
+    var delim = group.value.value;
+
+    if (delim === ".") {
+        // Empty delimiters still count as elements, even though they don't
+        // show anything.
+        return makeSpan([group.value.mclass]);
+    }
+
+    // Use delimiter.sizedDelim to generate the delimiter.
+    return delimiter.sizedDelim(
+            delim, group.value.size, options, group.mode,
+            [group.value.mclass]);
+};
+
+groupTypes.leftright = function(group, options) {
+    // Build the inner expression
+    var inner = buildExpression(group.value.body, options.reset(), true);
+
+    var innerHeight = 0;
+    var innerDepth = 0;
+    var hadMiddle = false;
+
+    // Calculate its height and depth
+    for (var i = 0; i < inner.length; i++) {
+        if (inner[i].isMiddle) {
+            hadMiddle = true;
+        } else {
+            innerHeight = Math.max(inner[i].height, innerHeight);
+            innerDepth = Math.max(inner[i].depth, innerDepth);
+        }
+    }
+
+    var style = options.style;
+
+    // The size of delimiters is the same, regardless of what style we are
+    // in. Thus, to correctly calculate the size of delimiter we need around
+    // a group, we scale down the inner size based on the size.
+    innerHeight *= style.sizeMultiplier;
+    innerDepth *= style.sizeMultiplier;
+
+    var leftDelim;
+    if (group.value.left === ".") {
+        // Empty delimiters in \left and \right make null delimiter spaces.
+        leftDelim = makeNullDelimiter(options, ["mopen"]);
+    } else {
+        // Otherwise, use leftRightDelim to generate the correct sized
+        // delimiter.
+        leftDelim = delimiter.leftRightDelim(
+            group.value.left, innerHeight, innerDepth, options,
+            group.mode, ["mopen"]);
+    }
+    // Add it to the beginning of the expression
+    inner.unshift(leftDelim);
+
+    // Handle middle delimiters
+    if (hadMiddle) {
+        for (i = 1; i < inner.length; i++) {
+            if (inner[i].isMiddle) {
+                // Apply the options that were active when \middle was called
+                inner[i] = delimiter.leftRightDelim(
+                    inner[i].isMiddle.value, innerHeight, innerDepth,
+                    inner[i].isMiddle.options, group.mode, []);
+            }
+        }
+    }
+
+    var rightDelim;
+    // Same for the right delimiter
+    if (group.value.right === ".") {
+        rightDelim = makeNullDelimiter(options, ["mclose"]);
+    } else {
+        rightDelim = delimiter.leftRightDelim(
+            group.value.right, innerHeight, innerDepth, options,
+            group.mode, ["mclose"]);
+    }
+    // Add it to the end of the expression.
+    inner.push(rightDelim);
+
+    return makeSpan(
+        ["minner", style.cls()], inner, options);
+};
+
+groupTypes.middle = function(group, options) {
+    var middleDelim;
+    if (group.value.value === ".") {
+        middleDelim = makeNullDelimiter(options, []);
+    } else {
+        middleDelim = delimiter.sizedDelim(
+            group.value.value, 1, options,
+            group.mode, []);
+        middleDelim.isMiddle = {value: group.value.value, options: options};
+    }
+    return middleDelim;
+};
+
+groupTypes.rule = function(group, options) {
+    // Make an empty span for the rule
+    var rule = makeSpan(["mord", "rule"], [], options);
+    var style = options.style;
+
+    // Calculate the shift, width, and height of the rule, and account for units
+    var shift = 0;
+    if (group.value.shift) {
+        shift = calculateSize(group.value.shift, style);
+    }
+
+    var width = calculateSize(group.value.width, style);
+    var height = calculateSize(group.value.height, style);
+
+    // The sizes of rules are absolute, so make it larger if we are in a
+    // smaller style.
+    shift /= style.sizeMultiplier;
+    width /= style.sizeMultiplier;
+    height /= style.sizeMultiplier;
+
+    // Style the rule to the right size
+    rule.style.borderRightWidth = width + "em";
+    rule.style.borderTopWidth = height + "em";
+    rule.style.bottom = shift + "em";
+
+    // Record the height and width
+    rule.width = width;
+    rule.height = height + shift;
+    rule.depth = -shift;
+
+    return rule;
+};
+
+groupTypes.kern = function(group, options) {
+    // Make an empty span for the rule
+    var rule = makeSpan(["mord", "rule"], [], options);
+    var style = options.style;
+
+    var dimension = 0;
+    if (group.value.dimension) {
+        dimension = calculateSize(group.value.dimension, style);
+    }
+
+    dimension /= style.sizeMultiplier;
+
+    rule.style.marginLeft = dimension + "em";
+
+    return rule;
+};
+
+groupTypes.accent = function(group, options) {
+    // Accents are handled in the TeXbook pg. 443, rule 12.
+    var base = group.value.base;
+    var style = options.style;
+
+    var supsubGroup;
+    if (group.type === "supsub") {
+        // If our base is a character box, and we have superscripts and
+        // subscripts, the supsub will defer to us. In particular, we want
+        // to attach the superscripts and subscripts to the inner body (so
+        // that the position of the superscripts and subscripts won't be
+        // affected by the height of the accent). We accomplish this by
+        // sticking the base of the accent into the base of the supsub, and
+        // rendering that, while keeping track of where the accent is.
+
+        // The supsub group is the group that was passed in
+        var supsub = group;
+        // The real accent group is the base of the supsub group
+        group = supsub.value.base;
+        // The character box is the base of the accent group
+        base = group.value.base;
+        // Stick the character box into the base of the supsub group
+        supsub.value.base = base;
+
+        // Rerender the supsub group with its new base, and store that
+        // result.
+        supsubGroup = buildGroup(
+            supsub, options.reset());
+    }
+
+    // Build the base group
+    var body = buildGroup(
+        base, options.withStyle(style.cramp()));
+
+    // Calculate the skew of the accent. This is based on the line "If the
+    // nucleus is not a single character, let s = 0; otherwise set s to the
+    // kern amount for the nucleus followed by the \skewchar of its font."
+    // Note that our skew metrics are just the kern between each character
+    // and the skewchar.
+    var skew;
+    if (isCharacterBox(base)) {
+        // If the base is a character box, then we want the skew of the
+        // innermost character. To do that, we find the innermost character:
+        var baseChar = getBaseElem(base);
+        // Then, we render its group to get the symbol inside it
+        var baseGroup = buildGroup(
+            baseChar, options.withStyle(style.cramp()));
+        // Finally, we pull the skew off of the symbol.
+        skew = baseGroup.skew;
+        // Note that we now throw away baseGroup, because the layers we
+        // removed with getBaseElem might contain things like \color which
+        // we can't get rid of.
+        // TODO(emily): Find a better way to get the skew
+    } else {
+        skew = 0;
+    }
+
+    // calculate the amount of space between the body and the accent
+    var clearance = Math.min(
+        body.height,
+        style.metrics.xHeight);
+
+    // Build the accent
+    var accent = buildCommon.makeSymbol(
+        group.value.accent, "Main-Regular", "math", options);
+    // Remove the italic correction of the accent, because it only serves to
+    // shift the accent over to a place we don't want.
+    accent.italic = 0;
+
+    // The \vec character that the fonts use is a combining character, and
+    // thus shows up much too far to the left. To account for this, we add a
+    // specific class which shifts the accent over to where we want it.
+    // TODO(emily): Fix this in a better way, like by changing the font
+    var vecClass = group.value.accent === "\\vec" ? "accent-vec" : null;
+
+    var accentBody = makeSpan(["accent-body", vecClass], [
+        makeSpan([], [accent])]);
+
+    accentBody = buildCommon.makeVList([
+        {type: "elem", elem: body},
+        {type: "kern", size: -clearance},
+        {type: "elem", elem: accentBody}
+    ], "firstBaseline", null, options);
+
+    // Shift the accent over by the skew. Note we shift by twice the skew
+    // because we are centering the accent, so by adding 2*skew to the left,
+    // we shift it to the right by 1*skew.
+    accentBody.children[1].style.marginLeft = 2 * skew + "em";
+
+    var accentWrap = makeSpan(["mord", "accent"], [accentBody], options);
+
+    if (supsubGroup) {
+        // Here, we replace the "base" child of the supsub with our newly
+        // generated accent.
+        supsubGroup.children[0] = accentWrap;
+
+        // Since we don't rerun the height calculation after replacing the
+        // accent, we manually recalculate height.
+        supsubGroup.height = Math.max(accentWrap.height, supsubGroup.height);
+
+        // Accents should always be ords, even when their innards are not.
+        supsubGroup.classes[0] = "mord";
+
+        return supsubGroup;
+    } else {
+        return accentWrap;
+    }
+};
+
+groupTypes.phantom = function(group, options) {
+    var elements = buildExpression(
+        group.value.value,
+        options.withPhantom(),
+        false
+    );
+
+    // \phantom isn't supposed to affect the elements it contains.
+    // See "color" for more details.
+    return new buildCommon.makeFragment(elements);
+};
+
+groupTypes.mclass = function(group, options) {
+    var elements = buildExpression(group.value.value, options, true);
+
+    return makeSpan([group.value.mclass], elements, options);
+};
+
+/**
+ * buildGroup is the function that takes a group and calls the correct groupType
+ * function for it. It also handles the interaction of size and style changes
+ * between parents and children.
+ */
+var buildGroup = function(group, options) {
+    if (!group) {
+        return makeSpan();
+    }
+
+    if (groupTypes[group.type]) {
+        // Call the groupTypes function
+        var groupNode = groupTypes[group.type](group, options);
+        var multiplier;
+
+        // If the style changed between the parent and the current group,
+        // account for the size difference
+        if (options.style !== options.parentStyle) {
+            multiplier = options.style.sizeMultiplier /
+                    options.parentStyle.sizeMultiplier;
+
+            groupNode.height *= multiplier;
+            groupNode.depth *= multiplier;
+        }
+
+        // If the size changed between the parent and the current group, account
+        // for that size difference.
+        if (options.size !== options.parentSize) {
+            multiplier = buildCommon.sizingMultiplier[options.size] /
+                    buildCommon.sizingMultiplier[options.parentSize];
+
+            groupNode.height *= multiplier;
+            groupNode.depth *= multiplier;
+        }
+
+        return groupNode;
+    } else {
+        throw new ParseError(
+            "Got group of unknown type: '" + group.type + "'");
+    }
+};
+
+/**
+ * Take an entire parse tree, and build it into an appropriate set of HTML
+ * nodes.
+ */
+var buildHTML = function(tree, options) {
+    // buildExpression is destructive, so we need to make a clone
+    // of the incoming tree so that it isn't accidentally changed
+    tree = JSON.parse(JSON.stringify(tree));
+
+    // Build the expression contained in the tree
+    var expression = buildExpression(tree, options, true);
+    var body = makeSpan(["base", options.style.cls()], expression, options);
+
+    // Add struts, which ensure that the top of the HTML element falls at the
+    // height of the expression, and the bottom of the HTML element falls at the
+    // depth of the expression.
+    var topStrut = makeSpan(["strut"]);
+    var bottomStrut = makeSpan(["strut", "bottom"]);
+
+    topStrut.style.height = body.height + "em";
+    bottomStrut.style.height = (body.height + body.depth) + "em";
+    // We'd like to use `vertical-align: top` but in IE 9 this lowers the
+    // baseline of the box to the bottom of this strut (instead staying in the
+    // normal place) so we use an absolute value for vertical-align instead
+    bottomStrut.style.verticalAlign = -body.depth + "em";
+
+    // Wrap the struts and body together
+    var htmlNode = makeSpan(["katex-html"], [topStrut, bottomStrut, body]);
+
+    htmlNode.setAttribute("aria-hidden", "true");
+
+    return htmlNode;
+};
+
+module.exports = buildHTML;
+
+},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./delimiter":14,"./domTree":15,"./fontMetrics":17,"./utils":25}],12:[function(require,module,exports){
+/**
+ * This file converts a parse tree into a cooresponding MathML tree. The main
+ * entry point is the `buildMathML` function, which takes a parse tree from the
+ * parser.
+ */
+
+var buildCommon = require("./buildCommon");
+var fontMetrics = require("./fontMetrics");
+var mathMLTree = require("./mathMLTree");
+var ParseError = require("./ParseError");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+var fontMap = buildCommon.fontMap;
+
+/**
+ * Takes a symbol and converts it into a MathML text node after performing
+ * optional replacement from symbols.js.
+ */
+var makeText = function(text, mode) {
+    if (symbols[mode][text] && symbols[mode][text].replace) {
+        text = symbols[mode][text].replace;
+    }
+
+    return new mathMLTree.TextNode(text);
+};
+
+/**
+ * Returns the math variant as a string or null if none is required.
+ */
+var getVariant = function(group, options) {
+    var font = options.font;
+    if (!font) {
+        return null;
+    }
+
+    var mode = group.mode;
+    if (font === "mathit") {
+        return "italic";
+    }
+
+    var value = group.value;
+    if (utils.contains(["\\imath", "\\jmath"], value)) {
+        return null;
+    }
+
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var fontName = fontMap[font].fontName;
+    if (fontMetrics.getCharacterMetrics(value, fontName)) {
+        return fontMap[options.font].variant;
+    }
+
+    return null;
+};
+
+/**
+ * Functions for handling the different types of groups found in the parse
+ * tree. Each function should take a parse group and return a MathML node.
+ */
+var groupTypes = {};
+
+groupTypes.mathord = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mi",
+        [makeText(group.value, group.mode)]);
+
+    var variant = getVariant(group, options);
+    if (variant) {
+        node.setAttribute("mathvariant", variant);
+    }
+    return node;
+};
+
+groupTypes.textord = function(group, options) {
+    var text = makeText(group.value, group.mode);
+
+    var variant = getVariant(group, options) || "normal";
+
+    var node;
+    if (/[0-9]/.test(group.value)) {
+        // TODO(kevinb) merge adjacent <mn> nodes
+        // do it as a post processing step
+        node = new mathMLTree.MathNode("mn", [text]);
+        if (options.font) {
+            node.setAttribute("mathvariant", variant);
+        }
+    } else {
+        node = new mathMLTree.MathNode("mi", [text]);
+        node.setAttribute("mathvariant", variant);
+    }
+
+    return node;
+};
+
+groupTypes.bin = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.rel = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.open = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.close = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.inner = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.punct = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    node.setAttribute("separator", "true");
+
+    return node;
+};
+
+groupTypes.ordgroup = function(group, options) {
+    var inner = buildExpression(group.value, options);
+
+    var node = new mathMLTree.MathNode("mrow", inner);
+
+    return node;
+};
+
+groupTypes.text = function(group, options) {
+    var inner = buildExpression(group.value.body, options);
+
+    var node = new mathMLTree.MathNode("mtext", inner);
+
+    return node;
+};
+
+groupTypes.color = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    node.setAttribute("mathcolor", group.value.color);
+
+    return node;
+};
+
+groupTypes.supsub = function(group, options) {
+    var children = [buildGroup(group.value.base, options)];
+
+    if (group.value.sub) {
+        children.push(buildGroup(group.value.sub, options));
+    }
+
+    if (group.value.sup) {
+        children.push(buildGroup(group.value.sup, options));
+    }
+
+    var nodeType;
+    if (!group.value.sub) {
+        nodeType = "msup";
+    } else if (!group.value.sup) {
+        nodeType = "msub";
+    } else {
+        nodeType = "msubsup";
+    }
+
+    var node = new mathMLTree.MathNode(nodeType, children);
+
+    return node;
+};
+
+groupTypes.genfrac = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mfrac",
+        [buildGroup(group.value.numer, options),
+            buildGroup(group.value.denom, options)]);
+
+    if (!group.value.hasBarLine) {
+        node.setAttribute("linethickness", "0px");
+    }
+
+    if (group.value.leftDelim != null || group.value.rightDelim != null) {
+        var withDelims = [];
+
+        if (group.value.leftDelim != null) {
+            var leftOp = new mathMLTree.MathNode(
+                "mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
+
+            leftOp.setAttribute("fence", "true");
+
+            withDelims.push(leftOp);
+        }
+
+        withDelims.push(node);
+
+        if (group.value.rightDelim != null) {
+            var rightOp = new mathMLTree.MathNode(
+                "mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
+
+            rightOp.setAttribute("fence", "true");
+
+            withDelims.push(rightOp);
+        }
+
+        var outerNode = new mathMLTree.MathNode("mrow", withDelims);
+
+        return outerNode;
+    }
+
+    return node;
+};
+
+groupTypes.array = function(group, options) {
+    return new mathMLTree.MathNode(
+        "mtable", group.value.body.map(function(row) {
+            return new mathMLTree.MathNode(
+                "mtr", row.map(function(cell) {
+                    return new mathMLTree.MathNode(
+                        "mtd", [buildGroup(cell, options)]);
+                }));
+        }));
+};
+
+groupTypes.sqrt = function(group, options) {
+    var node;
+    if (group.value.index) {
+        node = new mathMLTree.MathNode(
+            "mroot", [
+                buildGroup(group.value.body, options),
+                buildGroup(group.value.index, options)
+            ]);
+    } else {
+        node = new mathMLTree.MathNode(
+            "msqrt", [buildGroup(group.value.body, options)]);
+    }
+
+    return node;
+};
+
+groupTypes.leftright = function(group, options) {
+    var inner = buildExpression(group.value.body, options);
+
+    if (group.value.left !== ".") {
+        var leftNode = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.left, group.mode)]);
+
+        leftNode.setAttribute("fence", "true");
+
+        inner.unshift(leftNode);
+    }
+
+    if (group.value.right !== ".") {
+        var rightNode = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.right, group.mode)]);
+
+        rightNode.setAttribute("fence", "true");
+
+        inner.push(rightNode);
+    }
+
+    var outerNode = new mathMLTree.MathNode("mrow", inner);
+
+    return outerNode;
+};
+
+groupTypes.middle = function(group, options) {
+    var middleNode = new mathMLTree.MathNode(
+        "mo", [makeText(group.value.middle, group.mode)]);
+    middleNode.setAttribute("fence", "true");
+    return middleNode;
+};
+
+groupTypes.accent = function(group, options) {
+    var accentNode = new mathMLTree.MathNode(
+        "mo", [makeText(group.value.accent, group.mode)]);
+
+    var node = new mathMLTree.MathNode(
+        "mover",
+        [buildGroup(group.value.base, options),
+            accentNode]);
+
+    node.setAttribute("accent", "true");
+
+    return node;
+};
+
+groupTypes.spacing = function(group) {
+    var node;
+
+    if (group.value === "\\ " || group.value === "\\space" ||
+        group.value === " " || group.value === "~") {
+        node = new mathMLTree.MathNode(
+            "mtext", [new mathMLTree.TextNode("\u00a0")]);
+    } else {
+        node = new mathMLTree.MathNode("mspace");
+
+        node.setAttribute(
+            "width", buildCommon.spacingFunctions[group.value].size);
+    }
+
+    return node;
+};
+
+groupTypes.op = function(group, options) {
+    var node;
+
+    // TODO(emily): handle big operators using the `largeop` attribute
+
+    if (group.value.symbol) {
+        // This is a symbol. Just add the symbol.
+        node = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.body, group.mode)]);
+    } else if (group.value.value) {
+        // This is an operator with children. Add them.
+        node = new mathMLTree.MathNode(
+            "mo", buildExpression(group.value.value, options));
+    } else {
+        // This is a text operator. Add all of the characters from the
+        // operator's name.
+        // TODO(emily): Add a space in the middle of some of these
+        // operators, like \limsup.
+        node = new mathMLTree.MathNode(
+            "mi", [new mathMLTree.TextNode(group.value.body.slice(1))]);
+    }
+
+    return node;
+};
+
+groupTypes.mod = function(group, options) {
+    var inner = [];
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText("(", group.mode)]));
+    }
+    if (group.value.modType !== "pod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText("mod", group.mode)]));
+    }
+    if (group.value.value) {
+        var space = new mathMLTree.MathNode("mspace");
+        space.setAttribute("width", "0.333333em");
+        inner.push(space);
+        inner = inner.concat(buildExpression(group.value.value, options));
+    }
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText(")", group.mode)]));
+    }
+
+    return new mathMLTree.MathNode("mo", inner);
+};
+
+groupTypes.katex = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mtext", [new mathMLTree.TextNode("KaTeX")]);
+
+    return node;
+};
+
+groupTypes.font = function(group, options) {
+    var font = group.value.font;
+    return buildGroup(group.value.body, options.withFont(font));
+};
+
+groupTypes.delimsizing = function(group) {
+    var children = [];
+
+    if (group.value.value !== ".") {
+        children.push(makeText(group.value.value, group.mode));
+    }
+
+    var node = new mathMLTree.MathNode("mo", children);
+
+    if (group.value.mclass === "mopen" ||
+        group.value.mclass === "mclose") {
+        // Only some of the delimsizing functions act as fences, and they
+        // return "mopen" or "mclose" mclass.
+        node.setAttribute("fence", "true");
+    } else {
+        // Explicitly disable fencing if it's not a fence, to override the
+        // defaults.
+        node.setAttribute("fence", "false");
+    }
+
+    return node;
+};
+
+groupTypes.styling = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    var styleAttributes = {
+        "display": ["0", "true"],
+        "text": ["0", "false"],
+        "script": ["1", "false"],
+        "scriptscript": ["2", "false"]
+    };
+
+    var attr = styleAttributes[group.value.style];
+
+    node.setAttribute("scriptlevel", attr[0]);
+    node.setAttribute("displaystyle", attr[1]);
+
+    return node;
+};
+
+groupTypes.sizing = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    // TODO(emily): This doesn't produce the correct size for nested size
+    // changes, because we don't keep state of what style we're currently
+    // in, so we can't reset the size to normal before changing it.  Now
+    // that we're passing an options parameter we should be able to fix
+    // this.
+    node.setAttribute(
+        "mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
+
+    return node;
+};
+
+groupTypes.overline = function(group, options) {
+    var operator = new mathMLTree.MathNode(
+        "mo", [new mathMLTree.TextNode("\u203e")]);
+    operator.setAttribute("stretchy", "true");
+
+    var node = new mathMLTree.MathNode(
+        "mover",
+        [buildGroup(group.value.body, options),
+            operator]);
+    node.setAttribute("accent", "true");
+
+    return node;
+};
+
+groupTypes.underline = function(group, options) {
+    var operator = new mathMLTree.MathNode(
+        "mo", [new mathMLTree.TextNode("\u203e")]);
+    operator.setAttribute("stretchy", "true");
+
+    var node = new mathMLTree.MathNode(
+        "munder",
+        [buildGroup(group.value.body, options),
+            operator]);
+    node.setAttribute("accentunder", "true");
+
+    return node;
+};
+
+groupTypes.rule = function(group) {
+    // TODO(emily): Figure out if there's an actual way to draw black boxes
+    // in MathML.
+    var node = new mathMLTree.MathNode("mrow");
+
+    return node;
+};
+
+groupTypes.kern = function(group) {
+    // TODO(kevin): Figure out if there's a way to add space in MathML
+    var node = new mathMLTree.MathNode("mrow");
+
+    return node;
+};
+
+groupTypes.llap = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mpadded", [buildGroup(group.value.body, options)]);
+
+    node.setAttribute("lspace", "-1width");
+    node.setAttribute("width", "0px");
+
+    return node;
+};
+
+groupTypes.rlap = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mpadded", [buildGroup(group.value.body, options)]);
+
+    node.setAttribute("width", "0px");
+
+    return node;
+};
+
+groupTypes.phantom = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+    return new mathMLTree.MathNode("mphantom", inner);
+};
+
+groupTypes.mclass = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+    return new mathMLTree.MathNode("mstyle", inner);
+};
+
+/**
+ * Takes a list of nodes, builds them, and returns a list of the generated
+ * MathML nodes. A little simpler than the HTML version because we don't do any
+ * previous-node handling.
+ */
+var buildExpression = function(expression, options) {
+    var groups = [];
+    for (var i = 0; i < expression.length; i++) {
+        var group = expression[i];
+        groups.push(buildGroup(group, options));
+    }
+    return groups;
+};
+
+/**
+ * Takes a group from the parser and calls the appropriate groupTypes function
+ * on it to produce a MathML node.
+ */
+var buildGroup = function(group, options) {
+    if (!group) {
+        return new mathMLTree.MathNode("mrow");
+    }
+
+    if (groupTypes[group.type]) {
+        // Call the groupTypes function
+        return groupTypes[group.type](group, options);
+    } else {
+        throw new ParseError(
+            "Got group of unknown type: '" + group.type + "'");
+    }
+};
+
+/**
+ * Takes a full parse tree and settings and builds a MathML representation of
+ * it. In particular, we put the elements from building the parse tree into a
+ * <semantics> tag so we can also include that TeX source as an annotation.
+ *
+ * Note that we actually return a domTree element with a `<math>` inside it so
+ * we can do appropriate styling.
+ */
+var buildMathML = function(tree, texExpression, options) {
+    var expression = buildExpression(tree, options);
+
+    // Wrap up the expression in an mrow so it is presented in the semantics
+    // tag correctly.
+    var wrapper = new mathMLTree.MathNode("mrow", expression);
+
+    // Build a TeX annotation of the source
+    var annotation = new mathMLTree.MathNode(
+        "annotation", [new mathMLTree.TextNode(texExpression)]);
+
+    annotation.setAttribute("encoding", "application/x-tex");
+
+    var semantics = new mathMLTree.MathNode(
+        "semantics", [wrapper, annotation]);
+
+    var math = new mathMLTree.MathNode("math", [semantics]);
+
+    // You can't style <math> nodes, so we wrap the node in a span.
+    return makeSpan(["katex-mathml"], [math]);
+};
+
+module.exports = buildMathML;
+
+},{"./ParseError":6,"./buildCommon":10,"./fontMetrics":17,"./mathMLTree":20,"./symbols":23,"./utils":25}],13:[function(require,module,exports){
+var buildHTML = require("./buildHTML");
+var buildMathML = require("./buildMathML");
+var buildCommon = require("./buildCommon");
+var Options = require("./Options");
+var Settings = require("./Settings");
+var Style = require("./Style");
+
+var makeSpan = buildCommon.makeSpan;
+
+var buildTree = function(tree, expression, settings) {
+    settings = settings || new Settings({});
+
+    var startStyle = Style.TEXT;
+    if (settings.displayMode) {
+        startStyle = Style.DISPLAY;
+    }
+
+    // Setup the default options
+    var options = new Options({
+        style: startStyle,
+        size: "size5"
+    });
+
+    // `buildHTML` sometimes messes with the parse tree (like turning bins ->
+    // ords), so we build the MathML version first.
+    var mathMLNode = buildMathML(tree, expression, options);
+    var htmlNode = buildHTML(tree, options);
+
+    var katexNode = makeSpan(["katex"], [
+        mathMLNode, htmlNode
+    ]);
+
+    if (settings.displayMode) {
+        return makeSpan(["katex-display"], [katexNode]);
+    } else {
+        return katexNode;
+    }
+};
+
+module.exports = buildTree;
+
+},{"./Options":5,"./Settings":8,"./Style":9,"./buildCommon":10,"./buildHTML":11,"./buildMathML":12}],14:[function(require,module,exports){
+/**
+ * This file deals with creating delimiters of various sizes. The TeXbook
+ * discusses these routines on page 441-442, in the "Another subroutine sets box
+ * x to a specified variable delimiter" paragraph.
+ *
+ * There are three main routines here. `makeSmallDelim` makes a delimiter in the
+ * normal font, but in either text, script, or scriptscript style.
+ * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1,
+ * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of
+ * smaller pieces that are stacked on top of one another.
+ *
+ * The functions take a parameter `center`, which determines if the delimiter
+ * should be centered around the axis.
+ *
+ * Then, there are three exposed functions. `sizedDelim` makes a delimiter in
+ * one of the given sizes. This is used for things like `\bigl`.
+ * `customSizedDelim` makes a delimiter with a given total height+depth. It is
+ * called in places like `\sqrt`. `leftRightDelim` makes an appropriate
+ * delimiter which surrounds an expression of a given height an depth. It is
+ * used in `\left` and `\right`.
+ */
+
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var buildCommon = require("./buildCommon");
+var fontMetrics = require("./fontMetrics");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+
+/**
+ * Get the metrics for a given symbol and font, after transformation (i.e.
+ * after following replacement from symbols.js)
+ */
+var getMetrics = function(symbol, font) {
+    if (symbols.math[symbol] && symbols.math[symbol].replace) {
+        return fontMetrics.getCharacterMetrics(
+            symbols.math[symbol].replace, font);
+    } else {
+        return fontMetrics.getCharacterMetrics(
+            symbol, font);
+    }
+};
+
+/**
+ * Builds a symbol in the given font size (note size is an integer)
+ */
+var mathrmSize = function(value, size, mode, options) {
+    return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
+        mode, options);
+};
+
+/**
+ * Puts a delimiter span in a given style, and adds appropriate height, depth,
+ * and maxFontSizes.
+ */
+var styleWrap = function(delim, toStyle, options, classes) {
+    classes = classes || [];
+    var span = makeSpan(
+        classes.concat(["style-wrap", options.style.reset(), toStyle.cls()]),
+        [delim], options);
+
+    var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
+
+    span.height *= multiplier;
+    span.depth *= multiplier;
+    span.maxFontSize = toStyle.sizeMultiplier;
+
+    return span;
+};
+
+/**
+ * Makes a small delimiter. This is a delimiter that comes in the Main-Regular
+ * font, but is restyled to either be in textstyle, scriptstyle, or
+ * scriptscriptstyle.
+ */
+var makeSmallDelim = function(delim, style, center, options, mode, classes) {
+    var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
+
+    var span = styleWrap(text, style, options, classes);
+
+    if (center) {
+        var shift =
+            (1 - options.style.sizeMultiplier / style.sizeMultiplier) *
+            options.style.metrics.axisHeight;
+
+        span.style.top = shift + "em";
+        span.height -= shift;
+        span.depth += shift;
+    }
+
+    return span;
+};
+
+/**
+ * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
+ * Size3, or Size4 fonts. It is always rendered in textstyle.
+ */
+var makeLargeDelim = function(delim, size, center, options, mode, classes) {
+    var inner = mathrmSize(delim, size, mode, options);
+
+    var span = styleWrap(
+        makeSpan(["delimsizing", "size" + size], [inner], options),
+        Style.TEXT, options, classes);
+
+    if (center) {
+        var shift = (1 - options.style.sizeMultiplier) *
+            options.style.metrics.axisHeight;
+
+        span.style.top = shift + "em";
+        span.height -= shift;
+        span.depth += shift;
+    }
+
+    return span;
+};
+
+/**
+ * Make an inner span with the given offset and in the given font. This is used
+ * in `makeStackedDelim` to make the stacking pieces for the delimiter.
+ */
+var makeInner = function(symbol, font, mode) {
+    var sizeClass;
+    // Apply the correct CSS class to choose the right font.
+    if (font === "Size1-Regular") {
+        sizeClass = "delim-size1";
+    } else if (font === "Size4-Regular") {
+        sizeClass = "delim-size4";
+    }
+
+    var inner = makeSpan(
+        ["delimsizinginner", sizeClass],
+        [makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]);
+
+    // Since this will be passed into `makeVList` in the end, wrap the element
+    // in the appropriate tag that VList uses.
+    return {type: "elem", elem: inner};
+};
+
+/**
+ * Make a stacked delimiter out of a given delimiter, with the total height at
+ * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook.
+ */
+var makeStackedDelim = function(delim, heightTotal, center, options, mode,
+                                classes) {
+    // There are four parts, the top, an optional middle, a repeated part, and a
+    // bottom.
+    var top;
+    var middle;
+    var repeat;
+    var bottom;
+    top = repeat = bottom = delim;
+    middle = null;
+    // Also keep track of what font the delimiters are in
+    var font = "Size1-Regular";
+
+    // We set the parts and font based on the symbol. Note that we use
+    // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
+    // repeats of the arrows
+    if (delim === "\\uparrow") {
+        repeat = bottom = "\u23d0";
+    } else if (delim === "\\Uparrow") {
+        repeat = bottom = "\u2016";
+    } else if (delim === "\\downarrow") {
+        top = repeat = "\u23d0";
+    } else if (delim === "\\Downarrow") {
+        top = repeat = "\u2016";
+    } else if (delim === "\\updownarrow") {
+        top = "\\uparrow";
+        repeat = "\u23d0";
+        bottom = "\\downarrow";
+    } else if (delim === "\\Updownarrow") {
+        top = "\\Uparrow";
+        repeat = "\u2016";
+        bottom = "\\Downarrow";
+    } else if (delim === "[" || delim === "\\lbrack") {
+        top = "\u23a1";
+        repeat = "\u23a2";
+        bottom = "\u23a3";
+        font = "Size4-Regular";
+    } else if (delim === "]" || delim === "\\rbrack") {
+        top = "\u23a4";
+        repeat = "\u23a5";
+        bottom = "\u23a6";
+        font = "Size4-Regular";
+    } else if (delim === "\\lfloor") {
+        repeat = top = "\u23a2";
+        bottom = "\u23a3";
+        font = "Size4-Regular";
+    } else if (delim === "\\lceil") {
+        top = "\u23a1";
+        repeat = bottom = "\u23a2";
+        font = "Size4-Regular";
+    } else if (delim === "\\rfloor") {
+        repeat = top = "\u23a5";
+        bottom = "\u23a6";
+        font = "Size4-Regular";
+    } else if (delim === "\\rceil") {
+        top = "\u23a4";
+        repeat = bottom = "\u23a5";
+        font = "Size4-Regular";
+    } else if (delim === "(") {
+        top = "\u239b";
+        repeat = "\u239c";
+        bottom = "\u239d";
+        font = "Size4-Regular";
+    } else if (delim === ")") {
+        top = "\u239e";
+        repeat = "\u239f";
+        bottom = "\u23a0";
+        font = "Size4-Regular";
+    } else if (delim === "\\{" || delim === "\\lbrace") {
+        top = "\u23a7";
+        middle = "\u23a8";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\}" || delim === "\\rbrace") {
+        top = "\u23ab";
+        middle = "\u23ac";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\lgroup") {
+        top = "\u23a7";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\rgroup") {
+        top = "\u23ab";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\lmoustache") {
+        top = "\u23a7";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\rmoustache") {
+        top = "\u23ab";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\surd") {
+        top = "\ue001";
+        bottom = "\u23b7";
+        repeat = "\ue000";
+        font = "Size4-Regular";
+    }
+
+    // Get the metrics of the four sections
+    var topMetrics = getMetrics(top, font);
+    var topHeightTotal = topMetrics.height + topMetrics.depth;
+    var repeatMetrics = getMetrics(repeat, font);
+    var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
+    var bottomMetrics = getMetrics(bottom, font);
+    var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
+    var middleHeightTotal = 0;
+    var middleFactor = 1;
+    if (middle !== null) {
+        var middleMetrics = getMetrics(middle, font);
+        middleHeightTotal = middleMetrics.height + middleMetrics.depth;
+        middleFactor = 2; // repeat symmetrically above and below middle
+    }
+
+    // Calcuate the minimal height that the delimiter can have.
+    // It is at least the size of the top, bottom, and optional middle combined.
+    var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
+
+    // Compute the number of copies of the repeat symbol we will need
+    var repeatCount = Math.ceil(
+        (heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
+
+    // Compute the total height of the delimiter including all the symbols
+    var realHeightTotal =
+        minHeight + repeatCount * middleFactor * repeatHeightTotal;
+
+    // The center of the delimiter is placed at the center of the axis. Note
+    // that in this context, "center" means that the delimiter should be
+    // centered around the axis in the current style, while normally it is
+    // centered around the axis in textstyle.
+    var axisHeight = options.style.metrics.axisHeight;
+    if (center) {
+        axisHeight *= options.style.sizeMultiplier;
+    }
+    // Calculate the depth
+    var depth = realHeightTotal / 2 - axisHeight;
+
+    // Now, we start building the pieces that will go into the vlist
+
+    // Keep a list of the inner pieces
+    var inners = [];
+
+    // Add the bottom symbol
+    inners.push(makeInner(bottom, font, mode));
+
+    var i;
+    if (middle === null) {
+        // Add that many symbols
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+    } else {
+        // When there is a middle bit, we need the middle part and two repeated
+        // sections
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+        inners.push(makeInner(middle, font, mode));
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+    }
+
+    // Add the top symbol
+    inners.push(makeInner(top, font, mode));
+
+    // Finally, build the vlist
+    var inner = buildCommon.makeVList(inners, "bottom", depth, options);
+
+    return styleWrap(
+        makeSpan(["delimsizing", "mult"], [inner], options),
+        Style.TEXT, options, classes);
+};
+
+// There are three kinds of delimiters, delimiters that stack when they become
+// too large
+var stackLargeDelimiters = [
+    "(", ")", "[", "\\lbrack", "]", "\\rbrack",
+    "\\{", "\\lbrace", "\\}", "\\rbrace",
+    "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
+    "\\surd"
+];
+
+// delimiters that always stack
+var stackAlwaysDelimiters = [
+    "\\uparrow", "\\downarrow", "\\updownarrow",
+    "\\Uparrow", "\\Downarrow", "\\Updownarrow",
+    "|", "\\|", "\\vert", "\\Vert",
+    "\\lvert", "\\rvert", "\\lVert", "\\rVert",
+    "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache"
+];
+
+// and delimiters that never stack
+var stackNeverDelimiters = [
+    "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt"
+];
+
+// Metrics of the different sizes. Found by looking at TeX's output of
+// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
+// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
+var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
+
+/**
+ * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4.
+ */
+var makeSizedDelim = function(delim, size, options, mode, classes) {
+    // < and > turn into \langle and \rangle in delimiters
+    if (delim === "<" || delim === "\\lt") {
+        delim = "\\langle";
+    } else if (delim === ">" || delim === "\\gt") {
+        delim = "\\rangle";
+    }
+
+    // Sized delimiters are never centered.
+    if (utils.contains(stackLargeDelimiters, delim) ||
+        utils.contains(stackNeverDelimiters, delim)) {
+        return makeLargeDelim(delim, size, false, options, mode, classes);
+    } else if (utils.contains(stackAlwaysDelimiters, delim)) {
+        return makeStackedDelim(
+            delim, sizeToMaxHeight[size], false, options, mode, classes);
+    } else {
+        throw new ParseError("Illegal delimiter: '" + delim + "'");
+    }
+};
+
+/**
+ * There are three different sequences of delimiter sizes that the delimiters
+ * follow depending on the kind of delimiter. This is used when creating custom
+ * sized delimiters to decide whether to create a small, large, or stacked
+ * delimiter.
+ *
+ * In real TeX, these sequences aren't explicitly defined, but are instead
+ * defined inside the font metrics. Since there are only three sequences that
+ * are possible for the delimiters that TeX defines, it is easier to just encode
+ * them explicitly here.
+ */
+
+// Delimiters that never stack try small delimiters and large delimiters only
+var stackNeverDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "large", size: 1},
+    {type: "large", size: 2},
+    {type: "large", size: 3},
+    {type: "large", size: 4}
+];
+
+// Delimiters that always stack try the small delimiters first, then stack
+var stackAlwaysDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "stack"}
+];
+
+// Delimiters that stack when large try the small and then large delimiters, and
+// stack afterwards
+var stackLargeDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "large", size: 1},
+    {type: "large", size: 2},
+    {type: "large", size: 3},
+    {type: "large", size: 4},
+    {type: "stack"}
+];
+
+/**
+ * Get the font used in a delimiter based on what kind of delimiter it is.
+ */
+var delimTypeToFont = function(type) {
+    if (type.type === "small") {
+        return "Main-Regular";
+    } else if (type.type === "large") {
+        return "Size" + type.size + "-Regular";
+    } else if (type.type === "stack") {
+        return "Size4-Regular";
+    }
+};
+
+/**
+ * Traverse a sequence of types of delimiters to decide what kind of delimiter
+ * should be used to create a delimiter of the given height+depth.
+ */
+var traverseSequence = function(delim, height, sequence, options) {
+    // Here, we choose the index we should start at in the sequences. In smaller
+    // sizes (which correspond to larger numbers in style.size) we start earlier
+    // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts
+    // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2
+    var start = Math.min(2, 3 - options.style.size);
+    for (var i = start; i < sequence.length; i++) {
+        if (sequence[i].type === "stack") {
+            // This is always the last delimiter, so we just break the loop now.
+            break;
+        }
+
+        var metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
+        var heightDepth = metrics.height + metrics.depth;
+
+        // Small delimiters are scaled down versions of the same font, so we
+        // account for the style change size.
+
+        if (sequence[i].type === "small") {
+            heightDepth *= sequence[i].style.sizeMultiplier;
+        }
+
+        // Check if the delimiter at this size works for the given height.
+        if (heightDepth > height) {
+            return sequence[i];
+        }
+    }
+
+    // If we reached the end of the sequence, return the last sequence element.
+    return sequence[sequence.length - 1];
+};
+
+/**
+ * Make a delimiter of a given height+depth, with optional centering. Here, we
+ * traverse the sequences, and create a delimiter that the sequence tells us to.
+ */
+var makeCustomSizedDelim = function(delim, height, center, options, mode,
+                                    classes) {
+    if (delim === "<" || delim === "\\lt") {
+        delim = "\\langle";
+    } else if (delim === ">" || delim === "\\gt") {
+        delim = "\\rangle";
+    }
+
+    // Decide what sequence to use
+    var sequence;
+    if (utils.contains(stackNeverDelimiters, delim)) {
+        sequence = stackNeverDelimiterSequence;
+    } else if (utils.contains(stackLargeDelimiters, delim)) {
+        sequence = stackLargeDelimiterSequence;
+    } else {
+        sequence = stackAlwaysDelimiterSequence;
+    }
+
+    // Look through the sequence
+    var delimType = traverseSequence(delim, height, sequence, options);
+
+    // Depending on the sequence element we decided on, call the appropriate
+    // function.
+    if (delimType.type === "small") {
+        return makeSmallDelim(delim, delimType.style, center, options, mode,
+                              classes);
+    } else if (delimType.type === "large") {
+        return makeLargeDelim(delim, delimType.size, center, options, mode,
+                              classes);
+    } else if (delimType.type === "stack") {
+        return makeStackedDelim(delim, height, center, options, mode, classes);
+    }
+};
+
+/**
+ * Make a delimiter for use with `\left` and `\right`, given a height and depth
+ * of an expression that the delimiters surround.
+ */
+var makeLeftRightDelim = function(delim, height, depth, options, mode,
+                                  classes) {
+    // We always center \left/\right delimiters, so the axis is always shifted
+    var axisHeight =
+        options.style.metrics.axisHeight * options.style.sizeMultiplier;
+
+    // Taken from TeX source, tex.web, function make_left_right
+    var delimiterFactor = 901;
+    var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
+
+    var maxDistFromAxis = Math.max(
+        height - axisHeight, depth + axisHeight);
+
+    var totalHeight = Math.max(
+        // In real TeX, calculations are done using integral values which are
+        // 65536 per pt, or 655360 per em. So, the division here truncates in
+        // TeX but doesn't here, producing different results. If we wanted to
+        // exactly match TeX's calculation, we could do
+        //   Math.floor(655360 * maxDistFromAxis / 500) *
+        //    delimiterFactor / 655360
+        // (To see the difference, compare
+        //    x^{x^{\left(\rule{0.1em}{0.68em}\right)}}
+        // in TeX and KaTeX)
+        maxDistFromAxis / 500 * delimiterFactor,
+        2 * maxDistFromAxis - delimiterExtend);
+
+    // Finally, we defer to `makeCustomSizedDelim` with our calculated total
+    // height
+    return makeCustomSizedDelim(delim, totalHeight, true, options, mode,
+                                classes);
+};
+
+module.exports = {
+    sizedDelim: makeSizedDelim,
+    customSizedDelim: makeCustomSizedDelim,
+    leftRightDelim: makeLeftRightDelim
+};
+
+},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(require,module,exports){
+/**
+ * These objects store the data about the DOM nodes we create, as well as some
+ * extra data. They can then be transformed into real DOM nodes with the
+ * `toNode` function or HTML markup using `toMarkup`. They are useful for both
+ * storing extra properties on the nodes, as well as providing a way to easily
+ * work with the DOM.
+ *
+ * Similar functions for working with MathML nodes exist in mathMLTree.js.
+ */
+var unicodeRegexes = require("./unicodeRegexes");
+var utils = require("./utils");
+
+/**
+ * Create an HTML className based on a list of classes. In addition to joining
+ * with spaces, we also remove null or empty classes.
+ */
+var createClass = function(classes) {
+    classes = classes.slice();
+    for (var i = classes.length - 1; i >= 0; i--) {
+        if (!classes[i]) {
+            classes.splice(i, 1);
+        }
+    }
+
+    return classes.join(" ");
+};
+
+/**
+ * This node represents a span node, with a className, a list of children, and
+ * an inline style. It also contains information about its height, depth, and
+ * maxFontSize.
+ */
+function span(classes, children, options) {
+    this.classes = classes || [];
+    this.children = children || [];
+    this.height = 0;
+    this.depth = 0;
+    this.maxFontSize = 0;
+    this.style = {};
+    this.attributes = {};
+    if (options) {
+        if (options.style.isTight()) {
+            this.classes.push("mtight");
+        }
+        if (options.getColor()) {
+            this.style.color = options.getColor();
+        }
+    }
+}
+
+/**
+ * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all
+ * browsers support attributes the same, and having too many custom attributes
+ * is probably bad.
+ */
+span.prototype.setAttribute = function(attribute, value) {
+    this.attributes[attribute] = value;
+};
+
+span.prototype.tryCombine = function(sibling) {
+    return false;
+};
+
+/**
+ * Convert the span into an HTML node
+ */
+span.prototype.toNode = function() {
+    var span = document.createElement("span");
+
+    // Apply the class
+    span.className = createClass(this.classes);
+
+    // Apply inline styles
+    for (var style in this.style) {
+        if (Object.prototype.hasOwnProperty.call(this.style, style)) {
+            span.style[style] = this.style[style];
+        }
+    }
+
+    // Apply attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            span.setAttribute(attr, this.attributes[attr]);
+        }
+    }
+
+    // Append the children, also as HTML nodes
+    for (var i = 0; i < this.children.length; i++) {
+        span.appendChild(this.children[i].toNode());
+    }
+
+    return span;
+};
+
+/**
+ * Convert the span into an HTML markup string
+ */
+span.prototype.toMarkup = function() {
+    var markup = "<span";
+
+    // Add the class
+    if (this.classes.length) {
+        markup += " class=\"";
+        markup += utils.escape(createClass(this.classes));
+        markup += "\"";
+    }
+
+    var styles = "";
+
+    // Add the styles, after hyphenation
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
+        }
+    }
+
+    if (styles) {
+        markup += " style=\"" + utils.escape(styles) + "\"";
+    }
+
+    // Add the attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            markup += " " + attr + "=\"";
+            markup += utils.escape(this.attributes[attr]);
+            markup += "\"";
+        }
+    }
+
+    markup += ">";
+
+    // Add the markup of the children, also as markup
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    markup += "</span>";
+
+    return markup;
+};
+
+/**
+ * This node represents a document fragment, which contains elements, but when
+ * placed into the DOM doesn't have any representation itself. Thus, it only
+ * contains children and doesn't have any HTML properties. It also keeps track
+ * of a height, depth, and maxFontSize.
+ */
+function documentFragment(children) {
+    this.children = children || [];
+    this.height = 0;
+    this.depth = 0;
+    this.maxFontSize = 0;
+}
+
+/**
+ * Convert the fragment into a node
+ */
+documentFragment.prototype.toNode = function() {
+    // Create a fragment
+    var frag = document.createDocumentFragment();
+
+    // Append the children
+    for (var i = 0; i < this.children.length; i++) {
+        frag.appendChild(this.children[i].toNode());
+    }
+
+    return frag;
+};
+
+/**
+ * Convert the fragment into HTML markup
+ */
+documentFragment.prototype.toMarkup = function() {
+    var markup = "";
+
+    // Simply concatenate the markup for the children together
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    return markup;
+};
+
+var iCombinations = {
+    'î': '\u0131\u0302',
+    'ï': '\u0131\u0308',
+    'í': '\u0131\u0301',
+    // 'ī': '\u0131\u0304', // enable when we add Extended Latin
+    'ì': '\u0131\u0300'
+};
+
+/**
+ * A symbol node contains information about a single symbol. It either renders
+ * to a single text node, or a span with a single text node in it, depending on
+ * whether it has CSS classes, styles, or needs italic correction.
+ */
+function symbolNode(value, height, depth, italic, skew, classes, style) {
+    this.value = value || "";
+    this.height = height || 0;
+    this.depth = depth || 0;
+    this.italic = italic || 0;
+    this.skew = skew || 0;
+    this.classes = classes || [];
+    this.style = style || {};
+    this.maxFontSize = 0;
+
+    // Mark CJK characters with specific classes so that we can specify which
+    // fonts to use.  This allows us to render these characters with a serif
+    // font in situations where the browser would either default to a sans serif
+    // or render a placeholder character.
+    if (unicodeRegexes.cjkRegex.test(value)) {
+        // I couldn't find any fonts that contained Hangul as well as all of
+        // the other characters we wanted to test there for it gets its own
+        // CSS class.
+        if (unicodeRegexes.hangulRegex.test(value)) {
+            this.classes.push('hangul_fallback');
+        } else {
+            this.classes.push('cjk_fallback');
+        }
+    }
+
+    if (/[îïíì]/.test(this.value)) {    // add ī when we add Extended Latin
+        this.value = iCombinations[this.value];
+    }
+}
+
+symbolNode.prototype.tryCombine = function(sibling) {
+    if (!sibling
+        || !(sibling instanceof symbolNode)
+        || this.italic > 0
+        || createClass(this.classes) !== createClass(sibling.classes)
+        || this.skew !== sibling.skew
+        || this.maxFontSize !== sibling.maxFontSize) {
+        return false;
+    }
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)
+            && this.style[style] !== sibling.style[style]) {
+            return false;
+        }
+    }
+    for (style in sibling.style) {
+        if (sibling.style.hasOwnProperty(style)
+            && this.style[style] !== sibling.style[style]) {
+            return false;
+        }
+    }
+    this.value += sibling.value;
+    this.height = Math.max(this.height, sibling.height);
+    this.depth = Math.max(this.depth, sibling.depth);
+    this.italic = sibling.italic;
+    return true;
+};
+
+/**
+ * Creates a text node or span from a symbol node. Note that a span is only
+ * created if it is needed.
+ */
+symbolNode.prototype.toNode = function() {
+    var node = document.createTextNode(this.value);
+    var span = null;
+
+    if (this.italic > 0) {
+        span = document.createElement("span");
+        span.style.marginRight = this.italic + "em";
+    }
+
+    if (this.classes.length > 0) {
+        span = span || document.createElement("span");
+        span.className = createClass(this.classes);
+    }
+
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            span = span || document.createElement("span");
+            span.style[style] = this.style[style];
+        }
+    }
+
+    if (span) {
+        span.appendChild(node);
+        return span;
+    } else {
+        return node;
+    }
+};
+
+/**
+ * Creates markup for a symbol node.
+ */
+symbolNode.prototype.toMarkup = function() {
+    // TODO(alpert): More duplication than I'd like from
+    // span.prototype.toMarkup and symbolNode.prototype.toNode...
+    var needsSpan = false;
+
+    var markup = "<span";
+
+    if (this.classes.length) {
+        needsSpan = true;
+        markup += " class=\"";
+        markup += utils.escape(createClass(this.classes));
+        markup += "\"";
+    }
+
+    var styles = "";
+
+    if (this.italic > 0) {
+        styles += "margin-right:" + this.italic + "em;";
+    }
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
+        }
+    }
+
+    if (styles) {
+        needsSpan = true;
+        markup += " style=\"" + utils.escape(styles) + "\"";
+    }
+
+    var escaped = utils.escape(this.value);
+    if (needsSpan) {
+        markup += ">";
+        markup += escaped;
+        markup += "</span>";
+        return markup;
+    } else {
+        return escaped;
+    }
+};
+
+module.exports = {
+    span: span,
+    documentFragment: documentFragment,
+    symbolNode: symbolNode
+};
+
+},{"./unicodeRegexes":24,"./utils":25}],16:[function(require,module,exports){
+/* eslint no-constant-condition:0 */
+var parseData = require("./parseData");
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var ParseNode = parseData.ParseNode;
+
+/**
+ * Parse the body of the environment, with rows delimited by \\ and
+ * columns delimited by &, and create a nested list in row-major order
+ * with one group per cell.
+ */
+function parseArray(parser, result) {
+    var row = [];
+    var body = [row];
+    var rowGaps = [];
+    while (true) {
+        var cell = parser.parseExpression(false, null);
+        row.push(new ParseNode("ordgroup", cell, parser.mode));
+        var next = parser.nextToken.text;
+        if (next === "&") {
+            parser.consume();
+        } else if (next === "\\end") {
+            break;
+        } else if (next === "\\\\" || next === "\\cr") {
+            var cr = parser.parseFunction();
+            rowGaps.push(cr.value.size);
+            row = [];
+            body.push(row);
+        } else {
+            throw new ParseError("Expected & or \\\\ or \\end",
+                                 parser.nextToken);
+        }
+    }
+    result.body = body;
+    result.rowGaps = rowGaps;
+    return new ParseNode(result.type, result, parser.mode);
+}
+
+/*
+ * An environment definition is very similar to a function definition:
+ * it is declared with a name or a list of names, a set of properties
+ * and a handler containing the actual implementation.
+ *
+ * The properties include:
+ *  - numArgs: The number of arguments after the \begin{name} function.
+ *  - argTypes: (optional) Just like for a function
+ *  - allowedInText: (optional) Whether or not the environment is allowed inside
+ *                   text mode (default false) (not enforced yet)
+ *  - numOptionalArgs: (optional) Just like for a function
+ * A bare number instead of that object indicates the numArgs value.
+ *
+ * The handler function will receive two arguments
+ *  - context: information and references provided by the parser
+ *  - args: an array of arguments passed to \begin{name}
+ * The context contains the following properties:
+ *  - envName: the name of the environment, one of the listed names.
+ *  - parser: the parser object
+ *  - lexer: the lexer object
+ *  - positions: the positions associated with these arguments from args.
+ * The handler must return a ParseResult.
+ */
+
+function defineEnvironment(names, props, handler) {
+    if (typeof names === "string") {
+        names = [names];
+    }
+    if (typeof props === "number") {
+        props = { numArgs: props };
+    }
+    // Set default values of environments
+    var data = {
+        numArgs: props.numArgs || 0,
+        argTypes: props.argTypes,
+        greediness: 1,
+        allowedInText: !!props.allowedInText,
+        numOptionalArgs: props.numOptionalArgs || 0,
+        handler: handler
+    };
+    for (var i = 0; i < names.length; ++i) {
+        module.exports[names[i]] = data;
+    }
+}
+
+// Arrays are part of LaTeX, defined in lttab.dtx so its documentation
+// is part of the source2e.pdf file of LaTeX2e source documentation.
+defineEnvironment("array", {
+    numArgs: 1
+}, function(context, args) {
+    var colalign = args[0];
+    colalign = colalign.value.map ? colalign.value : [colalign];
+    var cols = colalign.map(function(node) {
+        var ca = node.value;
+        if ("lcr".indexOf(ca) !== -1) {
+            return {
+                type: "align",
+                align: ca
+            };
+        } else if (ca === "|") {
+            return {
+                type: "separator",
+                separator: "|"
+            };
+        }
+        throw new ParseError(
+            "Unknown column alignment: " + node.value,
+            node);
+    });
+    var res = {
+        type: "array",
+        cols: cols,
+        hskipBeforeAndAfter: true // \@preamble in lttab.dtx
+    };
+    res = parseArray(context.parser, res);
+    return res;
+});
+
+// The matrix environments of amsmath builds on the array environment
+// of LaTeX, which is discussed above.
+defineEnvironment([
+    "matrix",
+    "pmatrix",
+    "bmatrix",
+    "Bmatrix",
+    "vmatrix",
+    "Vmatrix"
+], {
+}, function(context) {
+    var delimiters = {
+        "matrix": null,
+        "pmatrix": ["(", ")"],
+        "bmatrix": ["[", "]"],
+        "Bmatrix": ["\\{", "\\}"],
+        "vmatrix": ["|", "|"],
+        "Vmatrix": ["\\Vert", "\\Vert"]
+    }[context.envName];
+    var res = {
+        type: "array",
+        hskipBeforeAndAfter: false // \hskip -\arraycolsep in amsmath
+    };
+    res = parseArray(context.parser, res);
+    if (delimiters) {
+        res = new ParseNode("leftright", {
+            body: [res],
+            left: delimiters[0],
+            right: delimiters[1]
+        }, context.mode);
+    }
+    return res;
+});
+
+// A cases environment (in amsmath.sty) is almost equivalent to
+// \def\arraystretch{1.2}%
+// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
+defineEnvironment("cases", {
+}, function(context) {
+    var res = {
+        type: "array",
+        arraystretch: 1.2,
+        cols: [{
+            type: "align",
+            align: "l",
+            pregap: 0,
+            // TODO(kevinb) get the current style.
+            // For now we use the metrics for TEXT style which is what we were
+            // doing before.  Before attempting to get the current style we
+            // should look at TeX's behavior especially for \over and matrices.
+            postgap: Style.TEXT.metrics.quad
+        }, {
+            type: "align",
+            align: "l",
+            pregap: 0,
+            postgap: 0
+        }]
+    };
+    res = parseArray(context.parser, res);
+    res = new ParseNode("leftright", {
+        body: [res],
+        left: "\\{",
+        right: "."
+    }, context.mode);
+    return res;
+});
+
+// An aligned environment is like the align* environment
+// except it operates within math mode.
+// Note that we assume \nomallineskiplimit to be zero,
+// so that \strut@ is the same as \strut.
+defineEnvironment("aligned", {
+}, function(context) {
+    var res = {
+        type: "array",
+        cols: []
+    };
+    res = parseArray(context.parser, res);
+    var emptyGroup = new ParseNode("ordgroup", [], context.mode);
+    var numCols = 0;
+    res.value.body.forEach(function(row) {
+        var i;
+        for (i = 1; i < row.length; i += 2) {
+            row[i].value.unshift(emptyGroup);
+        }
+        if (numCols < row.length) {
+            numCols = row.length;
+        }
+    });
+    for (var i = 0; i < numCols; ++i) {
+        var align = "r";
+        var pregap = 0;
+        if (i % 2 === 1) {
+            align = "l";
+        } else if (i > 0) {
+            pregap = 2; // one \qquad between columns
+        }
+        res.value.cols[i] = {
+            type: "align",
+            align: align,
+            pregap: pregap,
+            postgap: 0
+        };
+    }
+    return res;
+});
+
+},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(require,module,exports){
+/* eslint no-unused-vars:0 */
+
+var Style = require("./Style");
+var cjkRegex = require("./unicodeRegexes").cjkRegex;
+
+/**
+ * This file contains metrics regarding fonts and individual symbols. The sigma
+ * and xi variables, as well as the metricMap map contain data extracted from
+ * TeX, TeX font metrics, and the TTF files. These data are then exposed via the
+ * `metrics` variable and the getCharacterMetrics function.
+ */
+
+// In TeX, there are actually three sets of dimensions, one for each of
+// textstyle, scriptstyle, and scriptscriptstyle.  These are provided in the
+// the arrays below, in that order.
+//
+// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively.
+// This was determined by running the folllowing script:
+//
+//     latex -interaction=nonstopmode \
+//     '\documentclass{article}\usepackage{amsmath}\begin{document}' \
+//     '$a$ \expandafter\show\the\textfont2' \
+//     '\expandafter\show\the\scriptfont2' \
+//     '\expandafter\show\the\scriptscriptfont2' \
+//     '\stop'
+//
+// The metrics themselves were retreived using the following commands:
+//
+//     tftopl cmsy10
+//     tftopl cmsy7
+//     tftopl cmsy5
+//
+// The output of each of these commands is quite lengthy.  The only part we
+// care about is the FONTDIMEN section. Each value is measured in EMs.
+var sigmas = {
+    slant: [0.250, 0.250, 0.250],       // sigma1
+    space: [0.000, 0.000, 0.000],       // sigma2
+    stretch: [0.000, 0.000, 0.000],     // sigma3
+    shrink: [0.000, 0.000, 0.000],      // sigma4
+    xHeight: [0.431, 0.431, 0.431],     // sigma5
+    quad: [1.000, 1.171, 1.472],        // sigma6
+    extraSpace: [0.000, 0.000, 0.000],  // sigma7
+    num1: [0.677, 0.732, 0.925],        // sigma8
+    num2: [0.394, 0.384, 0.387],        // sigma9
+    num3: [0.444, 0.471, 0.504],        // sigma10
+    denom1: [0.686, 0.752, 1.025],      // sigma11
+    denom2: [0.345, 0.344, 0.532],      // sigma12
+    sup1: [0.413, 0.503, 0.504],        // sigma13
+    sup2: [0.363, 0.431, 0.404],        // sigma14
+    sup3: [0.289, 0.286, 0.294],        // sigma15
+    sub1: [0.150, 0.143, 0.200],        // sigma16
+    sub2: [0.247, 0.286, 0.400],        // sigma17
+    supDrop: [0.386, 0.353, 0.494],     // sigma18
+    subDrop: [0.050, 0.071, 0.100],     // sigma19
+    delim1: [2.390, 1.700, 1.980],      // sigma20
+    delim2: [1.010, 1.157, 1.420],      // sigma21
+    axisHeight: [0.250, 0.250, 0.250]  // sigma22
+};
+
+// These font metrics are extracted from TeX by using
+// \font\a=cmex10
+// \showthe\fontdimenX\a
+// where X is the corresponding variable number. These correspond to the font
+// parameters of the extension fonts (family 3). See the TeXbook, page 441.
+var xi1 = 0;
+var xi2 = 0;
+var xi3 = 0;
+var xi4 = 0;
+var xi5 = 0.431;
+var xi6 = 1;
+var xi7 = 0;
+var xi8 = 0.04;
+var xi9 = 0.111;
+var xi10 = 0.166;
+var xi11 = 0.2;
+var xi12 = 0.6;
+var xi13 = 0.1;
+
+// This value determines how large a pt is, for metrics which are defined in
+// terms of pts.
+// This value is also used in katex.less; if you change it make sure the values
+// match.
+var ptPerEm = 10.0;
+
+// The space between adjacent `|` columns in an array definition. From
+// `\showthe\doublerulesep` in LaTeX.
+var doubleRuleSep = 2.0 / ptPerEm;
+
+/**
+ * This is just a mapping from common names to real metrics
+ */
+var metrics = {
+    defaultRuleThickness: xi8,
+    bigOpSpacing1: xi9,
+    bigOpSpacing2: xi10,
+    bigOpSpacing3: xi11,
+    bigOpSpacing4: xi12,
+    bigOpSpacing5: xi13,
+    ptPerEm: ptPerEm,
+    doubleRuleSep: doubleRuleSep
+};
+
+// This map contains a mapping from font name and character code to character
+// metrics, including height, depth, italic correction, and skew (kern from the
+// character to the corresponding \skewchar)
+// This map is generated via `make metrics`. It should not be changed manually.
+var metricMap = require("./fontMetricsData");
+
+// These are very rough approximations.  We default to Times New Roman which
+// should have Latin-1 and Cyrillic characters, but may not depending on the
+// operating system.  The metrics do not account for extra height from the
+// accents.  In the case of Cyrillic characters which have both ascenders and
+// descenders we prefer approximations with ascenders, primarily to prevent
+// the fraction bar or root line from intersecting the glyph.
+// TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
+var extraCharacterMap = {
+    // Latin-1
+    'À': 'A',
+    'Á': 'A',
+    'Â': 'A',
+    'Ã': 'A',
+    'Ä': 'A',
+    'Å': 'A',
+    'Æ': 'A',
+    'Ç': 'C',
+    'È': 'E',
+    'É': 'E',
+    'Ê': 'E',
+    'Ë': 'E',
+    'Ì': 'I',
+    'Í': 'I',
+    'Î': 'I',
+    'Ï': 'I',
+    'Ð': 'D',
+    'Ñ': 'N',
+    'Ò': 'O',
+    'Ó': 'O',
+    'Ô': 'O',
+    'Õ': 'O',
+    'Ö': 'O',
+    'Ø': 'O',
+    'Ù': 'U',
+    'Ú': 'U',
+    'Û': 'U',
+    'Ü': 'U',
+    'Ý': 'Y',
+    'Þ': 'o',
+    'ß': 'B',
+    'à': 'a',
+    'á': 'a',
+    'â': 'a',
+    'ã': 'a',
+    'ä': 'a',
+    'å': 'a',
+    'æ': 'a',
+    'ç': 'c',
+    'è': 'e',
+    'é': 'e',
+    'ê': 'e',
+    'ë': 'e',
+    'ì': 'i',
+    'í': 'i',
+    'î': 'i',
+    'ï': 'i',
+    'ð': 'd',
+    'ñ': 'n',
+    'ò': 'o',
+    'ó': 'o',
+    'ô': 'o',
+    'õ': 'o',
+    'ö': 'o',
+    'ø': 'o',
+    'ù': 'u',
+    'ú': 'u',
+    'û': 'u',
+    'ü': 'u',
+    'ý': 'y',
+    'þ': 'o',
+    'ÿ': 'y',
+
+    // Cyrillic
+    'А': 'A',
+    'Б': 'B',
+    'В': 'B',
+    'Г': 'F',
+    'Д': 'A',
+    'Е': 'E',
+    'Ж': 'K',
+    'З': '3',
+    'И': 'N',
+    'Й': 'N',
+    'К': 'K',
+    'Л': 'N',
+    'М': 'M',
+    'Н': 'H',
+    'О': 'O',
+    'П': 'N',
+    'Р': 'P',
+    'С': 'C',
+    'Т': 'T',
+    'У': 'y',
+    'Ф': 'O',
+    'Х': 'X',
+    'Ц': 'U',
+    'Ч': 'h',
+    'Ш': 'W',
+    'Щ': 'W',
+    'Ъ': 'B',
+    'Ы': 'X',
+    'Ь': 'B',
+    'Э': '3',
+    'Ю': 'X',
+    'Я': 'R',
+    'а': 'a',
+    'б': 'b',
+    'в': 'a',
+    'г': 'r',
+    'д': 'y',
+    'е': 'e',
+    'ж': 'm',
+    'з': 'e',
+    'и': 'n',
+    'й': 'n',
+    'к': 'n',
+    'л': 'n',
+    'м': 'm',
+    'н': 'n',
+    'о': 'o',
+    'п': 'n',
+    'р': 'p',
+    'с': 'c',
+    'т': 'o',
+    'у': 'y',
+    'ф': 'b',
+    'х': 'x',
+    'ц': 'n',
+    'ч': 'n',
+    'ш': 'w',
+    'щ': 'w',
+    'ъ': 'a',
+    'ы': 'm',
+    'ь': 'a',
+    'э': 'e',
+    'ю': 'm',
+    'я': 'r'
+};
+
+/**
+ * This function is a convenience function for looking up information in the
+ * metricMap table. It takes a character as a string, and a style.
+ *
+ * Note: the `width` property may be undefined if fontMetricsData.js wasn't
+ * built using `Make extended_metrics`.
+ */
+var getCharacterMetrics = function(character, style) {
+    var ch = character.charCodeAt(0);
+    if (character[0] in extraCharacterMap) {
+        ch = extraCharacterMap[character[0]].charCodeAt(0);
+    } else if (cjkRegex.test(character[0])) {
+        ch = 'M'.charCodeAt(0);
+    }
+    var metrics = metricMap[style][ch];
+    if (metrics) {
+        return {
+            depth: metrics[0],
+            height: metrics[1],
+            italic: metrics[2],
+            skew: metrics[3],
+            width: metrics[4]
+        };
+    }
+};
+
+module.exports = {
+    metrics: metrics,
+    sigmas: sigmas,
+    getCharacterMetrics: getCharacterMetrics
+};
+
+},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(require,module,exports){
+module.exports = {
+    "AMS-Regular": {
+        "65": [0, 0.68889, 0, 0],
+        "66": [0, 0.68889, 0, 0],
+        "67": [0, 0.68889, 0, 0],
+        "68": [0, 0.68889, 0, 0],
+        "69": [0, 0.68889, 0, 0],
+        "70": [0, 0.68889, 0, 0],
+        "71": [0, 0.68889, 0, 0],
+        "72": [0, 0.68889, 0, 0],
+        "73": [0, 0.68889, 0, 0],
+        "74": [0.16667, 0.68889, 0, 0],
+        "75": [0, 0.68889, 0, 0],
+        "76": [0, 0.68889, 0, 0],
+        "77": [0, 0.68889, 0, 0],
+        "78": [0, 0.68889, 0, 0],
+        "79": [0.16667, 0.68889, 0, 0],
+        "80": [0, 0.68889, 0, 0],
+        "81": [0.16667, 0.68889, 0, 0],
+        "82": [0, 0.68889, 0, 0],
+        "83": [0, 0.68889, 0, 0],
+        "84": [0, 0.68889, 0, 0],
+        "85": [0, 0.68889, 0, 0],
+        "86": [0, 0.68889, 0, 0],
+        "87": [0, 0.68889, 0, 0],
+        "88": [0, 0.68889, 0, 0],
+        "89": [0, 0.68889, 0, 0],
+        "90": [0, 0.68889, 0, 0],
+        "107": [0, 0.68889, 0, 0],
+        "165": [0, 0.675, 0.025, 0],
+        "174": [0.15559, 0.69224, 0, 0],
+        "240": [0, 0.68889, 0, 0],
+        "295": [0, 0.68889, 0, 0],
+        "710": [0, 0.825, 0, 0],
+        "732": [0, 0.9, 0, 0],
+        "770": [0, 0.825, 0, 0],
+        "771": [0, 0.9, 0, 0],
+        "989": [0.08167, 0.58167, 0, 0],
+        "1008": [0, 0.43056, 0.04028, 0],
+        "8245": [0, 0.54986, 0, 0],
+        "8463": [0, 0.68889, 0, 0],
+        "8487": [0, 0.68889, 0, 0],
+        "8498": [0, 0.68889, 0, 0],
+        "8502": [0, 0.68889, 0, 0],
+        "8503": [0, 0.68889, 0, 0],
+        "8504": [0, 0.68889, 0, 0],
+        "8513": [0, 0.68889, 0, 0],
+        "8592": [-0.03598, 0.46402, 0, 0],
+        "8594": [-0.03598, 0.46402, 0, 0],
+        "8602": [-0.13313, 0.36687, 0, 0],
+        "8603": [-0.13313, 0.36687, 0, 0],
+        "8606": [0.01354, 0.52239, 0, 0],
+        "8608": [0.01354, 0.52239, 0, 0],
+        "8610": [0.01354, 0.52239, 0, 0],
+        "8611": [0.01354, 0.52239, 0, 0],
+        "8619": [0, 0.54986, 0, 0],
+        "8620": [0, 0.54986, 0, 0],
+        "8621": [-0.13313, 0.37788, 0, 0],
+        "8622": [-0.13313, 0.36687, 0, 0],
+        "8624": [0, 0.69224, 0, 0],
+        "8625": [0, 0.69224, 0, 0],
+        "8630": [0, 0.43056, 0, 0],
+        "8631": [0, 0.43056, 0, 0],
+        "8634": [0.08198, 0.58198, 0, 0],
+        "8635": [0.08198, 0.58198, 0, 0],
+        "8638": [0.19444, 0.69224, 0, 0],
+        "8639": [0.19444, 0.69224, 0, 0],
+        "8642": [0.19444, 0.69224, 0, 0],
+        "8643": [0.19444, 0.69224, 0, 0],
+        "8644": [0.1808, 0.675, 0, 0],
+        "8646": [0.1808, 0.675, 0, 0],
+        "8647": [0.1808, 0.675, 0, 0],
+        "8648": [0.19444, 0.69224, 0, 0],
+        "8649": [0.1808, 0.675, 0, 0],
+        "8650": [0.19444, 0.69224, 0, 0],
+        "8651": [0.01354, 0.52239, 0, 0],
+        "8652": [0.01354, 0.52239, 0, 0],
+        "8653": [-0.13313, 0.36687, 0, 0],
+        "8654": [-0.13313, 0.36687, 0, 0],
+        "8655": [-0.13313, 0.36687, 0, 0],
+        "8666": [0.13667, 0.63667, 0, 0],
+        "8667": [0.13667, 0.63667, 0, 0],
+        "8669": [-0.13313, 0.37788, 0, 0],
+        "8672": [-0.064, 0.437, 0, 0],
+        "8674": [-0.064, 0.437, 0, 0],
+        "8705": [0, 0.825, 0, 0],
+        "8708": [0, 0.68889, 0, 0],
+        "8709": [0.08167, 0.58167, 0, 0],
+        "8717": [0, 0.43056, 0, 0],
+        "8722": [-0.03598, 0.46402, 0, 0],
+        "8724": [0.08198, 0.69224, 0, 0],
+        "8726": [0.08167, 0.58167, 0, 0],
+        "8733": [0, 0.69224, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8737": [0, 0.69224, 0, 0],
+        "8738": [0.03517, 0.52239, 0, 0],
+        "8739": [0.08167, 0.58167, 0, 0],
+        "8740": [0.25142, 0.74111, 0, 0],
+        "8741": [0.08167, 0.58167, 0, 0],
+        "8742": [0.25142, 0.74111, 0, 0],
+        "8756": [0, 0.69224, 0, 0],
+        "8757": [0, 0.69224, 0, 0],
+        "8764": [-0.13313, 0.36687, 0, 0],
+        "8765": [-0.13313, 0.37788, 0, 0],
+        "8769": [-0.13313, 0.36687, 0, 0],
+        "8770": [-0.03625, 0.46375, 0, 0],
+        "8774": [0.30274, 0.79383, 0, 0],
+        "8776": [-0.01688, 0.48312, 0, 0],
+        "8778": [0.08167, 0.58167, 0, 0],
+        "8782": [0.06062, 0.54986, 0, 0],
+        "8783": [0.06062, 0.54986, 0, 0],
+        "8785": [0.08198, 0.58198, 0, 0],
+        "8786": [0.08198, 0.58198, 0, 0],
+        "8787": [0.08198, 0.58198, 0, 0],
+        "8790": [0, 0.69224, 0, 0],
+        "8791": [0.22958, 0.72958, 0, 0],
+        "8796": [0.08198, 0.91667, 0, 0],
+        "8806": [0.25583, 0.75583, 0, 0],
+        "8807": [0.25583, 0.75583, 0, 0],
+        "8808": [0.25142, 0.75726, 0, 0],
+        "8809": [0.25142, 0.75726, 0, 0],
+        "8812": [0.25583, 0.75583, 0, 0],
+        "8814": [0.20576, 0.70576, 0, 0],
+        "8815": [0.20576, 0.70576, 0, 0],
+        "8816": [0.30274, 0.79383, 0, 0],
+        "8817": [0.30274, 0.79383, 0, 0],
+        "8818": [0.22958, 0.72958, 0, 0],
+        "8819": [0.22958, 0.72958, 0, 0],
+        "8822": [0.1808, 0.675, 0, 0],
+        "8823": [0.1808, 0.675, 0, 0],
+        "8828": [0.13667, 0.63667, 0, 0],
+        "8829": [0.13667, 0.63667, 0, 0],
+        "8830": [0.22958, 0.72958, 0, 0],
+        "8831": [0.22958, 0.72958, 0, 0],
+        "8832": [0.20576, 0.70576, 0, 0],
+        "8833": [0.20576, 0.70576, 0, 0],
+        "8840": [0.30274, 0.79383, 0, 0],
+        "8841": [0.30274, 0.79383, 0, 0],
+        "8842": [0.13597, 0.63597, 0, 0],
+        "8843": [0.13597, 0.63597, 0, 0],
+        "8847": [0.03517, 0.54986, 0, 0],
+        "8848": [0.03517, 0.54986, 0, 0],
+        "8858": [0.08198, 0.58198, 0, 0],
+        "8859": [0.08198, 0.58198, 0, 0],
+        "8861": [0.08198, 0.58198, 0, 0],
+        "8862": [0, 0.675, 0, 0],
+        "8863": [0, 0.675, 0, 0],
+        "8864": [0, 0.675, 0, 0],
+        "8865": [0, 0.675, 0, 0],
+        "8872": [0, 0.69224, 0, 0],
+        "8873": [0, 0.69224, 0, 0],
+        "8874": [0, 0.69224, 0, 0],
+        "8876": [0, 0.68889, 0, 0],
+        "8877": [0, 0.68889, 0, 0],
+        "8878": [0, 0.68889, 0, 0],
+        "8879": [0, 0.68889, 0, 0],
+        "8882": [0.03517, 0.54986, 0, 0],
+        "8883": [0.03517, 0.54986, 0, 0],
+        "8884": [0.13667, 0.63667, 0, 0],
+        "8885": [0.13667, 0.63667, 0, 0],
+        "8888": [0, 0.54986, 0, 0],
+        "8890": [0.19444, 0.43056, 0, 0],
+        "8891": [0.19444, 0.69224, 0, 0],
+        "8892": [0.19444, 0.69224, 0, 0],
+        "8901": [0, 0.54986, 0, 0],
+        "8903": [0.08167, 0.58167, 0, 0],
+        "8905": [0.08167, 0.58167, 0, 0],
+        "8906": [0.08167, 0.58167, 0, 0],
+        "8907": [0, 0.69224, 0, 0],
+        "8908": [0, 0.69224, 0, 0],
+        "8909": [-0.03598, 0.46402, 0, 0],
+        "8910": [0, 0.54986, 0, 0],
+        "8911": [0, 0.54986, 0, 0],
+        "8912": [0.03517, 0.54986, 0, 0],
+        "8913": [0.03517, 0.54986, 0, 0],
+        "8914": [0, 0.54986, 0, 0],
+        "8915": [0, 0.54986, 0, 0],
+        "8916": [0, 0.69224, 0, 0],
+        "8918": [0.0391, 0.5391, 0, 0],
+        "8919": [0.0391, 0.5391, 0, 0],
+        "8920": [0.03517, 0.54986, 0, 0],
+        "8921": [0.03517, 0.54986, 0, 0],
+        "8922": [0.38569, 0.88569, 0, 0],
+        "8923": [0.38569, 0.88569, 0, 0],
+        "8926": [0.13667, 0.63667, 0, 0],
+        "8927": [0.13667, 0.63667, 0, 0],
+        "8928": [0.30274, 0.79383, 0, 0],
+        "8929": [0.30274, 0.79383, 0, 0],
+        "8934": [0.23222, 0.74111, 0, 0],
+        "8935": [0.23222, 0.74111, 0, 0],
+        "8936": [0.23222, 0.74111, 0, 0],
+        "8937": [0.23222, 0.74111, 0, 0],
+        "8938": [0.20576, 0.70576, 0, 0],
+        "8939": [0.20576, 0.70576, 0, 0],
+        "8940": [0.30274, 0.79383, 0, 0],
+        "8941": [0.30274, 0.79383, 0, 0],
+        "8994": [0.19444, 0.69224, 0, 0],
+        "8995": [0.19444, 0.69224, 0, 0],
+        "9416": [0.15559, 0.69224, 0, 0],
+        "9484": [0, 0.69224, 0, 0],
+        "9488": [0, 0.69224, 0, 0],
+        "9492": [0, 0.37788, 0, 0],
+        "9496": [0, 0.37788, 0, 0],
+        "9585": [0.19444, 0.68889, 0, 0],
+        "9586": [0.19444, 0.74111, 0, 0],
+        "9632": [0, 0.675, 0, 0],
+        "9633": [0, 0.675, 0, 0],
+        "9650": [0, 0.54986, 0, 0],
+        "9651": [0, 0.54986, 0, 0],
+        "9654": [0.03517, 0.54986, 0, 0],
+        "9660": [0, 0.54986, 0, 0],
+        "9661": [0, 0.54986, 0, 0],
+        "9664": [0.03517, 0.54986, 0, 0],
+        "9674": [0.11111, 0.69224, 0, 0],
+        "9733": [0.19444, 0.69224, 0, 0],
+        "10003": [0, 0.69224, 0, 0],
+        "10016": [0, 0.69224, 0, 0],
+        "10731": [0.11111, 0.69224, 0, 0],
+        "10846": [0.19444, 0.75583, 0, 0],
+        "10877": [0.13667, 0.63667, 0, 0],
+        "10878": [0.13667, 0.63667, 0, 0],
+        "10885": [0.25583, 0.75583, 0, 0],
+        "10886": [0.25583, 0.75583, 0, 0],
+        "10887": [0.13597, 0.63597, 0, 0],
+        "10888": [0.13597, 0.63597, 0, 0],
+        "10889": [0.26167, 0.75726, 0, 0],
+        "10890": [0.26167, 0.75726, 0, 0],
+        "10891": [0.48256, 0.98256, 0, 0],
+        "10892": [0.48256, 0.98256, 0, 0],
+        "10901": [0.13667, 0.63667, 0, 0],
+        "10902": [0.13667, 0.63667, 0, 0],
+        "10933": [0.25142, 0.75726, 0, 0],
+        "10934": [0.25142, 0.75726, 0, 0],
+        "10935": [0.26167, 0.75726, 0, 0],
+        "10936": [0.26167, 0.75726, 0, 0],
+        "10937": [0.26167, 0.75726, 0, 0],
+        "10938": [0.26167, 0.75726, 0, 0],
+        "10949": [0.25583, 0.75583, 0, 0],
+        "10950": [0.25583, 0.75583, 0, 0],
+        "10955": [0.28481, 0.79383, 0, 0],
+        "10956": [0.28481, 0.79383, 0, 0],
+        "57350": [0.08167, 0.58167, 0, 0],
+        "57351": [0.08167, 0.58167, 0, 0],
+        "57352": [0.08167, 0.58167, 0, 0],
+        "57353": [0, 0.43056, 0.04028, 0],
+        "57356": [0.25142, 0.75726, 0, 0],
+        "57357": [0.25142, 0.75726, 0, 0],
+        "57358": [0.41951, 0.91951, 0, 0],
+        "57359": [0.30274, 0.79383, 0, 0],
+        "57360": [0.30274, 0.79383, 0, 0],
+        "57361": [0.41951, 0.91951, 0, 0],
+        "57366": [0.25142, 0.75726, 0, 0],
+        "57367": [0.25142, 0.75726, 0, 0],
+        "57368": [0.25142, 0.75726, 0, 0],
+        "57369": [0.25142, 0.75726, 0, 0],
+        "57370": [0.13597, 0.63597, 0, 0],
+        "57371": [0.13597, 0.63597, 0, 0]
+    },
+    "Caligraphic-Regular": {
+        "48": [0, 0.43056, 0, 0],
+        "49": [0, 0.43056, 0, 0],
+        "50": [0, 0.43056, 0, 0],
+        "51": [0.19444, 0.43056, 0, 0],
+        "52": [0.19444, 0.43056, 0, 0],
+        "53": [0.19444, 0.43056, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0.19444, 0.43056, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0.19444, 0.43056, 0, 0],
+        "65": [0, 0.68333, 0, 0.19445],
+        "66": [0, 0.68333, 0.03041, 0.13889],
+        "67": [0, 0.68333, 0.05834, 0.13889],
+        "68": [0, 0.68333, 0.02778, 0.08334],
+        "69": [0, 0.68333, 0.08944, 0.11111],
+        "70": [0, 0.68333, 0.09931, 0.11111],
+        "71": [0.09722, 0.68333, 0.0593, 0.11111],
+        "72": [0, 0.68333, 0.00965, 0.11111],
+        "73": [0, 0.68333, 0.07382, 0],
+        "74": [0.09722, 0.68333, 0.18472, 0.16667],
+        "75": [0, 0.68333, 0.01445, 0.05556],
+        "76": [0, 0.68333, 0, 0.13889],
+        "77": [0, 0.68333, 0, 0.13889],
+        "78": [0, 0.68333, 0.14736, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.11111],
+        "80": [0, 0.68333, 0.08222, 0.08334],
+        "81": [0.09722, 0.68333, 0, 0.11111],
+        "82": [0, 0.68333, 0, 0.08334],
+        "83": [0, 0.68333, 0.075, 0.13889],
+        "84": [0, 0.68333, 0.25417, 0],
+        "85": [0, 0.68333, 0.09931, 0.08334],
+        "86": [0, 0.68333, 0.08222, 0],
+        "87": [0, 0.68333, 0.08222, 0.08334],
+        "88": [0, 0.68333, 0.14643, 0.13889],
+        "89": [0.09722, 0.68333, 0.08222, 0.08334],
+        "90": [0, 0.68333, 0.07944, 0.13889]
+    },
+    "Fraktur-Regular": {
+        "33": [0, 0.69141, 0, 0],
+        "34": [0, 0.69141, 0, 0],
+        "38": [0, 0.69141, 0, 0],
+        "39": [0, 0.69141, 0, 0],
+        "40": [0.24982, 0.74947, 0, 0],
+        "41": [0.24982, 0.74947, 0, 0],
+        "42": [0, 0.62119, 0, 0],
+        "43": [0.08319, 0.58283, 0, 0],
+        "44": [0, 0.10803, 0, 0],
+        "45": [0.08319, 0.58283, 0, 0],
+        "46": [0, 0.10803, 0, 0],
+        "47": [0.24982, 0.74947, 0, 0],
+        "48": [0, 0.47534, 0, 0],
+        "49": [0, 0.47534, 0, 0],
+        "50": [0, 0.47534, 0, 0],
+        "51": [0.18906, 0.47534, 0, 0],
+        "52": [0.18906, 0.47534, 0, 0],
+        "53": [0.18906, 0.47534, 0, 0],
+        "54": [0, 0.69141, 0, 0],
+        "55": [0.18906, 0.47534, 0, 0],
+        "56": [0, 0.69141, 0, 0],
+        "57": [0.18906, 0.47534, 0, 0],
+        "58": [0, 0.47534, 0, 0],
+        "59": [0.12604, 0.47534, 0, 0],
+        "61": [-0.13099, 0.36866, 0, 0],
+        "63": [0, 0.69141, 0, 0],
+        "65": [0, 0.69141, 0, 0],
+        "66": [0, 0.69141, 0, 0],
+        "67": [0, 0.69141, 0, 0],
+        "68": [0, 0.69141, 0, 0],
+        "69": [0, 0.69141, 0, 0],
+        "70": [0.12604, 0.69141, 0, 0],
+        "71": [0, 0.69141, 0, 0],
+        "72": [0.06302, 0.69141, 0, 0],
+        "73": [0, 0.69141, 0, 0],
+        "74": [0.12604, 0.69141, 0, 0],
+        "75": [0, 0.69141, 0, 0],
+        "76": [0, 0.69141, 0, 0],
+        "77": [0, 0.69141, 0, 0],
+        "78": [0, 0.69141, 0, 0],
+        "79": [0, 0.69141, 0, 0],
+        "80": [0.18906, 0.69141, 0, 0],
+        "81": [0.03781, 0.69141, 0, 0],
+        "82": [0, 0.69141, 0, 0],
+        "83": [0, 0.69141, 0, 0],
+        "84": [0, 0.69141, 0, 0],
+        "85": [0, 0.69141, 0, 0],
+        "86": [0, 0.69141, 0, 0],
+        "87": [0, 0.69141, 0, 0],
+        "88": [0, 0.69141, 0, 0],
+        "89": [0.18906, 0.69141, 0, 0],
+        "90": [0.12604, 0.69141, 0, 0],
+        "91": [0.24982, 0.74947, 0, 0],
+        "93": [0.24982, 0.74947, 0, 0],
+        "94": [0, 0.69141, 0, 0],
+        "97": [0, 0.47534, 0, 0],
+        "98": [0, 0.69141, 0, 0],
+        "99": [0, 0.47534, 0, 0],
+        "100": [0, 0.62119, 0, 0],
+        "101": [0, 0.47534, 0, 0],
+        "102": [0.18906, 0.69141, 0, 0],
+        "103": [0.18906, 0.47534, 0, 0],
+        "104": [0.18906, 0.69141, 0, 0],
+        "105": [0, 0.69141, 0, 0],
+        "106": [0, 0.69141, 0, 0],
+        "107": [0, 0.69141, 0, 0],
+        "108": [0, 0.69141, 0, 0],
+        "109": [0, 0.47534, 0, 0],
+        "110": [0, 0.47534, 0, 0],
+        "111": [0, 0.47534, 0, 0],
+        "112": [0.18906, 0.52396, 0, 0],
+        "113": [0.18906, 0.47534, 0, 0],
+        "114": [0, 0.47534, 0, 0],
+        "115": [0, 0.47534, 0, 0],
+        "116": [0, 0.62119, 0, 0],
+        "117": [0, 0.47534, 0, 0],
+        "118": [0, 0.52396, 0, 0],
+        "119": [0, 0.52396, 0, 0],
+        "120": [0.18906, 0.47534, 0, 0],
+        "121": [0.18906, 0.47534, 0, 0],
+        "122": [0.18906, 0.47534, 0, 0],
+        "8216": [0, 0.69141, 0, 0],
+        "8217": [0, 0.69141, 0, 0],
+        "58112": [0, 0.62119, 0, 0],
+        "58113": [0, 0.62119, 0, 0],
+        "58114": [0.18906, 0.69141, 0, 0],
+        "58115": [0.18906, 0.69141, 0, 0],
+        "58116": [0.18906, 0.47534, 0, 0],
+        "58117": [0, 0.69141, 0, 0],
+        "58118": [0, 0.62119, 0, 0],
+        "58119": [0, 0.47534, 0, 0]
+    },
+    "Main-Bold": {
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.13333, 0.63333, 0, 0],
+        "44": [0.19444, 0.15556, 0, 0],
+        "45": [0, 0.44444, 0, 0],
+        "46": [0, 0.15556, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.64444, 0, 0],
+        "49": [0, 0.64444, 0, 0],
+        "50": [0, 0.64444, 0, 0],
+        "51": [0, 0.64444, 0, 0],
+        "52": [0, 0.64444, 0, 0],
+        "53": [0, 0.64444, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0, 0.64444, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0, 0.64444, 0, 0],
+        "58": [0, 0.44444, 0, 0],
+        "59": [0.19444, 0.44444, 0, 0],
+        "60": [0.08556, 0.58556, 0, 0],
+        "61": [-0.10889, 0.39111, 0, 0],
+        "62": [0.08556, 0.58556, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.68611, 0, 0],
+        "66": [0, 0.68611, 0, 0],
+        "67": [0, 0.68611, 0, 0],
+        "68": [0, 0.68611, 0, 0],
+        "69": [0, 0.68611, 0, 0],
+        "70": [0, 0.68611, 0, 0],
+        "71": [0, 0.68611, 0, 0],
+        "72": [0, 0.68611, 0, 0],
+        "73": [0, 0.68611, 0, 0],
+        "74": [0, 0.68611, 0, 0],
+        "75": [0, 0.68611, 0, 0],
+        "76": [0, 0.68611, 0, 0],
+        "77": [0, 0.68611, 0, 0],
+        "78": [0, 0.68611, 0, 0],
+        "79": [0, 0.68611, 0, 0],
+        "80": [0, 0.68611, 0, 0],
+        "81": [0.19444, 0.68611, 0, 0],
+        "82": [0, 0.68611, 0, 0],
+        "83": [0, 0.68611, 0, 0],
+        "84": [0, 0.68611, 0, 0],
+        "85": [0, 0.68611, 0, 0],
+        "86": [0, 0.68611, 0.01597, 0],
+        "87": [0, 0.68611, 0.01597, 0],
+        "88": [0, 0.68611, 0, 0],
+        "89": [0, 0.68611, 0.02875, 0],
+        "90": [0, 0.68611, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "92": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.31, 0.13444, 0.03194, 0],
+        "96": [0, 0.69444, 0, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0, 0.69444, 0.10903, 0],
+        "103": [0.19444, 0.44444, 0.01597, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.69444, 0, 0],
+        "106": [0.19444, 0.69444, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0, 0],
+        "114": [0, 0.44444, 0, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.63492, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.01597, 0],
+        "119": [0, 0.44444, 0.01597, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.01597, 0],
+        "122": [0, 0.44444, 0, 0],
+        "123": [0.25, 0.75, 0, 0],
+        "124": [0.25, 0.75, 0, 0],
+        "125": [0.25, 0.75, 0, 0],
+        "126": [0.35, 0.34444, 0, 0],
+        "168": [0, 0.69444, 0, 0],
+        "172": [0, 0.44444, 0, 0],
+        "175": [0, 0.59611, 0, 0],
+        "176": [0, 0.69444, 0, 0],
+        "177": [0.13333, 0.63333, 0, 0],
+        "180": [0, 0.69444, 0, 0],
+        "215": [0.13333, 0.63333, 0, 0],
+        "247": [0.13333, 0.63333, 0, 0],
+        "305": [0, 0.44444, 0, 0],
+        "567": [0.19444, 0.44444, 0, 0],
+        "710": [0, 0.69444, 0, 0],
+        "711": [0, 0.63194, 0, 0],
+        "713": [0, 0.59611, 0, 0],
+        "714": [0, 0.69444, 0, 0],
+        "715": [0, 0.69444, 0, 0],
+        "728": [0, 0.69444, 0, 0],
+        "729": [0, 0.69444, 0, 0],
+        "730": [0, 0.69444, 0, 0],
+        "732": [0, 0.69444, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.69444, 0, 0],
+        "772": [0, 0.59611, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.69444, 0, 0],
+        "776": [0, 0.69444, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.63194, 0, 0],
+        "824": [0.19444, 0.69444, 0, 0],
+        "915": [0, 0.68611, 0, 0],
+        "916": [0, 0.68611, 0, 0],
+        "920": [0, 0.68611, 0, 0],
+        "923": [0, 0.68611, 0, 0],
+        "926": [0, 0.68611, 0, 0],
+        "928": [0, 0.68611, 0, 0],
+        "931": [0, 0.68611, 0, 0],
+        "933": [0, 0.68611, 0, 0],
+        "934": [0, 0.68611, 0, 0],
+        "936": [0, 0.68611, 0, 0],
+        "937": [0, 0.68611, 0, 0],
+        "8211": [0, 0.44444, 0.03194, 0],
+        "8212": [0, 0.44444, 0.03194, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0],
+        "8224": [0.19444, 0.69444, 0, 0],
+        "8225": [0.19444, 0.69444, 0, 0],
+        "8242": [0, 0.55556, 0, 0],
+        "8407": [0, 0.72444, 0.15486, 0],
+        "8463": [0, 0.69444, 0, 0],
+        "8465": [0, 0.69444, 0, 0],
+        "8467": [0, 0.69444, 0, 0],
+        "8472": [0.19444, 0.44444, 0, 0],
+        "8476": [0, 0.69444, 0, 0],
+        "8501": [0, 0.69444, 0, 0],
+        "8592": [-0.10889, 0.39111, 0, 0],
+        "8593": [0.19444, 0.69444, 0, 0],
+        "8594": [-0.10889, 0.39111, 0, 0],
+        "8595": [0.19444, 0.69444, 0, 0],
+        "8596": [-0.10889, 0.39111, 0, 0],
+        "8597": [0.25, 0.75, 0, 0],
+        "8598": [0.19444, 0.69444, 0, 0],
+        "8599": [0.19444, 0.69444, 0, 0],
+        "8600": [0.19444, 0.69444, 0, 0],
+        "8601": [0.19444, 0.69444, 0, 0],
+        "8636": [-0.10889, 0.39111, 0, 0],
+        "8637": [-0.10889, 0.39111, 0, 0],
+        "8640": [-0.10889, 0.39111, 0, 0],
+        "8641": [-0.10889, 0.39111, 0, 0],
+        "8656": [-0.10889, 0.39111, 0, 0],
+        "8657": [0.19444, 0.69444, 0, 0],
+        "8658": [-0.10889, 0.39111, 0, 0],
+        "8659": [0.19444, 0.69444, 0, 0],
+        "8660": [-0.10889, 0.39111, 0, 0],
+        "8661": [0.25, 0.75, 0, 0],
+        "8704": [0, 0.69444, 0, 0],
+        "8706": [0, 0.69444, 0.06389, 0],
+        "8707": [0, 0.69444, 0, 0],
+        "8709": [0.05556, 0.75, 0, 0],
+        "8711": [0, 0.68611, 0, 0],
+        "8712": [0.08556, 0.58556, 0, 0],
+        "8715": [0.08556, 0.58556, 0, 0],
+        "8722": [0.13333, 0.63333, 0, 0],
+        "8723": [0.13333, 0.63333, 0, 0],
+        "8725": [0.25, 0.75, 0, 0],
+        "8726": [0.25, 0.75, 0, 0],
+        "8727": [-0.02778, 0.47222, 0, 0],
+        "8728": [-0.02639, 0.47361, 0, 0],
+        "8729": [-0.02639, 0.47361, 0, 0],
+        "8730": [0.18, 0.82, 0, 0],
+        "8733": [0, 0.44444, 0, 0],
+        "8734": [0, 0.44444, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8739": [0.25, 0.75, 0, 0],
+        "8741": [0.25, 0.75, 0, 0],
+        "8743": [0, 0.55556, 0, 0],
+        "8744": [0, 0.55556, 0, 0],
+        "8745": [0, 0.55556, 0, 0],
+        "8746": [0, 0.55556, 0, 0],
+        "8747": [0.19444, 0.69444, 0.12778, 0],
+        "8764": [-0.10889, 0.39111, 0, 0],
+        "8768": [0.19444, 0.69444, 0, 0],
+        "8771": [0.00222, 0.50222, 0, 0],
+        "8776": [0.02444, 0.52444, 0, 0],
+        "8781": [0.00222, 0.50222, 0, 0],
+        "8801": [0.00222, 0.50222, 0, 0],
+        "8804": [0.19667, 0.69667, 0, 0],
+        "8805": [0.19667, 0.69667, 0, 0],
+        "8810": [0.08556, 0.58556, 0, 0],
+        "8811": [0.08556, 0.58556, 0, 0],
+        "8826": [0.08556, 0.58556, 0, 0],
+        "8827": [0.08556, 0.58556, 0, 0],
+        "8834": [0.08556, 0.58556, 0, 0],
+        "8835": [0.08556, 0.58556, 0, 0],
+        "8838": [0.19667, 0.69667, 0, 0],
+        "8839": [0.19667, 0.69667, 0, 0],
+        "8846": [0, 0.55556, 0, 0],
+        "8849": [0.19667, 0.69667, 0, 0],
+        "8850": [0.19667, 0.69667, 0, 0],
+        "8851": [0, 0.55556, 0, 0],
+        "8852": [0, 0.55556, 0, 0],
+        "8853": [0.13333, 0.63333, 0, 0],
+        "8854": [0.13333, 0.63333, 0, 0],
+        "8855": [0.13333, 0.63333, 0, 0],
+        "8856": [0.13333, 0.63333, 0, 0],
+        "8857": [0.13333, 0.63333, 0, 0],
+        "8866": [0, 0.69444, 0, 0],
+        "8867": [0, 0.69444, 0, 0],
+        "8868": [0, 0.69444, 0, 0],
+        "8869": [0, 0.69444, 0, 0],
+        "8900": [-0.02639, 0.47361, 0, 0],
+        "8901": [-0.02639, 0.47361, 0, 0],
+        "8902": [-0.02778, 0.47222, 0, 0],
+        "8968": [0.25, 0.75, 0, 0],
+        "8969": [0.25, 0.75, 0, 0],
+        "8970": [0.25, 0.75, 0, 0],
+        "8971": [0.25, 0.75, 0, 0],
+        "8994": [-0.13889, 0.36111, 0, 0],
+        "8995": [-0.13889, 0.36111, 0, 0],
+        "9651": [0.19444, 0.69444, 0, 0],
+        "9657": [-0.02778, 0.47222, 0, 0],
+        "9661": [0.19444, 0.69444, 0, 0],
+        "9667": [-0.02778, 0.47222, 0, 0],
+        "9711": [0.19444, 0.69444, 0, 0],
+        "9824": [0.12963, 0.69444, 0, 0],
+        "9825": [0.12963, 0.69444, 0, 0],
+        "9826": [0.12963, 0.69444, 0, 0],
+        "9827": [0.12963, 0.69444, 0, 0],
+        "9837": [0, 0.75, 0, 0],
+        "9838": [0.19444, 0.69444, 0, 0],
+        "9839": [0.19444, 0.69444, 0, 0],
+        "10216": [0.25, 0.75, 0, 0],
+        "10217": [0.25, 0.75, 0, 0],
+        "10815": [0, 0.68611, 0, 0],
+        "10927": [0.19667, 0.69667, 0, 0],
+        "10928": [0.19667, 0.69667, 0, 0]
+    },
+    "Main-Italic": {
+        "33": [0, 0.69444, 0.12417, 0],
+        "34": [0, 0.69444, 0.06961, 0],
+        "35": [0.19444, 0.69444, 0.06616, 0],
+        "37": [0.05556, 0.75, 0.13639, 0],
+        "38": [0, 0.69444, 0.09694, 0],
+        "39": [0, 0.69444, 0.12417, 0],
+        "40": [0.25, 0.75, 0.16194, 0],
+        "41": [0.25, 0.75, 0.03694, 0],
+        "42": [0, 0.75, 0.14917, 0],
+        "43": [0.05667, 0.56167, 0.03694, 0],
+        "44": [0.19444, 0.10556, 0, 0],
+        "45": [0, 0.43056, 0.02826, 0],
+        "46": [0, 0.10556, 0, 0],
+        "47": [0.25, 0.75, 0.16194, 0],
+        "48": [0, 0.64444, 0.13556, 0],
+        "49": [0, 0.64444, 0.13556, 0],
+        "50": [0, 0.64444, 0.13556, 0],
+        "51": [0, 0.64444, 0.13556, 0],
+        "52": [0.19444, 0.64444, 0.13556, 0],
+        "53": [0, 0.64444, 0.13556, 0],
+        "54": [0, 0.64444, 0.13556, 0],
+        "55": [0.19444, 0.64444, 0.13556, 0],
+        "56": [0, 0.64444, 0.13556, 0],
+        "57": [0, 0.64444, 0.13556, 0],
+        "58": [0, 0.43056, 0.0582, 0],
+        "59": [0.19444, 0.43056, 0.0582, 0],
+        "61": [-0.13313, 0.36687, 0.06616, 0],
+        "63": [0, 0.69444, 0.1225, 0],
+        "64": [0, 0.69444, 0.09597, 0],
+        "65": [0, 0.68333, 0, 0],
+        "66": [0, 0.68333, 0.10257, 0],
+        "67": [0, 0.68333, 0.14528, 0],
+        "68": [0, 0.68333, 0.09403, 0],
+        "69": [0, 0.68333, 0.12028, 0],
+        "70": [0, 0.68333, 0.13305, 0],
+        "71": [0, 0.68333, 0.08722, 0],
+        "72": [0, 0.68333, 0.16389, 0],
+        "73": [0, 0.68333, 0.15806, 0],
+        "74": [0, 0.68333, 0.14028, 0],
+        "75": [0, 0.68333, 0.14528, 0],
+        "76": [0, 0.68333, 0, 0],
+        "77": [0, 0.68333, 0.16389, 0],
+        "78": [0, 0.68333, 0.16389, 0],
+        "79": [0, 0.68333, 0.09403, 0],
+        "80": [0, 0.68333, 0.10257, 0],
+        "81": [0.19444, 0.68333, 0.09403, 0],
+        "82": [0, 0.68333, 0.03868, 0],
+        "83": [0, 0.68333, 0.11972, 0],
+        "84": [0, 0.68333, 0.13305, 0],
+        "85": [0, 0.68333, 0.16389, 0],
+        "86": [0, 0.68333, 0.18361, 0],
+        "87": [0, 0.68333, 0.18361, 0],
+        "88": [0, 0.68333, 0.15806, 0],
+        "89": [0, 0.68333, 0.19383, 0],
+        "90": [0, 0.68333, 0.14528, 0],
+        "91": [0.25, 0.75, 0.1875, 0],
+        "93": [0.25, 0.75, 0.10528, 0],
+        "94": [0, 0.69444, 0.06646, 0],
+        "95": [0.31, 0.12056, 0.09208, 0],
+        "97": [0, 0.43056, 0.07671, 0],
+        "98": [0, 0.69444, 0.06312, 0],
+        "99": [0, 0.43056, 0.05653, 0],
+        "100": [0, 0.69444, 0.10333, 0],
+        "101": [0, 0.43056, 0.07514, 0],
+        "102": [0.19444, 0.69444, 0.21194, 0],
+        "103": [0.19444, 0.43056, 0.08847, 0],
+        "104": [0, 0.69444, 0.07671, 0],
+        "105": [0, 0.65536, 0.1019, 0],
+        "106": [0.19444, 0.65536, 0.14467, 0],
+        "107": [0, 0.69444, 0.10764, 0],
+        "108": [0, 0.69444, 0.10333, 0],
+        "109": [0, 0.43056, 0.07671, 0],
+        "110": [0, 0.43056, 0.07671, 0],
+        "111": [0, 0.43056, 0.06312, 0],
+        "112": [0.19444, 0.43056, 0.06312, 0],
+        "113": [0.19444, 0.43056, 0.08847, 0],
+        "114": [0, 0.43056, 0.10764, 0],
+        "115": [0, 0.43056, 0.08208, 0],
+        "116": [0, 0.61508, 0.09486, 0],
+        "117": [0, 0.43056, 0.07671, 0],
+        "118": [0, 0.43056, 0.10764, 0],
+        "119": [0, 0.43056, 0.10764, 0],
+        "120": [0, 0.43056, 0.12042, 0],
+        "121": [0.19444, 0.43056, 0.08847, 0],
+        "122": [0, 0.43056, 0.12292, 0],
+        "126": [0.35, 0.31786, 0.11585, 0],
+        "163": [0, 0.69444, 0, 0],
+        "305": [0, 0.43056, 0, 0.02778],
+        "567": [0.19444, 0.43056, 0, 0.08334],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0.09694, 0],
+        "770": [0, 0.69444, 0.06646, 0],
+        "771": [0, 0.66786, 0.11585, 0],
+        "772": [0, 0.56167, 0.10333, 0],
+        "774": [0, 0.69444, 0.10806, 0],
+        "775": [0, 0.66786, 0.11752, 0],
+        "776": [0, 0.66786, 0.10474, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0.1225, 0],
+        "780": [0, 0.62847, 0.08295, 0],
+        "915": [0, 0.68333, 0.13305, 0],
+        "916": [0, 0.68333, 0, 0],
+        "920": [0, 0.68333, 0.09403, 0],
+        "923": [0, 0.68333, 0, 0],
+        "926": [0, 0.68333, 0.15294, 0],
+        "928": [0, 0.68333, 0.16389, 0],
+        "931": [0, 0.68333, 0.12028, 0],
+        "933": [0, 0.68333, 0.11111, 0],
+        "934": [0, 0.68333, 0.05986, 0],
+        "936": [0, 0.68333, 0.11111, 0],
+        "937": [0, 0.68333, 0.10257, 0],
+        "8211": [0, 0.43056, 0.09208, 0],
+        "8212": [0, 0.43056, 0.09208, 0],
+        "8216": [0, 0.69444, 0.12417, 0],
+        "8217": [0, 0.69444, 0.12417, 0],
+        "8220": [0, 0.69444, 0.1685, 0],
+        "8221": [0, 0.69444, 0.06961, 0],
+        "8463": [0, 0.68889, 0, 0]
+    },
+    "Main-Regular": {
+        "32": [0, 0, 0, 0],
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.08333, 0.58333, 0, 0],
+        "44": [0.19444, 0.10556, 0, 0],
+        "45": [0, 0.43056, 0, 0],
+        "46": [0, 0.10556, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.64444, 0, 0],
+        "49": [0, 0.64444, 0, 0],
+        "50": [0, 0.64444, 0, 0],
+        "51": [0, 0.64444, 0, 0],
+        "52": [0, 0.64444, 0, 0],
+        "53": [0, 0.64444, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0, 0.64444, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0, 0.64444, 0, 0],
+        "58": [0, 0.43056, 0, 0],
+        "59": [0.19444, 0.43056, 0, 0],
+        "60": [0.0391, 0.5391, 0, 0],
+        "61": [-0.13313, 0.36687, 0, 0],
+        "62": [0.0391, 0.5391, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.68333, 0, 0],
+        "66": [0, 0.68333, 0, 0],
+        "67": [0, 0.68333, 0, 0],
+        "68": [0, 0.68333, 0, 0],
+        "69": [0, 0.68333, 0, 0],
+        "70": [0, 0.68333, 0, 0],
+        "71": [0, 0.68333, 0, 0],
+        "72": [0, 0.68333, 0, 0],
+        "73": [0, 0.68333, 0, 0],
+        "74": [0, 0.68333, 0, 0],
+        "75": [0, 0.68333, 0, 0],
+        "76": [0, 0.68333, 0, 0],
+        "77": [0, 0.68333, 0, 0],
+        "78": [0, 0.68333, 0, 0],
+        "79": [0, 0.68333, 0, 0],
+        "80": [0, 0.68333, 0, 0],
+        "81": [0.19444, 0.68333, 0, 0],
+        "82": [0, 0.68333, 0, 0],
+        "83": [0, 0.68333, 0, 0],
+        "84": [0, 0.68333, 0, 0],
+        "85": [0, 0.68333, 0, 0],
+        "86": [0, 0.68333, 0.01389, 0],
+        "87": [0, 0.68333, 0.01389, 0],
+        "88": [0, 0.68333, 0, 0],
+        "89": [0, 0.68333, 0.025, 0],
+        "90": [0, 0.68333, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "92": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.31, 0.12056, 0.02778, 0],
+        "96": [0, 0.69444, 0, 0],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.43056, 0, 0],
+        "102": [0, 0.69444, 0.07778, 0],
+        "103": [0.19444, 0.43056, 0.01389, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.66786, 0, 0],
+        "106": [0.19444, 0.66786, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0],
+        "112": [0.19444, 0.43056, 0, 0],
+        "113": [0.19444, 0.43056, 0, 0],
+        "114": [0, 0.43056, 0, 0],
+        "115": [0, 0.43056, 0, 0],
+        "116": [0, 0.61508, 0, 0],
+        "117": [0, 0.43056, 0, 0],
+        "118": [0, 0.43056, 0.01389, 0],
+        "119": [0, 0.43056, 0.01389, 0],
+        "120": [0, 0.43056, 0, 0],
+        "121": [0.19444, 0.43056, 0.01389, 0],
+        "122": [0, 0.43056, 0, 0],
+        "123": [0.25, 0.75, 0, 0],
+        "124": [0.25, 0.75, 0, 0],
+        "125": [0.25, 0.75, 0, 0],
+        "126": [0.35, 0.31786, 0, 0],
+        "160": [0, 0, 0, 0],
+        "168": [0, 0.66786, 0, 0],
+        "172": [0, 0.43056, 0, 0],
+        "175": [0, 0.56778, 0, 0],
+        "176": [0, 0.69444, 0, 0],
+        "177": [0.08333, 0.58333, 0, 0],
+        "180": [0, 0.69444, 0, 0],
+        "215": [0.08333, 0.58333, 0, 0],
+        "247": [0.08333, 0.58333, 0, 0],
+        "305": [0, 0.43056, 0, 0],
+        "567": [0.19444, 0.43056, 0, 0],
+        "710": [0, 0.69444, 0, 0],
+        "711": [0, 0.62847, 0, 0],
+        "713": [0, 0.56778, 0, 0],
+        "714": [0, 0.69444, 0, 0],
+        "715": [0, 0.69444, 0, 0],
+        "728": [0, 0.69444, 0, 0],
+        "729": [0, 0.66786, 0, 0],
+        "730": [0, 0.69444, 0, 0],
+        "732": [0, 0.66786, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.66786, 0, 0],
+        "772": [0, 0.56778, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.66786, 0, 0],
+        "776": [0, 0.66786, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.62847, 0, 0],
+        "824": [0.19444, 0.69444, 0, 0],
+        "915": [0, 0.68333, 0, 0],
+        "916": [0, 0.68333, 0, 0],
+        "920": [0, 0.68333, 0, 0],
+        "923": [0, 0.68333, 0, 0],
+        "926": [0, 0.68333, 0, 0],
+        "928": [0, 0.68333, 0, 0],
+        "931": [0, 0.68333, 0, 0],
+        "933": [0, 0.68333, 0, 0],
+        "934": [0, 0.68333, 0, 0],
+        "936": [0, 0.68333, 0, 0],
+        "937": [0, 0.68333, 0, 0],
+        "8211": [0, 0.43056, 0.02778, 0],
+        "8212": [0, 0.43056, 0.02778, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0],
+        "8224": [0.19444, 0.69444, 0, 0],
+        "8225": [0.19444, 0.69444, 0, 0],
+        "8230": [0, 0.12, 0, 0],
+        "8242": [0, 0.55556, 0, 0],
+        "8407": [0, 0.71444, 0.15382, 0],
+        "8463": [0, 0.68889, 0, 0],
+        "8465": [0, 0.69444, 0, 0],
+        "8467": [0, 0.69444, 0, 0.11111],
+        "8472": [0.19444, 0.43056, 0, 0.11111],
+        "8476": [0, 0.69444, 0, 0],
+        "8501": [0, 0.69444, 0, 0],
+        "8592": [-0.13313, 0.36687, 0, 0],
+        "8593": [0.19444, 0.69444, 0, 0],
+        "8594": [-0.13313, 0.36687, 0, 0],
+        "8595": [0.19444, 0.69444, 0, 0],
+        "8596": [-0.13313, 0.36687, 0, 0],
+        "8597": [0.25, 0.75, 0, 0],
+        "8598": [0.19444, 0.69444, 0, 0],
+        "8599": [0.19444, 0.69444, 0, 0],
+        "8600": [0.19444, 0.69444, 0, 0],
+        "8601": [0.19444, 0.69444, 0, 0],
+        "8614": [0.011, 0.511, 0, 0],
+        "8617": [0.011, 0.511, 0, 0],
+        "8618": [0.011, 0.511, 0, 0],
+        "8636": [-0.13313, 0.36687, 0, 0],
+        "8637": [-0.13313, 0.36687, 0, 0],
+        "8640": [-0.13313, 0.36687, 0, 0],
+        "8641": [-0.13313, 0.36687, 0, 0],
+        "8652": [0.011, 0.671, 0, 0],
+        "8656": [-0.13313, 0.36687, 0, 0],
+        "8657": [0.19444, 0.69444, 0, 0],
+        "8658": [-0.13313, 0.36687, 0, 0],
+        "8659": [0.19444, 0.69444, 0, 0],
+        "8660": [-0.13313, 0.36687, 0, 0],
+        "8661": [0.25, 0.75, 0, 0],
+        "8704": [0, 0.69444, 0, 0],
+        "8706": [0, 0.69444, 0.05556, 0.08334],
+        "8707": [0, 0.69444, 0, 0],
+        "8709": [0.05556, 0.75, 0, 0],
+        "8711": [0, 0.68333, 0, 0],
+        "8712": [0.0391, 0.5391, 0, 0],
+        "8715": [0.0391, 0.5391, 0, 0],
+        "8722": [0.08333, 0.58333, 0, 0],
+        "8723": [0.08333, 0.58333, 0, 0],
+        "8725": [0.25, 0.75, 0, 0],
+        "8726": [0.25, 0.75, 0, 0],
+        "8727": [-0.03472, 0.46528, 0, 0],
+        "8728": [-0.05555, 0.44445, 0, 0],
+        "8729": [-0.05555, 0.44445, 0, 0],
+        "8730": [0.2, 0.8, 0, 0],
+        "8733": [0, 0.43056, 0, 0],
+        "8734": [0, 0.43056, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8739": [0.25, 0.75, 0, 0],
+        "8741": [0.25, 0.75, 0, 0],
+        "8743": [0, 0.55556, 0, 0],
+        "8744": [0, 0.55556, 0, 0],
+        "8745": [0, 0.55556, 0, 0],
+        "8746": [0, 0.55556, 0, 0],
+        "8747": [0.19444, 0.69444, 0.11111, 0],
+        "8764": [-0.13313, 0.36687, 0, 0],
+        "8768": [0.19444, 0.69444, 0, 0],
+        "8771": [-0.03625, 0.46375, 0, 0],
+        "8773": [-0.022, 0.589, 0, 0],
+        "8776": [-0.01688, 0.48312, 0, 0],
+        "8781": [-0.03625, 0.46375, 0, 0],
+        "8784": [-0.133, 0.67, 0, 0],
+        "8800": [0.215, 0.716, 0, 0],
+        "8801": [-0.03625, 0.46375, 0, 0],
+        "8804": [0.13597, 0.63597, 0, 0],
+        "8805": [0.13597, 0.63597, 0, 0],
+        "8810": [0.0391, 0.5391, 0, 0],
+        "8811": [0.0391, 0.5391, 0, 0],
+        "8826": [0.0391, 0.5391, 0, 0],
+        "8827": [0.0391, 0.5391, 0, 0],
+        "8834": [0.0391, 0.5391, 0, 0],
+        "8835": [0.0391, 0.5391, 0, 0],
+        "8838": [0.13597, 0.63597, 0, 0],
+        "8839": [0.13597, 0.63597, 0, 0],
+        "8846": [0, 0.55556, 0, 0],
+        "8849": [0.13597, 0.63597, 0, 0],
+        "8850": [0.13597, 0.63597, 0, 0],
+        "8851": [0, 0.55556, 0, 0],
+        "8852": [0, 0.55556, 0, 0],
+        "8853": [0.08333, 0.58333, 0, 0],
+        "8854": [0.08333, 0.58333, 0, 0],
+        "8855": [0.08333, 0.58333, 0, 0],
+        "8856": [0.08333, 0.58333, 0, 0],
+        "8857": [0.08333, 0.58333, 0, 0],
+        "8866": [0, 0.69444, 0, 0],
+        "8867": [0, 0.69444, 0, 0],
+        "8868": [0, 0.69444, 0, 0],
+        "8869": [0, 0.69444, 0, 0],
+        "8872": [0.249, 0.75, 0, 0],
+        "8900": [-0.05555, 0.44445, 0, 0],
+        "8901": [-0.05555, 0.44445, 0, 0],
+        "8902": [-0.03472, 0.46528, 0, 0],
+        "8904": [0.005, 0.505, 0, 0],
+        "8942": [0.03, 0.9, 0, 0],
+        "8943": [-0.19, 0.31, 0, 0],
+        "8945": [-0.1, 0.82, 0, 0],
+        "8968": [0.25, 0.75, 0, 0],
+        "8969": [0.25, 0.75, 0, 0],
+        "8970": [0.25, 0.75, 0, 0],
+        "8971": [0.25, 0.75, 0, 0],
+        "8994": [-0.14236, 0.35764, 0, 0],
+        "8995": [-0.14236, 0.35764, 0, 0],
+        "9136": [0.244, 0.744, 0, 0],
+        "9137": [0.244, 0.744, 0, 0],
+        "9651": [0.19444, 0.69444, 0, 0],
+        "9657": [-0.03472, 0.46528, 0, 0],
+        "9661": [0.19444, 0.69444, 0, 0],
+        "9667": [-0.03472, 0.46528, 0, 0],
+        "9711": [0.19444, 0.69444, 0, 0],
+        "9824": [0.12963, 0.69444, 0, 0],
+        "9825": [0.12963, 0.69444, 0, 0],
+        "9826": [0.12963, 0.69444, 0, 0],
+        "9827": [0.12963, 0.69444, 0, 0],
+        "9837": [0, 0.75, 0, 0],
+        "9838": [0.19444, 0.69444, 0, 0],
+        "9839": [0.19444, 0.69444, 0, 0],
+        "10216": [0.25, 0.75, 0, 0],
+        "10217": [0.25, 0.75, 0, 0],
+        "10222": [0.244, 0.744, 0, 0],
+        "10223": [0.244, 0.744, 0, 0],
+        "10229": [0.011, 0.511, 0, 0],
+        "10230": [0.011, 0.511, 0, 0],
+        "10231": [0.011, 0.511, 0, 0],
+        "10232": [0.024, 0.525, 0, 0],
+        "10233": [0.024, 0.525, 0, 0],
+        "10234": [0.024, 0.525, 0, 0],
+        "10236": [0.011, 0.511, 0, 0],
+        "10815": [0, 0.68333, 0, 0],
+        "10927": [0.13597, 0.63597, 0, 0],
+        "10928": [0.13597, 0.63597, 0, 0]
+    },
+    "Math-BoldItalic": {
+        "47": [0.19444, 0.69444, 0, 0],
+        "65": [0, 0.68611, 0, 0],
+        "66": [0, 0.68611, 0.04835, 0],
+        "67": [0, 0.68611, 0.06979, 0],
+        "68": [0, 0.68611, 0.03194, 0],
+        "69": [0, 0.68611, 0.05451, 0],
+        "70": [0, 0.68611, 0.15972, 0],
+        "71": [0, 0.68611, 0, 0],
+        "72": [0, 0.68611, 0.08229, 0],
+        "73": [0, 0.68611, 0.07778, 0],
+        "74": [0, 0.68611, 0.10069, 0],
+        "75": [0, 0.68611, 0.06979, 0],
+        "76": [0, 0.68611, 0, 0],
+        "77": [0, 0.68611, 0.11424, 0],
+        "78": [0, 0.68611, 0.11424, 0],
+        "79": [0, 0.68611, 0.03194, 0],
+        "80": [0, 0.68611, 0.15972, 0],
+        "81": [0.19444, 0.68611, 0, 0],
+        "82": [0, 0.68611, 0.00421, 0],
+        "83": [0, 0.68611, 0.05382, 0],
+        "84": [0, 0.68611, 0.15972, 0],
+        "85": [0, 0.68611, 0.11424, 0],
+        "86": [0, 0.68611, 0.25555, 0],
+        "87": [0, 0.68611, 0.15972, 0],
+        "88": [0, 0.68611, 0.07778, 0],
+        "89": [0, 0.68611, 0.25555, 0],
+        "90": [0, 0.68611, 0.06979, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0.19444, 0.69444, 0.11042, 0],
+        "103": [0.19444, 0.44444, 0.03704, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.69326, 0, 0],
+        "106": [0.19444, 0.69326, 0.0622, 0],
+        "107": [0, 0.69444, 0.01852, 0],
+        "108": [0, 0.69444, 0.0088, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0.03704, 0],
+        "114": [0, 0.44444, 0.03194, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.63492, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.03704, 0],
+        "119": [0, 0.44444, 0.02778, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.03704, 0],
+        "122": [0, 0.44444, 0.04213, 0],
+        "915": [0, 0.68611, 0.15972, 0],
+        "916": [0, 0.68611, 0, 0],
+        "920": [0, 0.68611, 0.03194, 0],
+        "923": [0, 0.68611, 0, 0],
+        "926": [0, 0.68611, 0.07458, 0],
+        "928": [0, 0.68611, 0.08229, 0],
+        "931": [0, 0.68611, 0.05451, 0],
+        "933": [0, 0.68611, 0.15972, 0],
+        "934": [0, 0.68611, 0, 0],
+        "936": [0, 0.68611, 0.11653, 0],
+        "937": [0, 0.68611, 0.04835, 0],
+        "945": [0, 0.44444, 0, 0],
+        "946": [0.19444, 0.69444, 0.03403, 0],
+        "947": [0.19444, 0.44444, 0.06389, 0],
+        "948": [0, 0.69444, 0.03819, 0],
+        "949": [0, 0.44444, 0, 0],
+        "950": [0.19444, 0.69444, 0.06215, 0],
+        "951": [0.19444, 0.44444, 0.03704, 0],
+        "952": [0, 0.69444, 0.03194, 0],
+        "953": [0, 0.44444, 0, 0],
+        "954": [0, 0.44444, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.44444, 0, 0],
+        "957": [0, 0.44444, 0.06898, 0],
+        "958": [0.19444, 0.69444, 0.03021, 0],
+        "959": [0, 0.44444, 0, 0],
+        "960": [0, 0.44444, 0.03704, 0],
+        "961": [0.19444, 0.44444, 0, 0],
+        "962": [0.09722, 0.44444, 0.07917, 0],
+        "963": [0, 0.44444, 0.03704, 0],
+        "964": [0, 0.44444, 0.13472, 0],
+        "965": [0, 0.44444, 0.03704, 0],
+        "966": [0.19444, 0.44444, 0, 0],
+        "967": [0.19444, 0.44444, 0, 0],
+        "968": [0.19444, 0.69444, 0.03704, 0],
+        "969": [0, 0.44444, 0.03704, 0],
+        "977": [0, 0.69444, 0, 0],
+        "981": [0.19444, 0.69444, 0, 0],
+        "982": [0, 0.44444, 0.03194, 0],
+        "1009": [0.19444, 0.44444, 0, 0],
+        "1013": [0, 0.44444, 0, 0]
+    },
+    "Math-Italic": {
+        "47": [0.19444, 0.69444, 0, 0],
+        "65": [0, 0.68333, 0, 0.13889],
+        "66": [0, 0.68333, 0.05017, 0.08334],
+        "67": [0, 0.68333, 0.07153, 0.08334],
+        "68": [0, 0.68333, 0.02778, 0.05556],
+        "69": [0, 0.68333, 0.05764, 0.08334],
+        "70": [0, 0.68333, 0.13889, 0.08334],
+        "71": [0, 0.68333, 0, 0.08334],
+        "72": [0, 0.68333, 0.08125, 0.05556],
+        "73": [0, 0.68333, 0.07847, 0.11111],
+        "74": [0, 0.68333, 0.09618, 0.16667],
+        "75": [0, 0.68333, 0.07153, 0.05556],
+        "76": [0, 0.68333, 0, 0.02778],
+        "77": [0, 0.68333, 0.10903, 0.08334],
+        "78": [0, 0.68333, 0.10903, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.08334],
+        "80": [0, 0.68333, 0.13889, 0.08334],
+        "81": [0.19444, 0.68333, 0, 0.08334],
+        "82": [0, 0.68333, 0.00773, 0.08334],
+        "83": [0, 0.68333, 0.05764, 0.08334],
+        "84": [0, 0.68333, 0.13889, 0.08334],
+        "85": [0, 0.68333, 0.10903, 0.02778],
+        "86": [0, 0.68333, 0.22222, 0],
+        "87": [0, 0.68333, 0.13889, 0],
+        "88": [0, 0.68333, 0.07847, 0.08334],
+        "89": [0, 0.68333, 0.22222, 0],
+        "90": [0, 0.68333, 0.07153, 0.08334],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0.05556],
+        "100": [0, 0.69444, 0, 0.16667],
+        "101": [0, 0.43056, 0, 0.05556],
+        "102": [0.19444, 0.69444, 0.10764, 0.16667],
+        "103": [0.19444, 0.43056, 0.03588, 0.02778],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.65952, 0, 0],
+        "106": [0.19444, 0.65952, 0.05724, 0],
+        "107": [0, 0.69444, 0.03148, 0],
+        "108": [0, 0.69444, 0.01968, 0.08334],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0.05556],
+        "112": [0.19444, 0.43056, 0, 0.08334],
+        "113": [0.19444, 0.43056, 0.03588, 0.08334],
+        "114": [0, 0.43056, 0.02778, 0.05556],
+        "115": [0, 0.43056, 0, 0.05556],
+        "116": [0, 0.61508, 0, 0.08334],
+        "117": [0, 0.43056, 0, 0.02778],
+        "118": [0, 0.43056, 0.03588, 0.02778],
+        "119": [0, 0.43056, 0.02691, 0.08334],
+        "120": [0, 0.43056, 0, 0.02778],
+        "121": [0.19444, 0.43056, 0.03588, 0.05556],
+        "122": [0, 0.43056, 0.04398, 0.05556],
+        "915": [0, 0.68333, 0.13889, 0.08334],
+        "916": [0, 0.68333, 0, 0.16667],
+        "920": [0, 0.68333, 0.02778, 0.08334],
+        "923": [0, 0.68333, 0, 0.16667],
+        "926": [0, 0.68333, 0.07569, 0.08334],
+        "928": [0, 0.68333, 0.08125, 0.05556],
+        "931": [0, 0.68333, 0.05764, 0.08334],
+        "933": [0, 0.68333, 0.13889, 0.05556],
+        "934": [0, 0.68333, 0, 0.08334],
+        "936": [0, 0.68333, 0.11, 0.05556],
+        "937": [0, 0.68333, 0.05017, 0.08334],
+        "945": [0, 0.43056, 0.0037, 0.02778],
+        "946": [0.19444, 0.69444, 0.05278, 0.08334],
+        "947": [0.19444, 0.43056, 0.05556, 0],
+        "948": [0, 0.69444, 0.03785, 0.05556],
+        "949": [0, 0.43056, 0, 0.08334],
+        "950": [0.19444, 0.69444, 0.07378, 0.08334],
+        "951": [0.19444, 0.43056, 0.03588, 0.05556],
+        "952": [0, 0.69444, 0.02778, 0.08334],
+        "953": [0, 0.43056, 0, 0.05556],
+        "954": [0, 0.43056, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.43056, 0, 0.02778],
+        "957": [0, 0.43056, 0.06366, 0.02778],
+        "958": [0.19444, 0.69444, 0.04601, 0.11111],
+        "959": [0, 0.43056, 0, 0.05556],
+        "960": [0, 0.43056, 0.03588, 0],
+        "961": [0.19444, 0.43056, 0, 0.08334],
+        "962": [0.09722, 0.43056, 0.07986, 0.08334],
+        "963": [0, 0.43056, 0.03588, 0],
+        "964": [0, 0.43056, 0.1132, 0.02778],
+        "965": [0, 0.43056, 0.03588, 0.02778],
+        "966": [0.19444, 0.43056, 0, 0.08334],
+        "967": [0.19444, 0.43056, 0, 0.05556],
+        "968": [0.19444, 0.69444, 0.03588, 0.11111],
+        "969": [0, 0.43056, 0.03588, 0],
+        "977": [0, 0.69444, 0, 0.08334],
+        "981": [0.19444, 0.69444, 0, 0.08334],
+        "982": [0, 0.43056, 0.02778, 0],
+        "1009": [0.19444, 0.43056, 0, 0.08334],
+        "1013": [0, 0.43056, 0, 0.05556]
+    },
+    "Math-Regular": {
+        "65": [0, 0.68333, 0, 0.13889],
+        "66": [0, 0.68333, 0.05017, 0.08334],
+        "67": [0, 0.68333, 0.07153, 0.08334],
+        "68": [0, 0.68333, 0.02778, 0.05556],
+        "69": [0, 0.68333, 0.05764, 0.08334],
+        "70": [0, 0.68333, 0.13889, 0.08334],
+        "71": [0, 0.68333, 0, 0.08334],
+        "72": [0, 0.68333, 0.08125, 0.05556],
+        "73": [0, 0.68333, 0.07847, 0.11111],
+        "74": [0, 0.68333, 0.09618, 0.16667],
+        "75": [0, 0.68333, 0.07153, 0.05556],
+        "76": [0, 0.68333, 0, 0.02778],
+        "77": [0, 0.68333, 0.10903, 0.08334],
+        "78": [0, 0.68333, 0.10903, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.08334],
+        "80": [0, 0.68333, 0.13889, 0.08334],
+        "81": [0.19444, 0.68333, 0, 0.08334],
+        "82": [0, 0.68333, 0.00773, 0.08334],
+        "83": [0, 0.68333, 0.05764, 0.08334],
+        "84": [0, 0.68333, 0.13889, 0.08334],
+        "85": [0, 0.68333, 0.10903, 0.02778],
+        "86": [0, 0.68333, 0.22222, 0],
+        "87": [0, 0.68333, 0.13889, 0],
+        "88": [0, 0.68333, 0.07847, 0.08334],
+        "89": [0, 0.68333, 0.22222, 0],
+        "90": [0, 0.68333, 0.07153, 0.08334],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0.05556],
+        "100": [0, 0.69444, 0, 0.16667],
+        "101": [0, 0.43056, 0, 0.05556],
+        "102": [0.19444, 0.69444, 0.10764, 0.16667],
+        "103": [0.19444, 0.43056, 0.03588, 0.02778],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.65952, 0, 0],
+        "106": [0.19444, 0.65952, 0.05724, 0],
+        "107": [0, 0.69444, 0.03148, 0],
+        "108": [0, 0.69444, 0.01968, 0.08334],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0.05556],
+        "112": [0.19444, 0.43056, 0, 0.08334],
+        "113": [0.19444, 0.43056, 0.03588, 0.08334],
+        "114": [0, 0.43056, 0.02778, 0.05556],
+        "115": [0, 0.43056, 0, 0.05556],
+        "116": [0, 0.61508, 0, 0.08334],
+        "117": [0, 0.43056, 0, 0.02778],
+        "118": [0, 0.43056, 0.03588, 0.02778],
+        "119": [0, 0.43056, 0.02691, 0.08334],
+        "120": [0, 0.43056, 0, 0.02778],
+        "121": [0.19444, 0.43056, 0.03588, 0.05556],
+        "122": [0, 0.43056, 0.04398, 0.05556],
+        "915": [0, 0.68333, 0.13889, 0.08334],
+        "916": [0, 0.68333, 0, 0.16667],
+        "920": [0, 0.68333, 0.02778, 0.08334],
+        "923": [0, 0.68333, 0, 0.16667],
+        "926": [0, 0.68333, 0.07569, 0.08334],
+        "928": [0, 0.68333, 0.08125, 0.05556],
+        "931": [0, 0.68333, 0.05764, 0.08334],
+        "933": [0, 0.68333, 0.13889, 0.05556],
+        "934": [0, 0.68333, 0, 0.08334],
+        "936": [0, 0.68333, 0.11, 0.05556],
+        "937": [0, 0.68333, 0.05017, 0.08334],
+        "945": [0, 0.43056, 0.0037, 0.02778],
+        "946": [0.19444, 0.69444, 0.05278, 0.08334],
+        "947": [0.19444, 0.43056, 0.05556, 0],
+        "948": [0, 0.69444, 0.03785, 0.05556],
+        "949": [0, 0.43056, 0, 0.08334],
+        "950": [0.19444, 0.69444, 0.07378, 0.08334],
+        "951": [0.19444, 0.43056, 0.03588, 0.05556],
+        "952": [0, 0.69444, 0.02778, 0.08334],
+        "953": [0, 0.43056, 0, 0.05556],
+        "954": [0, 0.43056, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.43056, 0, 0.02778],
+        "957": [0, 0.43056, 0.06366, 0.02778],
+        "958": [0.19444, 0.69444, 0.04601, 0.11111],
+        "959": [0, 0.43056, 0, 0.05556],
+        "960": [0, 0.43056, 0.03588, 0],
+        "961": [0.19444, 0.43056, 0, 0.08334],
+        "962": [0.09722, 0.43056, 0.07986, 0.08334],
+        "963": [0, 0.43056, 0.03588, 0],
+        "964": [0, 0.43056, 0.1132, 0.02778],
+        "965": [0, 0.43056, 0.03588, 0.02778],
+        "966": [0.19444, 0.43056, 0, 0.08334],
+        "967": [0.19444, 0.43056, 0, 0.05556],
+        "968": [0.19444, 0.69444, 0.03588, 0.11111],
+        "969": [0, 0.43056, 0.03588, 0],
+        "977": [0, 0.69444, 0, 0.08334],
+        "981": [0.19444, 0.69444, 0, 0.08334],
+        "982": [0, 0.43056, 0.02778, 0],
+        "1009": [0.19444, 0.43056, 0, 0.08334],
+        "1013": [0, 0.43056, 0, 0.05556]
+    },
+    "SansSerif-Regular": {
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.08333, 0.58333, 0, 0],
+        "44": [0.125, 0.08333, 0, 0],
+        "45": [0, 0.44444, 0, 0],
+        "46": [0, 0.08333, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.65556, 0, 0],
+        "49": [0, 0.65556, 0, 0],
+        "50": [0, 0.65556, 0, 0],
+        "51": [0, 0.65556, 0, 0],
+        "52": [0, 0.65556, 0, 0],
+        "53": [0, 0.65556, 0, 0],
+        "54": [0, 0.65556, 0, 0],
+        "55": [0, 0.65556, 0, 0],
+        "56": [0, 0.65556, 0, 0],
+        "57": [0, 0.65556, 0, 0],
+        "58": [0, 0.44444, 0, 0],
+        "59": [0.125, 0.44444, 0, 0],
+        "61": [-0.13, 0.37, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.69444, 0, 0],
+        "66": [0, 0.69444, 0, 0],
+        "67": [0, 0.69444, 0, 0],
+        "68": [0, 0.69444, 0, 0],
+        "69": [0, 0.69444, 0, 0],
+        "70": [0, 0.69444, 0, 0],
+        "71": [0, 0.69444, 0, 0],
+        "72": [0, 0.69444, 0, 0],
+        "73": [0, 0.69444, 0, 0],
+        "74": [0, 0.69444, 0, 0],
+        "75": [0, 0.69444, 0, 0],
+        "76": [0, 0.69444, 0, 0],
+        "77": [0, 0.69444, 0, 0],
+        "78": [0, 0.69444, 0, 0],
+        "79": [0, 0.69444, 0, 0],
+        "80": [0, 0.69444, 0, 0],
+        "81": [0.125, 0.69444, 0, 0],
+        "82": [0, 0.69444, 0, 0],
+        "83": [0, 0.69444, 0, 0],
+        "84": [0, 0.69444, 0, 0],
+        "85": [0, 0.69444, 0, 0],
+        "86": [0, 0.69444, 0.01389, 0],
+        "87": [0, 0.69444, 0.01389, 0],
+        "88": [0, 0.69444, 0, 0],
+        "89": [0, 0.69444, 0.025, 0],
+        "90": [0, 0.69444, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.35, 0.09444, 0.02778, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0, 0.69444, 0.06944, 0],
+        "103": [0.19444, 0.44444, 0.01389, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.67937, 0, 0],
+        "106": [0.19444, 0.67937, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0, 0],
+        "114": [0, 0.44444, 0.01389, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.57143, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.01389, 0],
+        "119": [0, 0.44444, 0.01389, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.01389, 0],
+        "122": [0, 0.44444, 0, 0],
+        "126": [0.35, 0.32659, 0, 0],
+        "305": [0, 0.44444, 0, 0],
+        "567": [0.19444, 0.44444, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.67659, 0, 0],
+        "772": [0, 0.60889, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.67937, 0, 0],
+        "776": [0, 0.67937, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.63194, 0, 0],
+        "915": [0, 0.69444, 0, 0],
+        "916": [0, 0.69444, 0, 0],
+        "920": [0, 0.69444, 0, 0],
+        "923": [0, 0.69444, 0, 0],
+        "926": [0, 0.69444, 0, 0],
+        "928": [0, 0.69444, 0, 0],
+        "931": [0, 0.69444, 0, 0],
+        "933": [0, 0.69444, 0, 0],
+        "934": [0, 0.69444, 0, 0],
+        "936": [0, 0.69444, 0, 0],
+        "937": [0, 0.69444, 0, 0],
+        "8211": [0, 0.44444, 0.02778, 0],
+        "8212": [0, 0.44444, 0.02778, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0]
+    },
+    "Script-Regular": {
+        "65": [0, 0.7, 0.22925, 0],
+        "66": [0, 0.7, 0.04087, 0],
+        "67": [0, 0.7, 0.1689, 0],
+        "68": [0, 0.7, 0.09371, 0],
+        "69": [0, 0.7, 0.18583, 0],
+        "70": [0, 0.7, 0.13634, 0],
+        "71": [0, 0.7, 0.17322, 0],
+        "72": [0, 0.7, 0.29694, 0],
+        "73": [0, 0.7, 0.19189, 0],
+        "74": [0.27778, 0.7, 0.19189, 0],
+        "75": [0, 0.7, 0.31259, 0],
+        "76": [0, 0.7, 0.19189, 0],
+        "77": [0, 0.7, 0.15981, 0],
+        "78": [0, 0.7, 0.3525, 0],
+        "79": [0, 0.7, 0.08078, 0],
+        "80": [0, 0.7, 0.08078, 0],
+        "81": [0, 0.7, 0.03305, 0],
+        "82": [0, 0.7, 0.06259, 0],
+        "83": [0, 0.7, 0.19189, 0],
+        "84": [0, 0.7, 0.29087, 0],
+        "85": [0, 0.7, 0.25815, 0],
+        "86": [0, 0.7, 0.27523, 0],
+        "87": [0, 0.7, 0.27523, 0],
+        "88": [0, 0.7, 0.26006, 0],
+        "89": [0, 0.7, 0.2939, 0],
+        "90": [0, 0.7, 0.24037, 0]
+    },
+    "Size1-Regular": {
+        "40": [0.35001, 0.85, 0, 0],
+        "41": [0.35001, 0.85, 0, 0],
+        "47": [0.35001, 0.85, 0, 0],
+        "91": [0.35001, 0.85, 0, 0],
+        "92": [0.35001, 0.85, 0, 0],
+        "93": [0.35001, 0.85, 0, 0],
+        "123": [0.35001, 0.85, 0, 0],
+        "125": [0.35001, 0.85, 0, 0],
+        "710": [0, 0.72222, 0, 0],
+        "732": [0, 0.72222, 0, 0],
+        "770": [0, 0.72222, 0, 0],
+        "771": [0, 0.72222, 0, 0],
+        "8214": [-0.00099, 0.601, 0, 0],
+        "8593": [1e-05, 0.6, 0, 0],
+        "8595": [1e-05, 0.6, 0, 0],
+        "8657": [1e-05, 0.6, 0, 0],
+        "8659": [1e-05, 0.6, 0, 0],
+        "8719": [0.25001, 0.75, 0, 0],
+        "8720": [0.25001, 0.75, 0, 0],
+        "8721": [0.25001, 0.75, 0, 0],
+        "8730": [0.35001, 0.85, 0, 0],
+        "8739": [-0.00599, 0.606, 0, 0],
+        "8741": [-0.00599, 0.606, 0, 0],
+        "8747": [0.30612, 0.805, 0.19445, 0],
+        "8748": [0.306, 0.805, 0.19445, 0],
+        "8749": [0.306, 0.805, 0.19445, 0],
+        "8750": [0.30612, 0.805, 0.19445, 0],
+        "8896": [0.25001, 0.75, 0, 0],
+        "8897": [0.25001, 0.75, 0, 0],
+        "8898": [0.25001, 0.75, 0, 0],
+        "8899": [0.25001, 0.75, 0, 0],
+        "8968": [0.35001, 0.85, 0, 0],
+        "8969": [0.35001, 0.85, 0, 0],
+        "8970": [0.35001, 0.85, 0, 0],
+        "8971": [0.35001, 0.85, 0, 0],
+        "9168": [-0.00099, 0.601, 0, 0],
+        "10216": [0.35001, 0.85, 0, 0],
+        "10217": [0.35001, 0.85, 0, 0],
+        "10752": [0.25001, 0.75, 0, 0],
+        "10753": [0.25001, 0.75, 0, 0],
+        "10754": [0.25001, 0.75, 0, 0],
+        "10756": [0.25001, 0.75, 0, 0],
+        "10758": [0.25001, 0.75, 0, 0]
+    },
+    "Size2-Regular": {
+        "40": [0.65002, 1.15, 0, 0],
+        "41": [0.65002, 1.15, 0, 0],
+        "47": [0.65002, 1.15, 0, 0],
+        "91": [0.65002, 1.15, 0, 0],
+        "92": [0.65002, 1.15, 0, 0],
+        "93": [0.65002, 1.15, 0, 0],
+        "123": [0.65002, 1.15, 0, 0],
+        "125": [0.65002, 1.15, 0, 0],
+        "710": [0, 0.75, 0, 0],
+        "732": [0, 0.75, 0, 0],
+        "770": [0, 0.75, 0, 0],
+        "771": [0, 0.75, 0, 0],
+        "8719": [0.55001, 1.05, 0, 0],
+        "8720": [0.55001, 1.05, 0, 0],
+        "8721": [0.55001, 1.05, 0, 0],
+        "8730": [0.65002, 1.15, 0, 0],
+        "8747": [0.86225, 1.36, 0.44445, 0],
+        "8748": [0.862, 1.36, 0.44445, 0],
+        "8749": [0.862, 1.36, 0.44445, 0],
+        "8750": [0.86225, 1.36, 0.44445, 0],
+        "8896": [0.55001, 1.05, 0, 0],
+        "8897": [0.55001, 1.05, 0, 0],
+        "8898": [0.55001, 1.05, 0, 0],
+        "8899": [0.55001, 1.05, 0, 0],
+        "8968": [0.65002, 1.15, 0, 0],
+        "8969": [0.65002, 1.15, 0, 0],
+        "8970": [0.65002, 1.15, 0, 0],
+        "8971": [0.65002, 1.15, 0, 0],
+        "10216": [0.65002, 1.15, 0, 0],
+        "10217": [0.65002, 1.15, 0, 0],
+        "10752": [0.55001, 1.05, 0, 0],
+        "10753": [0.55001, 1.05, 0, 0],
+        "10754": [0.55001, 1.05, 0, 0],
+        "10756": [0.55001, 1.05, 0, 0],
+        "10758": [0.55001, 1.05, 0, 0]
+    },
+    "Size3-Regular": {
+        "40": [0.95003, 1.45, 0, 0],
+        "41": [0.95003, 1.45, 0, 0],
+        "47": [0.95003, 1.45, 0, 0],
+        "91": [0.95003, 1.45, 0, 0],
+        "92": [0.95003, 1.45, 0, 0],
+        "93": [0.95003, 1.45, 0, 0],
+        "123": [0.95003, 1.45, 0, 0],
+        "125": [0.95003, 1.45, 0, 0],
+        "710": [0, 0.75, 0, 0],
+        "732": [0, 0.75, 0, 0],
+        "770": [0, 0.75, 0, 0],
+        "771": [0, 0.75, 0, 0],
+        "8730": [0.95003, 1.45, 0, 0],
+        "8968": [0.95003, 1.45, 0, 0],
+        "8969": [0.95003, 1.45, 0, 0],
+        "8970": [0.95003, 1.45, 0, 0],
+        "8971": [0.95003, 1.45, 0, 0],
+        "10216": [0.95003, 1.45, 0, 0],
+        "10217": [0.95003, 1.45, 0, 0]
+    },
+    "Size4-Regular": {
+        "40": [1.25003, 1.75, 0, 0],
+        "41": [1.25003, 1.75, 0, 0],
+        "47": [1.25003, 1.75, 0, 0],
+        "91": [1.25003, 1.75, 0, 0],
+        "92": [1.25003, 1.75, 0, 0],
+        "93": [1.25003, 1.75, 0, 0],
+        "123": [1.25003, 1.75, 0, 0],
+        "125": [1.25003, 1.75, 0, 0],
+        "710": [0, 0.825, 0, 0],
+        "732": [0, 0.825, 0, 0],
+        "770": [0, 0.825, 0, 0],
+        "771": [0, 0.825, 0, 0],
+        "8730": [1.25003, 1.75, 0, 0],
+        "8968": [1.25003, 1.75, 0, 0],
+        "8969": [1.25003, 1.75, 0, 0],
+        "8970": [1.25003, 1.75, 0, 0],
+        "8971": [1.25003, 1.75, 0, 0],
+        "9115": [0.64502, 1.155, 0, 0],
+        "9116": [1e-05, 0.6, 0, 0],
+        "9117": [0.64502, 1.155, 0, 0],
+        "9118": [0.64502, 1.155, 0, 0],
+        "9119": [1e-05, 0.6, 0, 0],
+        "9120": [0.64502, 1.155, 0, 0],
+        "9121": [0.64502, 1.155, 0, 0],
+        "9122": [-0.00099, 0.601, 0, 0],
+        "9123": [0.64502, 1.155, 0, 0],
+        "9124": [0.64502, 1.155, 0, 0],
+        "9125": [-0.00099, 0.601, 0, 0],
+        "9126": [0.64502, 1.155, 0, 0],
+        "9127": [1e-05, 0.9, 0, 0],
+        "9128": [0.65002, 1.15, 0, 0],
+        "9129": [0.90001, 0, 0, 0],
+        "9130": [0, 0.3, 0, 0],
+        "9131": [1e-05, 0.9, 0, 0],
+        "9132": [0.65002, 1.15, 0, 0],
+        "9133": [0.90001, 0, 0, 0],
+        "9143": [0.88502, 0.915, 0, 0],
+        "10216": [1.25003, 1.75, 0, 0],
+        "10217": [1.25003, 1.75, 0, 0],
+        "57344": [-0.00499, 0.605, 0, 0],
+        "57345": [-0.00499, 0.605, 0, 0],
+        "57680": [0, 0.12, 0, 0],
+        "57681": [0, 0.12, 0, 0],
+        "57682": [0, 0.12, 0, 0],
+        "57683": [0, 0.12, 0, 0]
+    },
+    "Typewriter-Regular": {
+        "33": [0, 0.61111, 0, 0],
+        "34": [0, 0.61111, 0, 0],
+        "35": [0, 0.61111, 0, 0],
+        "36": [0.08333, 0.69444, 0, 0],
+        "37": [0.08333, 0.69444, 0, 0],
+        "38": [0, 0.61111, 0, 0],
+        "39": [0, 0.61111, 0, 0],
+        "40": [0.08333, 0.69444, 0, 0],
+        "41": [0.08333, 0.69444, 0, 0],
+        "42": [0, 0.52083, 0, 0],
+        "43": [-0.08056, 0.53055, 0, 0],
+        "44": [0.13889, 0.125, 0, 0],
+        "45": [-0.08056, 0.53055, 0, 0],
+        "46": [0, 0.125, 0, 0],
+        "47": [0.08333, 0.69444, 0, 0],
+        "48": [0, 0.61111, 0, 0],
+        "49": [0, 0.61111, 0, 0],
+        "50": [0, 0.61111, 0, 0],
+        "51": [0, 0.61111, 0, 0],
+        "52": [0, 0.61111, 0, 0],
+        "53": [0, 0.61111, 0, 0],
+        "54": [0, 0.61111, 0, 0],
+        "55": [0, 0.61111, 0, 0],
+        "56": [0, 0.61111, 0, 0],
+        "57": [0, 0.61111, 0, 0],
+        "58": [0, 0.43056, 0, 0],
+        "59": [0.13889, 0.43056, 0, 0],
+        "60": [-0.05556, 0.55556, 0, 0],
+        "61": [-0.19549, 0.41562, 0, 0],
+        "62": [-0.05556, 0.55556, 0, 0],
+        "63": [0, 0.61111, 0, 0],
+        "64": [0, 0.61111, 0, 0],
+        "65": [0, 0.61111, 0, 0],
+        "66": [0, 0.61111, 0, 0],
+        "67": [0, 0.61111, 0, 0],
+        "68": [0, 0.61111, 0, 0],
+        "69": [0, 0.61111, 0, 0],
+        "70": [0, 0.61111, 0, 0],
+        "71": [0, 0.61111, 0, 0],
+        "72": [0, 0.61111, 0, 0],
+        "73": [0, 0.61111, 0, 0],
+        "74": [0, 0.61111, 0, 0],
+        "75": [0, 0.61111, 0, 0],
+        "76": [0, 0.61111, 0, 0],
+        "77": [0, 0.61111, 0, 0],
+        "78": [0, 0.61111, 0, 0],
+        "79": [0, 0.61111, 0, 0],
+        "80": [0, 0.61111, 0, 0],
+        "81": [0.13889, 0.61111, 0, 0],
+        "82": [0, 0.61111, 0, 0],
+        "83": [0, 0.61111, 0, 0],
+        "84": [0, 0.61111, 0, 0],
+        "85": [0, 0.61111, 0, 0],
+        "86": [0, 0.61111, 0, 0],
+        "87": [0, 0.61111, 0, 0],
+        "88": [0, 0.61111, 0, 0],
+        "89": [0, 0.61111, 0, 0],
+        "90": [0, 0.61111, 0, 0],
+        "91": [0.08333, 0.69444, 0, 0],
+        "92": [0.08333, 0.69444, 0, 0],
+        "93": [0.08333, 0.69444, 0, 0],
+        "94": [0, 0.61111, 0, 0],
+        "95": [0.09514, 0, 0, 0],
+        "96": [0, 0.61111, 0, 0],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.61111, 0, 0],
+        "99": [0, 0.43056, 0, 0],
+        "100": [0, 0.61111, 0, 0],
+        "101": [0, 0.43056, 0, 0],
+        "102": [0, 0.61111, 0, 0],
+        "103": [0.22222, 0.43056, 0, 0],
+        "104": [0, 0.61111, 0, 0],
+        "105": [0, 0.61111, 0, 0],
+        "106": [0.22222, 0.61111, 0, 0],
+        "107": [0, 0.61111, 0, 0],
+        "108": [0, 0.61111, 0, 0],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0],
+        "112": [0.22222, 0.43056, 0, 0],
+        "113": [0.22222, 0.43056, 0, 0],
+        "114": [0, 0.43056, 0, 0],
+        "115": [0, 0.43056, 0, 0],
+        "116": [0, 0.55358, 0, 0],
+        "117": [0, 0.43056, 0, 0],
+        "118": [0, 0.43056, 0, 0],
+        "119": [0, 0.43056, 0, 0],
+        "120": [0, 0.43056, 0, 0],
+        "121": [0.22222, 0.43056, 0, 0],
+        "122": [0, 0.43056, 0, 0],
+        "123": [0.08333, 0.69444, 0, 0],
+        "124": [0.08333, 0.69444, 0, 0],
+        "125": [0.08333, 0.69444, 0, 0],
+        "126": [0, 0.61111, 0, 0],
+        "127": [0, 0.61111, 0, 0],
+        "305": [0, 0.43056, 0, 0],
+        "567": [0.22222, 0.43056, 0, 0],
+        "768": [0, 0.61111, 0, 0],
+        "769": [0, 0.61111, 0, 0],
+        "770": [0, 0.61111, 0, 0],
+        "771": [0, 0.61111, 0, 0],
+        "772": [0, 0.56555, 0, 0],
+        "774": [0, 0.61111, 0, 0],
+        "776": [0, 0.61111, 0, 0],
+        "778": [0, 0.61111, 0, 0],
+        "780": [0, 0.56597, 0, 0],
+        "915": [0, 0.61111, 0, 0],
+        "916": [0, 0.61111, 0, 0],
+        "920": [0, 0.61111, 0, 0],
+        "923": [0, 0.61111, 0, 0],
+        "926": [0, 0.61111, 0, 0],
+        "928": [0, 0.61111, 0, 0],
+        "931": [0, 0.61111, 0, 0],
+        "933": [0, 0.61111, 0, 0],
+        "934": [0, 0.61111, 0, 0],
+        "936": [0, 0.61111, 0, 0],
+        "937": [0, 0.61111, 0, 0],
+        "2018": [0, 0.61111, 0, 0],
+        "2019": [0, 0.61111, 0, 0],
+        "8242": [0, 0.61111, 0, 0]
+    }
+};
+
+},{}],19:[function(require,module,exports){
+var utils = require("./utils");
+var ParseError = require("./ParseError");
+var parseData = require("./parseData");
+var ParseNode = parseData.ParseNode;
+
+/* This file contains a list of functions that we parse, identified by
+ * the calls to defineFunction.
+ *
+ * The first argument to defineFunction is a single name or a list of names.
+ * All functions named in such a list will share a single implementation.
+ *
+ * Each declared function can have associated properties, which
+ * include the following:
+ *
+ *  - numArgs: The number of arguments the function takes.
+ *             If this is the only property, it can be passed as a number
+ *             instead of an element of a properties object.
+ *  - argTypes: (optional) An array corresponding to each argument of the
+ *              function, giving the type of argument that should be parsed. Its
+ *              length should be equal to `numArgs + numOptionalArgs`. Valid
+ *              types:
+ *               - "size": A size-like thing, such as "1em" or "5ex"
+ *               - "color": An html color, like "#abc" or "blue"
+ *               - "original": The same type as the environment that the
+ *                             function being parsed is in (e.g. used for the
+ *                             bodies of functions like \color where the first
+ *                             argument is special and the second argument is
+ *                             parsed normally)
+ *              Other possible types (probably shouldn't be used)
+ *               - "text": Text-like (e.g. \text)
+ *               - "math": Normal math
+ *              If undefined, this will be treated as an appropriate length
+ *              array of "original" strings
+ *  - greediness: (optional) The greediness of the function to use ungrouped
+ *                arguments.
+ *
+ *                E.g. if you have an expression
+ *                  \sqrt \frac 1 2
+ *                since \frac has greediness=2 vs \sqrt's greediness=1, \frac
+ *                will use the two arguments '1' and '2' as its two arguments,
+ *                then that whole function will be used as the argument to
+ *                \sqrt. On the other hand, the expressions
+ *                  \frac \frac 1 2 3
+ *                and
+ *                  \frac \sqrt 1 2
+ *                will fail because \frac and \frac have equal greediness
+ *                and \sqrt has a lower greediness than \frac respectively. To
+ *                make these parse, we would have to change them to:
+ *                  \frac {\frac 1 2} 3
+ *                and
+ *                  \frac {\sqrt 1} 2
+ *
+ *                The default value is `1`
+ *  - allowedInText: (optional) Whether or not the function is allowed inside
+ *                   text mode (default false)
+ *  - numOptionalArgs: (optional) The number of optional arguments the function
+ *                     should parse. If the optional arguments aren't found,
+ *                     `null` will be passed to the handler in their place.
+ *                     (default 0)
+ *  - infix: (optional) Must be true if the function is an infix operator.
+ *
+ * The last argument is that implementation, the handler for the function(s).
+ * It is called to handle these functions and their arguments.
+ * It receives two arguments:
+ *  - context contains information and references provided by the parser
+ *  - args is an array of arguments obtained from TeX input
+ * The context contains the following properties:
+ *  - funcName: the text (i.e. name) of the function, including \
+ *  - parser: the parser object
+ *  - lexer: the lexer object
+ *  - positions: the positions in the overall string of the function
+ *               and the arguments.
+ * The latter three should only be used to produce error messages.
+ *
+ * The function should return an object with the following keys:
+ *  - type: The type of element that this is. This is then used in
+ *          buildHTML/buildMathML to determine which function
+ *          should be called to build this node into a DOM node
+ * Any other data can be added to the object, which will be passed
+ * in to the function in buildHTML/buildMathML as `group.value`.
+ */
+
+function defineFunction(names, props, handler) {
+    if (typeof names === "string") {
+        names = [names];
+    }
+    if (typeof props === "number") {
+        props = { numArgs: props };
+    }
+    // Set default values of functions
+    var data = {
+        numArgs: props.numArgs,
+        argTypes: props.argTypes,
+        greediness: (props.greediness === undefined) ? 1 : props.greediness,
+        allowedInText: !!props.allowedInText,
+        numOptionalArgs: props.numOptionalArgs || 0,
+        infix: !!props.infix,
+        handler: handler
+    };
+    for (var i = 0; i < names.length; ++i) {
+        module.exports[names[i]] = data;
+    }
+}
+
+// Since the corresponding buildHTML/buildMathML function expects a
+// list of elements, we normalize for different kinds of arguments
+var ordargument = function(arg) {
+    if (arg.type === "ordgroup") {
+        return arg.value;
+    } else {
+        return [arg];
+    }
+};
+
+// A normal square root
+defineFunction("\\sqrt", {
+    numArgs: 1,
+    numOptionalArgs: 1
+}, function(context, args) {
+    var index = args[0];
+    var body = args[1];
+    return {
+        type: "sqrt",
+        body: body,
+        index: index
+    };
+});
+
+// Non-mathy text, possibly in a font
+var textFunctionStyles = {
+    "\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
+    "\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
+    "\\textit": "textit"
+};
+
+defineFunction([
+    "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
+    "\\textbf", "\\textit"
+], {
+    numArgs: 1,
+    argTypes: ["text"],
+    greediness: 2,
+    allowedInText: true
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "text",
+        body: ordargument(body),
+        style: textFunctionStyles[context.funcName]
+    };
+});
+
+// A two-argument custom color
+defineFunction("\\color", {
+    numArgs: 2,
+    allowedInText: true,
+    greediness: 3,
+    argTypes: ["color", "original"]
+}, function(context, args) {
+    var color = args[0];
+    var body = args[1];
+    return {
+        type: "color",
+        color: color.value,
+        value: ordargument(body)
+    };
+});
+
+// An overline
+defineFunction("\\overline", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "overline",
+        body: body
+    };
+});
+
+// An underline
+defineFunction("\\underline", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "underline",
+        body: body
+    };
+});
+
+// A box of the width and height
+defineFunction("\\rule", {
+    numArgs: 2,
+    numOptionalArgs: 1,
+    argTypes: ["size", "size", "size"]
+}, function(context, args) {
+    var shift = args[0];
+    var width = args[1];
+    var height = args[2];
+    return {
+        type: "rule",
+        shift: shift && shift.value,
+        width: width.value,
+        height: height.value
+    };
+});
+
+// TODO: In TeX, \mkern only accepts mu-units, and \kern does not accept
+// mu-units. In current KaTeX we relax this; both commands accept any unit.
+defineFunction(["\\kern", "\\mkern"], {
+    numArgs: 1,
+    argTypes: ["size"]
+}, function(context, args) {
+    return {
+        type: "kern",
+        dimension: args[0].value
+    };
+});
+
+// A KaTeX logo
+defineFunction("\\KaTeX", {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "katex"
+    };
+});
+
+defineFunction("\\phantom", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "phantom",
+        value: ordargument(body)
+    };
+});
+
+// Math class commands except \mathop
+defineFunction([
+    "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
+    "\\mathclose", "\\mathpunct", "\\mathinner"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "mclass",
+        mclass: "m" + context.funcName.substr(5),
+        value: ordargument(body)
+    };
+});
+
+// Build a relation by placing one symbol on top of another
+defineFunction("\\stackrel", {
+    numArgs: 2
+}, function(context, args) {
+    var top = args[0];
+    var bottom = args[1];
+
+    var bottomop = new ParseNode("op", {
+        type: "op",
+        limits: true,
+        alwaysHandleSupSub: true,
+        symbol: false,
+        value: ordargument(bottom)
+    }, bottom.mode);
+
+    var supsub = new ParseNode("supsub", {
+        base: bottomop,
+        sup: top,
+        sub: null
+    }, top.mode);
+
+    return {
+        type: "mclass",
+        mclass: "mrel",
+        value: [supsub]
+    };
+});
+
+// \mod-type functions
+defineFunction("\\bmod", {
+    numArgs: 0
+}, function(context, args) {
+    return {
+        type: "mod",
+        modType: "bmod",
+        value: null
+    };
+});
+
+defineFunction(["\\pod", "\\pmod", "\\mod"], {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "mod",
+        modType: context.funcName.substr(1),
+        value: ordargument(body)
+    };
+});
+
+// Extra data needed for the delimiter handler down below
+var delimiterSizes = {
+    "\\bigl" : {mclass: "mopen",    size: 1},
+    "\\Bigl" : {mclass: "mopen",    size: 2},
+    "\\biggl": {mclass: "mopen",    size: 3},
+    "\\Biggl": {mclass: "mopen",    size: 4},
+    "\\bigr" : {mclass: "mclose",   size: 1},
+    "\\Bigr" : {mclass: "mclose",   size: 2},
+    "\\biggr": {mclass: "mclose",   size: 3},
+    "\\Biggr": {mclass: "mclose",   size: 4},
+    "\\bigm" : {mclass: "mrel",     size: 1},
+    "\\Bigm" : {mclass: "mrel",     size: 2},
+    "\\biggm": {mclass: "mrel",     size: 3},
+    "\\Biggm": {mclass: "mrel",     size: 4},
+    "\\big"  : {mclass: "mord",     size: 1},
+    "\\Big"  : {mclass: "mord",     size: 2},
+    "\\bigg" : {mclass: "mord",     size: 3},
+    "\\Bigg" : {mclass: "mord",     size: 4}
+};
+
+var delimiters = [
+    "(", ")", "[", "\\lbrack", "]", "\\rbrack",
+    "\\{", "\\lbrace", "\\}", "\\rbrace",
+    "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
+    "<", ">", "\\langle", "\\rangle", "\\lt", "\\gt",
+    "\\lvert", "\\rvert", "\\lVert", "\\rVert",
+    "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
+    "/", "\\backslash",
+    "|", "\\vert", "\\|", "\\Vert",
+    "\\uparrow", "\\Uparrow",
+    "\\downarrow", "\\Downarrow",
+    "\\updownarrow", "\\Updownarrow",
+    "."
+];
+
+var fontAliases = {
+    "\\Bbb": "\\mathbb",
+    "\\bold": "\\mathbf",
+    "\\frak": "\\mathfrak"
+};
+
+// Single-argument color functions
+defineFunction([
+    "\\blue", "\\orange", "\\pink", "\\red",
+    "\\green", "\\gray", "\\purple",
+    "\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
+    "\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
+    "\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
+    "\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
+    "\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
+    "\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
+    "\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
+    "\\mintA", "\\mintB", "\\mintC",
+    "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
+    "\\grayF", "\\grayG", "\\grayH", "\\grayI",
+    "\\kaBlue", "\\kaGreen"
+], {
+    numArgs: 1,
+    allowedInText: true,
+    greediness: 3
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "color",
+        color: "katex-" + context.funcName.slice(1),
+        value: ordargument(body)
+    };
+});
+
+// There are 2 flags for operators; whether they produce limits in
+// displaystyle, and whether they are symbols and should grow in
+// displaystyle. These four groups cover the four possible choices.
+
+// No limits, not symbols
+defineFunction([
+    "\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh",
+    "\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom",
+    "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh",
+    "\\tan", "\\tanh"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: false,
+        symbol: false,
+        body: context.funcName
+    };
+});
+
+// Limits, not symbols
+defineFunction([
+    "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
+    "\\min", "\\Pr", "\\sup"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: true,
+        symbol: false,
+        body: context.funcName
+    };
+});
+
+// No limits, symbols
+defineFunction([
+    "\\int", "\\iint", "\\iiint", "\\oint"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: false,
+        symbol: true,
+        body: context.funcName
+    };
+});
+
+// Limits, symbols
+defineFunction([
+    "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
+    "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
+    "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: true,
+        symbol: true,
+        body: context.funcName
+    };
+});
+
+// \mathop class command
+defineFunction("\\mathop", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "op",
+        limits: false,
+        symbol: false,
+        value: ordargument(body)
+    };
+});
+
+// Fractions
+defineFunction([
+    "\\dfrac", "\\frac", "\\tfrac",
+    "\\dbinom", "\\binom", "\\tbinom",
+    "\\\\atopfrac" // can’t be entered directly
+], {
+    numArgs: 2,
+    greediness: 2
+}, function(context, args) {
+    var numer = args[0];
+    var denom = args[1];
+    var hasBarLine;
+    var leftDelim = null;
+    var rightDelim = null;
+    var size = "auto";
+
+    switch (context.funcName) {
+        case "\\dfrac":
+        case "\\frac":
+        case "\\tfrac":
+            hasBarLine = true;
+            break;
+        case "\\\\atopfrac":
+            hasBarLine = false;
+            break;
+        case "\\dbinom":
+        case "\\binom":
+        case "\\tbinom":
+            hasBarLine = false;
+            leftDelim = "(";
+            rightDelim = ")";
+            break;
+        default:
+            throw new Error("Unrecognized genfrac command");
+    }
+
+    switch (context.funcName) {
+        case "\\dfrac":
+        case "\\dbinom":
+            size = "display";
+            break;
+        case "\\tfrac":
+        case "\\tbinom":
+            size = "text";
+            break;
+    }
+
+    return {
+        type: "genfrac",
+        numer: numer,
+        denom: denom,
+        hasBarLine: hasBarLine,
+        leftDelim: leftDelim,
+        rightDelim: rightDelim,
+        size: size
+    };
+});
+
+// Left and right overlap functions
+defineFunction(["\\llap", "\\rlap"], {
+    numArgs: 1,
+    allowedInText: true
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: context.funcName.slice(1),
+        body: body
+    };
+});
+
+// Delimiter functions
+var checkDelimiter = function(delim, context) {
+    if (utils.contains(delimiters, delim.value)) {
+        return delim;
+    } else {
+        throw new ParseError(
+            "Invalid delimiter: '" + delim.value + "' after '" +
+            context.funcName + "'", delim);
+    }
+};
+
+defineFunction([
+    "\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
+    "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
+    "\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
+    "\\big",  "\\Big",  "\\bigg",  "\\Bigg"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+
+    return {
+        type: "delimsizing",
+        size: delimiterSizes[context.funcName].size,
+        mclass: delimiterSizes[context.funcName].mclass,
+        value: delim.value
+    };
+});
+
+defineFunction([
+    "\\left", "\\right"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+
+    // \left and \right are caught somewhere in Parser.js, which is
+    // why this data doesn't match what is in buildHTML.
+    return {
+        type: "leftright",
+        value: delim.value
+    };
+});
+
+defineFunction("\\middle", {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+    if (!context.parser.leftrightDepth) {
+        throw new ParseError("\\middle without preceding \\left", delim);
+    }
+
+    return {
+        type: "middle",
+        value: delim.value
+    };
+});
+
+// Sizing functions (handled in Parser.js explicitly, hence no handler)
+defineFunction([
+    "\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
+    "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"
+], 0, null);
+
+// Style changing functions (handled in Parser.js explicitly, hence no
+// handler)
+defineFunction([
+    "\\displaystyle", "\\textstyle", "\\scriptstyle",
+    "\\scriptscriptstyle"
+], 0, null);
+
+defineFunction([
+    // styles
+    "\\mathrm", "\\mathit", "\\mathbf",
+
+    // families
+    "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
+    "\\mathtt",
+
+    // aliases
+    "\\Bbb", "\\bold", "\\frak"
+], {
+    numArgs: 1,
+    greediness: 2
+}, function(context, args) {
+    var body = args[0];
+    var func = context.funcName;
+    if (func in fontAliases) {
+        func = fontAliases[func];
+    }
+    return {
+        type: "font",
+        font: func.slice(1),
+        body: body
+    };
+});
+
+// Accents
+defineFunction([
+    "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
+    "\\check", "\\hat", "\\vec", "\\dot"
+    // We don't support expanding accents yet
+    // "\\widetilde", "\\widehat"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var base = args[0];
+    return {
+        type: "accent",
+        accent: context.funcName,
+        base: base
+    };
+});
+
+// Infix generalized fractions
+defineFunction(["\\over", "\\choose", "\\atop"], {
+    numArgs: 0,
+    infix: true
+}, function(context) {
+    var replaceWith;
+    switch (context.funcName) {
+        case "\\over":
+            replaceWith = "\\frac";
+            break;
+        case "\\choose":
+            replaceWith = "\\binom";
+            break;
+        case "\\atop":
+            replaceWith = "\\\\atopfrac";
+            break;
+        default:
+            throw new Error("Unrecognized infix genfrac command");
+    }
+    return {
+        type: "infix",
+        replaceWith: replaceWith,
+        token: context.token
+    };
+});
+
+// Row breaks for aligned data
+defineFunction(["\\\\", "\\cr"], {
+    numArgs: 0,
+    numOptionalArgs: 1,
+    argTypes: ["size"]
+}, function(context, args) {
+    var size = args[0];
+    return {
+        type: "cr",
+        size: size
+    };
+});
+
+// Environment delimiters
+defineFunction(["\\begin", "\\end"], {
+    numArgs: 1,
+    argTypes: ["text"]
+}, function(context, args) {
+    var nameGroup = args[0];
+    if (nameGroup.type !== "ordgroup") {
+        throw new ParseError("Invalid environment name", nameGroup);
+    }
+    var name = "";
+    for (var i = 0; i < nameGroup.value.length; ++i) {
+        name += nameGroup.value[i].value;
+    }
+    return {
+        type: "environment",
+        name: name,
+        nameGroup: nameGroup
+    };
+});
+
+},{"./ParseError":6,"./parseData":21,"./utils":25}],20:[function(require,module,exports){
+/**
+ * These objects store data about MathML nodes. This is the MathML equivalent
+ * of the types in domTree.js. Since MathML handles its own rendering, and
+ * since we're mainly using MathML to improve accessibility, we don't manage
+ * any of the styling state that the plain DOM nodes do.
+ *
+ * The `toNode` and `toMarkup` functions work simlarly to how they do in
+ * domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
+ */
+
+var utils = require("./utils");
+
+/**
+ * This node represents a general purpose MathML node of any type. The
+ * constructor requires the type of node to create (for example, `"mo"` or
+ * `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
+ */
+function MathNode(type, children) {
+    this.type = type;
+    this.attributes = {};
+    this.children = children || [];
+}
+
+/**
+ * Sets an attribute on a MathML node. MathML depends on attributes to convey a
+ * semantic content, so this is used heavily.
+ */
+MathNode.prototype.setAttribute = function(name, value) {
+    this.attributes[name] = value;
+};
+
+/**
+ * Converts the math node into a MathML-namespaced DOM element.
+ */
+MathNode.prototype.toNode = function() {
+    var node = document.createElementNS(
+        "http://www.w3.org/1998/Math/MathML", this.type);
+
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            node.setAttribute(attr, this.attributes[attr]);
+        }
+    }
+
+    for (var i = 0; i < this.children.length; i++) {
+        node.appendChild(this.children[i].toNode());
+    }
+
+    return node;
+};
+
+/**
+ * Converts the math node into an HTML markup string.
+ */
+MathNode.prototype.toMarkup = function() {
+    var markup = "<" + this.type;
+
+    // Add the attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            markup += " " + attr + "=\"";
+            markup += utils.escape(this.attributes[attr]);
+            markup += "\"";
+        }
+    }
+
+    markup += ">";
+
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    markup += "</" + this.type + ">";
+
+    return markup;
+};
+
+/**
+ * This node represents a piece of text.
+ */
+function TextNode(text) {
+    this.text = text;
+}
+
+/**
+ * Converts the text node into a DOM text node.
+ */
+TextNode.prototype.toNode = function() {
+    return document.createTextNode(this.text);
+};
+
+/**
+ * Converts the text node into HTML markup (which is just the text itself).
+ */
+TextNode.prototype.toMarkup = function() {
+    return utils.escape(this.text);
+};
+
+module.exports = {
+    MathNode: MathNode,
+    TextNode: TextNode
+};
+
+},{"./utils":25}],21:[function(require,module,exports){
+/**
+ * The resulting parse tree nodes of the parse tree.
+ *
+ * It is possible to provide position information, so that a ParseNode can
+ * fulfil a role similar to a Token in error reporting.
+ * For details on the corresponding properties see Token constructor.
+ * Providing such information can lead to better error reporting.
+ *
+ * @param {string}  type       type of node, like e.g. "ordgroup"
+ * @param {?object} value      type-specific representation of the node
+ * @param {string}  mode       parse mode in action for this node,
+ *                             "math" or "text"
+ * @param {Token=} firstToken  first token of the input for this node,
+ *                             will omit position information if unset
+ * @param {Token=} lastToken   last token of the input for this node,
+ *                             will default to firstToken if unset
+ */
+function ParseNode(type, value, mode, firstToken, lastToken) {
+    this.type = type;
+    this.value = value;
+    this.mode = mode;
+    if (firstToken && (!lastToken || lastToken.lexer === firstToken.lexer)) {
+        this.lexer = firstToken.lexer;
+        this.start = firstToken.start;
+        this.end = (lastToken || firstToken).end;
+    }
+}
+
+module.exports = {
+    ParseNode: ParseNode
+};
+
+
+},{}],22:[function(require,module,exports){
+/**
+ * Provides a single function for parsing an expression using a Parser
+ * TODO(emily): Remove this
+ */
+
+var Parser = require("./Parser");
+
+/**
+ * Parses an expression using a Parser, then returns the parsed result.
+ */
+var parseTree = function(toParse, settings) {
+    if (!(typeof toParse === 'string' || toParse instanceof String)) {
+        throw new TypeError('KaTeX can only parse string typed expression');
+    }
+    var parser = new Parser(toParse, settings);
+
+    return parser.parse();
+};
+
+module.exports = parseTree;
+
+},{"./Parser":7}],23:[function(require,module,exports){
+/**
+ * This file holds a list of all no-argument functions and single-character
+ * symbols (like 'a' or ';').
+ *
+ * For each of the symbols, there are three properties they can have:
+ * - font (required): the font to be used for this symbol. Either "main" (the
+     normal font), or "ams" (the ams fonts).
+ * - group (required): the ParseNode group type the symbol should have (i.e.
+     "textord", "mathord", etc).
+     See https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
+ * - replace: the character that this symbol or function should be
+ *   replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi
+ *   character in the main font).
+ *
+ * The outermost map in the table indicates what mode the symbols should be
+ * accepted in (e.g. "math" or "text").
+ */
+
+module.exports = {
+    math: {},
+    text: {}
+};
+
+function defineSymbol(mode, font, group, replace, name) {
+    module.exports[mode][name] = {
+        font: font,
+        group: group,
+        replace: replace
+    };
+}
+
+// Some abbreviations for commonly used strings.
+// This helps minify the code, and also spotting typos using jshint.
+
+// modes:
+var math = "math";
+var text = "text";
+
+// fonts:
+var main = "main";
+var ams = "ams";
+
+// groups:
+var accent = "accent";
+var bin = "bin";
+var close = "close";
+var inner = "inner";
+var mathord = "mathord";
+var op = "op";
+var open = "open";
+var punct = "punct";
+var rel = "rel";
+var spacing = "spacing";
+var textord = "textord";
+
+// Now comes the symbol table
+
+// Relation Symbols
+defineSymbol(math, main, rel, "\u2261", "\\equiv");
+defineSymbol(math, main, rel, "\u227a", "\\prec");
+defineSymbol(math, main, rel, "\u227b", "\\succ");
+defineSymbol(math, main, rel, "\u223c", "\\sim");
+defineSymbol(math, main, rel, "\u22a5", "\\perp");
+defineSymbol(math, main, rel, "\u2aaf", "\\preceq");
+defineSymbol(math, main, rel, "\u2ab0", "\\succeq");
+defineSymbol(math, main, rel, "\u2243", "\\simeq");
+defineSymbol(math, main, rel, "\u2223", "\\mid");
+defineSymbol(math, main, rel, "\u226a", "\\ll");
+defineSymbol(math, main, rel, "\u226b", "\\gg");
+defineSymbol(math, main, rel, "\u224d", "\\asymp");
+defineSymbol(math, main, rel, "\u2225", "\\parallel");
+defineSymbol(math, main, rel, "\u22c8", "\\bowtie");
+defineSymbol(math, main, rel, "\u2323", "\\smile");
+defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq");
+defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq");
+defineSymbol(math, main, rel, "\u2250", "\\doteq");
+defineSymbol(math, main, rel, "\u2322", "\\frown");
+defineSymbol(math, main, rel, "\u220b", "\\ni");
+defineSymbol(math, main, rel, "\u221d", "\\propto");
+defineSymbol(math, main, rel, "\u22a2", "\\vdash");
+defineSymbol(math, main, rel, "\u22a3", "\\dashv");
+defineSymbol(math, main, rel, "\u220b", "\\owns");
+
+// Punctuation
+defineSymbol(math, main, punct, "\u002e", "\\ldotp");
+defineSymbol(math, main, punct, "\u22c5", "\\cdotp");
+
+// Misc Symbols
+defineSymbol(math, main, textord, "\u0023", "\\#");
+defineSymbol(text, main, textord, "\u0023", "\\#");
+defineSymbol(math, main, textord, "\u0026", "\\&");
+defineSymbol(text, main, textord, "\u0026", "\\&");
+defineSymbol(math, main, textord, "\u2135", "\\aleph");
+defineSymbol(math, main, textord, "\u2200", "\\forall");
+defineSymbol(math, main, textord, "\u210f", "\\hbar");
+defineSymbol(math, main, textord, "\u2203", "\\exists");
+defineSymbol(math, main, textord, "\u2207", "\\nabla");
+defineSymbol(math, main, textord, "\u266d", "\\flat");
+defineSymbol(math, main, textord, "\u2113", "\\ell");
+defineSymbol(math, main, textord, "\u266e", "\\natural");
+defineSymbol(math, main, textord, "\u2663", "\\clubsuit");
+defineSymbol(math, main, textord, "\u2118", "\\wp");
+defineSymbol(math, main, textord, "\u266f", "\\sharp");
+defineSymbol(math, main, textord, "\u2662", "\\diamondsuit");
+defineSymbol(math, main, textord, "\u211c", "\\Re");
+defineSymbol(math, main, textord, "\u2661", "\\heartsuit");
+defineSymbol(math, main, textord, "\u2111", "\\Im");
+defineSymbol(math, main, textord, "\u2660", "\\spadesuit");
+
+// Math and Text
+defineSymbol(math, main, textord, "\u2020", "\\dag");
+defineSymbol(math, main, textord, "\u2021", "\\ddag");
+
+// Large Delimiters
+defineSymbol(math, main, close, "\u23b1", "\\rmoustache");
+defineSymbol(math, main, open, "\u23b0", "\\lmoustache");
+defineSymbol(math, main, close, "\u27ef", "\\rgroup");
+defineSymbol(math, main, open, "\u27ee", "\\lgroup");
+
+// Binary Operators
+defineSymbol(math, main, bin, "\u2213", "\\mp");
+defineSymbol(math, main, bin, "\u2296", "\\ominus");
+defineSymbol(math, main, bin, "\u228e", "\\uplus");
+defineSymbol(math, main, bin, "\u2293", "\\sqcap");
+defineSymbol(math, main, bin, "\u2217", "\\ast");
+defineSymbol(math, main, bin, "\u2294", "\\sqcup");
+defineSymbol(math, main, bin, "\u25ef", "\\bigcirc");
+defineSymbol(math, main, bin, "\u2219", "\\bullet");
+defineSymbol(math, main, bin, "\u2021", "\\ddagger");
+defineSymbol(math, main, bin, "\u2240", "\\wr");
+defineSymbol(math, main, bin, "\u2a3f", "\\amalg");
+
+// Arrow Symbols
+defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow");
+defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow");
+defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow");
+defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow");
+defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow");
+defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow");
+defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow");
+defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow");
+defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow");
+defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow");
+defineSymbol(math, main, rel, "\u21a6", "\\mapsto");
+defineSymbol(math, main, rel, "\u27fc", "\\longmapsto");
+defineSymbol(math, main, rel, "\u2197", "\\nearrow");
+defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow");
+defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow");
+defineSymbol(math, main, rel, "\u2198", "\\searrow");
+defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup");
+defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup");
+defineSymbol(math, main, rel, "\u2199", "\\swarrow");
+defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown");
+defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown");
+defineSymbol(math, main, rel, "\u2196", "\\nwarrow");
+defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons");
+
+// AMS Negated Binary Relations
+defineSymbol(math, ams, rel, "\u226e", "\\nless");
+defineSymbol(math, ams, rel, "\ue010", "\\nleqslant");
+defineSymbol(math, ams, rel, "\ue011", "\\nleqq");
+defineSymbol(math, ams, rel, "\u2a87", "\\lneq");
+defineSymbol(math, ams, rel, "\u2268", "\\lneqq");
+defineSymbol(math, ams, rel, "\ue00c", "\\lvertneqq");
+defineSymbol(math, ams, rel, "\u22e6", "\\lnsim");
+defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox");
+defineSymbol(math, ams, rel, "\u2280", "\\nprec");
+defineSymbol(math, ams, rel, "\u22e0", "\\npreceq");
+defineSymbol(math, ams, rel, "\u22e8", "\\precnsim");
+defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox");
+defineSymbol(math, ams, rel, "\u2241", "\\nsim");
+defineSymbol(math, ams, rel, "\ue006", "\\nshortmid");
+defineSymbol(math, ams, rel, "\u2224", "\\nmid");
+defineSymbol(math, ams, rel, "\u22ac", "\\nvdash");
+defineSymbol(math, ams, rel, "\u22ad", "\\nvDash");
+defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft");
+defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq");
+defineSymbol(math, ams, rel, "\u228a", "\\subsetneq");
+defineSymbol(math, ams, rel, "\ue01a", "\\varsubsetneq");
+defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq");
+defineSymbol(math, ams, rel, "\ue017", "\\varsubsetneqq");
+defineSymbol(math, ams, rel, "\u226f", "\\ngtr");
+defineSymbol(math, ams, rel, "\ue00f", "\\ngeqslant");
+defineSymbol(math, ams, rel, "\ue00e", "\\ngeqq");
+defineSymbol(math, ams, rel, "\u2a88", "\\gneq");
+defineSymbol(math, ams, rel, "\u2269", "\\gneqq");
+defineSymbol(math, ams, rel, "\ue00d", "\\gvertneqq");
+defineSymbol(math, ams, rel, "\u22e7", "\\gnsim");
+defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox");
+defineSymbol(math, ams, rel, "\u2281", "\\nsucc");
+defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq");
+defineSymbol(math, ams, rel, "\u22e9", "\\succnsim");
+defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox");
+defineSymbol(math, ams, rel, "\u2246", "\\ncong");
+defineSymbol(math, ams, rel, "\ue007", "\\nshortparallel");
+defineSymbol(math, ams, rel, "\u2226", "\\nparallel");
+defineSymbol(math, ams, rel, "\u22af", "\\nVDash");
+defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright");
+defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq");
+defineSymbol(math, ams, rel, "\ue018", "\\nsupseteqq");
+defineSymbol(math, ams, rel, "\u228b", "\\supsetneq");
+defineSymbol(math, ams, rel, "\ue01b", "\\varsupsetneq");
+defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq");
+defineSymbol(math, ams, rel, "\ue019", "\\varsupsetneqq");
+defineSymbol(math, ams, rel, "\u22ae", "\\nVdash");
+defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq");
+defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq");
+defineSymbol(math, ams, rel, "\ue016", "\\nsubseteqq");
+defineSymbol(math, ams, bin, "\u22b4", "\\unlhd");
+defineSymbol(math, ams, bin, "\u22b5", "\\unrhd");
+
+// AMS Negated Arrows
+defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow");
+defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow");
+defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow");
+defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow");
+defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow");
+defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow");
+
+// AMS Misc
+defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle");
+defineSymbol(math, ams, textord, "\u210f", "\\hslash");
+defineSymbol(math, ams, textord, "\u25bd", "\\triangledown");
+defineSymbol(math, ams, textord, "\u25ca", "\\lozenge");
+defineSymbol(math, ams, textord, "\u24c8", "\\circledS");
+defineSymbol(math, ams, textord, "\u00ae", "\\circledR");
+defineSymbol(math, ams, textord, "\u2221", "\\measuredangle");
+defineSymbol(math, ams, textord, "\u2204", "\\nexists");
+defineSymbol(math, ams, textord, "\u2127", "\\mho");
+defineSymbol(math, ams, textord, "\u2132", "\\Finv");
+defineSymbol(math, ams, textord, "\u2141", "\\Game");
+defineSymbol(math, ams, textord, "\u006b", "\\Bbbk");
+defineSymbol(math, ams, textord, "\u2035", "\\backprime");
+defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle");
+defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown");
+defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare");
+defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge");
+defineSymbol(math, ams, textord, "\u2605", "\\bigstar");
+defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle");
+defineSymbol(math, ams, textord, "\u2201", "\\complement");
+defineSymbol(math, ams, textord, "\u00f0", "\\eth");
+defineSymbol(math, ams, textord, "\u2571", "\\diagup");
+defineSymbol(math, ams, textord, "\u2572", "\\diagdown");
+defineSymbol(math, ams, textord, "\u25a1", "\\square");
+defineSymbol(math, ams, textord, "\u25a1", "\\Box");
+defineSymbol(math, ams, textord, "\u25ca", "\\Diamond");
+defineSymbol(math, ams, textord, "\u00a5", "\\yen");
+defineSymbol(math, ams, textord, "\u2713", "\\checkmark");
+
+// AMS Hebrew
+defineSymbol(math, ams, textord, "\u2136", "\\beth");
+defineSymbol(math, ams, textord, "\u2138", "\\daleth");
+defineSymbol(math, ams, textord, "\u2137", "\\gimel");
+
+// AMS Greek
+defineSymbol(math, ams, textord, "\u03dd", "\\digamma");
+defineSymbol(math, ams, textord, "\u03f0", "\\varkappa");
+
+// AMS Delimiters
+defineSymbol(math, ams, open, "\u250c", "\\ulcorner");
+defineSymbol(math, ams, close, "\u2510", "\\urcorner");
+defineSymbol(math, ams, open, "\u2514", "\\llcorner");
+defineSymbol(math, ams, close, "\u2518", "\\lrcorner");
+
+// AMS Binary Relations
+defineSymbol(math, ams, rel, "\u2266", "\\leqq");
+defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant");
+defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless");
+defineSymbol(math, ams, rel, "\u2272", "\\lesssim");
+defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox");
+defineSymbol(math, ams, rel, "\u224a", "\\approxeq");
+defineSymbol(math, ams, bin, "\u22d6", "\\lessdot");
+defineSymbol(math, ams, rel, "\u22d8", "\\lll");
+defineSymbol(math, ams, rel, "\u2276", "\\lessgtr");
+defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr");
+defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr");
+defineSymbol(math, ams, rel, "\u2251", "\\doteqdot");
+defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq");
+defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq");
+defineSymbol(math, ams, rel, "\u223d", "\\backsim");
+defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq");
+defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq");
+defineSymbol(math, ams, rel, "\u22d0", "\\Subset");
+defineSymbol(math, ams, rel, "\u228f", "\\sqsubset");
+defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq");
+defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec");
+defineSymbol(math, ams, rel, "\u227e", "\\precsim");
+defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox");
+defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft");
+defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq");
+defineSymbol(math, ams, rel, "\u22a8", "\\vDash");
+defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash");
+defineSymbol(math, ams, rel, "\u2323", "\\smallsmile");
+defineSymbol(math, ams, rel, "\u2322", "\\smallfrown");
+defineSymbol(math, ams, rel, "\u224f", "\\bumpeq");
+defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq");
+defineSymbol(math, ams, rel, "\u2267", "\\geqq");
+defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant");
+defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr");
+defineSymbol(math, ams, rel, "\u2273", "\\gtrsim");
+defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox");
+defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot");
+defineSymbol(math, ams, rel, "\u22d9", "\\ggg");
+defineSymbol(math, ams, rel, "\u2277", "\\gtrless");
+defineSymbol(math, ams, rel, "\u22db", "\\gtreqless");
+defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless");
+defineSymbol(math, ams, rel, "\u2256", "\\eqcirc");
+defineSymbol(math, ams, rel, "\u2257", "\\circeq");
+defineSymbol(math, ams, rel, "\u225c", "\\triangleq");
+defineSymbol(math, ams, rel, "\u223c", "\\thicksim");
+defineSymbol(math, ams, rel, "\u2248", "\\thickapprox");
+defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq");
+defineSymbol(math, ams, rel, "\u22d1", "\\Supset");
+defineSymbol(math, ams, rel, "\u2290", "\\sqsupset");
+defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq");
+defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc");
+defineSymbol(math, ams, rel, "\u227f", "\\succsim");
+defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox");
+defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright");
+defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq");
+defineSymbol(math, ams, rel, "\u22a9", "\\Vdash");
+defineSymbol(math, ams, rel, "\u2223", "\\shortmid");
+defineSymbol(math, ams, rel, "\u2225", "\\shortparallel");
+defineSymbol(math, ams, rel, "\u226c", "\\between");
+defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork");
+defineSymbol(math, ams, rel, "\u221d", "\\varpropto");
+defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft");
+defineSymbol(math, ams, rel, "\u2234", "\\therefore");
+defineSymbol(math, ams, rel, "\u220d", "\\backepsilon");
+defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright");
+defineSymbol(math, ams, rel, "\u2235", "\\because");
+defineSymbol(math, ams, rel, "\u22d8", "\\llless");
+defineSymbol(math, ams, rel, "\u22d9", "\\gggtr");
+defineSymbol(math, ams, bin, "\u22b2", "\\lhd");
+defineSymbol(math, ams, bin, "\u22b3", "\\rhd");
+defineSymbol(math, ams, rel, "\u2242", "\\eqsim");
+defineSymbol(math, main, rel, "\u22c8", "\\Join");
+defineSymbol(math, ams, rel, "\u2251", "\\Doteq");
+
+// AMS Binary Operators
+defineSymbol(math, ams, bin, "\u2214", "\\dotplus");
+defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus");
+defineSymbol(math, ams, bin, "\u22d2", "\\Cap");
+defineSymbol(math, ams, bin, "\u22d3", "\\Cup");
+defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge");
+defineSymbol(math, ams, bin, "\u229f", "\\boxminus");
+defineSymbol(math, ams, bin, "\u229e", "\\boxplus");
+defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes");
+defineSymbol(math, ams, bin, "\u22c9", "\\ltimes");
+defineSymbol(math, ams, bin, "\u22ca", "\\rtimes");
+defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes");
+defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes");
+defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge");
+defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee");
+defineSymbol(math, ams, bin, "\u229d", "\\circleddash");
+defineSymbol(math, ams, bin, "\u229b", "\\circledast");
+defineSymbol(math, ams, bin, "\u22c5", "\\centerdot");
+defineSymbol(math, ams, bin, "\u22ba", "\\intercal");
+defineSymbol(math, ams, bin, "\u22d2", "\\doublecap");
+defineSymbol(math, ams, bin, "\u22d3", "\\doublecup");
+defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes");
+
+// AMS Arrows
+defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow");
+defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow");
+defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows");
+defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows");
+defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow");
+defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow");
+defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail");
+defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft");
+defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons");
+defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft");
+defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft");
+defineSymbol(math, ams, rel, "\u21b0", "\\Lsh");
+defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows");
+defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft");
+defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft");
+defineSymbol(math, ams, rel, "\u22b8", "\\multimap");
+defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow");
+defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows");
+defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows");
+defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow");
+defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail");
+defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright");
+defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright");
+defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright");
+defineSymbol(math, ams, rel, "\u21b1", "\\Rsh");
+defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows");
+defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright");
+defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright");
+defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow");
+defineSymbol(math, ams, rel, "\u21dd", "\\leadsto");
+defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow");
+defineSymbol(math, ams, rel, "\u21be", "\\restriction");
+
+defineSymbol(math, main, textord, "\u2018", "`");
+defineSymbol(math, main, textord, "$", "\\$");
+defineSymbol(text, main, textord, "$", "\\$");
+defineSymbol(math, main, textord, "%", "\\%");
+defineSymbol(text, main, textord, "%", "\\%");
+defineSymbol(math, main, textord, "_", "\\_");
+defineSymbol(text, main, textord, "_", "\\_");
+defineSymbol(math, main, textord, "\u2220", "\\angle");
+defineSymbol(math, main, textord, "\u221e", "\\infty");
+defineSymbol(math, main, textord, "\u2032", "\\prime");
+defineSymbol(math, main, textord, "\u25b3", "\\triangle");
+defineSymbol(math, main, textord, "\u0393", "\\Gamma");
+defineSymbol(math, main, textord, "\u0394", "\\Delta");
+defineSymbol(math, main, textord, "\u0398", "\\Theta");
+defineSymbol(math, main, textord, "\u039b", "\\Lambda");
+defineSymbol(math, main, textord, "\u039e", "\\Xi");
+defineSymbol(math, main, textord, "\u03a0", "\\Pi");
+defineSymbol(math, main, textord, "\u03a3", "\\Sigma");
+defineSymbol(math, main, textord, "\u03a5", "\\Upsilon");
+defineSymbol(math, main, textord, "\u03a6", "\\Phi");
+defineSymbol(math, main, textord, "\u03a8", "\\Psi");
+defineSymbol(math, main, textord, "\u03a9", "\\Omega");
+defineSymbol(math, main, textord, "\u00ac", "\\neg");
+defineSymbol(math, main, textord, "\u00ac", "\\lnot");
+defineSymbol(math, main, textord, "\u22a4", "\\top");
+defineSymbol(math, main, textord, "\u22a5", "\\bot");
+defineSymbol(math, main, textord, "\u2205", "\\emptyset");
+defineSymbol(math, ams, textord, "\u2205", "\\varnothing");
+defineSymbol(math, main, mathord, "\u03b1", "\\alpha");
+defineSymbol(math, main, mathord, "\u03b2", "\\beta");
+defineSymbol(math, main, mathord, "\u03b3", "\\gamma");
+defineSymbol(math, main, mathord, "\u03b4", "\\delta");
+defineSymbol(math, main, mathord, "\u03f5", "\\epsilon");
+defineSymbol(math, main, mathord, "\u03b6", "\\zeta");
+defineSymbol(math, main, mathord, "\u03b7", "\\eta");
+defineSymbol(math, main, mathord, "\u03b8", "\\theta");
+defineSymbol(math, main, mathord, "\u03b9", "\\iota");
+defineSymbol(math, main, mathord, "\u03ba", "\\kappa");
+defineSymbol(math, main, mathord, "\u03bb", "\\lambda");
+defineSymbol(math, main, mathord, "\u03bc", "\\mu");
+defineSymbol(math, main, mathord, "\u03bd", "\\nu");
+defineSymbol(math, main, mathord, "\u03be", "\\xi");
+defineSymbol(math, main, mathord, "o", "\\omicron");
+defineSymbol(math, main, mathord, "\u03c0", "\\pi");
+defineSymbol(math, main, mathord, "\u03c1", "\\rho");
+defineSymbol(math, main, mathord, "\u03c3", "\\sigma");
+defineSymbol(math, main, mathord, "\u03c4", "\\tau");
+defineSymbol(math, main, mathord, "\u03c5", "\\upsilon");
+defineSymbol(math, main, mathord, "\u03d5", "\\phi");
+defineSymbol(math, main, mathord, "\u03c7", "\\chi");
+defineSymbol(math, main, mathord, "\u03c8", "\\psi");
+defineSymbol(math, main, mathord, "\u03c9", "\\omega");
+defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon");
+defineSymbol(math, main, mathord, "\u03d1", "\\vartheta");
+defineSymbol(math, main, mathord, "\u03d6", "\\varpi");
+defineSymbol(math, main, mathord, "\u03f1", "\\varrho");
+defineSymbol(math, main, mathord, "\u03c2", "\\varsigma");
+defineSymbol(math, main, mathord, "\u03c6", "\\varphi");
+defineSymbol(math, main, bin, "\u2217", "*");
+defineSymbol(math, main, bin, "+", "+");
+defineSymbol(math, main, bin, "\u2212", "-");
+defineSymbol(math, main, bin, "\u22c5", "\\cdot");
+defineSymbol(math, main, bin, "\u2218", "\\circ");
+defineSymbol(math, main, bin, "\u00f7", "\\div");
+defineSymbol(math, main, bin, "\u00b1", "\\pm");
+defineSymbol(math, main, bin, "\u00d7", "\\times");
+defineSymbol(math, main, bin, "\u2229", "\\cap");
+defineSymbol(math, main, bin, "\u222a", "\\cup");
+defineSymbol(math, main, bin, "\u2216", "\\setminus");
+defineSymbol(math, main, bin, "\u2227", "\\land");
+defineSymbol(math, main, bin, "\u2228", "\\lor");
+defineSymbol(math, main, bin, "\u2227", "\\wedge");
+defineSymbol(math, main, bin, "\u2228", "\\vee");
+defineSymbol(math, main, textord, "\u221a", "\\surd");
+defineSymbol(math, main, open, "(", "(");
+defineSymbol(math, main, open, "[", "[");
+defineSymbol(math, main, open, "\u27e8", "\\langle");
+defineSymbol(math, main, open, "\u2223", "\\lvert");
+defineSymbol(math, main, open, "\u2225", "\\lVert");
+defineSymbol(math, main, close, ")", ")");
+defineSymbol(math, main, close, "]", "]");
+defineSymbol(math, main, close, "?", "?");
+defineSymbol(math, main, close, "!", "!");
+defineSymbol(math, main, close, "\u27e9", "\\rangle");
+defineSymbol(math, main, close, "\u2223", "\\rvert");
+defineSymbol(math, main, close, "\u2225", "\\rVert");
+defineSymbol(math, main, rel, "=", "=");
+defineSymbol(math, main, rel, "<", "<");
+defineSymbol(math, main, rel, ">", ">");
+defineSymbol(math, main, rel, ":", ":");
+defineSymbol(math, main, rel, "\u2248", "\\approx");
+defineSymbol(math, main, rel, "\u2245", "\\cong");
+defineSymbol(math, main, rel, "\u2265", "\\ge");
+defineSymbol(math, main, rel, "\u2265", "\\geq");
+defineSymbol(math, main, rel, "\u2190", "\\gets");
+defineSymbol(math, main, rel, ">", "\\gt");
+defineSymbol(math, main, rel, "\u2208", "\\in");
+defineSymbol(math, main, rel, "\u2209", "\\notin");
+defineSymbol(math, main, rel, "\u2282", "\\subset");
+defineSymbol(math, main, rel, "\u2283", "\\supset");
+defineSymbol(math, main, rel, "\u2286", "\\subseteq");
+defineSymbol(math, main, rel, "\u2287", "\\supseteq");
+defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq");
+defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq");
+defineSymbol(math, main, rel, "\u22a8", "\\models");
+defineSymbol(math, main, rel, "\u2190", "\\leftarrow");
+defineSymbol(math, main, rel, "\u2264", "\\le");
+defineSymbol(math, main, rel, "\u2264", "\\leq");
+defineSymbol(math, main, rel, "<", "\\lt");
+defineSymbol(math, main, rel, "\u2260", "\\ne");
+defineSymbol(math, main, rel, "\u2260", "\\neq");
+defineSymbol(math, main, rel, "\u2192", "\\rightarrow");
+defineSymbol(math, main, rel, "\u2192", "\\to");
+defineSymbol(math, ams, rel, "\u2271", "\\ngeq");
+defineSymbol(math, ams, rel, "\u2270", "\\nleq");
+defineSymbol(math, main, spacing, null, "\\!");
+defineSymbol(math, main, spacing, "\u00a0", "\\ ");
+defineSymbol(math, main, spacing, "\u00a0", "~");
+defineSymbol(math, main, spacing, null, "\\,");
+defineSymbol(math, main, spacing, null, "\\:");
+defineSymbol(math, main, spacing, null, "\\;");
+defineSymbol(math, main, spacing, null, "\\enspace");
+defineSymbol(math, main, spacing, null, "\\qquad");
+defineSymbol(math, main, spacing, null, "\\quad");
+defineSymbol(math, main, spacing, "\u00a0", "\\space");
+defineSymbol(math, main, punct, ",", ",");
+defineSymbol(math, main, punct, ";", ";");
+defineSymbol(math, main, punct, ":", "\\colon");
+defineSymbol(math, ams, bin, "\u22bc", "\\barwedge");
+defineSymbol(math, ams, bin, "\u22bb", "\\veebar");
+defineSymbol(math, main, bin, "\u2299", "\\odot");
+defineSymbol(math, main, bin, "\u2295", "\\oplus");
+defineSymbol(math, main, bin, "\u2297", "\\otimes");
+defineSymbol(math, main, textord, "\u2202", "\\partial");
+defineSymbol(math, main, bin, "\u2298", "\\oslash");
+defineSymbol(math, ams, bin, "\u229a", "\\circledcirc");
+defineSymbol(math, ams, bin, "\u22a1", "\\boxdot");
+defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup");
+defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown");
+defineSymbol(math, main, bin, "\u2020", "\\dagger");
+defineSymbol(math, main, bin, "\u22c4", "\\diamond");
+defineSymbol(math, main, bin, "\u22c6", "\\star");
+defineSymbol(math, main, bin, "\u25c3", "\\triangleleft");
+defineSymbol(math, main, bin, "\u25b9", "\\triangleright");
+defineSymbol(math, main, open, "{", "\\{");
+defineSymbol(text, main, textord, "{", "\\{");
+defineSymbol(math, main, close, "}", "\\}");
+defineSymbol(text, main, textord, "}", "\\}");
+defineSymbol(math, main, open, "{", "\\lbrace");
+defineSymbol(math, main, close, "}", "\\rbrace");
+defineSymbol(math, main, open, "[", "\\lbrack");
+defineSymbol(math, main, close, "]", "\\rbrack");
+defineSymbol(math, main, open, "\u230a", "\\lfloor");
+defineSymbol(math, main, close, "\u230b", "\\rfloor");
+defineSymbol(math, main, open, "\u2308", "\\lceil");
+defineSymbol(math, main, close, "\u2309", "\\rceil");
+defineSymbol(math, main, textord, "\\", "\\backslash");
+defineSymbol(math, main, textord, "\u2223", "|");
+defineSymbol(math, main, textord, "\u2223", "\\vert");
+defineSymbol(math, main, textord, "\u2225", "\\|");
+defineSymbol(math, main, textord, "\u2225", "\\Vert");
+defineSymbol(math, main, rel, "\u2191", "\\uparrow");
+defineSymbol(math, main, rel, "\u21d1", "\\Uparrow");
+defineSymbol(math, main, rel, "\u2193", "\\downarrow");
+defineSymbol(math, main, rel, "\u21d3", "\\Downarrow");
+defineSymbol(math, main, rel, "\u2195", "\\updownarrow");
+defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow");
+defineSymbol(math, math, op, "\u2210", "\\coprod");
+defineSymbol(math, math, op, "\u22c1", "\\bigvee");
+defineSymbol(math, math, op, "\u22c0", "\\bigwedge");
+defineSymbol(math, math, op, "\u2a04", "\\biguplus");
+defineSymbol(math, math, op, "\u22c2", "\\bigcap");
+defineSymbol(math, math, op, "\u22c3", "\\bigcup");
+defineSymbol(math, math, op, "\u222b", "\\int");
+defineSymbol(math, math, op, "\u222b", "\\intop");
+defineSymbol(math, math, op, "\u222c", "\\iint");
+defineSymbol(math, math, op, "\u222d", "\\iiint");
+defineSymbol(math, math, op, "\u220f", "\\prod");
+defineSymbol(math, math, op, "\u2211", "\\sum");
+defineSymbol(math, math, op, "\u2a02", "\\bigotimes");
+defineSymbol(math, math, op, "\u2a01", "\\bigoplus");
+defineSymbol(math, math, op, "\u2a00", "\\bigodot");
+defineSymbol(math, math, op, "\u222e", "\\oint");
+defineSymbol(math, math, op, "\u2a06", "\\bigsqcup");
+defineSymbol(math, math, op, "\u222b", "\\smallint");
+defineSymbol(text, main, inner, "\u2026", "\\textellipsis");
+defineSymbol(math, main, inner, "\u2026", "\\mathellipsis");
+defineSymbol(text, main, inner, "\u2026", "\\ldots");
+defineSymbol(math, main, inner, "\u2026", "\\ldots");
+defineSymbol(math, main, inner, "\u22ef", "\\cdots");
+defineSymbol(math, main, inner, "\u22f1", "\\ddots");
+defineSymbol(math, main, textord, "\u22ee", "\\vdots");
+defineSymbol(math, main, accent, "\u00b4", "\\acute");
+defineSymbol(math, main, accent, "\u0060", "\\grave");
+defineSymbol(math, main, accent, "\u00a8", "\\ddot");
+defineSymbol(math, main, accent, "\u007e", "\\tilde");
+defineSymbol(math, main, accent, "\u00af", "\\bar");
+defineSymbol(math, main, accent, "\u02d8", "\\breve");
+defineSymbol(math, main, accent, "\u02c7", "\\check");
+defineSymbol(math, main, accent, "\u005e", "\\hat");
+defineSymbol(math, main, accent, "\u20d7", "\\vec");
+defineSymbol(math, main, accent, "\u02d9", "\\dot");
+defineSymbol(math, main, mathord, "\u0131", "\\imath");
+defineSymbol(math, main, mathord, "\u0237", "\\jmath");
+
+defineSymbol(text, main, textord, "\u2013", "--");
+defineSymbol(text, main, textord, "\u2014", "---");
+defineSymbol(text, main, textord, "\u2018", "`");
+defineSymbol(text, main, textord, "\u2019", "'");
+defineSymbol(text, main, textord, "\u201c", "``");
+defineSymbol(text, main, textord, "\u201d", "''");
+defineSymbol(math, main, textord, "\u00b0", "\\degree");
+defineSymbol(text, main, textord, "\u00b0", "\\degree");
+defineSymbol(math, main, mathord, "\u00a3", "\\pounds");
+defineSymbol(math, ams, textord, "\u2720", "\\maltese");
+defineSymbol(text, ams, textord, "\u2720", "\\maltese");
+
+defineSymbol(text, main, spacing, "\u00a0", "\\ ");
+defineSymbol(text, main, spacing, "\u00a0", " ");
+defineSymbol(text, main, spacing, "\u00a0", "~");
+
+// There are lots of symbols which are the same, so we add them in afterwards.
+var i;
+var ch;
+
+// All of these are textords in math mode
+var mathTextSymbols = "0123456789/@.\"";
+for (i = 0; i < mathTextSymbols.length; i++) {
+    ch = mathTextSymbols.charAt(i);
+    defineSymbol(math, main, textord, ch, ch);
+}
+
+// All of these are textords in text mode
+var textSymbols = "0123456789!@*()-=+[]\";:?/.,";
+for (i = 0; i < textSymbols.length; i++) {
+    ch = textSymbols.charAt(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// All of these are textords in text mode, and mathords in math mode
+var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+for (i = 0; i < letters.length; i++) {
+    ch = letters.charAt(i);
+    defineSymbol(math, main, mathord, ch, ch);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Latin-1 letters
+for (i = 0x00C0; i <= 0x00D6; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+for (i = 0x00D8; i <= 0x00F6; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+for (i = 0x00F8; i <= 0x00FF; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Cyrillic
+for (i = 0x0410; i <= 0x044F; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Unicode versions of existing characters
+defineSymbol(text, main, textord, "\u2013", "–");
+defineSymbol(text, main, textord, "\u2014", "—");
+defineSymbol(text, main, textord, "\u2018", "‘");
+defineSymbol(text, main, textord, "\u2019", "’");
+defineSymbol(text, main, textord, "\u201c", "“");
+defineSymbol(text, main, textord, "\u201d", "”");
+
+},{}],24:[function(require,module,exports){
+var hangulRegex = /[\uAC00-\uD7AF]/;
+
+// This regex combines
+// - Hiragana: [\u3040-\u309F]
+// - Katakana: [\u30A0-\u30FF]
+// - CJK ideograms: [\u4E00-\u9FAF]
+// - Hangul syllables: [\uAC00-\uD7AF]
+// Notably missing are halfwidth Katakana and Romanji glyphs.
+var cjkRegex =
+    /[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/;
+
+module.exports = {
+    cjkRegex: cjkRegex,
+    hangulRegex: hangulRegex
+};
+
+},{}],25:[function(require,module,exports){
+/**
+ * This file contains a list of utility functions which are useful in other
+ * files.
+ */
+
+/**
+ * Provide an `indexOf` function which works in IE8, but defers to native if
+ * possible.
+ */
+var nativeIndexOf = Array.prototype.indexOf;
+var indexOf = function(list, elem) {
+    if (list == null) {
+        return -1;
+    }
+    if (nativeIndexOf && list.indexOf === nativeIndexOf) {
+        return list.indexOf(elem);
+    }
+    var i = 0;
+    var l = list.length;
+    for (; i < l; i++) {
+        if (list[i] === elem) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Return whether an element is contained in a list
+ */
+var contains = function(list, elem) {
+    return indexOf(list, elem) !== -1;
+};
+
+/**
+ * Provide a default value if a setting is undefined
+ */
+var deflt = function(setting, defaultIfUndefined) {
+    return setting === undefined ? defaultIfUndefined : setting;
+};
+
+// hyphenate and escape adapted from Facebook's React under Apache 2 license
+
+var uppercase = /([A-Z])/g;
+var hyphenate = function(str) {
+    return str.replace(uppercase, "-$1").toLowerCase();
+};
+
+var ESCAPE_LOOKUP = {
+    "&": "&amp;",
+    ">": "&gt;",
+    "<": "&lt;",
+    "\"": "&quot;",
+    "'": "&#x27;"
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+    return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escape(text) {
+    return ("" + text).replace(ESCAPE_REGEX, escaper);
+}
+
+/**
+ * A function to set the text content of a DOM element in all supported
+ * browsers. Note that we don't define this if there is no document.
+ */
+var setTextContent;
+if (typeof document !== "undefined") {
+    var testNode = document.createElement("span");
+    if ("textContent" in testNode) {
+        setTextContent = function(node, text) {
+            node.textContent = text;
+        };
+    } else {
+        setTextContent = function(node, text) {
+            node.innerText = text;
+        };
+    }
+}
+
+/**
+ * A function to clear a node.
+ */
+function clearNode(node) {
+    setTextContent(node, "");
+}
+
+module.exports = {
+    contains: contains,
+    deflt: deflt,
+    escape: escape,
+    hyphenate: hyphenate,
+    indexOf: indexOf,
+    setTextContent: setTextContent,
+    clearNode: clearNode
+};
+
+},{}]},{},[1])(1)
+});
\ No newline at end of file
diff --git a/specs/es/3.2/katex/katex.min.css b/specs/es/3.2/katex/katex.min.css
new file mode 100644
index 0000000..d6fb837
--- /dev/null
+++ b/specs/es/3.2/katex/katex.min.css
@@ -0,0 +1 @@
+@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.eot);src:url(fonts/KaTeX_AMS-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_AMS-Regular.woff2) format('woff2'),url(fonts/KaTeX_AMS-Regular.woff) format('woff'),url(fonts/KaTeX_AMS-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.eot);src:url(fonts/KaTeX_Caligraphic-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Bold.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Bold.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.eot);src:url(fonts/KaTeX_Caligraphic-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Regular.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Regular.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.eot);src:url(fonts/KaTeX_Fraktur-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Bold.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Bold.woff) format('woff'),url(fonts/KaTeX_Fraktur-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.eot);src:url(fonts/KaTeX_Fraktur-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Regular.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Regular.woff) format('woff'),url(fonts/KaTeX_Fraktur-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.eot);src:url(fonts/KaTeX_Main-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Bold.woff2) format('woff2'),url(fonts/KaTeX_Main-Bold.woff) format('woff'),url(fonts/KaTeX_Main-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.eot);src:url(fonts/KaTeX_Main-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Italic.woff2) format('woff2'),url(fonts/KaTeX_Main-Italic.woff) format('woff'),url(fonts/KaTeX_Main-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.eot);src:url(fonts/KaTeX_Main-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Regular.woff2) format('woff2'),url(fonts/KaTeX_Main-Regular.woff) format('woff'),url(fonts/KaTeX_Main-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.eot);src:url(fonts/KaTeX_Math-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Math-Italic.woff2) format('woff2'),url(fonts/KaTeX_Math-Italic.woff) format('woff'),url(fonts/KaTeX_Math-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_SansSerif;src:url(fonts/KaTeX_SansSerif-Regular.eot);src:url(fonts/KaTeX_SansSerif-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_SansSerif-Regular.woff2) format('woff2'),url(fonts/KaTeX_SansSerif-Regular.woff) format('woff'),url(fonts/KaTeX_SansSerif-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.eot);src:url(fonts/KaTeX_Script-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Script-Regular.woff2) format('woff2'),url(fonts/KaTeX_Script-Regular.woff) format('woff'),url(fonts/KaTeX_Script-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.eot);src:url(fonts/KaTeX_Size1-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size1-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size1-Regular.woff) format('woff'),url(fonts/KaTeX_Size1-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.eot);src:url(fonts/KaTeX_Size2-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size2-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size2-Regular.woff) format('woff'),url(fonts/KaTeX_Size2-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.eot);src:url(fonts/KaTeX_Size3-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size3-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size3-Regular.woff) format('woff'),url(fonts/KaTeX_Size3-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.eot);src:url(fonts/KaTeX_Size4-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size4-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size4-Regular.woff) format('woff'),url(fonts/KaTeX_Size4-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.eot);src:url(fonts/KaTeX_Typewriter-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Typewriter-Regular.woff2) format('woff2'),url(fonts/KaTeX_Typewriter-Regular.woff) format('woff'),url(fonts/KaTeX_Typewriter-Regular.ttf) format('truetype');font-weight:400;font-style:normal}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:inline-block;text-align:initial}.katex{font:400 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;white-space:nowrap;text-indent:0}.katex .katex-html{display:inline-block}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .base,.katex .strut{display:inline-block}.katex .mathrm{font-style:normal}.katex .textit{font-style:italic}.katex .mathit{font-family:KaTeX_Math;font-style:italic}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .amsrm,.katex .mathbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr{font-family:KaTeX_Script}.katex .mathsf{font-family:KaTeX_SansSerif}.katex .mainit{font-family:KaTeX_Main;font-style:italic}.katex .mord+.mop{margin-left:.16667em}.katex .mord+.mbin{margin-left:.22222em}.katex .mord+.mrel{margin-left:.27778em}.katex .mop+.mop,.katex .mop+.mord,.katex .mord+.minner{margin-left:.16667em}.katex .mop+.mrel{margin-left:.27778em}.katex .mop+.minner{margin-left:.16667em}.katex .mbin+.minner,.katex .mbin+.mop,.katex .mbin+.mopen,.katex .mbin+.mord{margin-left:.22222em}.katex .mrel+.minner,.katex .mrel+.mop,.katex .mrel+.mopen,.katex .mrel+.mord{margin-left:.27778em}.katex .mclose+.mop{margin-left:.16667em}.katex .mclose+.mbin{margin-left:.22222em}.katex .mclose+.mrel{margin-left:.27778em}.katex .mclose+.minner,.katex .minner+.mop,.katex .minner+.mord,.katex .mpunct+.mclose,.katex .mpunct+.minner,.katex .mpunct+.mop,.katex .mpunct+.mopen,.katex .mpunct+.mord,.katex .mpunct+.mpunct,.katex .mpunct+.mrel{margin-left:.16667em}.katex .minner+.mbin{margin-left:.22222em}.katex .minner+.mrel{margin-left:.27778em}.katex .minner+.minner,.katex .minner+.mopen,.katex .minner+.mpunct{margin-left:.16667em}.katex .mbin.mtight,.katex .mclose.mtight,.katex .minner.mtight,.katex .mop.mtight,.katex .mopen.mtight,.katex .mord.mtight,.katex .mpunct.mtight,.katex .mrel.mtight{margin-left:0}.katex .mclose+.mop.mtight,.katex .minner+.mop.mtight,.katex .mop+.mop.mtight,.katex .mop+.mord.mtight,.katex .mord+.mop.mtight{margin-left:.16667em}.katex .reset-textstyle.textstyle{font-size:1em}.katex .reset-textstyle.scriptstyle{font-size:.7em}.katex .reset-textstyle.scriptscriptstyle{font-size:.5em}.katex .reset-scriptstyle.textstyle{font-size:1.42857em}.katex .reset-scriptstyle.scriptstyle{font-size:1em}.katex .reset-scriptstyle.scriptscriptstyle{font-size:.71429em}.katex .reset-scriptscriptstyle.textstyle{font-size:2em}.katex .reset-scriptscriptstyle.scriptstyle{font-size:1.4em}.katex .reset-scriptscriptstyle.scriptscriptstyle{font-size:1em}.katex .style-wrap{position:relative}.katex .vlist{display:inline-block}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist .baseline-fix{display:inline-table;table-layout:fixed}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{width:100%}.katex .mfrac .frac-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .mfrac .frac-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .mspace{display:inline-block}.katex .mspace.negativethinspace{margin-left:-.16667em}.katex .mspace.thinspace{width:.16667em}.katex .mspace.negativemediumspace{margin-left:-.22222em}.katex .mspace.mediumspace{width:.22222em}.katex .mspace.thickspace{width:.27778em}.katex .mspace.sixmuspace{width:.333333em}.katex .mspace.eightmuspace{width:.444444em}.katex .mspace.enspace{width:.5em}.katex .mspace.twelvemuspace{width:.666667em}.katex .mspace.quad{width:1em}.katex .mspace.qquad{width:2em}.katex .llap,.katex .rlap{width:0;position:relative}.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .rlap>.inner{left:0}.katex .katex-logo .a{font-size:.75em;margin-left:-.32em;position:relative;top:-.2em}.katex .katex-logo .t{margin-left:-.23em}.katex .katex-logo .e{margin-left:-.1667em;position:relative;top:.2155em}.katex .katex-logo .x{margin-left:-.125em}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .overline .overline-line,.katex .underline .underline-line{width:100%}.katex .overline .overline-line:before,.katex .underline .underline-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .overline .overline-line:after,.katex .underline .underline-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.sqrt-sign{position:relative}.katex .sqrt .sqrt-line{width:100%}.katex .sqrt .sqrt-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .sqrt .sqrt-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer,.katex .sizing{display:inline-block}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:2em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:3.46em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:4.14em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.98em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.47142857em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.95714286em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.55714286em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.875em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.125em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.25em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.5em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.8em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.1625em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.5875em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:3.1125em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.77777778em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.88888889em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.6em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.92222222em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.3em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.76666667em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.7em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.8em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.9em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.2em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.44em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.73em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:2.07em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.49em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.58333333em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.66666667em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.75em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.83333333em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44166667em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.725em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.075em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.48611111em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.55555556em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.625em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.69444444em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.20138889em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.4375em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72916667em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.28901734em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.40462428em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.46242775em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.52023121em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.57803468em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69364162em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83236994em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.19653179em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.43930636em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.24154589em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.33816425em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.38647343em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.43478261em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.48309179em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.57971014em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69565217em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83574879em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20289855em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.20080321em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2811245em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.32128514em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.36144578em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.40160643em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48192771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57831325em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69477912em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8313253em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist>span,.katex .op-limits>.vlist>span{text-align:center}.katex .accent .accent-body>span{width:0}.katex .accent .accent-body.accent-vec>span{position:relative;left:.326em}.katex .mtable .vertical-separator{display:inline-block;margin:0 -.025em;border-right:.05em solid #000}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist{text-align:center}.katex .mtable .col-align-l>.vlist{text-align:left}.katex .mtable .col-align-r>.vlist{text-align:right}
\ No newline at end of file
diff --git a/specs/es/3.2/katex/katex.min.js b/specs/es/3.2/katex/katex.min.js
new file mode 100644
index 0000000..66c0821
--- /dev/null
+++ b/specs/es/3.2/katex/katex.min.js
@@ -0,0 +1,4 @@
+(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.katex=e()}})(function(){var e,t,r;return function a(e,t,r){function i(s,l){if(!t[s]){if(!e[s]){var o=typeof require=="function"&&require;if(!l&&o)return o(s,!0);if(n)return n(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var p=t[s]={exports:{}};e[s][0].call(p.exports,function(t){var r=e[s][1][t];return i(r?r:t)},p,p.exports,a,e,t,r)}return t[s].exports}var n=typeof require=="function"&&require;for(var s=0;s<r.length;s++)i(r[s]);return i}({1:[function(e,t,r){var a=e("./src/ParseError");var i=e("./src/Settings");var n=e("./src/buildTree");var s=e("./src/parseTree");var l=e("./src/utils");var o=function(e,t,r){l.clearNode(t);var a=new i(r);var o=s(e,a);var u=n(o,e,a).toNode();t.appendChild(u)};if(typeof document!=="undefined"){if(document.compatMode!=="CSS1Compat"){typeof console!=="undefined"&&console.warn("Warning: KaTeX doesn't work in quirks mode. Make sure your "+"website has a suitable doctype.");o=function(){throw new a("KaTeX doesn't work in quirks mode.")}}}var u=function(e,t){var r=new i(t);var a=s(e,r);return n(a,e,r).toMarkup()};var p=function(e,t){var r=new i(t);return s(e,r)};t.exports={render:o,renderToString:u,__parse:p,ParseError:a}},{"./src/ParseError":6,"./src/Settings":8,"./src/buildTree":13,"./src/parseTree":22,"./src/utils":25}],2:[function(e,t,r){"use strict";function a(e){if(!e.__matchAtRelocatable){var t=e.source+"|()";var r="g"+(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"");e.__matchAtRelocatable=new RegExp(t,r)}return e.__matchAtRelocatable}function i(e,t,r){if(e.global||e.sticky){throw new Error("matchAt(...): Only non-global regexes are supported")}var i=a(e);i.lastIndex=r;var n=i.exec(t);if(n[n.length-1]==null){n.length=n.length-1;return n}else{return null}}t.exports=i},{}],3:[function(e,t,r){var a=e("match-at");var i=e("./ParseError");function n(e){this.input=e;this.pos=0}function s(e,t,r,a){this.text=e;this.start=t;this.end=r;this.lexer=a}s.prototype.range=function(e,t){if(e.lexer!==this.lexer){return new s(t)}return new s(t,this.start,e.end,this.lexer)};var l=new RegExp("([ \r\n	]+)|"+"([!-\\[\\]-\u2027\u202a-\ud7ff\uf900-\uffff]"+"|[\ud800-\udbff][\udc00-\udfff]"+"|\\\\(?:[a-zA-Z]+|[^\ud800-\udfff])"+")");n.prototype.lex=function(){var e=this.input;var t=this.pos;if(t===e.length){return new s("EOF",t,t,this)}var r=a(l,e,t);if(r===null){throw new i("Unexpected character: '"+e[t]+"'",new s(e[t],t,t+1,this))}var n=r[2]||" ";var o=this.pos;this.pos+=r[0].length;var u=this.pos;return new s(n,o,u,this)};t.exports=n},{"./ParseError":6,"match-at":2}],4:[function(e,t,r){var a=e("./Lexer");function i(e,t){this.lexer=new a(e);this.macros=t;this.stack=[];this.discardedWhiteSpace=[]}i.prototype.nextToken=function(){for(;;){if(this.stack.length===0){this.stack.push(this.lexer.lex())}var e=this.stack.pop();var t=e.text;if(!(t.charAt(0)==="\\"&&this.macros.hasOwnProperty(t))){return e}var r=this.macros[t];if(typeof r==="string"){var i=new a(r);r=[];var n=i.lex();while(n.text!=="EOF"){r.push(n);n=i.lex()}r.reverse();this.macros[t]=r}this.stack=this.stack.concat(r)}};i.prototype.get=function(e){this.discardedWhiteSpace=[];var t=this.nextToken();if(e){while(t.text===" "){this.discardedWhiteSpace.push(t);t=this.nextToken()}}return t};i.prototype.unget=function(e){this.stack.push(e);while(this.discardedWhiteSpace.length!==0){this.stack.push(this.discardedWhiteSpace.pop())}};t.exports=i},{"./Lexer":3}],5:[function(e,t,r){function a(e){this.style=e.style;this.color=e.color;this.size=e.size;this.phantom=e.phantom;this.font=e.font;if(e.parentStyle===undefined){this.parentStyle=e.style}else{this.parentStyle=e.parentStyle}if(e.parentSize===undefined){this.parentSize=e.size}else{this.parentSize=e.parentSize}}a.prototype.extend=function(e){var t={style:this.style,size:this.size,color:this.color,parentStyle:this.style,parentSize:this.size,phantom:this.phantom,font:this.font};for(var r in e){if(e.hasOwnProperty(r)){t[r]=e[r]}}return new a(t)};a.prototype.withStyle=function(e){return this.extend({style:e})};a.prototype.withSize=function(e){return this.extend({size:e})};a.prototype.withColor=function(e){return this.extend({color:e})};a.prototype.withPhantom=function(){return this.extend({phantom:true})};a.prototype.withFont=function(e){return this.extend({font:e||this.font})};a.prototype.reset=function(){return this.extend({})};var i={"katex-blue":"#6495ed","katex-orange":"#ffa500","katex-pink":"#ff00af","katex-red":"#df0030","katex-green":"#28ae7b","katex-gray":"gray","katex-purple":"#9d38bd","katex-blueA":"#ccfaff","katex-blueB":"#80f6ff","katex-blueC":"#63d9ea","katex-blueD":"#11accd","katex-blueE":"#0c7f99","katex-tealA":"#94fff5","katex-tealB":"#26edd5","katex-tealC":"#01d1c1","katex-tealD":"#01a995","katex-tealE":"#208170","katex-greenA":"#b6ffb0","katex-greenB":"#8af281","katex-greenC":"#74cf70","katex-greenD":"#1fab54","katex-greenE":"#0d923f","katex-goldA":"#ffd0a9","katex-goldB":"#ffbb71","katex-goldC":"#ff9c39","katex-goldD":"#e07d10","katex-goldE":"#a75a05","katex-redA":"#fca9a9","katex-redB":"#ff8482","katex-redC":"#f9685d","katex-redD":"#e84d39","katex-redE":"#bc2612","katex-maroonA":"#ffbde0","katex-maroonB":"#ff92c6","katex-maroonC":"#ed5fa6","katex-maroonD":"#ca337c","katex-maroonE":"#9e034e","katex-purpleA":"#ddd7ff","katex-purpleB":"#c6b9fc","katex-purpleC":"#aa87ff","katex-purpleD":"#7854ab","katex-purpleE":"#543b78","katex-mintA":"#f5f9e8","katex-mintB":"#edf2df","katex-mintC":"#e0e5cc","katex-grayA":"#f6f7f7","katex-grayB":"#f0f1f2","katex-grayC":"#e3e5e6","katex-grayD":"#d6d8da","katex-grayE":"#babec2","katex-grayF":"#888d93","katex-grayG":"#626569","katex-grayH":"#3b3e40","katex-grayI":"#21242c","katex-kaBlue":"#314453","katex-kaGreen":"#71B307"};a.prototype.getColor=function(){if(this.phantom){return"transparent"}else{return i[this.color]||this.color}};t.exports=a},{}],6:[function(e,t,r){function a(e,t){var r="KaTeX parse error: "+e;var i;var n;if(t&&t.lexer&&t.start<=t.end){var s=t.lexer.input;i=t.start;n=t.end;if(i===s.length){r+=" at end of input: "}else{r+=" at position "+(i+1)+": "}var l=s.slice(i,n).replace(/[^]/g,"$&\u0332");var o;if(i>15){o="\u2026"+s.slice(i-15,i)}else{o=s.slice(0,i)}var u;if(n+15<s.length){u=s.slice(n,n+15)+"\u2026"}else{u=s.slice(n)}r+=o+l+u}var p=new Error(r);p.name="ParseError";p.__proto__=a.prototype;p.position=i;return p}a.prototype.__proto__=Error.prototype;t.exports=a},{}],7:[function(e,t,r){var a=e("./functions");var i=e("./environments");var n=e("./MacroExpander");var s=e("./symbols");var l=e("./utils");var o=e("./unicodeRegexes").cjkRegex;var u=e("./parseData");var p=e("./ParseError");function h(e,t){this.gullet=new n(e,t.macros);this.settings=t;this.leftrightDepth=0}var c=u.ParseNode;function m(e,t,r){this.result=e;this.isFunction=t;this.token=r}h.prototype.expect=function(e,t){if(this.nextToken.text!==e){throw new p("Expected '"+e+"', got '"+this.nextToken.text+"'",this.nextToken)}if(t!==false){this.consume()}};h.prototype.consume=function(){this.nextToken=this.gullet.get(this.mode==="math")};h.prototype.switchMode=function(e){this.gullet.unget(this.nextToken);this.mode=e;this.consume()};h.prototype.parse=function(){this.mode="math";this.consume();var e=this.parseInput();return e};h.prototype.parseInput=function(){var e=this.parseExpression(false);this.expect("EOF",false);return e};var f=["}","\\end","\\right","&","\\\\","\\cr"];h.prototype.parseExpression=function(e,t){var r=[];while(true){var i=this.nextToken;if(f.indexOf(i.text)!==-1){break}if(t&&i.text===t){break}if(e&&a[i.text]&&a[i.text].infix){break}var n=this.parseAtom();if(!n){if(!this.settings.throwOnError&&i.text[0]==="\\"){var s=this.handleUnsupportedCmd();r.push(s);continue}break}r.push(n)}return this.handleInfixNodes(r)};h.prototype.handleInfixNodes=function(e){var t=-1;var r;for(var a=0;a<e.length;a++){var i=e[a];if(i.type==="infix"){if(t!==-1){throw new p("only one infix operator per group",i.value.token)}t=a;r=i.value.replaceWith}}if(t!==-1){var n;var s;var l=e.slice(0,t);var o=e.slice(t+1);if(l.length===1&&l[0].type==="ordgroup"){n=l[0]}else{n=new c("ordgroup",l,this.mode)}if(o.length===1&&o[0].type==="ordgroup"){s=o[0]}else{s=new c("ordgroup",o,this.mode)}var u=this.callFunction(r,[n,s],null);return[new c(u.type,u,this.mode)]}else{return e}};var v=1;h.prototype.handleSupSubscript=function(e){var t=this.nextToken;var r=t.text;this.consume();var i=this.parseGroup();if(!i){if(!this.settings.throwOnError&&this.nextToken.text[0]==="\\"){return this.handleUnsupportedCmd()}else{throw new p("Expected group after '"+r+"'",t)}}else if(i.isFunction){var n=a[i.result].greediness;if(n>v){return this.parseFunction(i)}else{throw new p("Got function '"+i.result+"' with no arguments "+"as "+e,t)}}else{return i.result}};h.prototype.handleUnsupportedCmd=function(){var e=this.nextToken.text;var t=[];for(var r=0;r<e.length;r++){t.push(new c("textord",e[r],"text"))}var a=new c("text",{body:t,type:"text"},this.mode);var i=new c("color",{color:this.settings.errorColor,value:[a],type:"color"},this.mode);this.consume();return i};h.prototype.parseAtom=function(){var e=this.parseImplicitGroup();if(this.mode==="text"){return e}var t;var r;while(true){var a=this.nextToken;if(a.text==="\\limits"||a.text==="\\nolimits"){if(!e||e.type!=="op"){throw new p("Limit controls must follow a math operator",a)}else{var i=a.text==="\\limits";e.value.limits=i;e.value.alwaysHandleSupSub=true}this.consume()}else if(a.text==="^"){if(t){throw new p("Double superscript",a)}t=this.handleSupSubscript("superscript")}else if(a.text==="_"){if(r){throw new p("Double subscript",a)}r=this.handleSupSubscript("subscript")}else if(a.text==="'"){var n=new c("textord","\\prime",this.mode);var s=[n];this.consume();while(this.nextToken.text==="'"){s.push(n);this.consume()}t=new c("ordgroup",s,this.mode)}else{break}}if(t||r){return new c("supsub",{base:e,sup:t,sub:r},this.mode)}else{return e}};var d=["\\tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];var g=["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"];h.prototype.parseImplicitGroup=function(){var e=this.parseSymbol();if(e==null){return this.parseFunction()}var t=e.result;var r;if(t==="\\left"){var a=this.parseFunction(e);++this.leftrightDepth;r=this.parseExpression(false);--this.leftrightDepth;this.expect("\\right",false);var n=this.parseFunction();return new c("leftright",{body:r,left:a.value.value,right:n.value.value},this.mode)}else if(t==="\\begin"){var s=this.parseFunction(e);var o=s.value.name;if(!i.hasOwnProperty(o)){throw new p("No such environment: "+o,s.value.nameGroup)}var u=i[o];var h=this.parseArguments("\\begin{"+o+"}",u);var m={mode:this.mode,envName:o,parser:this,positions:h.pop()};var f=u.handler(m,h);this.expect("\\end",false);var v=this.nextToken;var y=this.parseFunction();if(y.value.name!==o){throw new p("Mismatch: \\begin{"+o+"} matched "+"by \\end{"+y.value.name+"}",v)}f.position=y.position;return f}else if(l.contains(d,t)){r=this.parseExpression(false);return new c("sizing",{size:"size"+(l.indexOf(d,t)+1),value:r},this.mode)}else if(l.contains(g,t)){r=this.parseExpression(true);return new c("styling",{style:t.slice(1,t.length-5),value:r},this.mode)}else{return this.parseFunction(e)}};h.prototype.parseFunction=function(e){if(!e){e=this.parseGroup()}if(e){if(e.isFunction){var t=e.result;var r=a[t];if(this.mode==="text"&&!r.allowedInText){throw new p("Can't use function '"+t+"' in text mode",e.token)}var i=this.parseArguments(t,r);var n=e.token;var s=this.callFunction(t,i,i.pop(),n);return new c(s.type,s,this.mode)}else{return e.result}}else{return null}};h.prototype.callFunction=function(e,t,r,i){var n={funcName:e,parser:this,positions:r,token:i};return a[e].handler(n,t)};h.prototype.parseArguments=function(e,t){var r=t.numArgs+t.numOptionalArgs;if(r===0){return[[this.pos]]}var i=t.greediness;var n=[this.pos];var s=[];for(var l=0;l<r;l++){var o=this.nextToken;var u=t.argTypes&&t.argTypes[l];var h;if(l<t.numOptionalArgs){if(u){h=this.parseGroupOfType(u,true)}else{h=this.parseGroup(true)}if(!h){s.push(null);n.push(this.pos);continue}}else{if(u){h=this.parseGroupOfType(u)}else{h=this.parseGroup()}if(!h){if(!this.settings.throwOnError&&this.nextToken.text[0]==="\\"){h=new m(this.handleUnsupportedCmd(this.nextToken.text),false)}else{throw new p("Expected group after '"+e+"'",o)}}}var c;if(h.isFunction){var f=a[h.result].greediness;if(f>i){c=this.parseFunction(h)}else{throw new p("Got function '"+h.result+"' as "+"argument to '"+e+"'",o)}}else{c=h.result}s.push(c);n.push(this.pos)}s.push(n);return s};h.prototype.parseGroupOfType=function(e,t){var r=this.mode;if(e==="original"){e=r}if(e==="color"){return this.parseColorGroup(t)}if(e==="size"){return this.parseSizeGroup(t)}this.switchMode(e);if(e==="text"){while(this.nextToken.text===" "){this.consume()}}var a=this.parseGroup(t);this.switchMode(r);return a};h.prototype.parseStringGroup=function(e,t){if(t&&this.nextToken.text!=="["){return null}var r=this.mode;this.mode="text";this.expect(t?"[":"{");var a="";var i=this.nextToken;var n=i;while(this.nextToken.text!==(t?"]":"}")){if(this.nextToken.text==="EOF"){throw new p("Unexpected end of input in "+e,i.range(this.nextToken,a))}n=this.nextToken;a+=n.text;this.consume()}this.mode=r;this.expect(t?"]":"}");return i.range(n,a)};h.prototype.parseRegexGroup=function(e,t){var r=this.mode;this.mode="text";var a=this.nextToken;var i=a;var n="";while(this.nextToken.text!=="EOF"&&e.test(n+this.nextToken.text)){i=this.nextToken;n+=i.text;this.consume()}if(n===""){throw new p("Invalid "+t+": '"+a.text+"'",a)}this.mode=r;return a.range(i,n)};h.prototype.parseColorGroup=function(e){var t=this.parseStringGroup("color",e);if(!t){return null}var r=/^(#[a-z0-9]+|[a-z]+)$/i.exec(t.text);if(!r){throw new p("Invalid color: '"+t.text+"'",t)}return new m(new c("color",r[0],this.mode),false)};h.prototype.parseSizeGroup=function(e){var t;if(!e&&this.nextToken.text!=="{"){t=this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/,"size")}else{t=this.parseStringGroup("size",e)}if(!t){return null}var r=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(t.text);if(!r){throw new p("Invalid size: '"+t.text+"'",t)}var a={number:+(r[1]+r[2]),unit:r[3]};if(a.unit!=="em"&&a.unit!=="ex"&&a.unit!=="mu"){throw new p("Invalid unit: '"+a.unit+"'",t)}return new m(new c("color",a,this.mode),false)};h.prototype.parseGroup=function(e){var t=this.nextToken;if(this.nextToken.text===(e?"[":"{")){this.consume();var r=this.parseExpression(false,e?"]":null);var a=this.nextToken;this.expect(e?"]":"}");if(this.mode==="text"){this.formLigatures(r)}return new m(new c("ordgroup",r,this.mode,t,a),false)}else{return e?null:this.parseSymbol()}};h.prototype.formLigatures=function(e){var t;var r=e.length-1;for(t=0;t<r;++t){var a=e[t];var i=a.value;if(i==="-"&&e[t+1].value==="-"){if(t+1<r&&e[t+2].value==="-"){e.splice(t,3,new c("textord","---","text",a,e[t+2]));r-=2}else{e.splice(t,2,new c("textord","--","text",a,e[t+1]));r-=1}}if((i==="'"||i==="`")&&e[t+1].value===i){e.splice(t,2,new c("textord",i+i,"text",a,e[t+1]));r-=1}}};h.prototype.parseSymbol=function(){var e=this.nextToken;if(a[e.text]){this.consume();return new m(e.text,true,e)}else if(s[this.mode][e.text]){this.consume();return new m(new c(s[this.mode][e.text].group,e.text,this.mode,e),false,e)}else if(this.mode==="text"&&o.test(e.text)){this.consume();return new m(new c("textord",e.text,this.mode,e),false,e)}else{return null}};h.prototype.ParseNode=c;t.exports=h},{"./MacroExpander":4,"./ParseError":6,"./environments":16,"./functions":19,"./parseData":21,"./symbols":23,"./unicodeRegexes":24,"./utils":25}],8:[function(e,t,r){function a(e,t){return e===undefined?t:e}function i(e){e=e||{};this.displayMode=a(e.displayMode,false);this.throwOnError=a(e.throwOnError,true);this.errorColor=a(e.errorColor,"#cc0000");this.macros=e.macros||{}}t.exports=i},{}],9:[function(e,t,r){var a=e("./fontMetrics.js").sigmas;var i=[{},{},{}];var n;for(var s in a){if(a.hasOwnProperty(s)){for(n=0;n<3;n++){i[n][s]=a[s][n]}}}for(n=0;n<3;n++){i[n].emPerEx=a.xHeight[n]/a.quad[n]}function l(e,t,r,a){this.id=e;this.size=t;this.cramped=a;this.sizeMultiplier=r;this.metrics=i[t>0?t-1:0]}l.prototype.sup=function(){return y[x[this.id]]};l.prototype.sub=function(){return y[b[this.id]]};l.prototype.fracNum=function(){return y[w[this.id]]};l.prototype.fracDen=function(){return y[k[this.id]]};l.prototype.cramp=function(){return y[z[this.id]]};l.prototype.cls=function(){return d[this.size]+(this.cramped?" cramped":" uncramped")};l.prototype.reset=function(){return g[this.size]};l.prototype.isTight=function(){return this.size>=2};var o=0;var u=1;var p=2;var h=3;var c=4;var m=5;var f=6;var v=7;var d=["displaystyle textstyle","textstyle","scriptstyle","scriptscriptstyle"];var g=["reset-textstyle","reset-textstyle","reset-scriptstyle","reset-scriptscriptstyle"];var y=[new l(o,0,1,false),new l(u,0,1,true),new l(p,1,1,false),new l(h,1,1,true),new l(c,2,.7,false),new l(m,2,.7,true),new l(f,3,.5,false),new l(v,3,.5,true)];var x=[c,m,c,m,f,v,f,v];var b=[m,m,m,m,v,v,v,v];var w=[p,h,c,m,f,v,f,v];var k=[h,h,m,m,v,v,v,v];var z=[u,u,h,h,m,m,v,v];t.exports={DISPLAY:y[o],TEXT:y[p],SCRIPT:y[c],SCRIPTSCRIPT:y[f]}},{"./fontMetrics.js":17}],10:[function(e,t,r){var a=e("./domTree");var i=e("./fontMetrics");var n=e("./symbols");var s=e("./utils");var l=["\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma","\\Upsilon","\\Phi","\\Psi","\\Omega"];var o=["\u0131","\u0237","\xa3"];var u=function(e,t,r,s,l){if(n[r][e]&&n[r][e].replace){e=n[r][e].replace}var o=i.getCharacterMetrics(e,t);var u;if(o){var p=o.italic;if(r==="text"){p=0}u=new a.symbolNode(e,o.height,o.depth,p,o.skew,l)}else{typeof console!=="undefined"&&console.warn("No character metrics for '"+e+"' in style '"+t+"'");u=new a.symbolNode(e,0,0,0,0,l)}if(s){if(s.style.isTight()){u.classes.push("mtight")}if(s.getColor()){u.style.color=s.getColor()}}return u};var p=function(e,t,r,a){if(e==="\\"||n[t][e].font==="main"){return u(e,"Main-Regular",t,r,a)}else{return u(e,"AMS-Regular",t,r,a.concat(["amsrm"]))}};var h=function(e,t,r,a,i){if(i==="mathord"){return c(e,t,r,a)}else if(i==="textord"){return u(e,"Main-Regular",t,r,a.concat(["mathrm"]))}else{throw new Error("unexpected type: "+i+" in mathDefault")}};var c=function(e,t,r,a){if(/[0-9]/.test(e.charAt(0))||s.contains(o,e)||s.contains(l,e)){return u(e,"Main-Italic",t,r,a.concat(["mainit"]))}else{return u(e,"Math-Italic",t,r,a.concat(["mathit"]))}};var m=function(e,t,r){var a=e.mode;var l=e.value;if(n[a][l]&&n[a][l].replace){l=n[a][l].replace}var p=["mord"];var m=t.font;if(m){if(m==="mathit"||s.contains(o,l)){return c(l,a,t,p)}else{var f=k[m].fontName;if(i.getCharacterMetrics(l,f)){return u(l,f,a,t,p.concat([m]))}else{return h(l,a,t,p,r)}}}else{return h(l,a,t,p,r)}};var f=function(e){var t=0;var r=0;var a=0;if(e.children){for(var i=0;i<e.children.length;i++){if(e.children[i].height>t){t=e.children[i].height}if(e.children[i].depth>r){r=e.children[i].depth}if(e.children[i].maxFontSize>a){a=e.children[i].maxFontSize}}}e.height=t;e.depth=r;e.maxFontSize=a};var v=function(e,t,r){var i=new a.span(e,t,r);f(i);return i};var d=function(e,t){e.children=t.concat(e.children);f(e)};var g=function(e){var t=new a.documentFragment(e);f(t);return t};var y=function(e,t){var r=v([],[new a.symbolNode("\u200b")]);r.style.fontSize=t/e.style.sizeMultiplier+"em";var i=v(["fontsize-ensurer","reset-"+e.size,"size5"],[r]);return i};var x=function(e,t,r,i){var n;var s;var l;if(t==="individualShift"){var o=e;e=[o[0]];n=-o[0].shift-o[0].elem.depth;s=n;for(l=1;l<o.length;l++){var u=-o[l].shift-s-o[l].elem.depth;var p=u-(o[l-1].elem.height+o[l-1].elem.depth);s=s+u;e.push({type:"kern",size:p});e.push(o[l])}}else if(t==="top"){var h=r;for(l=0;l<e.length;l++){if(e[l].type==="kern"){h-=e[l].size}else{h-=e[l].elem.height+e[l].elem.depth}}n=h}else if(t==="bottom"){n=-r}else if(t==="shift"){n=-e[0].elem.depth-r}else if(t==="firstBaseline"){n=-e[0].elem.depth}else{n=0}var c=0;for(l=0;l<e.length;l++){if(e[l].type==="elem"){c=Math.max(c,e[l].elem.maxFontSize)}}var m=y(i,c);var f=[];s=n;for(l=0;l<e.length;l++){if(e[l].type==="kern"){s+=e[l].size}else{var d=e[l].elem;var g=-d.depth-s;s+=d.height+d.depth;var x=v([],[m,d]);x.height-=g;x.depth+=g;x.style.top=g+"em";f.push(x)}}var b=v(["baseline-fix"],[m,new a.symbolNode("\u200b")]);f.push(b);var w=v(["vlist"],f);w.height=Math.max(s,w.height);w.depth=Math.max(-n,w.depth);return w};var b={size1:.5,size2:.7,size3:.8,size4:.9,size5:1,size6:1.2,size7:1.44,size8:1.73,size9:2.07,size10:2.49};var w={"\\qquad":{size:"2em",className:"qquad"},"\\quad":{size:"1em",className:"quad"},"\\enspace":{size:"0.5em",className:"enspace"},"\\;":{size:"0.277778em",className:"thickspace"},"\\:":{size:"0.22222em",className:"mediumspace"},"\\,":{size:"0.16667em",className:"thinspace"},"\\!":{size:"-0.16667em",className:"negativethinspace"}};var k={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}};t.exports={fontMap:k,makeSymbol:u,mathsym:p,makeSpan:v,makeFragment:g,makeVList:x,makeOrd:m,prependChildren:d,sizingMultiplier:b,spacingFunctions:w}},{"./domTree":15,"./fontMetrics":17,"./symbols":23,"./utils":25}],11:[function(e,t,r){var a=e("./ParseError");var i=e("./Style");var n=e("./buildCommon");var s=e("./delimiter");var l=e("./domTree");var o=e("./fontMetrics");var u=e("./utils");var p=n.makeSpan;var h=function(e){return e instanceof l.span&&e.classes[0]==="mspace"};var c=function(e){return e&&e.classes[0]==="mbin"};var m=function(e,t){if(e){return u.contains(["mbin","mopen","mrel","mop","mpunct"],e.classes[0])}else{return t}};var f=function(e,t){if(e){return u.contains(["mrel","mclose","mpunct"],e.classes[0])}else{return t}};var v=function(e,t,r){var a=[];for(var i=0;i<e.length;i++){var s=e[i];var o=z(s,t);if(o instanceof l.documentFragment){Array.prototype.push.apply(a,o.children)}else{a.push(o)}}var u=null;for(i=0;i<a.length;i++){if(h(a[i])){u=u||[];u.push(a[i]);a.splice(i,1);i--}else if(u){if(a[i]instanceof l.symbolNode){a[i]=p([].concat(a[i].classes),[a[i]])}n.prependChildren(a[i],u);u=null}}if(u){Array.prototype.push.apply(a,u)}for(i=0;i<a.length;i++){if(c(a[i])&&(m(a[i-1],r)||f(a[i+1],r))){a[i].classes[0]="mord"}}return a};var d=function(e){if(e instanceof l.documentFragment){if(e.children.length){return d(e.children[e.children.length-1])}}else{if(u.contains(["mord","mop","mbin","mrel","mopen","mclose","mpunct","minner"],e.classes[0])){return e.classes[0]}}return null};var g=function(e,t){if(!e){return false}else if(e.type==="op"){return e.value.limits&&(t.style.size===i.DISPLAY.size||e.value.alwaysHandleSupSub)}else if(e.type==="accent"){return x(e.value.base)}else{return null}};var y=function(e){if(!e){return false}else if(e.type==="ordgroup"){if(e.value.length===1){return y(e.value[0])}else{return e}}else if(e.type==="color"){if(e.value.value.length===1){return y(e.value.value[0])}else{return e}}else if(e.type==="font"){return y(e.value.body)}else{return e}};var x=function(e){var t=y(e);return t.type==="mathord"||t.type==="textord"||t.type==="bin"||t.type==="rel"||t.type==="inner"||t.type==="open"||t.type==="close"||t.type==="punct"};var b=function(e,t){return p(t.concat(["sizing","reset-"+e.size,"size5",e.style.reset(),i.TEXT.cls(),"nulldelimiter"]))};var w={};w.mathord=function(e,t){return n.makeOrd(e,t,"mathord")};w.textord=function(e,t){return n.makeOrd(e,t,"textord")};w.bin=function(e,t){return n.mathsym(e.value,e.mode,t,["mbin"])};w.rel=function(e,t){return n.mathsym(e.value,e.mode,t,["mrel"])};w.open=function(e,t){return n.mathsym(e.value,e.mode,t,["mopen"])};w.close=function(e,t){return n.mathsym(e.value,e.mode,t,["mclose"])};w.inner=function(e,t){return n.mathsym(e.value,e.mode,t,["minner"])};w.punct=function(e,t){return n.mathsym(e.value,e.mode,t,["mpunct"])};w.ordgroup=function(e,t){return p(["mord",t.style.cls()],v(e.value,t.reset(),true),t)};w.text=function(e,t){var r=t.withFont(e.value.style);var a=v(e.value.body,r,true);for(var i=0;i<a.length-1;i++){if(a[i].tryCombine(a[i+1])){a.splice(i+1,1);i--}}return p(["mord","text",r.style.cls()],a,r)};w.color=function(e,t){var r=v(e.value.value,t.withColor(e.value.color),false);return new n.makeFragment(r)};w.supsub=function(e,t){if(g(e.value.base,t)){return w[e.value.base.type](e,t)}var r=z(e.value.base,t.reset());var a;var s;var u;var h;var c=t.style;var m;if(e.value.sup){m=t.withStyle(c.sup());u=z(e.value.sup,m);a=p([c.reset(),c.sup().cls()],[u],m)}if(e.value.sub){m=t.withStyle(c.sub());h=z(e.value.sub,m);s=p([c.reset(),c.sub().cls()],[h],m)}var f;var v;if(x(e.value.base)){f=0;v=0}else{f=r.height-c.metrics.supDrop;v=r.depth+c.metrics.subDrop}var y;if(c===i.DISPLAY){y=c.metrics.sup1}else if(c.cramped){y=c.metrics.sup3}else{y=c.metrics.sup2}var b=i.TEXT.sizeMultiplier*c.sizeMultiplier;var k=.5/o.metrics.ptPerEm/b+"em";var S;if(!e.value.sup){v=Math.max(v,c.metrics.sub1,h.height-.8*c.metrics.xHeight);S=n.makeVList([{type:"elem",elem:s}],"shift",v,t);S.children[0].style.marginRight=k;if(r instanceof l.symbolNode){S.children[0].style.marginLeft=-r.italic+"em"}}else if(!e.value.sub){f=Math.max(f,y,u.depth+.25*c.metrics.xHeight);S=n.makeVList([{type:"elem",elem:a}],"shift",-f,t);S.children[0].style.marginRight=k}else{f=Math.max(f,y,u.depth+.25*c.metrics.xHeight);v=Math.max(v,c.metrics.sub2);var M=o.metrics.defaultRuleThickness;if(f-u.depth-(h.height-v)<4*M){v=4*M-(f-u.depth)+h.height;var T=.8*c.metrics.xHeight-(f-u.depth);if(T>0){f+=T;v-=T}}S=n.makeVList([{type:"elem",elem:s,shift:v},{type:"elem",elem:a,shift:-f}],"individualShift",null,t);if(r instanceof l.symbolNode){S.children[0].style.marginLeft=-r.italic+"em"}S.children[0].style.marginRight=k;S.children[1].style.marginRight=k}var A=d(r)||"mord";return p([A],[r,p(["msupsub"],[S])],t)};w.genfrac=function(e,t){var r=t.style;if(e.value.size==="display"){r=i.DISPLAY}else if(e.value.size==="text"){r=i.TEXT}var a=r.fracNum();var l=r.fracDen();var u;u=t.withStyle(a);var h=z(e.value.numer,u);var c=p([r.reset(),a.cls()],[h],u);u=t.withStyle(l);var m=z(e.value.denom,u);var f=p([r.reset(),l.cls()],[m],u);var v;if(e.value.hasBarLine){v=o.metrics.defaultRuleThickness/t.style.sizeMultiplier}else{v=0}var d;var g;var y;if(r.size===i.DISPLAY.size){d=r.metrics.num1;if(v>0){g=3*v}else{g=7*o.metrics.defaultRuleThickness}y=r.metrics.denom1}else{if(v>0){d=r.metrics.num2;g=v}else{d=r.metrics.num3;g=3*o.metrics.defaultRuleThickness}y=r.metrics.denom2}var x;if(v===0){var w=d-h.depth-(m.height-y);if(w<g){d+=.5*(g-w);y+=.5*(g-w)}x=n.makeVList([{type:"elem",elem:f,shift:y},{type:"elem",elem:c,shift:-d}],"individualShift",null,t)}else{var k=r.metrics.axisHeight;if(d-h.depth-(k+.5*v)<g){d+=g-(d-h.depth-(k+.5*v))}if(k-.5*v-(m.height-y)<g){y+=g-(k-.5*v-(m.height-y))}var S=p([t.style.reset(),i.TEXT.cls(),"frac-line"]);S.height=v;var M=-(k-.5*v);x=n.makeVList([{type:"elem",elem:f,shift:y},{type:"elem",elem:S,shift:M},{type:"elem",elem:c,shift:-d}],"individualShift",null,t)}x.height*=r.sizeMultiplier/t.style.sizeMultiplier;x.depth*=r.sizeMultiplier/t.style.sizeMultiplier;var T;if(r.size===i.DISPLAY.size){T=r.metrics.delim1}else{T=r.metrics.delim2}var A;var N;if(e.value.leftDelim==null){A=b(t,["mopen"])}else{A=s.customSizedDelim(e.value.leftDelim,T,true,t.withStyle(r),e.mode,["mopen"])}if(e.value.rightDelim==null){N=b(t,["mclose"])}else{N=s.customSizedDelim(e.value.rightDelim,T,true,t.withStyle(r),e.mode,["mclose"])}return p(["mord",t.style.reset(),r.cls()],[A,p(["mfrac"],[x]),N],t)};var k=function(e,t){var r=e.number;if(e.unit==="ex"){r*=t.metrics.emPerEx}else if(e.unit==="mu"){r/=18}return r};w.array=function(e,t){var r;var i;var s=e.value.body.length;var l=0;var h=new Array(s);var c=t.style;var m=1/o.metrics.ptPerEm;var f=5*m;var v=12*m;var d=u.deflt(e.value.arraystretch,1);var g=d*v;var y=.7*g;var x=.3*g;var b=0;for(r=0;r<e.value.body.length;++r){var w=e.value.body[r];var S=y;var M=x;if(l<w.length){l=w.length}var T=new Array(w.length);for(i=0;i<w.length;++i){var A=z(w[i],t);if(M<A.depth){M=A.depth}if(S<A.height){S=A.height}T[i]=A}var N=0;if(e.value.rowGaps[r]){N=k(e.value.rowGaps[r].value,c);if(N>0){N+=x;if(M<N){M=N}N=0}}T.height=S;T.depth=M;b+=S;T.pos=b;b+=M+N;h[r]=T}var q=b/2+c.metrics.axisHeight;var R=e.value.cols||[];var E=[];var C;var D;for(i=0,D=0;i<l||D<R.length;++i,++D){var O=R[D]||{};var P=true;while(O.type==="separator"){if(!P){C=p(["arraycolsep"],[]);C.style.width=o.metrics.doubleRuleSep+"em";E.push(C)}if(O.separator==="|"){var F=p(["vertical-separator"],[]);F.style.height=b+"em";F.style.verticalAlign=-(b-q)+"em";E.push(F)}else{throw new a("Invalid separator type: "+O.separator)}D++;O=R[D]||{};P=false}if(i>=l){continue}var I;if(i>0||e.value.hskipBeforeAndAfter){I=u.deflt(O.pregap,f);if(I!==0){C=p(["arraycolsep"],[]);C.style.width=I+"em";E.push(C)}}var L=[];for(r=0;r<s;++r){var B=h[r];var G=B[i];if(!G){continue}var V=B.pos-q;G.depth=B.depth;G.height=B.height;L.push({type:"elem",elem:G,shift:V})}L=n.makeVList(L,"individualShift",null,t);L=p(["col-align-"+(O.align||"c")],[L]);E.push(L);if(i<l-1||e.value.hskipBeforeAndAfter){I=u.deflt(O.postgap,f);if(I!==0){C=p(["arraycolsep"],[]);C.style.width=I+"em";E.push(C)}}}h=p(["mtable"],E);return p(["mord"],[h],t)};w.spacing=function(e,t){if(e.value==="\\ "||e.value==="\\space"||e.value===" "||e.value==="~"){if(e.mode==="text"){return n.makeOrd(e,t,"textord")}else{return p(["mspace"],[n.mathsym(e.value,e.mode,t)],t)}}else{return p(["mspace",n.spacingFunctions[e.value].className],[],t)}};w.llap=function(e,t){var r=p(["inner"],[z(e.value.body,t.reset())]);var a=p(["fix"],[]);return p(["mord","llap",t.style.cls()],[r,a],t)};w.rlap=function(e,t){var r=p(["inner"],[z(e.value.body,t.reset())]);var a=p(["fix"],[]);return p(["mord","rlap",t.style.cls()],[r,a],t)};w.op=function(e,t){var r;var a;var s=false;if(e.type==="supsub"){r=e.value.sup;a=e.value.sub;e=e.value.base;s=true}var l=t.style;var h=["\\smallint"];var c=false;if(l.size===i.DISPLAY.size&&e.value.symbol&&!u.contains(h,e.value.body)){c=true}var m;var f=0;var d=0;if(e.value.symbol){var g=c?"Size2-Regular":"Size1-Regular";m=n.makeSymbol(e.value.body,g,"math",t,["mop","op-symbol",c?"large-op":"small-op"]);f=(m.height-m.depth)/2-l.metrics.axisHeight*l.sizeMultiplier;d=m.italic}else if(e.value.value){var y=v(e.value.value,t,true);m=p(["mop"],y,t)}else{var x=[];for(var b=1;b<e.value.body.length;b++){x.push(n.mathsym(e.value.body[b],e.mode))}m=p(["mop"],x,t)}if(s){m=p([],[m]);var w;var k;var S;var M;var T;if(r){T=t.withStyle(l.sup());var A=z(r,T);w=p([l.reset(),l.sup().cls()],[A],T);k=Math.max(o.metrics.bigOpSpacing1,o.metrics.bigOpSpacing3-A.depth)}if(a){T=t.withStyle(l.sub());var N=z(a,T);S=p([l.reset(),l.sub().cls()],[N],T);M=Math.max(o.metrics.bigOpSpacing2,o.metrics.bigOpSpacing4-N.height)}var q;var R;var E;if(!r){R=m.height-f;q=n.makeVList([{type:"kern",size:o.metrics.bigOpSpacing5},{type:"elem",elem:S},{type:"kern",size:M},{type:"elem",elem:m}],"top",R,t);q.children[0].style.marginLeft=-d+"em"}else if(!a){E=m.depth+f;q=n.makeVList([{type:"elem",elem:m},{type:"kern",size:k},{type:"elem",elem:w},{type:"kern",size:o.metrics.bigOpSpacing5}],"bottom",E,t);q.children[1].style.marginLeft=d+"em"}else if(!r&&!a){return m}else{E=o.metrics.bigOpSpacing5+S.height+S.depth+M+m.depth+f;
+q=n.makeVList([{type:"kern",size:o.metrics.bigOpSpacing5},{type:"elem",elem:S},{type:"kern",size:M},{type:"elem",elem:m},{type:"kern",size:k},{type:"elem",elem:w},{type:"kern",size:o.metrics.bigOpSpacing5}],"bottom",E,t);q.children[0].style.marginLeft=-d+"em";q.children[2].style.marginLeft=d+"em"}return p(["mop","op-limits"],[q],t)}else{if(e.value.symbol){m.style.top=f+"em"}return m}};w.mod=function(e,t){var r=[];if(e.value.modType==="bmod"){if(!t.style.isTight()){r.push(p(["mspace","negativemediumspace"],[],t))}r.push(p(["mspace","thickspace"],[],t))}else if(t.style.size===i.DISPLAY.size){r.push(p(["mspace","quad"],[],t))}else if(e.value.modType==="mod"){r.push(p(["mspace","twelvemuspace"],[],t))}else{r.push(p(["mspace","eightmuspace"],[],t))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(n.mathsym("(",e.mode))}if(e.value.modType!=="pod"){var a=[n.mathsym("m",e.mode),n.mathsym("o",e.mode),n.mathsym("d",e.mode)];if(e.value.modType==="bmod"){r.push(p(["mbin"],a,t));r.push(p(["mspace","thickspace"],[],t));if(!t.style.isTight()){r.push(p(["mspace","negativemediumspace"],[],t))}}else{Array.prototype.push.apply(r,a);r.push(p(["mspace","sixmuspace"],[],t))}}if(e.value.value){Array.prototype.push.apply(r,v(e.value.value,t,false))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(n.mathsym(")",e.mode))}return n.makeFragment(r)};w.katex=function(e,t){var r=p(["k"],[n.mathsym("K",e.mode)],t);var a=p(["a"],[n.mathsym("A",e.mode)],t);a.height=(a.height+.2)*.75;a.depth=(a.height-.2)*.75;var i=p(["t"],[n.mathsym("T",e.mode)],t);var s=p(["e"],[n.mathsym("E",e.mode)],t);s.height=s.height-.2155;s.depth=s.depth+.2155;var l=p(["x"],[n.mathsym("X",e.mode)],t);return p(["mord","katex-logo"],[r,a,i,s,l],t)};w.overline=function(e,t){var r=t.style;var a=z(e.value.body,t.withStyle(r.cramp()));var s=o.metrics.defaultRuleThickness/r.sizeMultiplier;var l=p([r.reset(),i.TEXT.cls(),"overline-line"]);l.height=s;l.maxFontSize=1;var u=n.makeVList([{type:"elem",elem:a},{type:"kern",size:3*s},{type:"elem",elem:l},{type:"kern",size:s}],"firstBaseline",null,t);return p(["mord","overline"],[u],t)};w.underline=function(e,t){var r=t.style;var a=z(e.value.body,t);var s=o.metrics.defaultRuleThickness/r.sizeMultiplier;var l=p([r.reset(),i.TEXT.cls(),"underline-line"]);l.height=s;l.maxFontSize=1;var u=n.makeVList([{type:"kern",size:s},{type:"elem",elem:l},{type:"kern",size:3*s},{type:"elem",elem:a}],"top",a.height,t);return p(["mord","underline"],[u],t)};w.sqrt=function(e,t){var r=t.style;var a=z(e.value.body,t.withStyle(r.cramp()));var l=o.metrics.defaultRuleThickness/r.sizeMultiplier;var u=p([r.reset(),i.TEXT.cls(),"sqrt-line"],[],t);u.height=l;u.maxFontSize=1;var h=l;if(r.id<i.TEXT.id){h=r.metrics.xHeight}var c=l+h/4;var m=(a.height+a.depth)*r.sizeMultiplier;var f=m+c+l;var v=p(["sqrt-sign"],[s.customSizedDelim("\\surd",f,false,t,e.mode)],t);var d=v.height+v.depth-l;if(d>a.height+a.depth+c){c=(c+d-a.height-a.depth)/2}var g=-(a.height+c+l)+v.height;v.style.top=g+"em";v.height-=g;v.depth+=g;var y;if(a.height===0&&a.depth===0){y=p()}else{y=n.makeVList([{type:"elem",elem:a},{type:"kern",size:c},{type:"elem",elem:u},{type:"kern",size:l}],"firstBaseline",null,t)}if(!e.value.index){return p(["mord","sqrt"],[v,y],t)}else{var x=t.withStyle(i.SCRIPTSCRIPT);var b=z(e.value.index,x);var w=p([r.reset(),i.SCRIPTSCRIPT.cls()],[b],x);var k=Math.max(v.height,y.height);var S=Math.max(v.depth,y.depth);var M=.6*(k-S);var T=n.makeVList([{type:"elem",elem:w}],"shift",-M,t);var A=p(["root"],[T]);return p(["mord","sqrt"],[A,v,y],t)}};w.sizing=function(e,t){var r=v(e.value.value,t.withSize(e.value.size),false);var a=t.style;var i=n.sizingMultiplier[e.value.size];i=i*a.sizeMultiplier;for(var s=0;s<r.length;s++){var l=u.indexOf(r[s].classes,"sizing");if(l<0){r[s].classes.push("sizing","reset-"+t.size,e.value.size,a.cls());r[s].maxFontSize=i}else if(r[s].classes[l+1]==="reset-"+e.value.size){r[s].classes[l+1]="reset-"+t.size}}return n.makeFragment(r)};w.styling=function(e,t){var r={display:i.DISPLAY,text:i.TEXT,script:i.SCRIPT,scriptscript:i.SCRIPTSCRIPT};var a=r[e.value.style];var s=t.withStyle(a);var l=v(e.value.value,s,false);for(var o=0;o<l.length;o++){var p=u.indexOf(l[o].classes,a.reset());if(p<0){l[o].classes.push(t.style.reset(),a.cls())}else{l[o].classes[p]=t.style.reset()}}return new n.makeFragment(l)};w.font=function(e,t){var r=e.value.font;return z(e.value.body,t.withFont(r))};w.delimsizing=function(e,t){var r=e.value.value;if(r==="."){return p([e.value.mclass])}return s.sizedDelim(r,e.value.size,t,e.mode,[e.value.mclass])};w.leftright=function(e,t){var r=v(e.value.body,t.reset(),true);var a=0;var i=0;var n=false;for(var l=0;l<r.length;l++){if(r[l].isMiddle){n=true}else{a=Math.max(r[l].height,a);i=Math.max(r[l].depth,i)}}var o=t.style;a*=o.sizeMultiplier;i*=o.sizeMultiplier;var u;if(e.value.left==="."){u=b(t,["mopen"])}else{u=s.leftRightDelim(e.value.left,a,i,t,e.mode,["mopen"])}r.unshift(u);if(n){for(l=1;l<r.length;l++){if(r[l].isMiddle){r[l]=s.leftRightDelim(r[l].isMiddle.value,a,i,r[l].isMiddle.options,e.mode,[])}}}var h;if(e.value.right==="."){h=b(t,["mclose"])}else{h=s.leftRightDelim(e.value.right,a,i,t,e.mode,["mclose"])}r.push(h);return p(["minner",o.cls()],r,t)};w.middle=function(e,t){var r;if(e.value.value==="."){r=b(t,[])}else{r=s.sizedDelim(e.value.value,1,t,e.mode,[]);r.isMiddle={value:e.value.value,options:t}}return r};w.rule=function(e,t){var r=p(["mord","rule"],[],t);var a=t.style;var i=0;if(e.value.shift){i=k(e.value.shift,a)}var n=k(e.value.width,a);var s=k(e.value.height,a);i/=a.sizeMultiplier;n/=a.sizeMultiplier;s/=a.sizeMultiplier;r.style.borderRightWidth=n+"em";r.style.borderTopWidth=s+"em";r.style.bottom=i+"em";r.width=n;r.height=s+i;r.depth=-i;return r};w.kern=function(e,t){var r=p(["mord","rule"],[],t);var a=t.style;var i=0;if(e.value.dimension){i=k(e.value.dimension,a)}i/=a.sizeMultiplier;r.style.marginLeft=i+"em";return r};w.accent=function(e,t){var r=e.value.base;var a=t.style;var i;if(e.type==="supsub"){var s=e;e=s.value.base;r=e.value.base;s.value.base=r;i=z(s,t.reset())}var l=z(r,t.withStyle(a.cramp()));var o;if(x(r)){var u=y(r);var h=z(u,t.withStyle(a.cramp()));o=h.skew}else{o=0}var c=Math.min(l.height,a.metrics.xHeight);var m=n.makeSymbol(e.value.accent,"Main-Regular","math",t);m.italic=0;var f=e.value.accent==="\\vec"?"accent-vec":null;var v=p(["accent-body",f],[p([],[m])]);v=n.makeVList([{type:"elem",elem:l},{type:"kern",size:-c},{type:"elem",elem:v}],"firstBaseline",null,t);v.children[1].style.marginLeft=2*o+"em";var d=p(["mord","accent"],[v],t);if(i){i.children[0]=d;i.height=Math.max(d.height,i.height);i.classes[0]="mord";return i}else{return d}};w.phantom=function(e,t){var r=v(e.value.value,t.withPhantom(),false);return new n.makeFragment(r)};w.mclass=function(e,t){var r=v(e.value.value,t,true);return p([e.value.mclass],r,t)};var z=function(e,t){if(!e){return p()}if(w[e.type]){var r=w[e.type](e,t);var i;if(t.style!==t.parentStyle){i=t.style.sizeMultiplier/t.parentStyle.sizeMultiplier;r.height*=i;r.depth*=i}if(t.size!==t.parentSize){i=n.sizingMultiplier[t.size]/n.sizingMultiplier[t.parentSize];r.height*=i;r.depth*=i}return r}else{throw new a("Got group of unknown type: '"+e.type+"'")}};var S=function(e,t){e=JSON.parse(JSON.stringify(e));var r=v(e,t,true);var a=p(["base",t.style.cls()],r,t);var i=p(["strut"]);var n=p(["strut","bottom"]);i.style.height=a.height+"em";n.style.height=a.height+a.depth+"em";n.style.verticalAlign=-a.depth+"em";var s=p(["katex-html"],[i,n,a]);s.setAttribute("aria-hidden","true");return s};t.exports=S},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./delimiter":14,"./domTree":15,"./fontMetrics":17,"./utils":25}],12:[function(e,t,r){var a=e("./buildCommon");var i=e("./fontMetrics");var n=e("./mathMLTree");var s=e("./ParseError");var l=e("./symbols");var o=e("./utils");var u=a.makeSpan;var p=a.fontMap;var h=function(e,t){if(l[t][e]&&l[t][e].replace){e=l[t][e].replace}return new n.TextNode(e)};var c=function(e,t){var r=t.font;if(!r){return null}var a=e.mode;if(r==="mathit"){return"italic"}var n=e.value;if(o.contains(["\\imath","\\jmath"],n)){return null}if(l[a][n]&&l[a][n].replace){n=l[a][n].replace}var s=p[r].fontName;if(i.getCharacterMetrics(n,s)){return p[t.font].variant}return null};var m={};m.mathord=function(e,t){var r=new n.MathNode("mi",[h(e.value,e.mode)]);var a=c(e,t);if(a){r.setAttribute("mathvariant",a)}return r};m.textord=function(e,t){var r=h(e.value,e.mode);var a=c(e,t)||"normal";var i;if(/[0-9]/.test(e.value)){i=new n.MathNode("mn",[r]);if(t.font){i.setAttribute("mathvariant",a)}}else{i=new n.MathNode("mi",[r]);i.setAttribute("mathvariant",a)}return i};m.bin=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.rel=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.open=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.close=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.inner=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.punct=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);t.setAttribute("separator","true");return t};m.ordgroup=function(e,t){var r=f(e.value,t);var a=new n.MathNode("mrow",r);return a};m.text=function(e,t){var r=f(e.value.body,t);var a=new n.MathNode("mtext",r);return a};m.color=function(e,t){var r=f(e.value.value,t);var a=new n.MathNode("mstyle",r);a.setAttribute("mathcolor",e.value.color);return a};m.supsub=function(e,t){var r=[v(e.value.base,t)];if(e.value.sub){r.push(v(e.value.sub,t))}if(e.value.sup){r.push(v(e.value.sup,t))}var a;if(!e.value.sub){a="msup"}else if(!e.value.sup){a="msub"}else{a="msubsup"}var i=new n.MathNode(a,r);return i};m.genfrac=function(e,t){var r=new n.MathNode("mfrac",[v(e.value.numer,t),v(e.value.denom,t)]);if(!e.value.hasBarLine){r.setAttribute("linethickness","0px")}if(e.value.leftDelim!=null||e.value.rightDelim!=null){var a=[];if(e.value.leftDelim!=null){var i=new n.MathNode("mo",[new n.TextNode(e.value.leftDelim)]);i.setAttribute("fence","true");a.push(i)}a.push(r);if(e.value.rightDelim!=null){var s=new n.MathNode("mo",[new n.TextNode(e.value.rightDelim)]);s.setAttribute("fence","true");a.push(s)}var l=new n.MathNode("mrow",a);return l}return r};m.array=function(e,t){return new n.MathNode("mtable",e.value.body.map(function(e){return new n.MathNode("mtr",e.map(function(e){return new n.MathNode("mtd",[v(e,t)])}))}))};m.sqrt=function(e,t){var r;if(e.value.index){r=new n.MathNode("mroot",[v(e.value.body,t),v(e.value.index,t)])}else{r=new n.MathNode("msqrt",[v(e.value.body,t)])}return r};m.leftright=function(e,t){var r=f(e.value.body,t);if(e.value.left!=="."){var a=new n.MathNode("mo",[h(e.value.left,e.mode)]);a.setAttribute("fence","true");r.unshift(a)}if(e.value.right!=="."){var i=new n.MathNode("mo",[h(e.value.right,e.mode)]);i.setAttribute("fence","true");r.push(i)}var s=new n.MathNode("mrow",r);return s};m.middle=function(e,t){var r=new n.MathNode("mo",[h(e.value.middle,e.mode)]);r.setAttribute("fence","true");return r};m.accent=function(e,t){var r=new n.MathNode("mo",[h(e.value.accent,e.mode)]);var a=new n.MathNode("mover",[v(e.value.base,t),r]);a.setAttribute("accent","true");return a};m.spacing=function(e){var t;if(e.value==="\\ "||e.value==="\\space"||e.value===" "||e.value==="~"){t=new n.MathNode("mtext",[new n.TextNode("\xa0")])}else{t=new n.MathNode("mspace");t.setAttribute("width",a.spacingFunctions[e.value].size)}return t};m.op=function(e,t){var r;if(e.value.symbol){r=new n.MathNode("mo",[h(e.value.body,e.mode)])}else if(e.value.value){r=new n.MathNode("mo",f(e.value.value,t))}else{r=new n.MathNode("mi",[new n.TextNode(e.value.body.slice(1))])}return r};m.mod=function(e,t){var r=[];if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(new n.MathNode("mo",[h("(",e.mode)]))}if(e.value.modType!=="pod"){r.push(new n.MathNode("mo",[h("mod",e.mode)]))}if(e.value.value){var a=new n.MathNode("mspace");a.setAttribute("width","0.333333em");r.push(a);r=r.concat(f(e.value.value,t))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(new n.MathNode("mo",[h(")",e.mode)]))}return new n.MathNode("mo",r)};m.katex=function(e){var t=new n.MathNode("mtext",[new n.TextNode("KaTeX")]);return t};m.font=function(e,t){var r=e.value.font;return v(e.value.body,t.withFont(r))};m.delimsizing=function(e){var t=[];if(e.value.value!=="."){t.push(h(e.value.value,e.mode))}var r=new n.MathNode("mo",t);if(e.value.mclass==="mopen"||e.value.mclass==="mclose"){r.setAttribute("fence","true")}else{r.setAttribute("fence","false")}return r};m.styling=function(e,t){var r=f(e.value.value,t);var a=new n.MathNode("mstyle",r);var i={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]};var s=i[e.value.style];a.setAttribute("scriptlevel",s[0]);a.setAttribute("displaystyle",s[1]);return a};m.sizing=function(e,t){var r=f(e.value.value,t);var i=new n.MathNode("mstyle",r);i.setAttribute("mathsize",a.sizingMultiplier[e.value.size]+"em");return i};m.overline=function(e,t){var r=new n.MathNode("mo",[new n.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new n.MathNode("mover",[v(e.value.body,t),r]);a.setAttribute("accent","true");return a};m.underline=function(e,t){var r=new n.MathNode("mo",[new n.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new n.MathNode("munder",[v(e.value.body,t),r]);a.setAttribute("accentunder","true");return a};m.rule=function(e){var t=new n.MathNode("mrow");return t};m.kern=function(e){var t=new n.MathNode("mrow");return t};m.llap=function(e,t){var r=new n.MathNode("mpadded",[v(e.value.body,t)]);r.setAttribute("lspace","-1width");r.setAttribute("width","0px");return r};m.rlap=function(e,t){var r=new n.MathNode("mpadded",[v(e.value.body,t)]);r.setAttribute("width","0px");return r};m.phantom=function(e,t){var r=f(e.value.value,t);return new n.MathNode("mphantom",r)};m.mclass=function(e,t){var r=f(e.value.value,t);return new n.MathNode("mstyle",r)};var f=function(e,t){var r=[];for(var a=0;a<e.length;a++){var i=e[a];r.push(v(i,t))}return r};var v=function(e,t){if(!e){return new n.MathNode("mrow")}if(m[e.type]){return m[e.type](e,t)}else{throw new s("Got group of unknown type: '"+e.type+"'")}};var d=function(e,t,r){var a=f(e,r);var i=new n.MathNode("mrow",a);var s=new n.MathNode("annotation",[new n.TextNode(t)]);s.setAttribute("encoding","application/x-tex");var l=new n.MathNode("semantics",[i,s]);var o=new n.MathNode("math",[l]);return u(["katex-mathml"],[o])};t.exports=d},{"./ParseError":6,"./buildCommon":10,"./fontMetrics":17,"./mathMLTree":20,"./symbols":23,"./utils":25}],13:[function(e,t,r){var a=e("./buildHTML");var i=e("./buildMathML");var n=e("./buildCommon");var s=e("./Options");var l=e("./Settings");var o=e("./Style");var u=n.makeSpan;var p=function(e,t,r){r=r||new l({});var n=o.TEXT;if(r.displayMode){n=o.DISPLAY}var p=new s({style:n,size:"size5"});var h=i(e,t,p);var c=a(e,p);var m=u(["katex"],[h,c]);if(r.displayMode){return u(["katex-display"],[m])}else{return m}};t.exports=p},{"./Options":5,"./Settings":8,"./Style":9,"./buildCommon":10,"./buildHTML":11,"./buildMathML":12}],14:[function(e,t,r){var a=e("./ParseError");var i=e("./Style");var n=e("./buildCommon");var s=e("./fontMetrics");var l=e("./symbols");var o=e("./utils");var u=n.makeSpan;var p=function(e,t){if(l.math[e]&&l.math[e].replace){return s.getCharacterMetrics(l.math[e].replace,t)}else{return s.getCharacterMetrics(e,t)}};var h=function(e,t,r,a){return n.makeSymbol(e,"Size"+t+"-Regular",r,a)};var c=function(e,t,r,a){a=a||[];var i=u(a.concat(["style-wrap",r.style.reset(),t.cls()]),[e],r);var n=t.sizeMultiplier/r.style.sizeMultiplier;i.height*=n;i.depth*=n;i.maxFontSize=t.sizeMultiplier;return i};var m=function(e,t,r,a,i,s){var l=n.makeSymbol(e,"Main-Regular",i,a);var o=c(l,t,a,s);if(r){var u=(1-a.style.sizeMultiplier/t.sizeMultiplier)*a.style.metrics.axisHeight;o.style.top=u+"em";o.height-=u;o.depth+=u}return o};var f=function(e,t,r,a,n,s){var l=h(e,t,n,a);var o=c(u(["delimsizing","size"+t],[l],a),i.TEXT,a,s);if(r){var p=(1-a.style.sizeMultiplier)*a.style.metrics.axisHeight;o.style.top=p+"em";o.height-=p;o.depth+=p}return o};var v=function(e,t,r){var a;if(t==="Size1-Regular"){a="delim-size1"}else if(t==="Size4-Regular"){a="delim-size4"}var i=u(["delimsizinginner",a],[u([],[n.makeSymbol(e,t,r)])]);return{type:"elem",elem:i}};var d=function(e,t,r,a,s,l){var o;var h;var m;var f;o=m=f=e;h=null;var d="Size1-Regular";if(e==="\\uparrow"){m=f="\u23d0"}else if(e==="\\Uparrow"){m=f="\u2016"}else if(e==="\\downarrow"){o=m="\u23d0"}else if(e==="\\Downarrow"){o=m="\u2016"}else if(e==="\\updownarrow"){o="\\uparrow";m="\u23d0";f="\\downarrow"}else if(e==="\\Updownarrow"){o="\\Uparrow";m="\u2016";f="\\Downarrow"}else if(e==="["||e==="\\lbrack"){o="\u23a1";m="\u23a2";f="\u23a3";d="Size4-Regular"}else if(e==="]"||e==="\\rbrack"){o="\u23a4";m="\u23a5";f="\u23a6";d="Size4-Regular"}else if(e==="\\lfloor"){m=o="\u23a2";f="\u23a3";d="Size4-Regular"}else if(e==="\\lceil"){o="\u23a1";m=f="\u23a2";d="Size4-Regular"}else if(e==="\\rfloor"){m=o="\u23a5";f="\u23a6";d="Size4-Regular"}else if(e==="\\rceil"){o="\u23a4";m=f="\u23a5";d="Size4-Regular"}else if(e==="("){o="\u239b";m="\u239c";f="\u239d";d="Size4-Regular"}else if(e===")"){o="\u239e";m="\u239f";f="\u23a0";d="Size4-Regular"}else if(e==="\\{"||e==="\\lbrace"){o="\u23a7";h="\u23a8";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\}"||e==="\\rbrace"){o="\u23ab";h="\u23ac";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\lgroup"){o="\u23a7";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\rgroup"){o="\u23ab";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\lmoustache"){o="\u23a7";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\rmoustache"){o="\u23ab";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\surd"){o="\ue001";f="\u23b7";m="\ue000";d="Size4-Regular"}var g=p(o,d);var y=g.height+g.depth;var x=p(m,d);var b=x.height+x.depth;var w=p(f,d);var k=w.height+w.depth;var z=0;var S=1;if(h!==null){var M=p(h,d);z=M.height+M.depth;S=2}var T=y+k+z;var A=Math.ceil((t-T)/(S*b));var N=T+A*S*b;var q=a.style.metrics.axisHeight;if(r){q*=a.style.sizeMultiplier}var R=N/2-q;var E=[];E.push(v(f,d,s));var C;if(h===null){for(C=0;C<A;C++){E.push(v(m,d,s))}}else{for(C=0;C<A;C++){E.push(v(m,d,s))}E.push(v(h,d,s));for(C=0;C<A;C++){E.push(v(m,d,s))}}E.push(v(o,d,s));var D=n.makeVList(E,"bottom",R,a);return c(u(["delimsizing","mult"],[D],a),i.TEXT,a,l)};var g=["(",")","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\\lceil","\\rceil","\\surd"];var y=["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\\lmoustache","\\rmoustache"];var x=["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"];var b=[0,1.2,1.8,2.4,3];var w=function(e,t,r,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}if(o.contains(g,e)||o.contains(x,e)){return f(e,t,false,r,i,n)}else if(o.contains(y,e)){return d(e,b[t],false,r,i,n)}else{throw new a("Illegal delimiter: '"+e+"'")}};var k=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}];var z=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"stack"}];var S=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}];var M=function(e){if(e.type==="small"){return"Main-Regular"}else if(e.type==="large"){return"Size"+e.size+"-Regular"}else if(e.type==="stack"){return"Size4-Regular"}};var T=function(e,t,r,a){var i=Math.min(2,3-a.style.size);for(var n=i;n<r.length;n++){if(r[n].type==="stack"){break}var s=p(e,M(r[n]));var l=s.height+s.depth;if(r[n].type==="small"){l*=r[n].style.sizeMultiplier}if(l>t){return r[n]}}return r[r.length-1]};var A=function(e,t,r,a,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}var s;if(o.contains(x,e)){s=k}else if(o.contains(g,e)){s=S}else{s=z}var l=T(e,t,s,a);if(l.type==="small"){return m(e,l.style,r,a,i,n)}else if(l.type==="large"){return f(e,l.size,r,a,i,n)}else if(l.type==="stack"){return d(e,t,r,a,i,n)}};var N=function(e,t,r,a,i,n){var l=a.style.metrics.axisHeight*a.style.sizeMultiplier;var o=901;var u=5/s.metrics.ptPerEm;var p=Math.max(t-l,r+l);var h=Math.max(p/500*o,2*p-u);return A(e,h,true,a,i,n)};t.exports={sizedDelim:w,customSizedDelim:A,leftRightDelim:N}},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(e,t,r){var a=e("./unicodeRegexes");var i=e("./utils");var n=function(e){e=e.slice();for(var t=e.length-1;t>=0;t--){if(!e[t]){e.splice(t,1)}}return e.join(" ")};function s(e,t,r){this.classes=e||[];this.children=t||[];this.height=0;this.depth=0;this.maxFontSize=0;this.style={};this.attributes={};if(r){if(r.style.isTight()){this.classes.push("mtight")}if(r.getColor()){this.style.color=r.getColor()}}}s.prototype.setAttribute=function(e,t){this.attributes[e]=t};s.prototype.tryCombine=function(e){return false};s.prototype.toNode=function(){var e=document.createElement("span");e.className=n(this.classes);for(var t in this.style){if(Object.prototype.hasOwnProperty.call(this.style,t)){e.style[t]=this.style[t]}}for(var r in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,r)){e.setAttribute(r,this.attributes[r])}}for(var a=0;a<this.children.length;a++){e.appendChild(this.children[a].toNode())}return e};s.prototype.toMarkup=function(){var e="<span";if(this.classes.length){e+=' class="';e+=i.escape(n(this.classes));e+='"'}var t="";for(var r in this.style){if(this.style.hasOwnProperty(r)){t+=i.hyphenate(r)+":"+this.style[r]+";"}}if(t){e+=' style="'+i.escape(t)+'"'}for(var a in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,a)){e+=" "+a+'="';e+=i.escape(this.attributes[a]);e+='"'}}e+=">";for(var s=0;s<this.children.length;s++){e+=this.children[s].toMarkup()}e+="</span>";return e};function l(e){this.children=e||[];this.height=0;this.depth=0;this.maxFontSize=0}l.prototype.toNode=function(){var e=document.createDocumentFragment();for(var t=0;t<this.children.length;t++){e.appendChild(this.children[t].toNode())}return e};l.prototype.toMarkup=function(){var e="";for(var t=0;t<this.children.length;t++){e+=this.children[t].toMarkup()}return e};var o={"\xee":"\u0131\u0302","\xef":"\u0131\u0308","\xed":"\u0131\u0301","\xec":"\u0131\u0300"};function u(e,t,r,i,n,s,l){this.value=e||"";this.height=t||0;this.depth=r||0;this.italic=i||0;this.skew=n||0;this.classes=s||[];this.style=l||{};this.maxFontSize=0;if(a.cjkRegex.test(e)){if(a.hangulRegex.test(e)){this.classes.push("hangul_fallback")}else{this.classes.push("cjk_fallback")}}if(/[\xee\xef\xed\xec]/.test(this.value)){this.value=o[this.value]}}u.prototype.tryCombine=function(e){if(!e||!(e instanceof u)||this.italic>0||n(this.classes)!==n(e.classes)||this.skew!==e.skew||this.maxFontSize!==e.maxFontSize){return false}for(var t in this.style){if(this.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}for(t in e.style){if(e.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}this.value+=e.value;this.height=Math.max(this.height,e.height);this.depth=Math.max(this.depth,e.depth);this.italic=e.italic;return true};u.prototype.toNode=function(){var e=document.createTextNode(this.value);var t=null;if(this.italic>0){t=document.createElement("span");t.style.marginRight=this.italic+"em"}if(this.classes.length>0){t=t||document.createElement("span");t.className=n(this.classes)}for(var r in this.style){if(this.style.hasOwnProperty(r)){t=t||document.createElement("span");t.style[r]=this.style[r]}}if(t){t.appendChild(e);return t}else{return e}};u.prototype.toMarkup=function(){var e=false;var t="<span";if(this.classes.length){e=true;t+=' class="';t+=i.escape(n(this.classes));t+='"'}var r="";if(this.italic>0){r+="margin-right:"+this.italic+"em;"}for(var a in this.style){if(this.style.hasOwnProperty(a)){r+=i.hyphenate(a)+":"+this.style[a]+";"}}if(r){e=true;t+=' style="'+i.escape(r)+'"'}var s=i.escape(this.value);if(e){t+=">";t+=s;t+="</span>";return t}else{return s}};t.exports={span:s,documentFragment:l,symbolNode:u}},{"./unicodeRegexes":24,"./utils":25}],16:[function(e,t,r){var a=e("./parseData");var i=e("./ParseError");var n=e("./Style");var s=a.ParseNode;function l(e,t){var r=[];var a=[r];var n=[];while(true){var l=e.parseExpression(false,null);r.push(new s("ordgroup",l,e.mode));var o=e.nextToken.text;if(o==="&"){e.consume()}else if(o==="\\end"){break}else if(o==="\\\\"||o==="\\cr"){var u=e.parseFunction();n.push(u.value.size);r=[];a.push(r)}else{throw new i("Expected & or \\\\ or \\end",e.nextToken)}}t.body=a;t.rowGaps=n;return new s(t.type,t,e.mode)}function o(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs||0,argTypes:r.argTypes,greediness:1,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,handler:a};for(var n=0;n<e.length;++n){t.exports[e[n]]=i}}o("array",{numArgs:1},function(e,t){var r=t[0];r=r.value.map?r.value:[r];var a=r.map(function(e){var t=e.value;if("lcr".indexOf(t)!==-1){return{type:"align",align:t}}else if(t==="|"){return{type:"separator",separator:"|"}}throw new i("Unknown column alignment: "+e.value,e)});var n={type:"array",cols:a,hskipBeforeAndAfter:true};n=l(e.parser,n);return n});o(["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix"],{},function(e){var t={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[e.envName];var r={type:"array",hskipBeforeAndAfter:false};r=l(e.parser,r);if(t){r=new s("leftright",{body:[r],left:t[0],right:t[1]},e.mode)}return r});o("cases",{},function(e){var t={type:"array",arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:n.TEXT.metrics.quad},{type:"align",align:"l",pregap:0,postgap:0}]};t=l(e.parser,t);t=new s("leftright",{body:[t],left:"\\{",right:"."},e.mode);return t});o("aligned",{},function(e){var t={type:"array",cols:[]};t=l(e.parser,t);var r=new s("ordgroup",[],e.mode);var a=0;t.value.body.forEach(function(e){var t;for(t=1;t<e.length;t+=2){e[t].value.unshift(r)}if(a<e.length){a=e.length}});for(var i=0;i<a;++i){var n="r";var o=0;if(i%2===1){n="l"}else if(i>0){o=2}t.value.cols[i]={type:"align",align:n,pregap:o,postgap:0}}return t})},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(e,t,r){var a=e("./Style");var i=e("./unicodeRegexes").cjkRegex;var n={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25]};var s=0;var l=0;var o=0;var u=0;var p=.431;var h=1;var c=0;var m=.04;var f=.111;var v=.166;var d=.2;var g=.6;var y=.1;var x=10;var b=2/x;var w={defaultRuleThickness:m,bigOpSpacing1:f,bigOpSpacing2:v,bigOpSpacing3:d,bigOpSpacing4:g,bigOpSpacing5:y,ptPerEm:x,doubleRuleSep:b};var k=e("./fontMetricsData");var z={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xc6":"A","\xc7":"C","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xd0":"D","\xd1":"N","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xdd":"Y","\xde":"o","\xdf":"B","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xe6":"a","\xe7":"c","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xf0":"d","\xf1":"n","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xfd":"y","\xfe":"o","\xff":"y","\u0410":"A","\u0411":"B","\u0412":"B","\u0413":"F","\u0414":"A","\u0415":"E","\u0416":"K","\u0417":"3","\u0418":"N","\u0419":"N","\u041a":"K","\u041b":"N","\u041c":"M","\u041d":"H","\u041e":"O","\u041f":"N","\u0420":"P","\u0421":"C","\u0422":"T","\u0423":"y","\u0424":"O","\u0425":"X","\u0426":"U","\u0427":"h","\u0428":"W","\u0429":"W","\u042a":"B","\u042b":"X","\u042c":"B","\u042d":"3","\u042e":"X","\u042f":"R","\u0430":"a","\u0431":"b","\u0432":"a","\u0433":"r","\u0434":"y","\u0435":"e","\u0436":"m","\u0437":"e","\u0438":"n","\u0439":"n","\u043a":"n","\u043b":"n","\u043c":"m","\u043d":"n","\u043e":"o","\u043f":"n","\u0440":"p","\u0441":"c","\u0442":"o","\u0443":"y","\u0444":"b","\u0445":"x","\u0446":"n","\u0447":"n","\u0448":"w","\u0449":"w","\u044a":"a","\u044b":"m","\u044c":"a","\u044d":"e","\u044e":"m","\u044f":"r"};var S=function(e,t){var r=e.charCodeAt(0);if(e[0]in z){r=z[e[0]].charCodeAt(0)}else if(i.test(e[0])){r="M".charCodeAt(0)}var a=k[t][r];if(a){return{depth:a[0],height:a[1],italic:a[2],skew:a[3],width:a[4]}}};t.exports={metrics:w,sigmas:n,getCharacterMetrics:S}},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(e,t,r){t.exports={"AMS-Regular":{65:[0,.68889,0,0],66:[0,.68889,0,0],67:[0,.68889,0,0],68:[0,.68889,0,0],69:[0,.68889,0,0],70:[0,.68889,0,0],71:[0,.68889,0,0],72:[0,.68889,0,0],73:[0,.68889,0,0],74:[.16667,.68889,0,0],75:[0,.68889,0,0],76:[0,.68889,0,0],77:[0,.68889,0,0],78:[0,.68889,0,0],79:[.16667,.68889,0,0],80:[0,.68889,0,0],81:[.16667,.68889,0,0],82:[0,.68889,0,0],83:[0,.68889,0,0],84:[0,.68889,0,0],85:[0,.68889,0,0],86:[0,.68889,0,0],87:[0,.68889,0,0],88:[0,.68889,0,0],89:[0,.68889,0,0],90:[0,.68889,0,0],107:[0,.68889,0,0],165:[0,.675,.025,0],174:[.15559,.69224,0,0],240:[0,.68889,0,0],295:[0,.68889,0,0],710:[0,.825,0,0],732:[0,.9,0,0],770:[0,.825,0,0],771:[0,.9,0,0],989:[.08167,.58167,0,0],1008:[0,.43056,.04028,0],8245:[0,.54986,0,0],8463:[0,.68889,0,0],8487:[0,.68889,0,0],8498:[0,.68889,0,0],8502:[0,.68889,0,0],8503:[0,.68889,0,0],8504:[0,.68889,0,0],8513:[0,.68889,0,0],8592:[-.03598,.46402,0,0],8594:[-.03598,.46402,0,0],8602:[-.13313,.36687,0,0],8603:[-.13313,.36687,0,0],8606:[.01354,.52239,0,0],8608:[.01354,.52239,0,0],8610:[.01354,.52239,0,0],8611:[.01354,.52239,0,0],8619:[0,.54986,0,0],8620:[0,.54986,0,0],8621:[-.13313,.37788,0,0],8622:[-.13313,.36687,0,0],8624:[0,.69224,0,0],8625:[0,.69224,0,0],8630:[0,.43056,0,0],8631:[0,.43056,0,0],8634:[.08198,.58198,0,0],8635:[.08198,.58198,0,0],8638:[.19444,.69224,0,0],8639:[.19444,.69224,0,0],8642:[.19444,.69224,0,0],8643:[.19444,.69224,0,0],8644:[.1808,.675,0,0],8646:[.1808,.675,0,0],8647:[.1808,.675,0,0],8648:[.19444,.69224,0,0],8649:[.1808,.675,0,0],8650:[.19444,.69224,0,0],8651:[.01354,.52239,0,0],8652:[.01354,.52239,0,0],8653:[-.13313,.36687,0,0],8654:[-.13313,.36687,0,0],8655:[-.13313,.36687,0,0],8666:[.13667,.63667,0,0],8667:[.13667,.63667,0,0],8669:[-.13313,.37788,0,0],8672:[-.064,.437,0,0],8674:[-.064,.437,0,0],8705:[0,.825,0,0],8708:[0,.68889,0,0],8709:[.08167,.58167,0,0],8717:[0,.43056,0,0],8722:[-.03598,.46402,0,0],8724:[.08198,.69224,0,0],8726:[.08167,.58167,0,0],8733:[0,.69224,0,0],8736:[0,.69224,0,0],8737:[0,.69224,0,0],8738:[.03517,.52239,0,0],8739:[.08167,.58167,0,0],8740:[.25142,.74111,0,0],8741:[.08167,.58167,0,0],8742:[.25142,.74111,0,0],8756:[0,.69224,0,0],8757:[0,.69224,0,0],8764:[-.13313,.36687,0,0],8765:[-.13313,.37788,0,0],8769:[-.13313,.36687,0,0],8770:[-.03625,.46375,0,0],8774:[.30274,.79383,0,0],8776:[-.01688,.48312,0,0],8778:[.08167,.58167,0,0],8782:[.06062,.54986,0,0],8783:[.06062,.54986,0,0],8785:[.08198,.58198,0,0],8786:[.08198,.58198,0,0],8787:[.08198,.58198,0,0],8790:[0,.69224,0,0],8791:[.22958,.72958,0,0],8796:[.08198,.91667,0,0],8806:[.25583,.75583,0,0],
+8807:[.25583,.75583,0,0],8808:[.25142,.75726,0,0],8809:[.25142,.75726,0,0],8812:[.25583,.75583,0,0],8814:[.20576,.70576,0,0],8815:[.20576,.70576,0,0],8816:[.30274,.79383,0,0],8817:[.30274,.79383,0,0],8818:[.22958,.72958,0,0],8819:[.22958,.72958,0,0],8822:[.1808,.675,0,0],8823:[.1808,.675,0,0],8828:[.13667,.63667,0,0],8829:[.13667,.63667,0,0],8830:[.22958,.72958,0,0],8831:[.22958,.72958,0,0],8832:[.20576,.70576,0,0],8833:[.20576,.70576,0,0],8840:[.30274,.79383,0,0],8841:[.30274,.79383,0,0],8842:[.13597,.63597,0,0],8843:[.13597,.63597,0,0],8847:[.03517,.54986,0,0],8848:[.03517,.54986,0,0],8858:[.08198,.58198,0,0],8859:[.08198,.58198,0,0],8861:[.08198,.58198,0,0],8862:[0,.675,0,0],8863:[0,.675,0,0],8864:[0,.675,0,0],8865:[0,.675,0,0],8872:[0,.69224,0,0],8873:[0,.69224,0,0],8874:[0,.69224,0,0],8876:[0,.68889,0,0],8877:[0,.68889,0,0],8878:[0,.68889,0,0],8879:[0,.68889,0,0],8882:[.03517,.54986,0,0],8883:[.03517,.54986,0,0],8884:[.13667,.63667,0,0],8885:[.13667,.63667,0,0],8888:[0,.54986,0,0],8890:[.19444,.43056,0,0],8891:[.19444,.69224,0,0],8892:[.19444,.69224,0,0],8901:[0,.54986,0,0],8903:[.08167,.58167,0,0],8905:[.08167,.58167,0,0],8906:[.08167,.58167,0,0],8907:[0,.69224,0,0],8908:[0,.69224,0,0],8909:[-.03598,.46402,0,0],8910:[0,.54986,0,0],8911:[0,.54986,0,0],8912:[.03517,.54986,0,0],8913:[.03517,.54986,0,0],8914:[0,.54986,0,0],8915:[0,.54986,0,0],8916:[0,.69224,0,0],8918:[.0391,.5391,0,0],8919:[.0391,.5391,0,0],8920:[.03517,.54986,0,0],8921:[.03517,.54986,0,0],8922:[.38569,.88569,0,0],8923:[.38569,.88569,0,0],8926:[.13667,.63667,0,0],8927:[.13667,.63667,0,0],8928:[.30274,.79383,0,0],8929:[.30274,.79383,0,0],8934:[.23222,.74111,0,0],8935:[.23222,.74111,0,0],8936:[.23222,.74111,0,0],8937:[.23222,.74111,0,0],8938:[.20576,.70576,0,0],8939:[.20576,.70576,0,0],8940:[.30274,.79383,0,0],8941:[.30274,.79383,0,0],8994:[.19444,.69224,0,0],8995:[.19444,.69224,0,0],9416:[.15559,.69224,0,0],9484:[0,.69224,0,0],9488:[0,.69224,0,0],9492:[0,.37788,0,0],9496:[0,.37788,0,0],9585:[.19444,.68889,0,0],9586:[.19444,.74111,0,0],9632:[0,.675,0,0],9633:[0,.675,0,0],9650:[0,.54986,0,0],9651:[0,.54986,0,0],9654:[.03517,.54986,0,0],9660:[0,.54986,0,0],9661:[0,.54986,0,0],9664:[.03517,.54986,0,0],9674:[.11111,.69224,0,0],9733:[.19444,.69224,0,0],10003:[0,.69224,0,0],10016:[0,.69224,0,0],10731:[.11111,.69224,0,0],10846:[.19444,.75583,0,0],10877:[.13667,.63667,0,0],10878:[.13667,.63667,0,0],10885:[.25583,.75583,0,0],10886:[.25583,.75583,0,0],10887:[.13597,.63597,0,0],10888:[.13597,.63597,0,0],10889:[.26167,.75726,0,0],10890:[.26167,.75726,0,0],10891:[.48256,.98256,0,0],10892:[.48256,.98256,0,0],10901:[.13667,.63667,0,0],10902:[.13667,.63667,0,0],10933:[.25142,.75726,0,0],10934:[.25142,.75726,0,0],10935:[.26167,.75726,0,0],10936:[.26167,.75726,0,0],10937:[.26167,.75726,0,0],10938:[.26167,.75726,0,0],10949:[.25583,.75583,0,0],10950:[.25583,.75583,0,0],10955:[.28481,.79383,0,0],10956:[.28481,.79383,0,0],57350:[.08167,.58167,0,0],57351:[.08167,.58167,0,0],57352:[.08167,.58167,0,0],57353:[0,.43056,.04028,0],57356:[.25142,.75726,0,0],57357:[.25142,.75726,0,0],57358:[.41951,.91951,0,0],57359:[.30274,.79383,0,0],57360:[.30274,.79383,0,0],57361:[.41951,.91951,0,0],57366:[.25142,.75726,0,0],57367:[.25142,.75726,0,0],57368:[.25142,.75726,0,0],57369:[.25142,.75726,0,0],57370:[.13597,.63597,0,0],57371:[.13597,.63597,0,0]},"Caligraphic-Regular":{48:[0,.43056,0,0],49:[0,.43056,0,0],50:[0,.43056,0,0],51:[.19444,.43056,0,0],52:[.19444,.43056,0,0],53:[.19444,.43056,0,0],54:[0,.64444,0,0],55:[.19444,.43056,0,0],56:[0,.64444,0,0],57:[.19444,.43056,0,0],65:[0,.68333,0,.19445],66:[0,.68333,.03041,.13889],67:[0,.68333,.05834,.13889],68:[0,.68333,.02778,.08334],69:[0,.68333,.08944,.11111],70:[0,.68333,.09931,.11111],71:[.09722,.68333,.0593,.11111],72:[0,.68333,.00965,.11111],73:[0,.68333,.07382,0],74:[.09722,.68333,.18472,.16667],75:[0,.68333,.01445,.05556],76:[0,.68333,0,.13889],77:[0,.68333,0,.13889],78:[0,.68333,.14736,.08334],79:[0,.68333,.02778,.11111],80:[0,.68333,.08222,.08334],81:[.09722,.68333,0,.11111],82:[0,.68333,0,.08334],83:[0,.68333,.075,.13889],84:[0,.68333,.25417,0],85:[0,.68333,.09931,.08334],86:[0,.68333,.08222,0],87:[0,.68333,.08222,.08334],88:[0,.68333,.14643,.13889],89:[.09722,.68333,.08222,.08334],90:[0,.68333,.07944,.13889]},"Fraktur-Regular":{33:[0,.69141,0,0],34:[0,.69141,0,0],38:[0,.69141,0,0],39:[0,.69141,0,0],40:[.24982,.74947,0,0],41:[.24982,.74947,0,0],42:[0,.62119,0,0],43:[.08319,.58283,0,0],44:[0,.10803,0,0],45:[.08319,.58283,0,0],46:[0,.10803,0,0],47:[.24982,.74947,0,0],48:[0,.47534,0,0],49:[0,.47534,0,0],50:[0,.47534,0,0],51:[.18906,.47534,0,0],52:[.18906,.47534,0,0],53:[.18906,.47534,0,0],54:[0,.69141,0,0],55:[.18906,.47534,0,0],56:[0,.69141,0,0],57:[.18906,.47534,0,0],58:[0,.47534,0,0],59:[.12604,.47534,0,0],61:[-.13099,.36866,0,0],63:[0,.69141,0,0],65:[0,.69141,0,0],66:[0,.69141,0,0],67:[0,.69141,0,0],68:[0,.69141,0,0],69:[0,.69141,0,0],70:[.12604,.69141,0,0],71:[0,.69141,0,0],72:[.06302,.69141,0,0],73:[0,.69141,0,0],74:[.12604,.69141,0,0],75:[0,.69141,0,0],76:[0,.69141,0,0],77:[0,.69141,0,0],78:[0,.69141,0,0],79:[0,.69141,0,0],80:[.18906,.69141,0,0],81:[.03781,.69141,0,0],82:[0,.69141,0,0],83:[0,.69141,0,0],84:[0,.69141,0,0],85:[0,.69141,0,0],86:[0,.69141,0,0],87:[0,.69141,0,0],88:[0,.69141,0,0],89:[.18906,.69141,0,0],90:[.12604,.69141,0,0],91:[.24982,.74947,0,0],93:[.24982,.74947,0,0],94:[0,.69141,0,0],97:[0,.47534,0,0],98:[0,.69141,0,0],99:[0,.47534,0,0],100:[0,.62119,0,0],101:[0,.47534,0,0],102:[.18906,.69141,0,0],103:[.18906,.47534,0,0],104:[.18906,.69141,0,0],105:[0,.69141,0,0],106:[0,.69141,0,0],107:[0,.69141,0,0],108:[0,.69141,0,0],109:[0,.47534,0,0],110:[0,.47534,0,0],111:[0,.47534,0,0],112:[.18906,.52396,0,0],113:[.18906,.47534,0,0],114:[0,.47534,0,0],115:[0,.47534,0,0],116:[0,.62119,0,0],117:[0,.47534,0,0],118:[0,.52396,0,0],119:[0,.52396,0,0],120:[.18906,.47534,0,0],121:[.18906,.47534,0,0],122:[.18906,.47534,0,0],8216:[0,.69141,0,0],8217:[0,.69141,0,0],58112:[0,.62119,0,0],58113:[0,.62119,0,0],58114:[.18906,.69141,0,0],58115:[.18906,.69141,0,0],58116:[.18906,.47534,0,0],58117:[0,.69141,0,0],58118:[0,.62119,0,0],58119:[0,.47534,0,0]},"Main-Bold":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.13333,.63333,0,0],44:[.19444,.15556,0,0],45:[0,.44444,0,0],46:[0,.15556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.44444,0,0],59:[.19444,.44444,0,0],60:[.08556,.58556,0,0],61:[-.10889,.39111,0,0],62:[.08556,.58556,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,0,0],67:[0,.68611,0,0],68:[0,.68611,0,0],69:[0,.68611,0,0],70:[0,.68611,0,0],71:[0,.68611,0,0],72:[0,.68611,0,0],73:[0,.68611,0,0],74:[0,.68611,0,0],75:[0,.68611,0,0],76:[0,.68611,0,0],77:[0,.68611,0,0],78:[0,.68611,0,0],79:[0,.68611,0,0],80:[0,.68611,0,0],81:[.19444,.68611,0,0],82:[0,.68611,0,0],83:[0,.68611,0,0],84:[0,.68611,0,0],85:[0,.68611,0,0],86:[0,.68611,.01597,0],87:[0,.68611,.01597,0],88:[0,.68611,0,0],89:[0,.68611,.02875,0],90:[0,.68611,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.13444,.03194,0],96:[0,.69444,0,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.10903,0],103:[.19444,.44444,.01597,0],104:[0,.69444,0,0],105:[0,.69444,0,0],106:[.19444,.69444,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,0,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.01597,0],119:[0,.44444,.01597,0],120:[0,.44444,0,0],121:[.19444,.44444,.01597,0],122:[0,.44444,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.34444,0,0],168:[0,.69444,0,0],172:[0,.44444,0,0],175:[0,.59611,0,0],176:[0,.69444,0,0],177:[.13333,.63333,0,0],180:[0,.69444,0,0],215:[.13333,.63333,0,0],247:[.13333,.63333,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],710:[0,.69444,0,0],711:[0,.63194,0,0],713:[0,.59611,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.69444,0,0],730:[0,.69444,0,0],732:[0,.69444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.69444,0,0],772:[0,.59611,0,0],774:[0,.69444,0,0],775:[0,.69444,0,0],776:[0,.69444,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],824:[.19444,.69444,0,0],915:[0,.68611,0,0],916:[0,.68611,0,0],920:[0,.68611,0,0],923:[0,.68611,0,0],926:[0,.68611,0,0],928:[0,.68611,0,0],931:[0,.68611,0,0],933:[0,.68611,0,0],934:[0,.68611,0,0],936:[0,.68611,0,0],937:[0,.68611,0,0],8211:[0,.44444,.03194,0],8212:[0,.44444,.03194,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8242:[0,.55556,0,0],8407:[0,.72444,.15486,0],8463:[0,.69444,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,0],8472:[.19444,.44444,0,0],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.10889,.39111,0,0],8593:[.19444,.69444,0,0],8594:[-.10889,.39111,0,0],8595:[.19444,.69444,0,0],8596:[-.10889,.39111,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8636:[-.10889,.39111,0,0],8637:[-.10889,.39111,0,0],8640:[-.10889,.39111,0,0],8641:[-.10889,.39111,0,0],8656:[-.10889,.39111,0,0],8657:[.19444,.69444,0,0],8658:[-.10889,.39111,0,0],8659:[.19444,.69444,0,0],8660:[-.10889,.39111,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.06389,0],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68611,0,0],8712:[.08556,.58556,0,0],8715:[.08556,.58556,0,0],8722:[.13333,.63333,0,0],8723:[.13333,.63333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.02778,.47222,0,0],8728:[-.02639,.47361,0,0],8729:[-.02639,.47361,0,0],8730:[.18,.82,0,0],8733:[0,.44444,0,0],8734:[0,.44444,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.12778,0],8764:[-.10889,.39111,0,0],8768:[.19444,.69444,0,0],8771:[.00222,.50222,0,0],8776:[.02444,.52444,0,0],8781:[.00222,.50222,0,0],8801:[.00222,.50222,0,0],8804:[.19667,.69667,0,0],8805:[.19667,.69667,0,0],8810:[.08556,.58556,0,0],8811:[.08556,.58556,0,0],8826:[.08556,.58556,0,0],8827:[.08556,.58556,0,0],8834:[.08556,.58556,0,0],8835:[.08556,.58556,0,0],8838:[.19667,.69667,0,0],8839:[.19667,.69667,0,0],8846:[0,.55556,0,0],8849:[.19667,.69667,0,0],8850:[.19667,.69667,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.13333,.63333,0,0],8854:[.13333,.63333,0,0],8855:[.13333,.63333,0,0],8856:[.13333,.63333,0,0],8857:[.13333,.63333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8900:[-.02639,.47361,0,0],8901:[-.02639,.47361,0,0],8902:[-.02778,.47222,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.13889,.36111,0,0],8995:[-.13889,.36111,0,0],9651:[.19444,.69444,0,0],9657:[-.02778,.47222,0,0],9661:[.19444,.69444,0,0],9667:[-.02778,.47222,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10815:[0,.68611,0,0],10927:[.19667,.69667,0,0],10928:[.19667,.69667,0,0]},"Main-Italic":{33:[0,.69444,.12417,0],34:[0,.69444,.06961,0],35:[.19444,.69444,.06616,0],37:[.05556,.75,.13639,0],38:[0,.69444,.09694,0],39:[0,.69444,.12417,0],40:[.25,.75,.16194,0],41:[.25,.75,.03694,0],42:[0,.75,.14917,0],43:[.05667,.56167,.03694,0],44:[.19444,.10556,0,0],45:[0,.43056,.02826,0],46:[0,.10556,0,0],47:[.25,.75,.16194,0],48:[0,.64444,.13556,0],49:[0,.64444,.13556,0],50:[0,.64444,.13556,0],51:[0,.64444,.13556,0],52:[.19444,.64444,.13556,0],53:[0,.64444,.13556,0],54:[0,.64444,.13556,0],55:[.19444,.64444,.13556,0],56:[0,.64444,.13556,0],57:[0,.64444,.13556,0],58:[0,.43056,.0582,0],59:[.19444,.43056,.0582,0],61:[-.13313,.36687,.06616,0],63:[0,.69444,.1225,0],64:[0,.69444,.09597,0],65:[0,.68333,0,0],66:[0,.68333,.10257,0],67:[0,.68333,.14528,0],68:[0,.68333,.09403,0],69:[0,.68333,.12028,0],70:[0,.68333,.13305,0],71:[0,.68333,.08722,0],72:[0,.68333,.16389,0],73:[0,.68333,.15806,0],74:[0,.68333,.14028,0],75:[0,.68333,.14528,0],76:[0,.68333,0,0],77:[0,.68333,.16389,0],78:[0,.68333,.16389,0],79:[0,.68333,.09403,0],80:[0,.68333,.10257,0],81:[.19444,.68333,.09403,0],82:[0,.68333,.03868,0],83:[0,.68333,.11972,0],84:[0,.68333,.13305,0],85:[0,.68333,.16389,0],86:[0,.68333,.18361,0],87:[0,.68333,.18361,0],88:[0,.68333,.15806,0],89:[0,.68333,.19383,0],90:[0,.68333,.14528,0],91:[.25,.75,.1875,0],93:[.25,.75,.10528,0],94:[0,.69444,.06646,0],95:[.31,.12056,.09208,0],97:[0,.43056,.07671,0],98:[0,.69444,.06312,0],99:[0,.43056,.05653,0],100:[0,.69444,.10333,0],101:[0,.43056,.07514,0],102:[.19444,.69444,.21194,0],103:[.19444,.43056,.08847,0],104:[0,.69444,.07671,0],105:[0,.65536,.1019,0],106:[.19444,.65536,.14467,0],107:[0,.69444,.10764,0],108:[0,.69444,.10333,0],109:[0,.43056,.07671,0],110:[0,.43056,.07671,0],111:[0,.43056,.06312,0],112:[.19444,.43056,.06312,0],113:[.19444,.43056,.08847,0],114:[0,.43056,.10764,0],115:[0,.43056,.08208,0],116:[0,.61508,.09486,0],117:[0,.43056,.07671,0],118:[0,.43056,.10764,0],119:[0,.43056,.10764,0],120:[0,.43056,.12042,0],121:[.19444,.43056,.08847,0],122:[0,.43056,.12292,0],126:[.35,.31786,.11585,0],163:[0,.69444,0,0],305:[0,.43056,0,.02778],567:[.19444,.43056,0,.08334],768:[0,.69444,0,0],769:[0,.69444,.09694,0],770:[0,.69444,.06646,0],771:[0,.66786,.11585,0],772:[0,.56167,.10333,0],774:[0,.69444,.10806,0],775:[0,.66786,.11752,0],776:[0,.66786,.10474,0],778:[0,.69444,0,0],779:[0,.69444,.1225,0],780:[0,.62847,.08295,0],915:[0,.68333,.13305,0],916:[0,.68333,0,0],920:[0,.68333,.09403,0],923:[0,.68333,0,0],926:[0,.68333,.15294,0],928:[0,.68333,.16389,0],931:[0,.68333,.12028,0],933:[0,.68333,.11111,0],934:[0,.68333,.05986,0],936:[0,.68333,.11111,0],937:[0,.68333,.10257,0],8211:[0,.43056,.09208,0],8212:[0,.43056,.09208,0],8216:[0,.69444,.12417,0],8217:[0,.69444,.12417,0],8220:[0,.69444,.1685,0],8221:[0,.69444,.06961,0],8463:[0,.68889,0,0]},"Main-Regular":{32:[0,0,0,0],33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.19444,.10556,0,0],45:[0,.43056,0,0],46:[0,.10556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.43056,0,0],59:[.19444,.43056,0,0],60:[.0391,.5391,0,0],61:[-.13313,.36687,0,0],62:[.0391,.5391,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68333,0,0],66:[0,.68333,0,0],67:[0,.68333,0,0],68:[0,.68333,0,0],69:[0,.68333,0,0],70:[0,.68333,0,0],71:[0,.68333,0,0],72:[0,.68333,0,0],73:[0,.68333,0,0],74:[0,.68333,0,0],75:[0,.68333,0,0],76:[0,.68333,0,0],77:[0,.68333,0,0],78:[0,.68333,0,0],79:[0,.68333,0,0],80:[0,.68333,0,0],81:[.19444,.68333,0,0],82:[0,.68333,0,0],83:[0,.68333,0,0],84:[0,.68333,0,0],85:[0,.68333,0,0],86:[0,.68333,.01389,0],87:[0,.68333,.01389,0],88:[0,.68333,0,0],89:[0,.68333,.025,0],90:[0,.68333,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.12056,.02778,0],96:[0,.69444,0,0],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,0],100:[0,.69444,0,0],101:[0,.43056,0,0],102:[0,.69444,.07778,0],103:[.19444,.43056,.01389,0],104:[0,.69444,0,0],105:[0,.66786,0,0],106:[.19444,.66786,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.19444,.43056,0,0],113:[.19444,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.61508,0,0],117:[0,.43056,0,0],118:[0,.43056,.01389,0],119:[0,.43056,.01389,0],120:[0,.43056,0,0],121:[.19444,.43056,.01389,0],122:[0,.43056,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.31786,0,0],160:[0,0,0,0],168:[0,.66786,0,0],172:[0,.43056,0,0],175:[0,.56778,0,0],176:[0,.69444,0,0],177:[.08333,.58333,0,0],180:[0,.69444,0,0],215:[.08333,.58333,0,0],247:[.08333,.58333,0,0],305:[0,.43056,0,0],567:[.19444,.43056,0,0],710:[0,.69444,0,0],711:[0,.62847,0,0],713:[0,.56778,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.66786,0,0],730:[0,.69444,0,0],732:[0,.66786,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.66786,0,0],772:[0,.56778,0,0],774:[0,.69444,0,0],775:[0,.66786,0,0],776:[0,.66786,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.62847,0,0],824:[.19444,.69444,0,0],915:[0,.68333,0,0],916:[0,.68333,0,0],920:[0,.68333,0,0],923:[0,.68333,0,0],926:[0,.68333,0,0],928:[0,.68333,0,0],931:[0,.68333,0,0],933:[0,.68333,0,0],934:[0,.68333,0,0],936:[0,.68333,0,0],937:[0,.68333,0,0],8211:[0,.43056,.02778,0],8212:[0,.43056,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8230:[0,.12,0,0],8242:[0,.55556,0,0],8407:[0,.71444,.15382,0],8463:[0,.68889,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,.11111],8472:[.19444,.43056,0,.11111],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.13313,.36687,0,0],8593:[.19444,.69444,0,0],8594:[-.13313,.36687,0,0],8595:[.19444,.69444,0,0],8596:[-.13313,.36687,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8614:[.011,.511,0,0],8617:[.011,.511,0,0],8618:[.011,.511,0,0],8636:[-.13313,.36687,0,0],8637:[-.13313,.36687,0,0],8640:[-.13313,.36687,0,0],8641:[-.13313,.36687,0,0],8652:[.011,.671,0,0],8656:[-.13313,.36687,0,0],8657:[.19444,.69444,0,0],8658:[-.13313,.36687,0,0],8659:[.19444,.69444,0,0],8660:[-.13313,.36687,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.05556,.08334],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68333,0,0],8712:[.0391,.5391,0,0],8715:[.0391,.5391,0,0],8722:[.08333,.58333,0,0],8723:[.08333,.58333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.03472,.46528,0,0],8728:[-.05555,.44445,0,0],8729:[-.05555,.44445,0,0],8730:[.2,.8,0,0],8733:[0,.43056,0,0],8734:[0,.43056,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.11111,0],8764:[-.13313,.36687,0,0],8768:[.19444,.69444,0,0],8771:[-.03625,.46375,0,0],8773:[-.022,.589,0,0],8776:[-.01688,.48312,0,0],8781:[-.03625,.46375,0,0],8784:[-.133,.67,0,0],8800:[.215,.716,0,0],8801:[-.03625,.46375,0,0],8804:[.13597,.63597,0,0],8805:[.13597,.63597,0,0],8810:[.0391,.5391,0,0],8811:[.0391,.5391,0,0],8826:[.0391,.5391,0,0],8827:[.0391,.5391,0,0],8834:[.0391,.5391,0,0],8835:[.0391,.5391,0,0],8838:[.13597,.63597,0,0],8839:[.13597,.63597,0,0],8846:[0,.55556,0,0],8849:[.13597,.63597,0,0],8850:[.13597,.63597,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.08333,.58333,0,0],8854:[.08333,.58333,0,0],8855:[.08333,.58333,0,0],8856:[.08333,.58333,0,0],8857:[.08333,.58333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8872:[.249,.75,0,0],8900:[-.05555,.44445,0,0],8901:[-.05555,.44445,0,0],8902:[-.03472,.46528,0,0],8904:[.005,.505,0,0],8942:[.03,.9,0,0],8943:[-.19,.31,0,0],8945:[-.1,.82,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.14236,.35764,0,0],8995:[-.14236,.35764,0,0],9136:[.244,.744,0,0],9137:[.244,.744,0,0],9651:[.19444,.69444,0,0],9657:[-.03472,.46528,0,0],9661:[.19444,.69444,0,0],9667:[-.03472,.46528,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10222:[.244,.744,0,0],10223:[.244,.744,0,0],10229:[.011,.511,0,0],10230:[.011,.511,0,0],10231:[.011,.511,0,0],10232:[.024,.525,0,0],10233:[.024,.525,0,0],10234:[.024,.525,0,0],10236:[.011,.511,0,0],10815:[0,.68333,0,0],10927:[.13597,.63597,0,0],10928:[.13597,.63597,0,0]},"Math-BoldItalic":{47:[.19444,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,.04835,0],67:[0,.68611,.06979,0],68:[0,.68611,.03194,0],69:[0,.68611,.05451,0],70:[0,.68611,.15972,0],71:[0,.68611,0,0],72:[0,.68611,.08229,0],73:[0,.68611,.07778,0],74:[0,.68611,.10069,0],75:[0,.68611,.06979,0],76:[0,.68611,0,0],77:[0,.68611,.11424,0],78:[0,.68611,.11424,0],79:[0,.68611,.03194,0],80:[0,.68611,.15972,0],81:[.19444,.68611,0,0],82:[0,.68611,.00421,0],83:[0,.68611,.05382,0],84:[0,.68611,.15972,0],85:[0,.68611,.11424,0],86:[0,.68611,.25555,0],87:[0,.68611,.15972,0],88:[0,.68611,.07778,0],89:[0,.68611,.25555,0],90:[0,.68611,.06979,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[.19444,.69444,.11042,0],103:[.19444,.44444,.03704,0],104:[0,.69444,0,0],105:[0,.69326,0,0],106:[.19444,.69326,.0622,0],107:[0,.69444,.01852,0],108:[0,.69444,.0088,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,.03704,0],114:[0,.44444,.03194,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.03704,0],119:[0,.44444,.02778,0],120:[0,.44444,0,0],121:[.19444,.44444,.03704,0],122:[0,.44444,.04213,0],915:[0,.68611,.15972,0],916:[0,.68611,0,0],920:[0,.68611,.03194,0],923:[0,.68611,0,0],926:[0,.68611,.07458,0],928:[0,.68611,.08229,0],931:[0,.68611,.05451,0],933:[0,.68611,.15972,0],934:[0,.68611,0,0],936:[0,.68611,.11653,0],937:[0,.68611,.04835,0],945:[0,.44444,0,0],946:[.19444,.69444,.03403,0],947:[.19444,.44444,.06389,0],948:[0,.69444,.03819,0],949:[0,.44444,0,0],950:[.19444,.69444,.06215,0],951:[.19444,.44444,.03704,0],952:[0,.69444,.03194,0],953:[0,.44444,0,0],954:[0,.44444,0,0],955:[0,.69444,0,0],956:[.19444,.44444,0,0],957:[0,.44444,.06898,0],958:[.19444,.69444,.03021,0],959:[0,.44444,0,0],960:[0,.44444,.03704,0],961:[.19444,.44444,0,0],962:[.09722,.44444,.07917,0],963:[0,.44444,.03704,0],964:[0,.44444,.13472,0],965:[0,.44444,.03704,0],966:[.19444,.44444,0,0],967:[.19444,.44444,0,0],968:[.19444,.69444,.03704,0],969:[0,.44444,.03704,0],977:[0,.69444,0,0],981:[.19444,.69444,0,0],982:[0,.44444,.03194,0],1009:[.19444,.44444,0,0],1013:[0,.44444,0,0]},"Math-Italic":{47:[.19444,.69444,0,0],65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"Math-Regular":{65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"SansSerif-Regular":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.125,.08333,0,0],45:[0,.44444,0,0],46:[0,.08333,0,0],47:[.25,.75,0,0],48:[0,.65556,0,0],49:[0,.65556,0,0],50:[0,.65556,0,0],51:[0,.65556,0,0],52:[0,.65556,0,0],53:[0,.65556,0,0],54:[0,.65556,0,0],55:[0,.65556,0,0],56:[0,.65556,0,0],57:[0,.65556,0,0],58:[0,.44444,0,0],59:[.125,.44444,0,0],61:[-.13,.37,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.69444,0,0],66:[0,.69444,0,0],67:[0,.69444,0,0],68:[0,.69444,0,0],69:[0,.69444,0,0],70:[0,.69444,0,0],71:[0,.69444,0,0],72:[0,.69444,0,0],73:[0,.69444,0,0],74:[0,.69444,0,0],75:[0,.69444,0,0],76:[0,.69444,0,0],77:[0,.69444,0,0],78:[0,.69444,0,0],79:[0,.69444,0,0],80:[0,.69444,0,0],81:[.125,.69444,0,0],82:[0,.69444,0,0],83:[0,.69444,0,0],84:[0,.69444,0,0],85:[0,.69444,0,0],86:[0,.69444,.01389,0],87:[0,.69444,.01389,0],88:[0,.69444,0,0],89:[0,.69444,.025,0],90:[0,.69444,0,0],91:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.35,.09444,.02778,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.06944,0],103:[.19444,.44444,.01389,0],104:[0,.69444,0,0],105:[0,.67937,0,0],106:[.19444,.67937,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,.01389,0],115:[0,.44444,0,0],116:[0,.57143,0,0],117:[0,.44444,0,0],118:[0,.44444,.01389,0],119:[0,.44444,.01389,0],120:[0,.44444,0,0],121:[.19444,.44444,.01389,0],122:[0,.44444,0,0],126:[.35,.32659,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.67659,0,0],772:[0,.60889,0,0],774:[0,.69444,0,0],775:[0,.67937,0,0],776:[0,.67937,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],915:[0,.69444,0,0],916:[0,.69444,0,0],920:[0,.69444,0,0],923:[0,.69444,0,0],926:[0,.69444,0,0],928:[0,.69444,0,0],931:[0,.69444,0,0],933:[0,.69444,0,0],934:[0,.69444,0,0],936:[0,.69444,0,0],937:[0,.69444,0,0],8211:[0,.44444,.02778,0],8212:[0,.44444,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0]},"Script-Regular":{65:[0,.7,.22925,0],66:[0,.7,.04087,0],67:[0,.7,.1689,0],68:[0,.7,.09371,0],69:[0,.7,.18583,0],70:[0,.7,.13634,0],71:[0,.7,.17322,0],72:[0,.7,.29694,0],73:[0,.7,.19189,0],74:[.27778,.7,.19189,0],75:[0,.7,.31259,0],76:[0,.7,.19189,0],77:[0,.7,.15981,0],78:[0,.7,.3525,0],79:[0,.7,.08078,0],80:[0,.7,.08078,0],81:[0,.7,.03305,0],82:[0,.7,.06259,0],83:[0,.7,.19189,0],84:[0,.7,.29087,0],85:[0,.7,.25815,0],86:[0,.7,.27523,0],87:[0,.7,.27523,0],88:[0,.7,.26006,0],89:[0,.7,.2939,0],90:[0,.7,.24037,0]},"Size1-Regular":{40:[.35001,.85,0,0],41:[.35001,.85,0,0],47:[.35001,.85,0,0],91:[.35001,.85,0,0],92:[.35001,.85,0,0],93:[.35001,.85,0,0],123:[.35001,.85,0,0],125:[.35001,.85,0,0],710:[0,.72222,0,0],732:[0,.72222,0,0],770:[0,.72222,0,0],771:[0,.72222,0,0],8214:[-99e-5,.601,0,0],8593:[1e-5,.6,0,0],8595:[1e-5,.6,0,0],8657:[1e-5,.6,0,0],8659:[1e-5,.6,0,0],8719:[.25001,.75,0,0],8720:[.25001,.75,0,0],8721:[.25001,.75,0,0],8730:[.35001,.85,0,0],8739:[-.00599,.606,0,0],8741:[-.00599,.606,0,0],8747:[.30612,.805,.19445,0],8748:[.306,.805,.19445,0],8749:[.306,.805,.19445,0],8750:[.30612,.805,.19445,0],8896:[.25001,.75,0,0],8897:[.25001,.75,0,0],8898:[.25001,.75,0,0],8899:[.25001,.75,0,0],8968:[.35001,.85,0,0],8969:[.35001,.85,0,0],8970:[.35001,.85,0,0],8971:[.35001,.85,0,0],9168:[-99e-5,.601,0,0],10216:[.35001,.85,0,0],10217:[.35001,.85,0,0],10752:[.25001,.75,0,0],10753:[.25001,.75,0,0],10754:[.25001,.75,0,0],10756:[.25001,.75,0,0],10758:[.25001,.75,0,0]},"Size2-Regular":{40:[.65002,1.15,0,0],41:[.65002,1.15,0,0],47:[.65002,1.15,0,0],91:[.65002,1.15,0,0],92:[.65002,1.15,0,0],93:[.65002,1.15,0,0],123:[.65002,1.15,0,0],125:[.65002,1.15,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8719:[.55001,1.05,0,0],8720:[.55001,1.05,0,0],8721:[.55001,1.05,0,0],8730:[.65002,1.15,0,0],8747:[.86225,1.36,.44445,0],8748:[.862,1.36,.44445,0],8749:[.862,1.36,.44445,0],8750:[.86225,1.36,.44445,0],8896:[.55001,1.05,0,0],8897:[.55001,1.05,0,0],8898:[.55001,1.05,0,0],8899:[.55001,1.05,0,0],8968:[.65002,1.15,0,0],8969:[.65002,1.15,0,0],8970:[.65002,1.15,0,0],8971:[.65002,1.15,0,0],10216:[.65002,1.15,0,0],10217:[.65002,1.15,0,0],10752:[.55001,1.05,0,0],10753:[.55001,1.05,0,0],10754:[.55001,1.05,0,0],
+10756:[.55001,1.05,0,0],10758:[.55001,1.05,0,0]},"Size3-Regular":{40:[.95003,1.45,0,0],41:[.95003,1.45,0,0],47:[.95003,1.45,0,0],91:[.95003,1.45,0,0],92:[.95003,1.45,0,0],93:[.95003,1.45,0,0],123:[.95003,1.45,0,0],125:[.95003,1.45,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8730:[.95003,1.45,0,0],8968:[.95003,1.45,0,0],8969:[.95003,1.45,0,0],8970:[.95003,1.45,0,0],8971:[.95003,1.45,0,0],10216:[.95003,1.45,0,0],10217:[.95003,1.45,0,0]},"Size4-Regular":{40:[1.25003,1.75,0,0],41:[1.25003,1.75,0,0],47:[1.25003,1.75,0,0],91:[1.25003,1.75,0,0],92:[1.25003,1.75,0,0],93:[1.25003,1.75,0,0],123:[1.25003,1.75,0,0],125:[1.25003,1.75,0,0],710:[0,.825,0,0],732:[0,.825,0,0],770:[0,.825,0,0],771:[0,.825,0,0],8730:[1.25003,1.75,0,0],8968:[1.25003,1.75,0,0],8969:[1.25003,1.75,0,0],8970:[1.25003,1.75,0,0],8971:[1.25003,1.75,0,0],9115:[.64502,1.155,0,0],9116:[1e-5,.6,0,0],9117:[.64502,1.155,0,0],9118:[.64502,1.155,0,0],9119:[1e-5,.6,0,0],9120:[.64502,1.155,0,0],9121:[.64502,1.155,0,0],9122:[-99e-5,.601,0,0],9123:[.64502,1.155,0,0],9124:[.64502,1.155,0,0],9125:[-99e-5,.601,0,0],9126:[.64502,1.155,0,0],9127:[1e-5,.9,0,0],9128:[.65002,1.15,0,0],9129:[.90001,0,0,0],9130:[0,.3,0,0],9131:[1e-5,.9,0,0],9132:[.65002,1.15,0,0],9133:[.90001,0,0,0],9143:[.88502,.915,0,0],10216:[1.25003,1.75,0,0],10217:[1.25003,1.75,0,0],57344:[-.00499,.605,0,0],57345:[-.00499,.605,0,0],57680:[0,.12,0,0],57681:[0,.12,0,0],57682:[0,.12,0,0],57683:[0,.12,0,0]},"Typewriter-Regular":{33:[0,.61111,0,0],34:[0,.61111,0,0],35:[0,.61111,0,0],36:[.08333,.69444,0,0],37:[.08333,.69444,0,0],38:[0,.61111,0,0],39:[0,.61111,0,0],40:[.08333,.69444,0,0],41:[.08333,.69444,0,0],42:[0,.52083,0,0],43:[-.08056,.53055,0,0],44:[.13889,.125,0,0],45:[-.08056,.53055,0,0],46:[0,.125,0,0],47:[.08333,.69444,0,0],48:[0,.61111,0,0],49:[0,.61111,0,0],50:[0,.61111,0,0],51:[0,.61111,0,0],52:[0,.61111,0,0],53:[0,.61111,0,0],54:[0,.61111,0,0],55:[0,.61111,0,0],56:[0,.61111,0,0],57:[0,.61111,0,0],58:[0,.43056,0,0],59:[.13889,.43056,0,0],60:[-.05556,.55556,0,0],61:[-.19549,.41562,0,0],62:[-.05556,.55556,0,0],63:[0,.61111,0,0],64:[0,.61111,0,0],65:[0,.61111,0,0],66:[0,.61111,0,0],67:[0,.61111,0,0],68:[0,.61111,0,0],69:[0,.61111,0,0],70:[0,.61111,0,0],71:[0,.61111,0,0],72:[0,.61111,0,0],73:[0,.61111,0,0],74:[0,.61111,0,0],75:[0,.61111,0,0],76:[0,.61111,0,0],77:[0,.61111,0,0],78:[0,.61111,0,0],79:[0,.61111,0,0],80:[0,.61111,0,0],81:[.13889,.61111,0,0],82:[0,.61111,0,0],83:[0,.61111,0,0],84:[0,.61111,0,0],85:[0,.61111,0,0],86:[0,.61111,0,0],87:[0,.61111,0,0],88:[0,.61111,0,0],89:[0,.61111,0,0],90:[0,.61111,0,0],91:[.08333,.69444,0,0],92:[.08333,.69444,0,0],93:[.08333,.69444,0,0],94:[0,.61111,0,0],95:[.09514,0,0,0],96:[0,.61111,0,0],97:[0,.43056,0,0],98:[0,.61111,0,0],99:[0,.43056,0,0],100:[0,.61111,0,0],101:[0,.43056,0,0],102:[0,.61111,0,0],103:[.22222,.43056,0,0],104:[0,.61111,0,0],105:[0,.61111,0,0],106:[.22222,.61111,0,0],107:[0,.61111,0,0],108:[0,.61111,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.22222,.43056,0,0],113:[.22222,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.55358,0,0],117:[0,.43056,0,0],118:[0,.43056,0,0],119:[0,.43056,0,0],120:[0,.43056,0,0],121:[.22222,.43056,0,0],122:[0,.43056,0,0],123:[.08333,.69444,0,0],124:[.08333,.69444,0,0],125:[.08333,.69444,0,0],126:[0,.61111,0,0],127:[0,.61111,0,0],305:[0,.43056,0,0],567:[.22222,.43056,0,0],768:[0,.61111,0,0],769:[0,.61111,0,0],770:[0,.61111,0,0],771:[0,.61111,0,0],772:[0,.56555,0,0],774:[0,.61111,0,0],776:[0,.61111,0,0],778:[0,.61111,0,0],780:[0,.56597,0,0],915:[0,.61111,0,0],916:[0,.61111,0,0],920:[0,.61111,0,0],923:[0,.61111,0,0],926:[0,.61111,0,0],928:[0,.61111,0,0],931:[0,.61111,0,0],933:[0,.61111,0,0],934:[0,.61111,0,0],936:[0,.61111,0,0],937:[0,.61111,0,0],2018:[0,.61111,0,0],2019:[0,.61111,0,0],8242:[0,.61111,0,0]}}},{}],19:[function(e,t,r){var a=e("./utils");var i=e("./ParseError");var n=e("./parseData");var s=n.ParseNode;function l(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs,argTypes:r.argTypes,greediness:r.greediness===undefined?1:r.greediness,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,infix:!!r.infix,handler:a};for(var n=0;n<e.length;++n){t.exports[e[n]]=i}}var o=function(e){if(e.type==="ordgroup"){return e.value}else{return[e]}};l("\\sqrt",{numArgs:1,numOptionalArgs:1},function(e,t){var r=t[0];var a=t[1];return{type:"sqrt",body:a,index:r}});var u={"\\text":undefined,"\\textrm":"mathrm","\\textsf":"mathsf","\\texttt":"mathtt","\\textnormal":"mathrm","\\textbf":"mathbf","\\textit":"textit"};l(["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textit"],{numArgs:1,argTypes:["text"],greediness:2,allowedInText:true},function(e,t){var r=t[0];return{type:"text",body:o(r),style:u[e.funcName]}});l("\\color",{numArgs:2,allowedInText:true,greediness:3,argTypes:["color","original"]},function(e,t){var r=t[0];var a=t[1];return{type:"color",color:r.value,value:o(a)}});l("\\overline",{numArgs:1},function(e,t){var r=t[0];return{type:"overline",body:r}});l("\\underline",{numArgs:1},function(e,t){var r=t[0];return{type:"underline",body:r}});l("\\rule",{numArgs:2,numOptionalArgs:1,argTypes:["size","size","size"]},function(e,t){var r=t[0];var a=t[1];var i=t[2];return{type:"rule",shift:r&&r.value,width:a.value,height:i.value}});l(["\\kern","\\mkern"],{numArgs:1,argTypes:["size"]},function(e,t){return{type:"kern",dimension:t[0].value}});l("\\KaTeX",{numArgs:0},function(e){return{type:"katex"}});l("\\phantom",{numArgs:1},function(e,t){var r=t[0];return{type:"phantom",value:o(r)}});l(["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],{numArgs:1},function(e,t){var r=t[0];return{type:"mclass",mclass:"m"+e.funcName.substr(5),value:o(r)}});l("\\stackrel",{numArgs:2},function(e,t){var r=t[0];var a=t[1];var i=new s("op",{type:"op",limits:true,alwaysHandleSupSub:true,symbol:false,value:o(a)},a.mode);var n=new s("supsub",{base:i,sup:r,sub:null},r.mode);return{type:"mclass",mclass:"mrel",value:[n]}});l("\\bmod",{numArgs:0},function(e,t){return{type:"mod",modType:"bmod",value:null}});l(["\\pod","\\pmod","\\mod"],{numArgs:1},function(e,t){var r=t[0];return{type:"mod",modType:e.funcName.substr(1),value:o(r)}});var p={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}};var h=["(",")","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\\lceil","\\rceil","<",">","\\langle","\\rangle","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\\lmoustache","\\rmoustache","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];var c={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak"};l(["\\blue","\\orange","\\pink","\\red","\\green","\\gray","\\purple","\\blueA","\\blueB","\\blueC","\\blueD","\\blueE","\\tealA","\\tealB","\\tealC","\\tealD","\\tealE","\\greenA","\\greenB","\\greenC","\\greenD","\\greenE","\\goldA","\\goldB","\\goldC","\\goldD","\\goldE","\\redA","\\redB","\\redC","\\redD","\\redE","\\maroonA","\\maroonB","\\maroonC","\\maroonD","\\maroonE","\\purpleA","\\purpleB","\\purpleC","\\purpleD","\\purpleE","\\mintA","\\mintB","\\mintC","\\grayA","\\grayB","\\grayC","\\grayD","\\grayE","\\grayF","\\grayG","\\grayH","\\grayI","\\kaBlue","\\kaGreen"],{numArgs:1,allowedInText:true,greediness:3},function(e,t){var r=t[0];return{type:"color",color:"katex-"+e.funcName.slice(1),value:o(r)}});l(["\\arcsin","\\arccos","\\arctan","\\arg","\\cos","\\cosh","\\cot","\\coth","\\csc","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\tan","\\tanh"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:false,body:e.funcName}});l(["\\det","\\gcd","\\inf","\\lim","\\liminf","\\limsup","\\max","\\min","\\Pr","\\sup"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:false,body:e.funcName}});l(["\\int","\\iint","\\iiint","\\oint"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:true,body:e.funcName}});l(["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:true,body:e.funcName}});l("\\mathop",{numArgs:1},function(e,t){var r=t[0];return{type:"op",limits:false,symbol:false,value:o(r)}});l(["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac"],{numArgs:2,greediness:2},function(e,t){var r=t[0];var a=t[1];var i;var n=null;var s=null;var l="auto";switch(e.funcName){case"\\dfrac":case"\\frac":case"\\tfrac":i=true;break;case"\\\\atopfrac":i=false;break;case"\\dbinom":case"\\binom":case"\\tbinom":i=false;n="(";s=")";break;default:throw new Error("Unrecognized genfrac command")}switch(e.funcName){case"\\dfrac":case"\\dbinom":l="display";break;case"\\tfrac":case"\\tbinom":l="text";break}return{type:"genfrac",numer:r,denom:a,hasBarLine:i,leftDelim:n,rightDelim:s,size:l}});l(["\\llap","\\rlap"],{numArgs:1,allowedInText:true},function(e,t){var r=t[0];return{type:e.funcName.slice(1),body:r}});var m=function(e,t){if(a.contains(h,e.value)){return e}else{throw new i("Invalid delimiter: '"+e.value+"' after '"+t.funcName+"'",e)}};l(["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"delimsizing",size:p[e.funcName].size,mclass:p[e.funcName].mclass,value:r.value}});l(["\\left","\\right"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"leftright",value:r.value}});l("\\middle",{numArgs:1},function(e,t){var r=m(t[0],e);if(!e.parser.leftrightDepth){throw new i("\\middle without preceding \\left",r)}return{type:"middle",value:r.value}});l(["\\tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"],0,null);l(["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],0,null);l(["\\mathrm","\\mathit","\\mathbf","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],{numArgs:1,greediness:2},function(e,t){var r=t[0];var a=e.funcName;if(a in c){a=c[a]}return{type:"font",font:a.slice(1),body:r}});l(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot"],{numArgs:1},function(e,t){var r=t[0];return{type:"accent",accent:e.funcName,base:r}});l(["\\over","\\choose","\\atop"],{numArgs:0,infix:true},function(e){var t;switch(e.funcName){case"\\over":t="\\frac";break;case"\\choose":t="\\binom";break;case"\\atop":t="\\\\atopfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",replaceWith:t,token:e.token}});l(["\\\\","\\cr"],{numArgs:0,numOptionalArgs:1,argTypes:["size"]},function(e,t){var r=t[0];return{type:"cr",size:r}});l(["\\begin","\\end"],{numArgs:1,argTypes:["text"]},function(e,t){var r=t[0];if(r.type!=="ordgroup"){throw new i("Invalid environment name",r)}var a="";for(var n=0;n<r.value.length;++n){a+=r.value[n].value}return{type:"environment",name:a,nameGroup:r}})},{"./ParseError":6,"./parseData":21,"./utils":25}],20:[function(e,t,r){var a=e("./utils");function i(e,t){this.type=e;this.attributes={};this.children=t||[]}i.prototype.setAttribute=function(e,t){this.attributes[e]=t};i.prototype.toNode=function(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,t)){e.setAttribute(t,this.attributes[t])}}for(var r=0;r<this.children.length;r++){e.appendChild(this.children[r].toNode())}return e};i.prototype.toMarkup=function(){var e="<"+this.type;for(var t in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,t)){e+=" "+t+'="';e+=a.escape(this.attributes[t]);e+='"'}}e+=">";for(var r=0;r<this.children.length;r++){e+=this.children[r].toMarkup()}e+="</"+this.type+">";return e};function n(e){this.text=e}n.prototype.toNode=function(){return document.createTextNode(this.text)};n.prototype.toMarkup=function(){return a.escape(this.text)};t.exports={MathNode:i,TextNode:n}},{"./utils":25}],21:[function(e,t,r){function a(e,t,r,a,i){this.type=e;this.value=t;this.mode=r;if(a&&(!i||i.lexer===a.lexer)){this.lexer=a.lexer;this.start=a.start;this.end=(i||a).end}}t.exports={ParseNode:a}},{}],22:[function(e,t,r){var a=e("./Parser");var i=function(e,t){if(!(typeof e==="string"||e instanceof String)){throw new TypeError("KaTeX can only parse string typed expression")}var r=new a(e,t);return r.parse()};t.exports=i},{"./Parser":7}],23:[function(e,t,r){t.exports={math:{},text:{}};function a(e,r,a,i,n){t.exports[e][n]={font:r,group:a,replace:i}}var i="math";var n="text";var s="main";var l="ams";var o="accent";var u="bin";var p="close";var h="inner";var c="mathord";var m="op";var f="open";var v="punct";var d="rel";var g="spacing";var y="textord";a(i,s,d,"\u2261","\\equiv");a(i,s,d,"\u227a","\\prec");a(i,s,d,"\u227b","\\succ");a(i,s,d,"\u223c","\\sim");a(i,s,d,"\u22a5","\\perp");a(i,s,d,"\u2aaf","\\preceq");a(i,s,d,"\u2ab0","\\succeq");a(i,s,d,"\u2243","\\simeq");a(i,s,d,"\u2223","\\mid");a(i,s,d,"\u226a","\\ll");a(i,s,d,"\u226b","\\gg");a(i,s,d,"\u224d","\\asymp");a(i,s,d,"\u2225","\\parallel");a(i,s,d,"\u22c8","\\bowtie");a(i,s,d,"\u2323","\\smile");a(i,s,d,"\u2291","\\sqsubseteq");a(i,s,d,"\u2292","\\sqsupseteq");a(i,s,d,"\u2250","\\doteq");a(i,s,d,"\u2322","\\frown");a(i,s,d,"\u220b","\\ni");a(i,s,d,"\u221d","\\propto");a(i,s,d,"\u22a2","\\vdash");a(i,s,d,"\u22a3","\\dashv");a(i,s,d,"\u220b","\\owns");a(i,s,v,".","\\ldotp");a(i,s,v,"\u22c5","\\cdotp");a(i,s,y,"#","\\#");a(n,s,y,"#","\\#");a(i,s,y,"&","\\&");a(n,s,y,"&","\\&");a(i,s,y,"\u2135","\\aleph");a(i,s,y,"\u2200","\\forall");a(i,s,y,"\u210f","\\hbar");a(i,s,y,"\u2203","\\exists");a(i,s,y,"\u2207","\\nabla");a(i,s,y,"\u266d","\\flat");a(i,s,y,"\u2113","\\ell");a(i,s,y,"\u266e","\\natural");a(i,s,y,"\u2663","\\clubsuit");a(i,s,y,"\u2118","\\wp");a(i,s,y,"\u266f","\\sharp");a(i,s,y,"\u2662","\\diamondsuit");a(i,s,y,"\u211c","\\Re");a(i,s,y,"\u2661","\\heartsuit");a(i,s,y,"\u2111","\\Im");a(i,s,y,"\u2660","\\spadesuit");a(i,s,y,"\u2020","\\dag");a(i,s,y,"\u2021","\\ddag");a(i,s,p,"\u23b1","\\rmoustache");a(i,s,f,"\u23b0","\\lmoustache");a(i,s,p,"\u27ef","\\rgroup");a(i,s,f,"\u27ee","\\lgroup");a(i,s,u,"\u2213","\\mp");a(i,s,u,"\u2296","\\ominus");a(i,s,u,"\u228e","\\uplus");a(i,s,u,"\u2293","\\sqcap");a(i,s,u,"\u2217","\\ast");a(i,s,u,"\u2294","\\sqcup");a(i,s,u,"\u25ef","\\bigcirc");a(i,s,u,"\u2219","\\bullet");a(i,s,u,"\u2021","\\ddagger");a(i,s,u,"\u2240","\\wr");a(i,s,u,"\u2a3f","\\amalg");a(i,s,d,"\u27f5","\\longleftarrow");a(i,s,d,"\u21d0","\\Leftarrow");a(i,s,d,"\u27f8","\\Longleftarrow");a(i,s,d,"\u27f6","\\longrightarrow");a(i,s,d,"\u21d2","\\Rightarrow");a(i,s,d,"\u27f9","\\Longrightarrow");a(i,s,d,"\u2194","\\leftrightarrow");a(i,s,d,"\u27f7","\\longleftrightarrow");a(i,s,d,"\u21d4","\\Leftrightarrow");a(i,s,d,"\u27fa","\\Longleftrightarrow");a(i,s,d,"\u21a6","\\mapsto");a(i,s,d,"\u27fc","\\longmapsto");a(i,s,d,"\u2197","\\nearrow");a(i,s,d,"\u21a9","\\hookleftarrow");a(i,s,d,"\u21aa","\\hookrightarrow");a(i,s,d,"\u2198","\\searrow");a(i,s,d,"\u21bc","\\leftharpoonup");a(i,s,d,"\u21c0","\\rightharpoonup");a(i,s,d,"\u2199","\\swarrow");a(i,s,d,"\u21bd","\\leftharpoondown");a(i,s,d,"\u21c1","\\rightharpoondown");a(i,s,d,"\u2196","\\nwarrow");a(i,s,d,"\u21cc","\\rightleftharpoons");a(i,l,d,"\u226e","\\nless");a(i,l,d,"\ue010","\\nleqslant");a(i,l,d,"\ue011","\\nleqq");a(i,l,d,"\u2a87","\\lneq");a(i,l,d,"\u2268","\\lneqq");a(i,l,d,"\ue00c","\\lvertneqq");a(i,l,d,"\u22e6","\\lnsim");a(i,l,d,"\u2a89","\\lnapprox");a(i,l,d,"\u2280","\\nprec");a(i,l,d,"\u22e0","\\npreceq");a(i,l,d,"\u22e8","\\precnsim");a(i,l,d,"\u2ab9","\\precnapprox");a(i,l,d,"\u2241","\\nsim");a(i,l,d,"\ue006","\\nshortmid");a(i,l,d,"\u2224","\\nmid");a(i,l,d,"\u22ac","\\nvdash");a(i,l,d,"\u22ad","\\nvDash");a(i,l,d,"\u22ea","\\ntriangleleft");a(i,l,d,"\u22ec","\\ntrianglelefteq");a(i,l,d,"\u228a","\\subsetneq");a(i,l,d,"\ue01a","\\varsubsetneq");a(i,l,d,"\u2acb","\\subsetneqq");a(i,l,d,"\ue017","\\varsubsetneqq");a(i,l,d,"\u226f","\\ngtr");a(i,l,d,"\ue00f","\\ngeqslant");a(i,l,d,"\ue00e","\\ngeqq");a(i,l,d,"\u2a88","\\gneq");a(i,l,d,"\u2269","\\gneqq");a(i,l,d,"\ue00d","\\gvertneqq");a(i,l,d,"\u22e7","\\gnsim");a(i,l,d,"\u2a8a","\\gnapprox");a(i,l,d,"\u2281","\\nsucc");a(i,l,d,"\u22e1","\\nsucceq");a(i,l,d,"\u22e9","\\succnsim");a(i,l,d,"\u2aba","\\succnapprox");a(i,l,d,"\u2246","\\ncong");a(i,l,d,"\ue007","\\nshortparallel");a(i,l,d,"\u2226","\\nparallel");a(i,l,d,"\u22af","\\nVDash");a(i,l,d,"\u22eb","\\ntriangleright");a(i,l,d,"\u22ed","\\ntrianglerighteq");a(i,l,d,"\ue018","\\nsupseteqq");a(i,l,d,"\u228b","\\supsetneq");a(i,l,d,"\ue01b","\\varsupsetneq");a(i,l,d,"\u2acc","\\supsetneqq");a(i,l,d,"\ue019","\\varsupsetneqq");a(i,l,d,"\u22ae","\\nVdash");a(i,l,d,"\u2ab5","\\precneqq");a(i,l,d,"\u2ab6","\\succneqq");a(i,l,d,"\ue016","\\nsubseteqq");a(i,l,u,"\u22b4","\\unlhd");a(i,l,u,"\u22b5","\\unrhd");a(i,l,d,"\u219a","\\nleftarrow");a(i,l,d,"\u219b","\\nrightarrow");a(i,l,d,"\u21cd","\\nLeftarrow");a(i,l,d,"\u21cf","\\nRightarrow");a(i,l,d,"\u21ae","\\nleftrightarrow");a(i,l,d,"\u21ce","\\nLeftrightarrow");a(i,l,d,"\u25b3","\\vartriangle");a(i,l,y,"\u210f","\\hslash");a(i,l,y,"\u25bd","\\triangledown");a(i,l,y,"\u25ca","\\lozenge");a(i,l,y,"\u24c8","\\circledS");a(i,l,y,"\xae","\\circledR");a(i,l,y,"\u2221","\\measuredangle");a(i,l,y,"\u2204","\\nexists");a(i,l,y,"\u2127","\\mho");a(i,l,y,"\u2132","\\Finv");a(i,l,y,"\u2141","\\Game");a(i,l,y,"k","\\Bbbk");a(i,l,y,"\u2035","\\backprime");a(i,l,y,"\u25b2","\\blacktriangle");a(i,l,y,"\u25bc","\\blacktriangledown");a(i,l,y,"\u25a0","\\blacksquare");a(i,l,y,"\u29eb","\\blacklozenge");a(i,l,y,"\u2605","\\bigstar");a(i,l,y,"\u2222","\\sphericalangle");a(i,l,y,"\u2201","\\complement");a(i,l,y,"\xf0","\\eth");a(i,l,y,"\u2571","\\diagup");a(i,l,y,"\u2572","\\diagdown");a(i,l,y,"\u25a1","\\square");a(i,l,y,"\u25a1","\\Box");a(i,l,y,"\u25ca","\\Diamond");a(i,l,y,"\xa5","\\yen");a(i,l,y,"\u2713","\\checkmark");a(i,l,y,"\u2136","\\beth");a(i,l,y,"\u2138","\\daleth");a(i,l,y,"\u2137","\\gimel");a(i,l,y,"\u03dd","\\digamma");a(i,l,y,"\u03f0","\\varkappa");a(i,l,f,"\u250c","\\ulcorner");a(i,l,p,"\u2510","\\urcorner");a(i,l,f,"\u2514","\\llcorner");a(i,l,p,"\u2518","\\lrcorner");a(i,l,d,"\u2266","\\leqq");a(i,l,d,"\u2a7d","\\leqslant");a(i,l,d,"\u2a95","\\eqslantless");a(i,l,d,"\u2272","\\lesssim");a(i,l,d,"\u2a85","\\lessapprox");a(i,l,d,"\u224a","\\approxeq");a(i,l,u,"\u22d6","\\lessdot");a(i,l,d,"\u22d8","\\lll");a(i,l,d,"\u2276","\\lessgtr");a(i,l,d,"\u22da","\\lesseqgtr");a(i,l,d,"\u2a8b","\\lesseqqgtr");a(i,l,d,"\u2251","\\doteqdot");a(i,l,d,"\u2253","\\risingdotseq");a(i,l,d,"\u2252","\\fallingdotseq");a(i,l,d,"\u223d","\\backsim");a(i,l,d,"\u22cd","\\backsimeq");a(i,l,d,"\u2ac5","\\subseteqq");a(i,l,d,"\u22d0","\\Subset");a(i,l,d,"\u228f","\\sqsubset");a(i,l,d,"\u227c","\\preccurlyeq");a(i,l,d,"\u22de","\\curlyeqprec");a(i,l,d,"\u227e","\\precsim");a(i,l,d,"\u2ab7","\\precapprox");a(i,l,d,"\u22b2","\\vartriangleleft");a(i,l,d,"\u22b4","\\trianglelefteq");a(i,l,d,"\u22a8","\\vDash");a(i,l,d,"\u22aa","\\Vvdash");a(i,l,d,"\u2323","\\smallsmile");a(i,l,d,"\u2322","\\smallfrown");a(i,l,d,"\u224f","\\bumpeq");a(i,l,d,"\u224e","\\Bumpeq");a(i,l,d,"\u2267","\\geqq");a(i,l,d,"\u2a7e","\\geqslant");a(i,l,d,"\u2a96","\\eqslantgtr");a(i,l,d,"\u2273","\\gtrsim");a(i,l,d,"\u2a86","\\gtrapprox");a(i,l,u,"\u22d7","\\gtrdot");a(i,l,d,"\u22d9","\\ggg");a(i,l,d,"\u2277","\\gtrless");a(i,l,d,"\u22db","\\gtreqless");a(i,l,d,"\u2a8c","\\gtreqqless");a(i,l,d,"\u2256","\\eqcirc");a(i,l,d,"\u2257","\\circeq");a(i,l,d,"\u225c","\\triangleq");a(i,l,d,"\u223c","\\thicksim");a(i,l,d,"\u2248","\\thickapprox");a(i,l,d,"\u2ac6","\\supseteqq");a(i,l,d,"\u22d1","\\Supset");a(i,l,d,"\u2290","\\sqsupset");a(i,l,d,"\u227d","\\succcurlyeq");a(i,l,d,"\u22df","\\curlyeqsucc");a(i,l,d,"\u227f","\\succsim");a(i,l,d,"\u2ab8","\\succapprox");a(i,l,d,"\u22b3","\\vartriangleright");a(i,l,d,"\u22b5","\\trianglerighteq");a(i,l,d,"\u22a9","\\Vdash");a(i,l,d,"\u2223","\\shortmid");a(i,l,d,"\u2225","\\shortparallel");a(i,l,d,"\u226c","\\between");a(i,l,d,"\u22d4","\\pitchfork");a(i,l,d,"\u221d","\\varpropto");a(i,l,d,"\u25c0","\\blacktriangleleft");a(i,l,d,"\u2234","\\therefore");a(i,l,d,"\u220d","\\backepsilon");a(i,l,d,"\u25b6","\\blacktriangleright");a(i,l,d,"\u2235","\\because");a(i,l,d,"\u22d8","\\llless");a(i,l,d,"\u22d9","\\gggtr");a(i,l,u,"\u22b2","\\lhd");a(i,l,u,"\u22b3","\\rhd");a(i,l,d,"\u2242","\\eqsim");a(i,s,d,"\u22c8","\\Join");a(i,l,d,"\u2251","\\Doteq");a(i,l,u,"\u2214","\\dotplus");a(i,l,u,"\u2216","\\smallsetminus");a(i,l,u,"\u22d2","\\Cap");a(i,l,u,"\u22d3","\\Cup");a(i,l,u,"\u2a5e","\\doublebarwedge");a(i,l,u,"\u229f","\\boxminus");a(i,l,u,"\u229e","\\boxplus");a(i,l,u,"\u22c7","\\divideontimes");a(i,l,u,"\u22c9","\\ltimes");a(i,l,u,"\u22ca","\\rtimes");a(i,l,u,"\u22cb","\\leftthreetimes");a(i,l,u,"\u22cc","\\rightthreetimes");a(i,l,u,"\u22cf","\\curlywedge");a(i,l,u,"\u22ce","\\curlyvee");a(i,l,u,"\u229d","\\circleddash");a(i,l,u,"\u229b","\\circledast");a(i,l,u,"\u22c5","\\centerdot");a(i,l,u,"\u22ba","\\intercal");a(i,l,u,"\u22d2","\\doublecap");a(i,l,u,"\u22d3","\\doublecup");a(i,l,u,"\u22a0","\\boxtimes");a(i,l,d,"\u21e2","\\dashrightarrow");a(i,l,d,"\u21e0","\\dashleftarrow");a(i,l,d,"\u21c7","\\leftleftarrows");a(i,l,d,"\u21c6","\\leftrightarrows");a(i,l,d,"\u21da","\\Lleftarrow");a(i,l,d,"\u219e","\\twoheadleftarrow");a(i,l,d,"\u21a2","\\leftarrowtail");a(i,l,d,"\u21ab","\\looparrowleft");a(i,l,d,"\u21cb","\\leftrightharpoons");a(i,l,d,"\u21b6","\\curvearrowleft");a(i,l,d,"\u21ba","\\circlearrowleft");a(i,l,d,"\u21b0","\\Lsh");a(i,l,d,"\u21c8","\\upuparrows");a(i,l,d,"\u21bf","\\upharpoonleft");a(i,l,d,"\u21c3","\\downharpoonleft");a(i,l,d,"\u22b8","\\multimap");a(i,l,d,"\u21ad","\\leftrightsquigarrow");a(i,l,d,"\u21c9","\\rightrightarrows");a(i,l,d,"\u21c4","\\rightleftarrows");a(i,l,d,"\u21a0","\\twoheadrightarrow");a(i,l,d,"\u21a3","\\rightarrowtail");a(i,l,d,"\u21ac","\\looparrowright");a(i,l,d,"\u21b7","\\curvearrowright");a(i,l,d,"\u21bb","\\circlearrowright");a(i,l,d,"\u21b1","\\Rsh");a(i,l,d,"\u21ca","\\downdownarrows");a(i,l,d,"\u21be","\\upharpoonright");a(i,l,d,"\u21c2","\\downharpoonright");a(i,l,d,"\u21dd","\\rightsquigarrow");a(i,l,d,"\u21dd","\\leadsto");a(i,l,d,"\u21db","\\Rrightarrow");a(i,l,d,"\u21be","\\restriction");a(i,s,y,"\u2018","`");a(i,s,y,"$","\\$");a(n,s,y,"$","\\$");a(i,s,y,"%","\\%");a(n,s,y,"%","\\%");a(i,s,y,"_","\\_");a(n,s,y,"_","\\_");a(i,s,y,"\u2220","\\angle");a(i,s,y,"\u221e","\\infty");a(i,s,y,"\u2032","\\prime");a(i,s,y,"\u25b3","\\triangle");a(i,s,y,"\u0393","\\Gamma");a(i,s,y,"\u0394","\\Delta");a(i,s,y,"\u0398","\\Theta");a(i,s,y,"\u039b","\\Lambda");a(i,s,y,"\u039e","\\Xi");a(i,s,y,"\u03a0","\\Pi");a(i,s,y,"\u03a3","\\Sigma");a(i,s,y,"\u03a5","\\Upsilon");a(i,s,y,"\u03a6","\\Phi");a(i,s,y,"\u03a8","\\Psi");a(i,s,y,"\u03a9","\\Omega");a(i,s,y,"\xac","\\neg");a(i,s,y,"\xac","\\lnot");a(i,s,y,"\u22a4","\\top");a(i,s,y,"\u22a5","\\bot");a(i,s,y,"\u2205","\\emptyset");a(i,l,y,"\u2205","\\varnothing");a(i,s,c,"\u03b1","\\alpha");a(i,s,c,"\u03b2","\\beta");a(i,s,c,"\u03b3","\\gamma");a(i,s,c,"\u03b4","\\delta");a(i,s,c,"\u03f5","\\epsilon");a(i,s,c,"\u03b6","\\zeta");a(i,s,c,"\u03b7","\\eta");a(i,s,c,"\u03b8","\\theta");a(i,s,c,"\u03b9","\\iota");a(i,s,c,"\u03ba","\\kappa");a(i,s,c,"\u03bb","\\lambda");a(i,s,c,"\u03bc","\\mu");a(i,s,c,"\u03bd","\\nu");a(i,s,c,"\u03be","\\xi");a(i,s,c,"o","\\omicron");a(i,s,c,"\u03c0","\\pi");a(i,s,c,"\u03c1","\\rho");a(i,s,c,"\u03c3","\\sigma");a(i,s,c,"\u03c4","\\tau");a(i,s,c,"\u03c5","\\upsilon");a(i,s,c,"\u03d5","\\phi");a(i,s,c,"\u03c7","\\chi");a(i,s,c,"\u03c8","\\psi");a(i,s,c,"\u03c9","\\omega");a(i,s,c,"\u03b5","\\varepsilon");a(i,s,c,"\u03d1","\\vartheta");a(i,s,c,"\u03d6","\\varpi");a(i,s,c,"\u03f1","\\varrho");a(i,s,c,"\u03c2","\\varsigma");a(i,s,c,"\u03c6","\\varphi");a(i,s,u,"\u2217","*");a(i,s,u,"+","+");a(i,s,u,"\u2212","-");a(i,s,u,"\u22c5","\\cdot");a(i,s,u,"\u2218","\\circ");a(i,s,u,"\xf7","\\div");a(i,s,u,"\xb1","\\pm");a(i,s,u,"\xd7","\\times");a(i,s,u,"\u2229","\\cap");a(i,s,u,"\u222a","\\cup");a(i,s,u,"\u2216","\\setminus");a(i,s,u,"\u2227","\\land");a(i,s,u,"\u2228","\\lor");a(i,s,u,"\u2227","\\wedge");a(i,s,u,"\u2228","\\vee");a(i,s,y,"\u221a","\\surd");a(i,s,f,"(","(");a(i,s,f,"[","[");a(i,s,f,"\u27e8","\\langle");a(i,s,f,"\u2223","\\lvert");a(i,s,f,"\u2225","\\lVert");a(i,s,p,")",")");a(i,s,p,"]","]");a(i,s,p,"?","?");a(i,s,p,"!","!");a(i,s,p,"\u27e9","\\rangle");a(i,s,p,"\u2223","\\rvert");a(i,s,p,"\u2225","\\rVert");a(i,s,d,"=","=");a(i,s,d,"<","<");a(i,s,d,">",">");a(i,s,d,":",":");a(i,s,d,"\u2248","\\approx");a(i,s,d,"\u2245","\\cong");a(i,s,d,"\u2265","\\ge");a(i,s,d,"\u2265","\\geq");a(i,s,d,"\u2190","\\gets");a(i,s,d,">","\\gt");a(i,s,d,"\u2208","\\in");a(i,s,d,"\u2209","\\notin");a(i,s,d,"\u2282","\\subset");a(i,s,d,"\u2283","\\supset");a(i,s,d,"\u2286","\\subseteq");a(i,s,d,"\u2287","\\supseteq");a(i,l,d,"\u2288","\\nsubseteq");a(i,l,d,"\u2289","\\nsupseteq");a(i,s,d,"\u22a8","\\models");a(i,s,d,"\u2190","\\leftarrow");a(i,s,d,"\u2264","\\le");a(i,s,d,"\u2264","\\leq");a(i,s,d,"<","\\lt");a(i,s,d,"\u2260","\\ne");a(i,s,d,"\u2260","\\neq");a(i,s,d,"\u2192","\\rightarrow");a(i,s,d,"\u2192","\\to");a(i,l,d,"\u2271","\\ngeq");a(i,l,d,"\u2270","\\nleq");a(i,s,g,null,"\\!");a(i,s,g,"\xa0","\\ ");a(i,s,g,"\xa0","~");a(i,s,g,null,"\\,");a(i,s,g,null,"\\:");a(i,s,g,null,"\\;");a(i,s,g,null,"\\enspace");a(i,s,g,null,"\\qquad");a(i,s,g,null,"\\quad");a(i,s,g,"\xa0","\\space");a(i,s,v,",",",");a(i,s,v,";",";");a(i,s,v,":","\\colon");a(i,l,u,"\u22bc","\\barwedge");a(i,l,u,"\u22bb","\\veebar");a(i,s,u,"\u2299","\\odot");a(i,s,u,"\u2295","\\oplus");a(i,s,u,"\u2297","\\otimes");a(i,s,y,"\u2202","\\partial");a(i,s,u,"\u2298","\\oslash");a(i,l,u,"\u229a","\\circledcirc");a(i,l,u,"\u22a1","\\boxdot");a(i,s,u,"\u25b3","\\bigtriangleup");a(i,s,u,"\u25bd","\\bigtriangledown");a(i,s,u,"\u2020","\\dagger");a(i,s,u,"\u22c4","\\diamond");a(i,s,u,"\u22c6","\\star");a(i,s,u,"\u25c3","\\triangleleft");a(i,s,u,"\u25b9","\\triangleright");a(i,s,f,"{","\\{");a(n,s,y,"{","\\{");a(i,s,p,"}","\\}");a(n,s,y,"}","\\}");a(i,s,f,"{","\\lbrace");a(i,s,p,"}","\\rbrace");a(i,s,f,"[","\\lbrack");a(i,s,p,"]","\\rbrack");a(i,s,f,"\u230a","\\lfloor");a(i,s,p,"\u230b","\\rfloor");a(i,s,f,"\u2308","\\lceil");a(i,s,p,"\u2309","\\rceil");a(i,s,y,"\\","\\backslash");a(i,s,y,"\u2223","|");a(i,s,y,"\u2223","\\vert");a(i,s,y,"\u2225","\\|");a(i,s,y,"\u2225","\\Vert");a(i,s,d,"\u2191","\\uparrow");a(i,s,d,"\u21d1","\\Uparrow");a(i,s,d,"\u2193","\\downarrow");a(i,s,d,"\u21d3","\\Downarrow");a(i,s,d,"\u2195","\\updownarrow");a(i,s,d,"\u21d5","\\Updownarrow");a(i,i,m,"\u2210","\\coprod");a(i,i,m,"\u22c1","\\bigvee");a(i,i,m,"\u22c0","\\bigwedge");a(i,i,m,"\u2a04","\\biguplus");a(i,i,m,"\u22c2","\\bigcap");a(i,i,m,"\u22c3","\\bigcup");a(i,i,m,"\u222b","\\int");a(i,i,m,"\u222b","\\intop");a(i,i,m,"\u222c","\\iint");a(i,i,m,"\u222d","\\iiint");a(i,i,m,"\u220f","\\prod");a(i,i,m,"\u2211","\\sum");a(i,i,m,"\u2a02","\\bigotimes");a(i,i,m,"\u2a01","\\bigoplus");a(i,i,m,"\u2a00","\\bigodot");a(i,i,m,"\u222e","\\oint");a(i,i,m,"\u2a06","\\bigsqcup");a(i,i,m,"\u222b","\\smallint");a(n,s,h,"\u2026","\\textellipsis");a(i,s,h,"\u2026","\\mathellipsis");a(n,s,h,"\u2026","\\ldots");a(i,s,h,"\u2026","\\ldots");a(i,s,h,"\u22ef","\\cdots");a(i,s,h,"\u22f1","\\ddots");a(i,s,y,"\u22ee","\\vdots");a(i,s,o,"\xb4","\\acute");a(i,s,o,"`","\\grave");a(i,s,o,"\xa8","\\ddot");a(i,s,o,"~","\\tilde");a(i,s,o,"\xaf","\\bar");a(i,s,o,"\u02d8","\\breve");a(i,s,o,"\u02c7","\\check");a(i,s,o,"^","\\hat");a(i,s,o,"\u20d7","\\vec");a(i,s,o,"\u02d9","\\dot");a(i,s,c,"\u0131","\\imath");a(i,s,c,"\u0237","\\jmath");a(n,s,y,"\u2013","--");a(n,s,y,"\u2014","---");a(n,s,y,"\u2018","`");a(n,s,y,"\u2019","'");a(n,s,y,"\u201c","``");a(n,s,y,"\u201d","''");a(i,s,y,"\xb0","\\degree");a(n,s,y,"\xb0","\\degree");a(i,s,c,"\xa3","\\pounds");a(i,l,y,"\u2720","\\maltese");a(n,l,y,"\u2720","\\maltese");a(n,s,g,"\xa0","\\ ");a(n,s,g,"\xa0"," ");a(n,s,g,"\xa0","~");var x;var b;var w='0123456789/@."';for(x=0;x<w.length;x++){b=w.charAt(x);a(i,s,y,b,b)}var k='0123456789!@*()-=+[]";:?/.,';for(x=0;x<k.length;x++){b=k.charAt(x);a(n,s,y,b,b)}var z="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";for(x=0;x<z.length;x++){b=z.charAt(x);a(i,s,c,b,b);a(n,s,y,b,b)}for(x=192;x<=214;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=216;x<=246;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=248;x<=255;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=1040;x<=1103;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}a(n,s,y,"\u2013","\u2013");a(n,s,y,"\u2014","\u2014");a(n,s,y,"\u2018","\u2018");a(n,s,y,"\u2019","\u2019");a(n,s,y,"\u201c","\u201c");a(n,s,y,"\u201d","\u201d")},{}],24:[function(e,t,r){var a=/[\uAC00-\uD7AF]/;var i=/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/;t.exports={cjkRegex:i,hangulRegex:a}},{}],25:[function(e,t,r){var a=Array.prototype.indexOf;var i=function(e,t){if(e==null){return-1}if(a&&e.indexOf===a){return e.indexOf(t)}var r=0;var i=e.length;for(;r<i;r++){if(e[r]===t){return r}}return-1};var n=function(e,t){return i(e,t)!==-1};var s=function(e,t){return e===undefined?t:e};var l=/([A-Z])/g;var o=function(e){return e.replace(l,"-$1").toLowerCase()};var u={"&":"&amp;",">":"&gt;","<":"&lt;",'"':"&quot;","'":"&#x27;"};var p=/[&><"']/g;function h(e){return u[e]}function c(e){return(""+e).replace(p,h)}var m;if(typeof document!=="undefined"){var f=document.createElement("span");if("textContent"in f){m=function(e,t){e.textContent=t}}else{m=function(e,t){e.innerText=t}}}function v(e){m(e,"")}t.exports={contains:n,deflt:s,escape:c,hyphenate:o,indexOf:i,setTextContent:m,clearNode:v}},{}]},{},[1])(1)});
diff --git a/specs/gl/GLSLangSpec.4.60.html b/specs/gl/GLSLangSpec.4.60.html
new file mode 100644
index 0000000..e289efb
--- /dev/null
+++ b/specs/gl/GLSLangSpec.4.60.html
@@ -0,0 +1,16882 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.7.1">
+<meta name="author" content="John Kessenich, Google (Editor and Author) ; Dave Baldwin and Randi Rost (Version 1.1 Authors)">
+<title>The OpenGL&#174; Shading Language, Version 4.60.6</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
+<style>
+/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
+/* Uncomment @import statement below to use as custom stylesheet */
+/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
+audio,canvas,video{display:inline-block}
+audio:not([controls]){display:none;height:0}
+script{display:none!important}
+html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
+a{background:transparent}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+dfn{font-style:italic}
+hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.center{margin-left:auto;margin-right:auto}
+.stretch{width:100%}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:none}
+p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
+ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
+ul.square{list-style-type:square}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
+abbr{text-transform:none}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
+blockquote cite::before{content:"\2014 \0020"}
+blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
+table thead,table tfoot{background:#f7f8f7}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
+.clearfix::after,.float-group::after{clear:both}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
+pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menuref{color:#000}
+.menuseq b:not(.caret),.menuref{font-weight:inherit}
+.menuseq{word-spacing:-.02em}
+.menuseq b.caret{font-size:1.25em;line-height:.8}
+.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
+b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
+b.button::before{content:"[";padding:0 3px 0 2px}
+b.button::after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
+#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
+#content{margin-top:1.25em}
+#content::before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
+#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span::before{content:"\00a0\2013\00a0"}
+#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark::before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber::after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+@media screen and (min-width:768px){#toctitle{font-size:1.375em}
+body.toc2{padding-left:15em;padding-right:0}
+#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
+@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{width:20em}
+#toc.toc2 #toctitle{font-size:1.375em}
+#toc.toc2>ul{font-size:.95em}
+#toc.toc2 ul ul{padding-left:1.25em}
+body.toc2.toc-right{padding-left:0;padding-right:20em}}
+#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+#content #toc>:first-child{margin-top:0}
+#content #toc>:last-child{margin-bottom:0}
+#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
+#content{margin-bottom:.625em}
+.sect1{padding-bottom:.625em}
+@media screen and (min-width:768px){#content{margin-bottom:1.25em}
+.sect1{padding-bottom:1.25em}}
+.sect1:last-child{padding-bottom:0}
+.sect1+.sect1{border-top:1px solid #efefed}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
+.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
+table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
+.exampleblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child{margin-bottom:0}
+.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+.sidebarblock>:first-child{margin-top:0}
+.sidebarblock>:last-child{margin-bottom:0}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
+.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
+.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
+@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
+@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
+.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
+.listingblock:hover code[data-lang]::before{display:block}
+.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
+.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
+table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
+table.pyhltable td.code{padding-left:.75em;padding-right:0}
+pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
+pre.pygments .lineno{display:inline-block;margin-right:.25em}
+table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
+.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
+.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
+.quoteblock .quoteblock blockquote::before{display:none}
+.verseblock{margin:0 1em 1.25em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract{margin:0 1em 1.25em;display:block}
+.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
+.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{word-spacing:0;line-height:1.6}
+.quoteblock.abstract blockquote::before,.quoteblock.abstract p::before{display:none}
+table.tableblock{max-width:100%;border-collapse:separate}
+p.tableblock:last-child{margin-bottom:0}
+td.tableblock>.content{margin-bottom:-1.25em}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
+table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
+table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
+table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
+table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
+table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
+table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
+table.frame-all{border-width:1px}
+table.frame-sides{border-width:0 1px}
+table.frame-topbot,table.frame-ends{border-width:1px 0}
+table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
+table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+td>div.verse{white-space:pre}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
+ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
+ul.unstyled,ol.unstyled{margin-left:0}
+ul.checklist{margin-left:.625em}
+ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
+ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
+ul.inline>li{margin-left:1.25em}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
+.colist td:not([class]):first-child img{max-width:none}
+.colist td:not([class]):last-child{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
+.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
+.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
+.gist .file-data>table td.line-data{width:99%}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background-color:#00fafa}
+.black{color:#000}
+.black-background{background-color:#000}
+.blue{color:#0000bf}
+.blue-background{background-color:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background-color:#fa00fa}
+.gray{color:#606060}
+.gray-background{background-color:#7d7d7d}
+.green{color:#006000}
+.green-background{background-color:#007d00}
+.lime{color:#00bf00}
+.lime-background{background-color:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background-color:#7d0000}
+.navy{color:#000060}
+.navy-background{background-color:#00007d}
+.olive{color:#606000}
+.olive-background{background-color:#7d7d00}
+.purple{color:#600060}
+.purple-background{background-color:#7d007d}
+.red{color:#bf0000}
+.red-background{background-color:#fa0000}
+.silver{color:#909090}
+.silver-background{background-color:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background-color:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background-color:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background-color:#fafa00}
+span.icon>.fa{cursor:default}
+a span.icon>.fa{cursor:inherit}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]::after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
+.print-only{display:none!important}
+@page{margin:1.25cm .75cm}
+@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
+html{font-size:80%}
+a{color:inherit!important;text-decoration:underline!important}
+a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
+a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
+abbr[title]::after{content:" (" attr(title) ")"}
+pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
+thead{display:table-header-group}
+svg{max-width:100%}
+p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
+h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
+#toc,.sidebarblock,.exampleblock>.content{background:none!important}
+#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
+body.book #header{text-align:center}
+body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
+body.book #header .details{border:0!important;display:block;padding:0!important}
+body.book #header .details span:first-child{margin-left:0!important}
+body.book #header .details br{display:block}
+body.book #header .details br+span::before{content:none!important}
+body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
+body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
+.listingblock code[data-lang]::before{display:block}
+#footer{padding:0 .9375em}
+.hide-on-print{display:none!important}
+.print-only{display:block!important}
+.hide-for-print{display:none!important}
+.show-for-print{display:inherit!important}}
+@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
+.sect1{padding:0!important}
+.sect1+.sect1{border:0}
+#footer{background:none}
+#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
+@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
+</style>
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+<style>
+/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
+/*pre.CodeRay {background-color:#f7f7f8;}*/
+.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em}
+.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)}
+.CodeRay .line-numbers strong{color:rgba(0,0,0,.4)}
+table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none}
+table.CodeRay td{vertical-align: top;line-height:1.45}
+table.CodeRay td.line-numbers{text-align:right}
+table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)}
+table.CodeRay td.code{padding:0 0 0 .5em}
+table.CodeRay td.code>pre{padding:0}
+.CodeRay .debug{color:#fff !important;background:#000080 !important}
+.CodeRay .annotation{color:#007}
+.CodeRay .attribute-name{color:#000080}
+.CodeRay .attribute-value{color:#700}
+.CodeRay .binary{color:#509}
+.CodeRay .comment{color:#998;font-style:italic}
+.CodeRay .char{color:#04d}
+.CodeRay .char .content{color:#04d}
+.CodeRay .char .delimiter{color:#039}
+.CodeRay .class{color:#458;font-weight:bold}
+.CodeRay .complex{color:#a08}
+.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
+.CodeRay .color{color:#099}
+.CodeRay .class-variable{color:#369}
+.CodeRay .decorator{color:#b0b}
+.CodeRay .definition{color:#099}
+.CodeRay .delimiter{color:#000}
+.CodeRay .doc{color:#970}
+.CodeRay .doctype{color:#34b}
+.CodeRay .doc-string{color:#d42}
+.CodeRay .escape{color:#666}
+.CodeRay .entity{color:#800}
+.CodeRay .error{color:#808}
+.CodeRay .exception{color:inherit}
+.CodeRay .filename{color:#099}
+.CodeRay .function{color:#900;font-weight:bold}
+.CodeRay .global-variable{color:#008080}
+.CodeRay .hex{color:#058}
+.CodeRay .integer,.CodeRay .float{color:#099}
+.CodeRay .include{color:#555}
+.CodeRay .inline{color:#000}
+.CodeRay .inline .inline{background:#ccc}
+.CodeRay .inline .inline .inline{background:#bbb}
+.CodeRay .inline .inline-delimiter{color:#d14}
+.CodeRay .inline-delimiter{color:#d14}
+.CodeRay .important{color:#555;font-weight:bold}
+.CodeRay .interpreted{color:#b2b}
+.CodeRay .instance-variable{color:#008080}
+.CodeRay .label{color:#970}
+.CodeRay .local-variable{color:#963}
+.CodeRay .octal{color:#40e}
+.CodeRay .predefined{color:#369}
+.CodeRay .preprocessor{color:#579}
+.CodeRay .pseudo-class{color:#555}
+.CodeRay .directive{font-weight:bold}
+.CodeRay .type{font-weight:bold}
+.CodeRay .predefined-type{color:inherit}
+.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
+.CodeRay .key{color:#808}
+.CodeRay .key .delimiter{color:#606}
+.CodeRay .key .char{color:#80f}
+.CodeRay .value{color:#088}
+.CodeRay .regexp .delimiter{color:#808}
+.CodeRay .regexp .content{color:#808}
+.CodeRay .regexp .modifier{color:#808}
+.CodeRay .regexp .char{color:#d14}
+.CodeRay .regexp .function{color:#404;font-weight:bold}
+.CodeRay .string{color:#d20}
+.CodeRay .string .string .string{background:#ffd0d0}
+.CodeRay .string .content{color:#d14}
+.CodeRay .string .char{color:#d14}
+.CodeRay .string .delimiter{color:#d14}
+.CodeRay .shell{color:#d14}
+.CodeRay .shell .delimiter{color:#d14}
+.CodeRay .symbol{color:#990073}
+.CodeRay .symbol .content{color:#a60}
+.CodeRay .symbol .delimiter{color:#630}
+.CodeRay .tag{color:#008080}
+.CodeRay .tag-special{color:#d70}
+.CodeRay .variable{color:#036}
+.CodeRay .insert{background:#afa}
+.CodeRay .delete{background:#faa}
+.CodeRay .change{color:#aaf;background:#007}
+.CodeRay .head{color:#f8f;background:#505}
+.CodeRay .insert .insert{color:#080}
+.CodeRay .delete .delete{color:#800}
+.CodeRay .change .change{color:#66f}
+.CodeRay .head .head{color:#f4f}
+</style>
+<link rel="stylesheet" href="../katex/katex.min.css">
+<script src="../katex/katex.min.js"></script>
+<script src="../katex/contrib/auto-render.min.js"></script>
+    <!-- Use KaTeX to render math once document is loaded, see
+         https://github.com/Khan/KaTeX/tree/master/contrib/auto-render -->
+<script>
+    document.addEventListener("DOMContentLoaded", function () {
+        renderMathInElement(
+            document.body,
+            {
+                delimiters: [
+                    { left: "$$", right: "$$", display: true},
+                    { left: "\\[", right: "\\]", display: true},
+                    { left: "$", right: "$", display: false},
+                    { left: "\\(", right: "\\)", display: false}
+                ]
+            }
+        );
+    });
+</script></head>
+<body class="book toc2 toc-left" style="max-width: 100;">
+<div id="header">
+<h1>The OpenGL<sup>&#174;</sup> Shading Language, Version 4.60.6</h1>
+<div class="details">
+<span id="author" class="author">John Kessenich, Google (Editor and Author) ; Dave Baldwin and Randi Rost (Version 1.1 Authors)</span><br>
+<span id="revnumber">version 4.60.6,</span>
+<span id="revdate">Wed, 12 Dec 2018 23:37:49 +0000</span>
+<br><span id="revremark">Git branch information not available</span>
+</div>
+<div id="toc" class="toc2">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#introduction">1. Introduction</a>
+<ul class="sectlevel2">
+<li><a href="#changes">1.1. Changes</a></li>
+<li><a href="#overview">1.2. Overview</a></li>
+<li><a href="#error-handling">1.3. Error Handling</a></li>
+<li><a href="#typographical-conventions">1.4. Typographical Conventions</a></li>
+<li><a href="#deprecation">1.5. Deprecation</a></li>
+</ul>
+</li>
+<li><a href="#overview-of-opengl-shading">2. Overview of OpenGL Shading</a>
+<ul class="sectlevel2">
+<li><a href="#vertex-processor">2.1. Vertex Processor</a></li>
+<li><a href="#tessellation-control-processor">2.2. Tessellation Control Processor</a></li>
+<li><a href="#tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</a></li>
+<li><a href="#geometry-processor">2.4. Geometry Processor</a></li>
+<li><a href="#fragment-processor">2.5. Fragment Processor</a></li>
+<li><a href="#compute-processor">2.6. Compute Processor</a></li>
+</ul>
+</li>
+<li><a href="#basics">3. Basics</a>
+<ul class="sectlevel2">
+<li><a href="#character-set">3.1. Character Set and Phases of Compilation</a></li>
+<li><a href="#source-strings">3.2. Source Strings</a></li>
+<li><a href="#preprocessor">3.3. Preprocessor</a></li>
+<li><a href="#comments">3.4. Comments</a></li>
+<li><a href="#tokens">3.5. Tokens</a></li>
+<li><a href="#keywords">3.6. Keywords</a></li>
+<li><a href="#identifiers">3.7. Identifiers</a></li>
+<li><a href="#definitions">3.8. Definitions</a></li>
+</ul>
+</li>
+<li><a href="#variables-and-types">4. Variables and Types</a>
+<ul class="sectlevel2">
+<li><a href="#basic-types">4.1. Basic Types</a></li>
+<li><a href="#scoping">4.2. Scoping</a></li>
+<li><a href="#storage-qualifiers">4.3. Storage Qualifiers</a></li>
+<li><a href="#layout-qualifiers">4.4. Layout Qualifiers</a></li>
+<li><a href="#interpolation-qualifiers">4.5. Interpolation Qualifiers</a></li>
+<li><a href="#parameter-qualifiers">4.6. Parameter Qualifiers</a></li>
+<li><a href="#precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</a></li>
+<li><a href="#variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</a></li>
+<li><a href="#the-precise-qualifier">4.9. The Precise Qualifier</a></li>
+<li><a href="#memory-qualifiers">4.10. Memory Qualifiers</a></li>
+<li><a href="#specialization-constant-qualifier">4.11. Specialization-Constant Qualifier</a></li>
+<li><a href="#order-of-qualification">4.12. Order and Repetition of Qualification</a></li>
+<li><a href="#empty-declarations">4.13. Empty Declarations</a></li>
+</ul>
+</li>
+<li><a href="#operators-and-expressions">5. Operators and Expressions</a>
+<ul class="sectlevel2">
+<li><a href="#operators">5.1. Operators</a></li>
+<li><a href="#array-operations">5.2. Array Operations</a></li>
+<li><a href="#function-calls">5.3. Function Calls</a></li>
+<li><a href="#constructors">5.4. Constructors</a></li>
+<li><a href="#vector-components">5.5. Vector and Scalar Components and Length</a></li>
+<li><a href="#matrix-components">5.6. Matrix Components</a></li>
+<li><a href="#structure-and-array-operations">5.7. Structure and Array Operations</a></li>
+<li><a href="#assignments">5.8. Assignments</a></li>
+<li><a href="#expressions">5.9. Expressions</a></li>
+<li><a href="#vector-and-matrix-operations">5.10. Vector and Matrix Operations</a></li>
+<li><a href="#out-of-bounds-accesses">5.11. Out-of-Bounds Accesses</a></li>
+<li><a href="#specialization-constant-operations">5.12. Specialization Constant Operations</a></li>
+</ul>
+</li>
+<li><a href="#statements-and-structure">6. Statements and Structure</a>
+<ul class="sectlevel2">
+<li><a href="#function-definitions">6.1. Function Definitions</a></li>
+<li><a href="#selection">6.2. Selection</a></li>
+<li><a href="#iteration">6.3. Iteration</a></li>
+<li><a href="#jumps">6.4. Jumps</a></li>
+</ul>
+</li>
+<li><a href="#built-in-variables">7. Built-In Variables</a>
+<ul class="sectlevel2">
+<li><a href="#built-in-language-variables">7.1. Built-In Language Variables</a></li>
+<li><a href="#compatibility-profile-vertex-shader-built-in-inputs">7.2. Compatibility Profile Vertex Shader Built-In Inputs</a></li>
+<li><a href="#built-in-constants">7.3. Built-In Constants</a></li>
+<li><a href="#built-in-uniform-state">7.4. Built-In Uniform State</a></li>
+<li><a href="#redeclaring-built-in-blocks">7.5. Redeclaring Built-In Blocks</a></li>
+</ul>
+</li>
+<li><a href="#built-in-functions">8. Built-In Functions</a>
+<ul class="sectlevel2">
+<li><a href="#angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</a></li>
+<li><a href="#exponential-functions">8.2. Exponential Functions</a></li>
+<li><a href="#common-functions">8.3. Common Functions</a></li>
+<li><a href="#floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</a></li>
+<li><a href="#geometric-functions">8.5. Geometric Functions</a></li>
+<li><a href="#matrix-functions">8.6. Matrix Functions</a></li>
+<li><a href="#vector-relational-functions">8.7. Vector Relational Functions</a></li>
+<li><a href="#integer-functions">8.8. Integer Functions</a></li>
+<li><a href="#texture-functions">8.9. Texture Functions</a></li>
+<li><a href="#atomic-counter-functions">8.10. Atomic Counter Functions</a></li>
+<li><a href="#atomic-memory-functions">8.11. Atomic Memory Functions</a></li>
+<li><a href="#image-functions">8.12. Image Functions</a></li>
+<li><a href="#geometry-shader-functions">8.13. Geometry Shader Functions</a></li>
+<li><a href="#fragment-processing-functions">8.14. Fragment Processing Functions</a></li>
+<li><a href="#noise-functions">8.15. Noise Functions</a></li>
+<li><a href="#shader-invocation-control-functions">8.16. Shader Invocation Control Functions</a></li>
+<li><a href="#shader-memory-control-functions">8.17. Shader Memory Control Functions</a></li>
+<li><a href="#shader-invocation-group-functions">8.18. Shader Invocation Group Functions</a></li>
+</ul>
+</li>
+<li><a href="#shading-language-grammar">9. Shading Language Grammar</a></li>
+<li><a href="#acknowledgments">10. Acknowledgments</a></li>
+<li><a href="#references">11. Normative References</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div style="page-break-after: always;"></div>
+<div class="paragraph">
+<p>Copyright &#169; 2008-2018 The Khronos Group Inc. All Rights Reserved.</p>
+</div>
+<div class="paragraph">
+<p>This specification is protected by copyright laws and contains material
+proprietary to the Khronos Group, Inc. It or any components may not be
+reproduced, republished, distributed, transmitted, displayed, broadcast,
+or otherwise exploited in any manner without the express prior written
+permission of Khronos Group. You may use this specification for
+implementing the functionality therein, without altering or removing any
+trademark, copyright or other notice from the specification, but the
+receipt or possession of this specification does not convey any rights
+to reproduce, disclose, or distribute its contents, or to manufacture,
+use, or sell anything that it may describe, in whole or in part.</p>
+</div>
+<div class="paragraph">
+<p>Khronos Group grants express permission to any current Promoter,
+Contributor or Adopter member of Khronos to copy and redistribute
+UNMODIFIED versions of this specification in any fashion, provided that
+NO CHARGE is made for the specification and the latest available update
+of the specification for any version of the API is used whenever
+possible. Such distributed specification may be reformatted AS LONG AS
+the contents of the specification are not changed in any way. The
+specification may be incorporated into a product that is sold as long as
+such product includes significant independent work developed by the
+seller. A link to the current version of this specification on the
+Khronos Group website should be included whenever possible with
+specification distributions.</p>
+</div>
+<div class="paragraph">
+<p>Khronos Group makes no, and expressly disclaims any, representations or
+warranties, express or implied, regarding this specification, including,
+without limitation, any implied warranties of merchantability or fitness
+for a particular purpose or noninfringement of any intellectual
+property. Khronos Group makes no, and expressly disclaims any,
+warranties, express or implied, regarding the correctness, accuracy,
+completeness, timeliness, and reliability of the specification. Under no
+circumstances will the Khronos Group, or any of its Promoters,
+Contributors or Members or their respective partners, officers,
+directors, employees, agents, or representatives be liable for any
+damages, whether direct, indirect, special or consequential damages for
+lost revenues, lost profits, or otherwise, arising from or in connection
+with these materials.</p>
+</div>
+<div class="paragraph">
+<p>Khronos, Vulkan, SYCL, SPIR, WebGL, EGL, COLLADA, StreamInput, OpenVX,
+OpenKCam, glTF, OpenKODE, OpenVG, OpenWF, OpenSL ES, OpenMAX, OpenMAX
+AL, OpenMAX IL and OpenMAX DL are trademarks and WebCL is a
+certification mark of the Khronos Group Inc. OpenCL is a trademark of
+Apple Inc. and OpenGL and OpenML are registered trademarks and the
+OpenGL ES and OpenGL SC logos are trademarks of Silicon Graphics
+International used under license by Khronos. All other product names,
+trademarks, and/or company names are used solely for identification and
+belong to their respective owners.</p>
+</div>
+<div style="page-break-after: always;"></div>
+<!-- toc disabled -->
+</div>
+</div>
+<div class="sect1">
+<h2 id="introduction">1. Introduction</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This document specifies only version 4.60 of the OpenGL Shading Language.
+It requires __VERSION__ to substitute 460, and requires
+<strong>#version</strong> to accept only
+<code>460</code>.
+If <strong>#version</strong> is declared with a smaller number, the language accepted is a
+previous version of the shading language, which will be supported depending
+on the version and type of context in the OpenGL API.
+See the <a href="#references">OpenGL Specification</a> for details on what language versions are
+supported.</p>
+</div>
+<div class="paragraph">
+<p>Previous versions of the OpenGL Shading Language, as well as the OpenGL ES Shading Language,
+are not strict subsets of the version specified here, particularly with
+respect to precision, name-hiding rules, and treatment of interface
+variables.
+See the specification corresponding to a particular language version for
+details specific to that version of the language.</p>
+</div>
+<div class="paragraph">
+<p>The OpenGL API will specify the commands used to manipulate SPIR-V
+shaders.
+Independent offline tool chains will compile GLSL down to the SPIR-V
+intermediate language.
+SPIR-V generation is not enabled with a <strong>#extension</strong>, <strong>#version</strong>, or a
+profile.
+Instead, use of GLSL for SPIR-V is determined by offline tool-chain use.
+See the documentation of such tools to see how to request generation of
+SPIR-V for OpenGL.</p>
+</div>
+<div class="paragraph">
+<p>GLSL &#8594; SPIR-V compilers must be directed as to what SPIR-V <strong>Capabilities</strong>
+are legal at run-time and give errors for GLSL feature use outside those
+capabilities.
+This is also true for implementation-dependent limits that can be error
+checked by the front-end against built-in constants present in the GLSL
+source: the front-end can be informed of such limits, and report errors when
+they are exceeded.</p>
+</div>
+<div class="paragraph">
+<p>All references in this specification to the <a href="#references">OpenGL Specification</a> are to
+the Core profile of version 4.6, unless a different profile is
+specified.</p>
+</div>
+<div class="sect2">
+<h3 id="changes">1.1. Changes</h3>
+<div class="sect3">
+<h4 id="_changes_from_revision_5_of_glsl_4_6">1.1.1. Changes from Revision 5 of GLSL 4.6</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Private GLSL issue #34: Clarify/consolidate implicit conversion rules from int &#8594; uint
+to be the same as explicit construction.</p>
+</li>
+<li>
+<p>Private GLSL issue #24: Clarify that <strong>barrier</strong>() by itself is enough to synchronize
+both control flow and memory accesses to <strong>shared</strong> variables and tessellation
+control output variables. For other memory accesses an additional memory
+barrier is still required.</p>
+</li>
+<li>
+<p>Normatively reference IEEE-754 for definitions of floating-point formats.</p>
+</li>
+<li>
+<p>Private GLSL issue 36: <strong>refract</strong> function on <strong>double</strong> types requires eta
+argument to have type <strong>double</strong>.</p>
+</li>
+<li>
+<p>Clarify restrictions on input variables in tessellation and geometry stages.</p>
+</li>
+<li>
+<p>Private GLSL issue 15: Clarify the ordering of bindings for arrays of arrays.</p>
+</li>
+<li>
+<p>Private GLSL issue 14: Uniform variables need only match at link time if they
+are statically used.</p>
+</li>
+<li>
+<p>For <strong>precise</strong> computations, the controlling expressions for
+control flow and ternary operators (<strong>?:</strong>) are not included.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_changes_from_revision_4_of_glsl_4_6">1.1.2. Changes from Revision 4 of GLSL 4.6</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Private bug 13012: Clarified that builtin uniform variables might only
+be available in the fragment stage.</p>
+</li>
+<li>
+<p>Private bug 13837: Ternary and sequence operators may operate on <strong>void</strong> types.</p>
+</li>
+<li>
+<p>Clarified that errors arising from preprocessing must be returned at compile time.</p>
+</li>
+<li>
+<p>Clarified that access to any part of a variable constitutes a static use.</p>
+</li>
+<li>
+<p>Private GLSL issue 19: A statement is required following any label at the end of a <strong>switch</strong>.</p>
+</li>
+<li>
+<p>Private GLSL issue 26: <strong>noise</strong> is not valid when compiling for SPIR-V.</p>
+</li>
+<li>
+<p>Private GLSL issue 20: <strong>length</strong>() expressions returning a constant value may not
+contain side effects.</p>
+</li>
+<li>
+<p>Public OpenGL-API issue 7: Variables can be declared as both <strong>readonly</strong>
+and <strong>writeonly</strong>.</p>
+</li>
+<li>
+<p>Private GLSL issue 16: Use of constant expressions within <strong>#line</strong> directives is undefined.</p>
+</li>
+<li>
+<p>Corrected return type of <strong>imageAtomicExchange</strong> on <strong>float</strong> images.</p>
+</li>
+<li>
+<p>Private GLSL issue 32: Remove <strong>length</strong>() method contradiction:
+Non runtime-sized arrays only support <strong>length</strong>() on explicitly
+sized arrays.</p>
+</li>
+<li>
+<p>Private GLSL issue 21: Clarified the l-value restriction on <strong>interpolateAt</strong>.</p>
+</li>
+<li>
+<p>Private OpenGL-API issue 53: Clarified bit-width requirements for location aliasing.</p>
+</li>
+<li>
+<p>Public GLSL issue 15: <strong>gl_in</strong> can be redeclared using unsized-array syntax.</p>
+</li>
+<li>
+<p>Clarification of the formats needed for DEPTH_COMPONENT and
+STENCIL_COMPONENT for depth/stencil textures.</p>
+</li>
+<li>
+<p>Added image formats to the layout-qualifier table in the
+<a href="#layout-qualifiers">Layout Qualifiers</a> section.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_changes_from_revision_3_of_glsl_4_6">1.1.3. Changes from Revision 3 of GLSL 4.6</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Private GLSL issue 13: Fix misspelling of <strong>allInvocationsEqual</strong>().
+(The one in the table was incorrectly listed as <strong>anyInvocationsEqual</strong>(),
+other spellings were correct.)</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_summary_of_changes_from_revision_7_of_glsl_version_4_50">1.1.4. Summary of Changes from Revision 7 of GLSL Version 4.50</h4>
+<div class="ulist">
+<ul>
+<li>
+<p>Incorporated the GL_ARB_shader_atomic_counter_ops extension.</p>
+</li>
+<li>
+<p>Incorporated the GL_ARB_shader_draw_parameters extension.</p>
+</li>
+<li>
+<p>Incorporated the GL_ARB_shader_group_vote extension.</p>
+</li>
+<li>
+<p>Incorporated the GL_ARB_gl_spirv extension.</p>
+</li>
+<li>
+<p>Private Bug 16070: Allow extra semi-colons at global scope.</p>
+</li>
+<li>
+<p>Private GLSL Issue 5: Be explicit that &#8220;fail to link&#8221; is really
+&#8220;compile-time or link-time error&#8221;, for some forms of error.</p>
+</li>
+<li>
+<p>Private GLSL Issue 7: Change <em>gl_MaxComputeUniformComponents</em> to 1024.</p>
+</li>
+<li>
+<p>Private OpenGL API Issue 35: Require location on transparent individual
+uniform variables for SPIR-V.</p>
+</li>
+<li>
+<p>Private GLSL Issue 8: Be more clear an <strong>interpolateAt</strong>() interpolant can
+be a structure member.</p>
+</li>
+<li>
+<p>Private GLSL Issue 9: Specify how <strong>xfb_buffer</strong> interacts with a block
+array: the capturing buffer increments for each block array element.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="overview">1.2. Overview</h3>
+<div class="paragraph">
+<p>This document describes <em>The OpenGL Shading Language, version 4.60</em>.</p>
+</div>
+<div class="paragraph">
+<p>Independent compilation units written in this language are called <em>shaders</em>.
+A <em>program</em> is a set of shaders that are compiled and linked
+together,
+completely creating one or more of the programmable stages of the
+OpenGL pipeline.
+All the shaders for a single programmable stage must be within the same
+program.
+A complete set of programmable stages can be put into a single program or
+the stages can be partitioned across multiple programs.
+The aim of this document is to thoroughly specify the programming language.
+The <a href="#references">OpenGL Specification</a> will specify the OpenGL entry points used to
+manipulate and communicate with programs and shaders.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="error-handling">1.3. Error Handling</h3>
+<div class="paragraph">
+<p>Compilers, in general, accept programs that are ill-formed, due to the
+impossibility of detecting all ill-formed programs.
+Portability is only ensured for well-formed programs, which this
+specification describes.
+Compilers are encouraged to detect ill-formed programs and issue diagnostic
+messages, but are not required to do so for all cases.
+Compile-time errors must be returned for lexically or grammatically
+incorrect shaders.
+Other errors are reported at compile time or link time as indicated.
+Code that is &#8220;dead&#8221; must still be error checked.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">if</span> (<span class="predefined-constant">false</span>)     <span class="comment">// changing false to true cannot uncover additional errors</span>
+    statement; <span class="comment">// statement must be error checked regardless</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="typographical-conventions">1.4. Typographical Conventions</h3>
+<div class="paragraph">
+<p>Italic, bold, and font choices have been used in this specification
+primarily to improve readability.
+Code fragments use a fixed width font.
+Identifiers embedded in text are italicized.
+Keywords embedded in text are bold.
+Operators are called by their name, followed by their symbol in bold in
+parentheses.
+The clarifying grammar fragments in the text use bold for literals and
+italics for non-terminals.
+The official grammar in &#8220;<a href="#shading-language-grammar">Shading Language
+Grammar</a>&#8221; uses all capitals for terminals and lower case for
+non-terminals.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="deprecation">1.5. Deprecation</h3>
+<div class="paragraph">
+<p>The OpenGL Shading Language has deprecated some features.
+These are clearly called out in this specification as &#8220;deprecated&#8221;.
+They are still present in this version of the language, but are targeted for
+potential removal in a future version of the shading language.
+The OpenGL API has a forward compatibility mode that will disallow use of
+deprecated features.
+If compiling in a mode where use of deprecated features is disallowed, their
+use causes compile-time or link-time errors.
+See the <a href="#references">OpenGL Specification</a> for details on what causes deprecated
+language features to be accepted or to return an error.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="overview-of-opengl-shading">2. Overview of OpenGL Shading</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The OpenGL Shading Language is actually several closely related languages.
+These languages are used to create shaders for each of the programmable
+processors contained in the OpenGL processing pipeline.
+Currently, these processors are the vertex, tessellation control,
+tessellation evaluation, geometry, fragment, and compute processors.</p>
+</div>
+<div class="paragraph">
+<p>Unless otherwise noted in this paper, a language feature applies to all
+languages, and common usage will refer to these languages as a single
+language.
+The specific languages will be referred to by the name of the processor they
+target: vertex, tessellation control, tessellation evaluation, geometry,
+fragment, or compute.</p>
+</div>
+<div class="paragraph">
+<p>Most OpenGL state is not tracked or made available to shaders.
+Typically, user-defined variables will be used for communicating between
+different stages of the OpenGL pipeline.
+However, a small amount of state is still tracked and automatically made
+available to shaders, and there are a few built-in variables for interfaces
+between different stages of the OpenGL pipeline.</p>
+</div>
+<div class="sect2">
+<h3 id="vertex-processor">2.1. Vertex Processor</h3>
+<div class="paragraph">
+<p>The <em>vertex processor</em> is a programmable unit that operates on incoming
+vertices and their associated data.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+<em>vertex shaders</em>.
+When a set of vertex shaders are successfully compiled and linked, they
+result in a <em>vertex shader executable</em> that runs on the vertex processor.</p>
+</div>
+<div class="paragraph">
+<p>The vertex processor operates on one vertex at a time.
+It does not replace graphics operations that require knowledge of several
+vertices at a time.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tessellation-control-processor">2.2. Tessellation Control Processor</h3>
+<div class="paragraph">
+<p>The <em>tessellation control processor</em> is a programmable unit that operates on
+a patch of incoming vertices and their associated data, emitting a new
+output patch.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+tessellation control shaders.
+When a set of tessellation control shaders are successfully compiled and
+linked, they result in a <em>tessellation control shader executable</em> that runs
+on the tessellation control processor.</p>
+</div>
+<div class="paragraph">
+<p>The tessellation control shader is invoked for each vertex of the output
+patch.
+Each invocation can read the attributes of any vertex in the input or output
+patches, but can only write per-vertex attributes for the corresponding
+output patch vertex.
+The shader invocations collectively produce a set of per-patch attributes
+for the output patch.</p>
+</div>
+<div class="paragraph">
+<p>After all tessellation control shader invocations have completed, the output
+vertices and per-patch attributes are assembled to form a patch to be used
+by subsequent pipeline stages.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control shader invocations run mostly independently, with
+undefined relative execution order.
+However, the built-in function <strong>barrier</strong>() can be used to control execution
+order by synchronizing invocations, effectively dividing tessellation
+control shader execution into a set of phases.
+Tessellation control shaders will get undefined results if one invocation
+reads from a per-vertex or per-patch attribute written by another invocation
+at any point during the same phase, or if two invocations attempt to write
+different values to the same per-patch output
+32-bit component
+in a single phase.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tessellation-evaluation-processor">2.3. Tessellation Evaluation Processor</h3>
+<div class="paragraph">
+<p>The <em>tessellation evaluation processor</em> is a programmable unit that
+evaluates the position and other attributes of a vertex generated by the
+tessellation primitive generator, using a patch of incoming vertices and
+their associated data.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+tessellation evaluation shaders.
+When a set of tessellation evaluation shaders are successfully compiled and
+linked, they result in a <em>tessellation evaluation shader executable</em> that
+runs on the tessellation evaluation processor.</p>
+</div>
+<div class="paragraph">
+<p>Each invocation of the tessellation evaluation executable computes the
+position and attributes of a single vertex generated by the tessellation
+primitive generator.
+The executable can read the attributes of any vertex in the input patch,
+plus the tessellation coordinate, which is the relative location of the
+vertex in the primitive being tessellated.
+The executable writes the position and other attributes of the vertex.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="geometry-processor">2.4. Geometry Processor</h3>
+<div class="paragraph">
+<p>The <em>geometry processor</em> is a programmable unit that operates on data for
+incoming vertices for a primitive assembled after vertex processing and
+outputs a sequence of vertices forming output primitives.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+<em>geometry shaders</em>.
+When a set of geometry shaders are successfully compiled and linked, they
+result in a <em>geometry shader executable</em> that runs on the geometry
+processor.</p>
+</div>
+<div class="paragraph">
+<p>A single invocation of the geometry shader executable on the geometry
+processor will operate on a declared input primitive with a fixed number of
+vertices.
+This single invocation can emit a variable number of vertices that are
+assembled into primitives of a declared output primitive type and passed to
+subsequent pipeline stages.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="fragment-processor">2.5. Fragment Processor</h3>
+<div class="paragraph">
+<p>The <em>fragment processor</em> is a programmable unit that operates on fragment
+values and their associated data.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+<em>fragment shaders</em>.
+When a set of fragment shaders are successfully compiled and linked, they
+result in a <em>fragment shader executable</em> that runs on the fragment
+processor.</p>
+</div>
+<div class="paragraph">
+<p>A fragment shader cannot change a fragment&#8217;s (<em>x</em>, <em>y</em>) position.
+Access to neighboring fragments is not allowed.
+The values computed by the fragment shader are ultimately used to update
+framebuffer memory or texture memory, depending on the current OpenGL
+state and the OpenGL command that caused the fragments to be generated.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="compute-processor">2.6. Compute Processor</h3>
+<div class="paragraph">
+<p>The <em>compute processor</em> is a programmable unit that operates independently
+from the other shader processors.
+Compilation units written in the OpenGL Shading Language to run on this processor are called
+<em>compute shaders</em>.
+When a set of compute shaders are successfully compiled and linked, they
+result in a <em>compute shader executable</em> that runs on the compute processor.</p>
+</div>
+<div class="paragraph">
+<p>A compute shader has access to many of the same resources as fragment and
+other shader processors, such as textures, buffers, image variables, and
+atomic counters.
+It does not have fixed-function outputs.
+It is not part of the graphics pipeline and its visible side effects are
+through changes to images, storage buffers, and atomic counters.</p>
+</div>
+<div class="paragraph">
+<p>A compute shader operates on a group of work items called a <em>workgroup</em>.
+A workgroup is a collection of shader invocations that execute the same
+code, potentially in parallel.
+An invocation within a workgroup may share data with other members of the
+same workgroup through shared variables and issue memory and control flow
+barriers to synchronize with other members of the same workgroup.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="basics">3. Basics</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="character-set">3.1. Character Set and Phases of Compilation</h3>
+<div class="paragraph">
+<p>The source character set used for the OpenGL Shading Language is Unicode in the UTF-8
+encoding scheme.</p>
+</div>
+<div class="paragraph">
+<p>After preprocessing, only the following characters are allowed in the
+resulting stream of GLSL tokens:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The letters <strong>a-z</strong>, <strong>A-Z</strong>, and the underscore (<strong>_</strong>).</p>
+</li>
+<li>
+<p>The numbers <strong>0-9</strong>.</p>
+</li>
+<li>
+<p>The symbols period (<strong>.</strong>), plus (<strong>+</strong>), dash (<strong>-</strong>), slash (<strong>/</strong>), asterisk
+(<strong>*</strong>), percent (<strong>%</strong>), angled brackets (<strong>&lt;</strong> and <strong>&gt;</strong>), square brackets
+(<strong>[</strong> and <strong>]</strong>), parentheses (<strong>(</strong> and <strong>)</strong>), braces (<strong>{</strong> and <strong>}</strong>), caret
+(<strong>^</strong>), vertical bar (<strong>|</strong>), ampersand (<strong>&amp;</strong>), tilde (<strong>~</strong>), equals (<strong>=</strong>),
+exclamation point (<strong>!</strong>), colon (<strong>:</strong>), semicolon (<strong>;</strong>), comma (<strong>,</strong>), and
+question mark (<strong>?</strong>).</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>A compile-time error will be given if any other character is used in a GLSL
+token.</p>
+</div>
+<div class="paragraph">
+<p>There are no digraphs or trigraphs.
+There are no escape sequences or other uses of the backslash beyond use as
+the line-continuation character.</p>
+</div>
+<div class="paragraph">
+<p>Lines are relevant for compiler diagnostic messages and the preprocessor.
+They are terminated by carriage-return or line-feed.
+If both are used together, it will count as only a single line termination.
+For the remainder of this document, any of these combinations is simply
+referred to as a new-line.
+Lines may be of arbitrary length.</p>
+</div>
+<div class="paragraph">
+<p>In general, the language&#8217;s use of this character set is case sensitive.</p>
+</div>
+<div class="paragraph">
+<p>There are no character or string data types, so no quoting characters are
+included.</p>
+</div>
+<div class="paragraph">
+<p>There is no end-of-file character.</p>
+</div>
+<div class="paragraph">
+<p>More formally, compilation happens as if the following logical phases were
+executed in order:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Source strings are concatenated to form a single input.
+All provided new-lines are retained.</p>
+</li>
+<li>
+<p>Line numbering is noted, based on all present new-lines, and does not
+change when new-lines are later eliminated.</p>
+</li>
+<li>
+<p>Wherever a backslash ('\') occurs immediately before a new-line, both
+are eliminated.
+(Note no white space is substituted, allowing a single token to span a
+new-line.) Any newly formed backslash followed by a new-line is not
+eliminated; only those pairs originally occurring after phase 1 are
+eliminated.</p>
+</li>
+<li>
+<p>All comments are replaced with a single space.
+(Note that '//' style comments end before their terminating new-lines
+and white space is generally relevant to preprocessing.)</p>
+</li>
+<li>
+<p>Preprocessing is done, resulting in a sequence of GLSL tokens, formed
+from the character set stated above.</p>
+</li>
+<li>
+<p>GLSL processing is done on the sequence of GLSL tokens.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Details that fully define source strings, comments, line numbering, new-line
+elimination, and preprocessing are all discussed in upcoming sections.
+Sections beyond those describe GLSL processing.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="source-strings">3.2. Source Strings</h3>
+<div class="paragraph">
+<p>The source for a single shader is an array of strings of characters from the
+character set.
+A single shader is made from the concatenation of these strings.
+Each string can contain multiple lines, separated by new-lines.
+No new-lines need be present in a string; a single line can be formed from
+multiple strings.
+No new-lines or other characters are inserted by the implementation when it
+concatenates the strings to form a single shader.
+Multiple shaders can be linked together to form a single program.</p>
+</div>
+<div class="paragraph">
+<p>Diagnostic messages returned from compiling a shader must identify both the
+line number within a string and which source string the message applies to.
+Source strings are counted sequentially with the first string being string
+0.
+Line numbers are one more than the number of new-lines that have been
+processed, including counting the new-lines that will be removed by the
+line-continuation character (<strong>\</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Lines separated by the line-continuation character preceding a new-line are
+concatenated together before either comment processing or preprocessing.
+This means that no white space is substituted for the line-continuation
+character.
+That is, a single token could be formed by the concatenation by taking the
+characters at the end of one line concatenating them with the characters at
+the beginning of the next line.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> f\
+oo;
+<span class="comment">// forms a single line equivalent to &quot;float foo;&quot;</span>
+<span class="comment">// (assuming '\' is the last character before the new-line and &quot;oo&quot; are</span>
+<span class="comment">// the first two characters of the next line)</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="preprocessor">3.3. Preprocessor</h3>
+<div class="paragraph">
+<p>There is a preprocessor that processes the source strings as part of the
+compilation process.
+Except as noted below, it behaves as the C++ standard preprocessor (see
+&#8220;<a href="#references">Normative References</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>The complete list of preprocessor directives is as follows.</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#<br>
+#define<br>
+#undef<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#if<br>
+#ifdef<br>
+#ifndef<br>
+#else<br>
+#elif<br>
+#endif<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#error<br>
+#pragma<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#extension<br>
+#version<br></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>#line</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The following
+operators are
+also available:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>defined<br>
+##</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Each number sign (<strong>#</strong>) can be preceded in its line only by spaces or
+horizontal tabs.
+It may also be followed by spaces and horizontal tabs, preceding the
+directive.
+Each directive is terminated by a new-line.
+Preprocessing does not change the number or relative location of new-lines
+in a source string.
+Preprocessing takes places after new-lines have been removed by the
+line-continuation character.</p>
+</div>
+<div class="paragraph">
+<p>The number sign (<strong>#</strong>) on a line by itself is ignored.
+Any directive not listed above will cause a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p><strong>#define</strong> and <strong>#undef</strong> functionality are defined as is standard for C++
+preprocessors for macro definitions both with and without macro parameters.</p>
+</div>
+<div class="paragraph">
+<p>The following predefined macros are available:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>__LINE__<br>
+__FILE__<br>
+__VERSION__<br></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>__LINE__ will substitute a decimal integer constant that is one more than
+the number of preceding new-lines in the current source string.</p>
+</div>
+<div class="paragraph">
+<p>__FILE__ will substitute a decimal integer constant that says which source
+string number is currently being processed.</p>
+</div>
+<div class="paragraph">
+<p>__VERSION__ will substitute a decimal integer reflecting the version
+number of the OpenGL Shading Language.
+The version of the shading language described in this document will have
+__VERSION__ substitute the decimal integer 460.</p>
+</div>
+<div class="paragraph">
+<p>By convention, all macro names containing two consecutive underscores (__)
+are reserved for use by underlying software layers.
+Defining
+or undefining
+such a name in a shader does not itself result in an error, but may
+result in unintended behaviors that stem from having multiple definitions of
+the same name.
+All macro names prefixed with &#8220;GL_&#8221; (&#8220;GL&#8221; followed by a single
+underscore) are also reserved, and defining
+or undefining
+such a name results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>Implementations must support macro-name lengths of up to 1024 characters.
+Implementations are allowed to generate an error for a macro name of length
+greater than 1024 characters, but are also allowed to support lengths
+greater than 1024.</p>
+</div>
+<div class="paragraph">
+<p><strong>#if</strong>, <strong>#ifdef</strong>, <strong>#ifndef</strong>, <strong>#else</strong>, <strong>#elif</strong>, and <strong>#endif</strong> are defined to
+operate as is standard for C++ preprocessors except for the following:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Expressions following <strong>#if</strong> and <strong>#elif</strong> are
+further restricted to
+expressions operating on literal integer constants, plus identifiers
+consumed by the <strong>defined</strong> operator.</p>
+</li>
+<li>
+<p>Character constants are not supported.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The operators available are as follows.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Precedence</th>
+<th class="tableblock halign-left valign-top">Operator class</th>
+<th class="tableblock halign-left valign-top">Operators</th>
+<th class="tableblock halign-left valign-top">Associativity</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">unary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">defined<br>
+                                         + - ~ !</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;&lt; &gt;&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt; &gt; &lt;= &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">12 (lowest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The <strong>defined</strong> operator can be used in either of the following ways:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">defined identifier
+defined ( identifier )</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Two tokens in a macro can be concatenated into one token using the token
+pasting (<strong>##</strong>) operator, as is standard for C++ preprocessors.
+The result must be a valid single token, which will then be subject to macro
+expansion.
+That is, macro expansion happens only after token pasting.
+There are no other number sign based operators (e.g. no <strong>#</strong> or <strong>#@</strong>), nor is
+there a <strong>sizeof</strong> operator.</p>
+</div>
+<div class="paragraph">
+<p>The semantics of applying operators to integer literals in the preprocessor
+match those standard in the C++ preprocessor, not those in the OpenGL Shading Language.</p>
+</div>
+<div class="paragraph">
+<p>Preprocessor expressions will be evaluated according to the behavior of the
+host processor, not the processor targeted by the shader.</p>
+</div>
+<div class="paragraph">
+<p><strong>#error</strong> will cause the implementation to put a compile-time diagnostic message
+into the shader object&#8217;s information log (see section 7.12 &#8220;Shader, Program
+and Program Pipeline Queries&#8221; of the <a href="#references">OpenGL Specification</a> for how to
+access a shader object&#8217;s information log).
+The message will be the tokens following the <strong>#error</strong> directive, up to the
+first new-line.
+The implementation must treat the presence of a <strong>#error</strong> directive as a
+compile-time error.</p>
+</div>
+<div class="paragraph">
+<p><strong>#pragma</strong> allows implementation-dependent compiler control.
+Tokens following <strong>#pragma</strong> are not subject to preprocessor macro expansion.
+If an implementation does not recognize the tokens following <strong>#pragma</strong>, then
+it will ignore that pragma.
+The following pragmas are defined as part of the language.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>STDGL</strong> pragma is used to reserve pragmas for use by future revisions of
+this language.
+No implementation may use a pragma whose first token is <strong>STDGL</strong>.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> optimize(on)
+<span class="preprocessor">#pragma</span> optimize(off)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to turn off optimizations as an aid in developing and debugging
+shaders.
+It can only be used outside function definitions.
+By default, optimization is turned on for all shaders.
+The debug pragma</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> debug(on)
+<span class="preprocessor">#pragma</span> debug(off)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to enable compiling and annotating a shader with debug
+information, so that it can be used with a debugger.
+It can only be used outside function definitions.
+By default, debug is turned off.</p>
+</div>
+<div class="paragraph">
+<p>Shaders should declare the version of the language they are written to.
+The language version a shader is written to is specified by</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#version</span> number profile_opt</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>number</em> must be a version of the language, following the same
+convention as __VERSION__ above.
+The directive &#8220;<strong>#version 460</strong>&#8221; is required in any shader that
+uses version 4.60 of the language.
+Any <em>number</em> representing a version of the language a compiler does not
+support will cause a compile-time error to be generated.
+Version 1.10 of the language does not require shaders to include this
+directive, and shaders that do not include a <strong>#version</strong> directive will be
+treated as targeting version 1.10.
+Shaders that specify <strong>#version</strong> 100 will be treated as targeting version
+1.00 of the OpenGL ES Shading Language.
+Shaders that specify <strong>#version</strong> 300 will be treated as targeting version
+3.00 of the OpenGL ES Shading Language.
+Shaders that specify <strong>#version</strong> 310 will be treated as targeting version
+3.10 of the OpenGL ES Shading Language.</p>
+</div>
+<div class="paragraph">
+<p>If the optional <em>profile</em> argument is provided, it must be the name of an
+OpenGL profile.
+Currently, there are three choices:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">core
+compatibility
+es</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A <em>profile</em> argument can only be used with version 150 or greater.
+If no profile argument is provided and the version is 150 or greater, the
+default is <strong>core</strong>.
+If version 300 or 310 is specified, the profile argument is not optional and
+must be <strong>es</strong>, or a compile-time error results.
+The Language Specification for the <strong>es</strong> profile is specified in The OpenGL
+ES Shading Language specification.</p>
+</div>
+<div class="paragraph">
+<p>Shaders for the <strong>core</strong> or <strong>compatibility</strong> profiles that declare different
+versions can be linked together.
+However, <strong>es</strong> profile shaders cannot be linked with non-<strong>es</strong> profile shaders
+or with <strong>es</strong> profile shaders of a different version, or a link-time error
+will result.
+When linking shaders of versions allowed by these rules, remaining link-time
+errors will be given as per the linking rules in the GLSL version
+corresponding to the version of the context the shaders are linked under.
+Shader compile-time errors must still be given strictly based on the version
+declared (or defaulted to) within each shader.</p>
+</div>
+<div class="paragraph">
+<p>Unless otherwise specified, this specification is documenting the core
+profile, and everything specified for the core profile is also available in
+the compatibility profile.
+Features specified as belonging specifically to the compatibility profile
+are not available in the core profile.
+Compatibility-profile features are not available when generating SPIR-V.</p>
+</div>
+<div class="paragraph">
+<p>There is a built-in macro definition for each profile the implementation
+supports.
+All implementations provide the following macro:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_core_profile <span class="integer">1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Implementations providing the <strong>compatibility</strong> profile provide the following
+macro:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_compatibility_profile <span class="integer">1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Implementations providing the <strong>es</strong> profile provide the following macro:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_es_profile <span class="integer">1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>#version</strong> directive must occur in a shader before anything else, except
+for comments and white space.</p>
+</div>
+<div class="paragraph">
+<p>By default, compilers of this language must issue compile-time
+lexical
+and
+grammatical errors for shaders that do not conform to this specification.
+Any extended behavior must first be enabled.
+Directives to control the behavior of the compiler with respect to
+extensions are declared with the <strong>#extension</strong> directive</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> extension_name : behavior
+<span class="preprocessor">#extension</span> all : behavior</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>extension_name</em> is the name of an extension.
+Extension names are not documented in this specification.
+The token <strong>all</strong> means the behavior applies to all extensions supported by
+the compiler.
+The <em>behavior</em> can be one of the following:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Behavior</th>
+<th class="tableblock halign-left valign-top">Effect</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>require</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br>
+              Give a compile-time error on the <strong>#extension</strong> if the extension
+              <em>extension_name</em> is not supported, or if <strong>all</strong> is specified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>enable</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.<br>
+              Give a compile-time error on the <strong>#extension</strong> if <strong>all</strong> is
+              specified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>warn</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave as specified by the extension <em>extension_name</em>,
+              except issue warnings on any detectable use of that extension,
+              unless such use is supported by other enabled or required
+              extensions.<br>
+              If <strong>all</strong> is specified, then warn on all detectable uses of any
+              extension used.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>disable</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Behave (including issuing errors and warnings) as if the
+              extension <em>extension_name</em> is not part of the language
+              definition.<br>
+              If <strong>all</strong> is specified, then behavior must revert back to that
+              of the non-extended core version of the language being
+              compiled to.<br>
+              Warn on the <strong>#extension</strong> if the extension <em>extension_name</em> is
+              not supported.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The <strong>extension</strong> directive is a simple, low-level mechanism to set the
+behavior for each extension.
+It does not define policies such as which combinations are appropriate,
+those must be defined elsewhere.
+Order of directives matters in setting the behavior for each extension:
+Directives that occur later override those seen earlier.
+The <strong>all</strong> variant sets the behavior for all extensions, overriding all
+previously issued <strong>extension</strong> directives, but only for the <em>behaviors</em>
+<strong>warn</strong> and <strong>disable</strong>.</p>
+</div>
+<div class="paragraph">
+<p>The initial state of the compiler is as if the directive</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#extension</span> all : disable</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>was issued, telling the compiler that all error and warning reporting must
+be done according to this specification, ignoring any extensions.</p>
+</div>
+<div class="paragraph">
+<p>Each extension can define its allowed granularity of scope.
+If nothing is said, the granularity is a shader (that is, a single
+compilation unit), and the extension directives must occur before any
+non-preprocessor tokens.
+If necessary, the linker can enforce granularities larger than a single
+compilation unit, in which case each involved shader will have to contain
+the necessary extension directive.</p>
+</div>
+<div class="paragraph">
+<p>Macro expansion is not done on lines containing <strong>#extension</strong> and <strong>#version</strong>
+directives.</p>
+</div>
+<div class="paragraph">
+<p><strong>#line</strong> must have, after macro substitution, one of the following forms:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#line</span> line
+<span class="preprocessor">#line</span> line source-<span class="predefined-type">string</span>-number</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>line</em> and <em>source-string-number</em> are
+constant integer expressions.
+If these constant expressions are not integer literals then behavior is undefined.
+After processing this directive (including its new-line), the implementation
+will behave as if it is compiling at line number <em>line</em> and source string
+number <em>source-string-number</em>.
+Subsequent source strings will be numbered sequentially, until another
+<strong>#line</strong> directive overrides that numbering.</p>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="title">Note</div>
+<div class="paragraph">
+<p>Some implementations have allowed constant expressions in #line directives and
+some have not. Even where expressions are supported the grammar is ambiguous and so
+results are implementation dependent. For example,
++ #line +2 +2               // Line number set to 4, or file to 2 and line to 2</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>When shaders are compiled for OpenGL SPIR-V, the following predefined
+macro is available:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_SPIRV <span class="integer">100</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="comments">3.4. Comments</h3>
+<div class="paragraph">
+<p>Comments are delimited by <strong>/*</strong> and <strong>*/</strong>, or by <strong>//</strong> and a new-line.
+The begin comment delimiters (/* or //) are not recognized as comment
+delimiters inside of a comment, hence comments cannot be nested.
+A <strong>/*</strong> comment includes its terminating delimiter (*/).
+However, a <strong>//</strong> comment does not include (or eliminate) its terminating new
+line.</p>
+</div>
+<div class="paragraph">
+<p>Inside comments, any byte values may be used, except a byte whose value is
+0.
+No errors will be given for the content of comments and no validation on the
+content of comments need be done.</p>
+</div>
+<div class="paragraph">
+<p>Removal of new-lines by the line-continuation character (<strong>\</strong>) logically
+occurs before comments are processed.
+That is, a single-line comment ending in the line-continuation character
+(<strong>\</strong>) includes the next line in the comment.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// a single-line comment containing the next line \
+a = b; // this is still in the first comment</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="tokens">3.5. Tokens</h3>
+<div class="paragraph">
+<p>The language, after preprocessing, is a sequence of tokens.
+A token can be</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>token</em> : </dt>
+<dd>
+<p><em>keyword</em><br>
+<em>identifier</em><br>
+<em>integer-constant</em><br>
+<em>floating-constant</em><br>
+<em>operator</em><br>
+<strong>;</strong> <strong>{</strong> <strong>}</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="keywords">3.6. Keywords</h3>
+<div class="paragraph">
+<p>The following are the keywords in the language and (after
+preprocessing) can only be used as described in this specification,
+or a compile-time error results:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>const</strong> <strong>uniform</strong> <strong>buffer</strong> <strong>shared</strong>
+<strong>attribute</strong> <strong>varying</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>coherent</strong> <strong>volatile</strong> <strong>restrict</strong> <strong>readonly</strong> <strong>writeonly</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>atomic_uint</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>layout</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>centroid</strong> <strong>flat</strong> <strong>smooth</strong>
+<strong>noperspective</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>patch</strong> <strong>sample</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>invariant</strong> <strong>precise</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>break</strong> <strong>continue</strong> <strong>do</strong> <strong>for</strong> <strong>while</strong> <strong>switch</strong> <strong>case</strong> <strong>default</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>if</strong> <strong>else</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>subroutine</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>in</strong> <strong>out</strong> <strong>inout</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>int</strong> <strong>void</strong> <strong>bool</strong> <strong>true</strong> <strong>false</strong> <strong>float</strong>
+<strong>double</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>discard</strong> <strong>return</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>vec2</strong> <strong>vec3</strong> <strong>vec4</strong> <strong>ivec2</strong> <strong>ivec3</strong> <strong>ivec4</strong> <strong>bvec2</strong> <strong>bvec3</strong> <strong>bvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>uint</strong> <strong>uvec2</strong> <strong>uvec3</strong> <strong>uvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dvec2</strong> <strong>dvec3</strong> <strong>dvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat2</strong> <strong>mat3</strong> <strong>mat4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat2x2</strong> <strong>mat2x3</strong> <strong>mat2x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat3x2</strong> <strong>mat3x3</strong> <strong>mat3x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>mat4x2</strong> <strong>mat4x3</strong> <strong>mat4x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat2</strong> <strong>dmat3</strong> <strong>dmat4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat2x2</strong> <strong>dmat2x3</strong> <strong>dmat2x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat3x2</strong> <strong>dmat3x3</strong> <strong>dmat3x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>dmat4x2</strong> <strong>dmat4x3</strong> <strong>dmat4x4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>lowp</strong> <strong>mediump</strong> <strong>highp</strong> <strong>precision</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler1D</strong> <strong>sampler1DShadow</strong> <strong>sampler1DArray</strong> <strong>sampler1DArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isampler1D</strong> <strong>isampler1DArray</strong> <strong>usampler1D</strong> <strong>usampler1DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2D</strong> <strong>sampler2DShadow</strong> <strong>sampler2DArray</strong> <strong>sampler2DArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isampler2D</strong> <strong>isampler2DArray</strong> <strong>usampler2D</strong> <strong>usampler2DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DRect</strong> <strong>sampler2DRectShadow</strong> <strong>isampler2DRect</strong> <strong>usampler2DRect</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DMS</strong> <strong>isampler2DMS</strong> <strong>usampler2DMS</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler2DMSArray</strong> <strong>isampler2DMSArray</strong> <strong>usampler2DMSArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler3D</strong> <strong>isampler3D</strong> <strong>usampler3D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerCube</strong> <strong>samplerCubeShadow</strong> <strong>isamplerCube</strong> <strong>usamplerCube</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerCubeArray</strong> <strong>samplerCubeArrayShadow</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>isamplerCubeArray</strong> <strong>usamplerCubeArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>samplerBuffer</strong> <strong>isamplerBuffer</strong> <strong>usamplerBuffer</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image1D</strong> <strong>iimage1D</strong> <strong>uimage1D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image1DArray</strong> <strong>iimage1DArray</strong> <strong>uimage1DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2D</strong> <strong>iimage2D</strong> <strong>uimage2D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DArray</strong> <strong>iimage2DArray</strong> <strong>uimage2DArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DRect</strong> <strong>iimage2DRect</strong> <strong>uimage2DRect</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DMS</strong> <strong>iimage2DMS</strong> <strong>uimage2DMS</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image2DMSArray</strong> <strong>iimage2DMSArray</strong> <strong>uimage2DMSArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>image3D</strong> <strong>iimage3D</strong> <strong>uimage3D</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageCube</strong> <strong>iimageCube</strong> <strong>uimageCube</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageCubeArray</strong> <strong>iimageCubeArray</strong> <strong>uimageCubeArray</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>imageBuffer</strong> <strong>iimageBuffer</strong> <strong>uimageBuffer</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>struct</strong></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The following are the keywords reserved for future use.
+Using them will result in a compile-time error:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>common</strong> <strong>partition</strong> <strong>active</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>asm</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>class</strong> <strong>union</strong> <strong>enum</strong> <strong>typedef</strong> <strong>template</strong> <strong>this</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>resource</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>goto</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>inline</strong> <strong>noinline</strong> <strong>public</strong> <strong>static</strong> <strong>extern</strong> <strong>external</strong> <strong>interface</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>long</strong> <strong>short</strong> <strong>half</strong> <strong>fixed</strong> <strong>unsigned</strong> <strong>superp</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>input</strong> <strong>output</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>hvec2</strong> <strong>hvec3</strong> <strong>hvec4</strong> <strong>fvec2</strong> <strong>fvec3</strong> <strong>fvec4</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>filter</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sizeof</strong> <strong>cast</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>namespace</strong> <strong>using</strong></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p><strong>sampler3DRect</strong></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>In addition, all identifiers containing two consecutive underscores (__)
+are reserved for use by underlying software layers.
+Defining such a name in a shader does not itself result in an error, but may
+result in unintended behaviors that stem from having multiple definitions of
+the same name.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="identifiers">3.7. Identifiers</h3>
+<div class="paragraph">
+<p>Identifiers are used for variable names, function names, structure names,
+and field selectors (field selectors select components of
+<code><a href="#vector-components">vectors</a></code> and <code><a href="#matrix-components">matrices</a></code>,
+similarly to structure members).
+Identifiers have the form:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>identifier</em> : </dt>
+<dd>
+<p><em>nondigit</em><br>
+<em>identifier</em> <em>nondigit</em><br>
+<em>identifier</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>nondigit</em> : one of </dt>
+<dd>
+<p><strong>_</strong> <strong>a b c d e f g h i j k l m n o p q r s t u v w x y z</strong><br>
+<strong>A B C D E F G H I J K L M N O P Q R S T U V W X Y Z</strong></p>
+</dd>
+<dt class="hdlist1"><em>digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7 8 9</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Identifiers starting with &#8220;gl_&#8221; are reserved for use by OpenGL, and
+in general, may not be declared in a shader;
+this results in a compile-time error.
+However, as noted in the specification, there are some cases where
+previously declared variables can be redeclared, and predeclared &#8220;gl_&#8221;
+names are allowed to be redeclared in a shader only for these specific
+purposes.</p>
+</div>
+<div class="paragraph">
+<p>Implementations must support identifier lengths of up to 1024 characters.
+Implementations are allowed to generate an error for an identifier of length
+greater than 1024 characters, but are also allowed to support lengths
+greater than 1024.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="definitions">3.8. Definitions</h3>
+<div class="paragraph">
+<p>Some language rules described below depend on the following definitions.</p>
+</div>
+<div class="sect3">
+<h4 id="static-use">3.8.1. Static Use</h4>
+<div class="paragraph">
+<p>A shader contains a <em>static use</em> of a variable <em>x</em> if, after preprocessing,
+the shader contains a statement that would access any part of <em>x</em>,
+whether or not flow of control will cause that statement to be executed.
+Such a variable is referred to as being <em>statically used</em>. If the access is a
+write then <em>x</em> is further said to be <em>statically assigned</em>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="dynamically-uniform-expressions-and-uniform-control-flow">3.8.2. Dynamically Uniform Expressions and Uniform Control Flow</h4>
+<div class="paragraph">
+<p>Some operations require an expression to be <em>dynamically uniform</em>, or that
+it be located in <em>uniform control flow</em>.
+These requirements are defined by the following set of definitions.</p>
+</div>
+<div class="paragraph">
+<p>An <em>invocation</em> is a single execution of <em>main()</em> for a particular stage,
+operating only on the amount of data explicitly exposed within that stage&#8217;s
+shaders.
+(Any implicit operation on additional instances of data would comprise
+additional invocations.) For example, in compute execution models, a single
+invocation operates only on a single work item, or, in a vertex execution
+model, a single invocation operates only on a single vertex.</p>
+</div>
+<div class="paragraph">
+<p>An <em>invocation group</em> is the complete set of invocations collectively
+processing a particular compute workgroup or graphical operation, where the
+scope of a "graphical operation" is implementation-dependent, but at least
+as large as a single triangle or patch, and at most as large as a single
+rendering command, as defined by the client API.</p>
+</div>
+<div class="paragraph">
+<p>Within a single invocation, a single shader statement can be executed
+multiple times, giving multiple <em>dynamic instances</em> of that instruction.
+This can happen when the instruction is executed in a loop, or in a function
+called from multiple call sites, or combinations of multiple of these.
+Different loop iterations and different dynamic function-call-site chains
+yield different dynamic instances of such an instruction.
+Dynamic instances are distinguished by their control-flow path within an
+invocation, not by which invocation executed it.
+That is, different invocations of <em>main()</em> execute the same dynamic
+instances of an instruction when they follow the same control-flow path.</p>
+</div>
+<div class="paragraph">
+<p>An expression is _dynamically uniform for a dynamic instance consuming it
+when its value is the same for all invocations (in the invocation group)
+that execute that dynamic instance.</p>
+</div>
+<div class="paragraph">
+<p><em>Uniform control flow</em> (or converged control flow) occurs when all
+invocations in the invocation group execute the same control-flow path (and
+hence the same sequence of dynamic instances of instructions).
+Uniform control flow is the initial state at the entry into <em>main()</em>, and
+lasts until a conditional branch takes different control paths for different
+invocations (non-uniform or divergent control flow).
+Such divergence can reconverge, with all the invocations once again
+executing the same control-flow path, and this re-establishes the existence
+of uniform control flow.
+If control flow is uniform upon entry into a selection or loop, and all
+invocations in the invocation group subsequently leave that selection or
+loop, then control flow reconverges to be uniform.</p>
+</div>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">main()
+{
+    <span class="predefined-type">float</span> a = ...; <span class="comment">// this is uniform control flow</span>
+    <span class="keyword">if</span> (a &lt; b) {   <span class="comment">// this expression is true for some fragments, not all</span>
+        ...;       <span class="comment">// non-uniform control flow</span>
+    } <span class="keyword">else</span> {
+        ...;       <span class="comment">// non-uniform control flow</span>
+    }
+    ...;           <span class="comment">// uniform control flow again</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note that constant expressions are trivially dynamically uniform.
+It follows that typical loop counters based on these are also dynamically
+uniform.</p>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="variables-and-types">4. Variables and Types</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>All variables and functions must be declared before being used.
+Variable and function names are identifiers.</p>
+</div>
+<div class="paragraph">
+<p>There are no default types.
+All variable and function declarations must have a declared type, and
+optionally qualifiers.
+A variable is declared by specifying its type followed by one or more names
+separated by commas.
+In many cases, a variable can be initialized as part of its declaration by
+using the assignment operator (<strong>=</strong>).</p>
+</div>
+<div class="paragraph">
+<p>User-defined types may be defined using <strong>struct</strong> to aggregate a list of
+existing types into a single name.</p>
+</div>
+<div class="paragraph">
+<p>The OpenGL Shading Language is type safe.
+There are some implicit conversions between types.
+Exactly how and when this can occur is described in section
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; and as referenced by other
+sections in this specification.</p>
+</div>
+<div class="sect2">
+<h3 id="basic-types">4.1. Basic Types</h3>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>A <em>basic type</em> is a type defined by a keyword in the language.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The OpenGL Shading Language supports the following basic data types, grouped as follows.</p>
+</div>
+<div class="sect3">
+<h4 id="_transparent_types">4.1.1. Transparent Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>void</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for functions that do not return a value</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bool</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a conditional type, taking on values of true or false</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a signed integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uint</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">an unsigned integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>float</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point scalar</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>double</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point scalar</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component single-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component double-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component double-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component double-precision floating-point vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>bvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component Boolean vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component signed integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a two-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a three-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a four-component unsigned integer vector</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 2 × 2 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 3 × 3 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 4 × 4 single-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 2 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 3 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a single-precision floating-point matrix with 4 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>mat4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 2 × 2 double-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 3 × 3 double-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a 4 × 4 double-precision floating-point matrix</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>dmat2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 2 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 2 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 3 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>dmat3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 3 columns and 4 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 4 columns and 2 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a double-precision floating-point matrix with 4 columns and 3 rows</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as a <strong>dmat4</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Note that where the following tables say &#8220;accessing a texture&#8221;, the
+<strong>sampler*</strong> opaque types access textures, and the <strong>image*</strong> opaque types
+access images, of a specified type.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_floating_point_opaque_types">4.1.2. Floating-Point Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler1D</strong><br>
+  <strong>image1D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 1D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler1DShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 1D depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler1DArray</strong><br>
+  <strong>image1DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 1D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler1DArrayShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 1D array depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2D</strong><br>
+  <strong>image2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArray</strong><br>
+  <strong>image2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DArrayShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D array depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMS</strong><br>
+  <strong>image2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DMSArray</strong><br>
+  <strong>image2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DRect</strong><br>
+  <strong>image2DRect</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a rectangle texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler2DRectShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a rectangle texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sampler3D</strong><br>
+  <strong>image3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCube</strong><br>
+  <strong>imageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArray</strong><br>
+  <strong>imageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerCubeArrayShadow</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a cube map array depth texture with comparison</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>samplerBuffer</strong><br>
+  <strong>imageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing a buffer texture</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_signed_integer_opaque_types">4.1.3. Signed Integer Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler1D</strong><br>
+  <strong>iimage1D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 1D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler1DArray</strong><br>
+  <strong>iimage1DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 1D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2D</strong><br>
+  <strong>iimage2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DArray</strong><br>
+  <strong>iimage2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMS</strong><br>
+  <strong>iimage2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DMSArray</strong><br>
+  <strong>iimage2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler2DRect</strong><br>
+  <strong>iimage2DRect</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 2D rectangle texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isampler3D</strong><br>
+  <strong>iimage3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCube</strong><br>
+  <strong>iimageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerCubeArray</strong><br>
+  <strong>iimageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>isamplerBuffer</strong><br>
+  <strong>iimageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an integer buffer texture</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_unsigned_integer_opaque_types">4.1.4. Unsigned Integer Opaque Types</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler1D</strong><br>
+  <strong>uimage1D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 1D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler1DArray</strong><br>
+  <strong>uimage1DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 1D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2D</strong><br>
+  <strong>uimage2D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DArray</strong><br>
+  <strong>uimage2DArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMS</strong><br>
+  <strong>uimage2DMS</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DMSArray</strong><br>
+  <strong>uimage2DMSArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 2D multisample array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler2DRect</strong><br>
+  <strong>uimage2DRect</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer rectangle texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usampler3D</strong><br>
+  <strong>uimage3D</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer 3D texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCube</strong><br>
+  <strong>uimageCube</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube mapped texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerCubeArray</strong><br>
+  <strong>uimageCubeArray</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer cube map array texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>usamplerBuffer</strong><br>
+  <strong>uimageBuffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer buffer texture</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>atomic_uint</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a handle for accessing an unsigned integer atomic counter</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>In addition, a shader can aggregate these basic types using arrays and
+structures to build more complex types.</p>
+</div>
+<div class="paragraph">
+<p>There are no pointer types.</p>
+</div>
+<div class="paragraph">
+<p>In this specification, an <em>aggregate</em> will mean a structure or array.
+(Matrices and vectors are not by themselves aggregates.) Aggregates,
+matrices, and vectors will collectively be referred to as <em>composites</em>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="void">4.1.5. Void</h4>
+<div class="paragraph">
+<p>Functions that do not return a value must be declared as <strong>void</strong>.
+There is no default function return type.
+The keyword <strong>void</strong> cannot be used in any other declarations (except for
+empty formal or actual parameter lists), or a compile-time error results.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="booleans">4.1.6. Booleans</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>A <em>boolean type</em> is any boolean scalar or vector type (<strong>bool</strong>, <strong>bvec2</strong>,
+<strong>bvec3</strong>, <strong>bvec4</strong>)</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>To make conditional execution of code easier to express, the type <strong>bool</strong> is
+supported.
+There is no expectation that hardware directly supports variables of this
+type.
+It is a genuine Boolean type, holding only one of two values meaning either
+true or false.
+Two keywords <strong>true</strong> and <strong>false</strong> can be used as literal Boolean constants.
+Booleans are declared and optionally initialized as in the follow example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">bool</span> success;      <span class="comment">// declare &quot;success&quot; to be a Boolean</span>
+<span class="predefined-type">bool</span> done = <span class="predefined-constant">false</span>; <span class="comment">// declare and initialize &quot;done&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Expressions used for conditional jumps (<strong>if</strong>, <strong>for</strong>, <strong>?:</strong>, <strong>while</strong>,
+<strong>do</strong>-<strong>while</strong>) must evaluate to the type <strong>bool</strong>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="integers">4.1.7. Integers</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definitions</dt>
+<dd>
+<p>An <em>integral type</em> is any signed or unsigned, scalar or vector integer type.
+It excludes arrays and structures.</p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>A <em>scalar integral type</em> is a scalar signed or unsigned integer type:</p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>A <em>vector integral type</em> is a vector of signed or unsigned integers:</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Signed and unsigned integer variables are fully supported.
+In this document, the term <em>integer</em> is meant to generally include both
+signed and unsigned integers.
+Unsigned
+integers have exactly 32 bits of precision.
+Signed
+integers use 32 bits, including a sign bit, in two&#8217;s complement form.</p>
+</div>
+<div class="paragraph">
+<p>Addition, subtraction, and shift
+operations resulting in overflow or
+underflow will not cause any exception, nor will they saturate, rather they
+will &#8220;wrap&#8221; to yield the low-order
+32 bits of the result.
+Division and multiplication operations resulting in overflow or underflow
+will not cause any exception but will result in an undefined value.</p>
+</div>
+<div class="paragraph">
+<p>Integers are declared and optionally initialized with integer expressions,
+as in the following example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> i, j = <span class="integer">42</span>; <span class="comment">// default integer literal type is int</span>
+uint k = <span class="integer">3</span>u;   <span class="comment">// &quot;u&quot; establishes the type as uint</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Literal integer constants can be expressed in decimal (base 10), octal (base
+8), or hexadecimal (base 16) as follows.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>integer-constant</em> : </dt>
+<dd>
+<p><em>decimal-constant</em> <em>integer-suffix<sub>opt</sub></em><br>
+<em>octal-constant</em> <em>integer-suffix<sub>opt</sub></em><br>
+<em>hexadecimal-constant</em> <em>integer-suffix<sub>opt</sub></em></p>
+</dd>
+<dt class="hdlist1"><em>integer-suffix</em> : one of </dt>
+<dd>
+<p><strong>u</strong> <strong>U</strong></p>
+</dd>
+<dt class="hdlist1"><em>decimal-constant</em> : </dt>
+<dd>
+<p><em>nonzero-digit</em><br>
+<em>decimal-constant</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>octal-constant</em> : </dt>
+<dd>
+<p><strong>0</strong><br>
+<em>octal-constant</em> <em>octal-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>hexadecimal-constant</em> : </dt>
+<dd>
+<p><strong>0x</strong> <em>hexadecimal-digit</em><br>
+<strong>0X</strong> <em>hexadecimal-digit</em><br>
+<em>hexadecimal-constant</em> <em>hexadecimal-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>digit</em> : </dt>
+<dd>
+<p><strong>0</strong><br>
+<em>nonzero-digit</em></p>
+</dd>
+<dt class="hdlist1"><em>nonzero-digit</em> : one of </dt>
+<dd>
+<p><strong>1 2 3 4 5 6 7 8 9</strong></p>
+</dd>
+<dt class="hdlist1"><em>octal-digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7</strong></p>
+</dd>
+<dt class="hdlist1"><em>hexadecimal-digit</em> : one of </dt>
+<dd>
+<p><strong>0 1 2 3 4 5 6 7 8 9<br>
+a b c d e f<br>
+A B C D E F</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>No white space is allowed between the digits of an integer constant,
+including after the leading <strong>0</strong> or after the leading <strong>0x</strong> or <strong>0X</strong> of a
+constant, or before the suffix <strong>u</strong> or <strong>U</strong>.
+When tokenizing, the maximal token matching the above will be recognized
+before a new token is started.
+When the suffix <strong>u</strong> or <strong>U</strong> is present, the literal has type <strong>uint</strong>,
+otherwise the type is <strong>int</strong>.
+A leading unary minus sign (-) is interpreted as an arithmetic unary
+negation, not as part of the constant.
+Hence, literals themselves are always expressed with non-negative syntax,
+though they could result in a negative value.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to provide a literal integer whose bit pattern
+cannot fit in 32 bits.
+The bit pattern of the literal is always used unmodified.
+So a signed literal whose bit pattern includes a set sign bit creates a
+negative value.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="integer">1</span>             <span class="comment">// OK. Signed integer, value 1</span>
+<span class="integer">1</span>u            <span class="comment">// OK. Unsigned integer, value 1</span>
+-<span class="integer">1</span>            <span class="comment">// OK. Unary minus applied to signed integer.</span>
+              <span class="comment">// result is a signed integer, value -1</span>
+-<span class="integer">1</span>u           <span class="comment">// OK. Unary minus applies to unsigned integer.</span>
+              <span class="comment">// Result is an unsigned integer, value 0xffffffff</span>
+<span class="hex">0xA0000000</span>    <span class="comment">// OK. 32-bit signed hexadecimal</span>
+<span class="hex">0xABcdEF00</span>u   <span class="comment">// OK. 32-bit unsigned hexadecimal</span>
+<span class="hex">0xffffffff</span>    <span class="comment">// OK. Signed integer, value -1</span>
+<span class="hex">0x80000000</span>    <span class="comment">// OK. Evaluates to -2147483648</span>
+<span class="hex">0xffffffff</span>u   <span class="comment">// OK. Unsigned integer, value 0xffffffff</span>
+<span class="hex">0xfffffffff</span>   <span class="comment">// Error: needs more than 32 bits</span>
+<span class="integer">3000000000</span>    <span class="comment">// OK. A signed decimal literal taking 32 bits.</span>
+              <span class="comment">// It evaluates to -1294967296</span>
+<span class="integer">2147483648</span>    <span class="comment">// OK. Evaluates to -2147483648 (the literal set the sign bit)</span>
+<span class="integer">5000000000</span>    <span class="comment">// Error: needs more than 32 bits</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="floats">4.1.8. Floats</h4>
+<div class="paragraph">
+<p>Single-precision and double-precision floating-point variables are available
+for use in a variety of scalar calculations.
+Generally, the term <em>floating-point</em> will refer to both single- and
+double-precision floating-point.
+Floating-point variables are defined as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a, b = <span class="float">1</span><span class="float">.5</span>;    <span class="comment">// single-precision floating-point</span>
+<span class="predefined-type">double</span> c, d = <span class="float">2</span><span class="float">.0</span>LF; <span class="comment">// double-precision floating-point</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>As an input value to one of the processing units, a single-precision or
+double-precision floating-point variable is expected to match the
+corresponding IEEE 754 floating-point definition for precision and dynamic
+range.
+Floating-point variables within a shader are also encoded according to the
+IEEE 754 specification for single-precision floating-point values</p>
+</div>
+<div class="paragraph">
+<p>(logically, not necessarily physically).
+While encodings are logically IEEE 754, operations (addition,
+multiplication, etc.) are not necessarily performed as required by IEEE 754.
+See &#8220;<a href="#range-and-precision">Range and Precision</a>&#8221; for more details on
+precision and usage of NaNs (Not a Number) and Infs (positive or negative
+infinities).</p>
+</div>
+<div class="paragraph">
+<p>Floating-point constants are defined as follows.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>floating-constant</em> : </dt>
+<dd>
+<p><em>fractional-constant</em> <em>exponent-part<sub>opt</sub></em> <em>floating-suffix<sub>opt</sub></em><br>
+<em>digit-sequence</em> <em>exponent-part</em> <em>floating-suffix<sub>opt</sub></em></p>
+</dd>
+<dt class="hdlist1"><em>fractional-constant</em> : </dt>
+<dd>
+<p><em>digit-sequence</em> <strong>.</strong> <em>digit-sequence</em><br>
+<em>digit-sequence</em> <strong>.</strong><br>
+<strong>.</strong> <em>digit-sequence</em></p>
+</dd>
+<dt class="hdlist1"><em>exponent-part</em> : </dt>
+<dd>
+<p><strong>e</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em><br>
+<strong>E</strong> <em>sign<sub>opt</sub></em> <em>digit-sequence</em></p>
+</dd>
+<dt class="hdlist1"><em>sign</em> : one of </dt>
+<dd>
+<p><strong>+</strong> <strong>-</strong></p>
+</dd>
+<dt class="hdlist1"><em>digit-sequence</em> : </dt>
+<dd>
+<p><em>digit</em><br>
+<em>digit-sequence</em> <em>digit</em></p>
+</dd>
+<dt class="hdlist1"><em>floating-suffix</em> : one of </dt>
+<dd>
+<p>    <strong>f</strong> <strong>F</strong>
+<strong>lf</strong> <strong>LF</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>A decimal point (<strong>.</strong>) is not needed if the exponent part is present.
+No white space may appear anywhere within a floating-point constant,
+including before a suffix.
+When tokenizing, the maximal token matching the above will be recognized
+before a new token is started.
+When the suffix "lf" or "LF" is present, the literal has type <strong>double</strong>.
+Otherwise, the literal has type <strong>float</strong>.
+A leading unary minus sign (<strong>-</strong>) is interpreted as a unary operator and is
+not part of the floating-point constant.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="vectors">4.1.9. Vectors</h4>
+<div class="paragraph">
+<p>The OpenGL Shading Language includes data types for generic 2-, 3-, and 4-component vectors
+of floating-point values, integers, and Booleans.
+Floating-point vector variables can be used to store colors, normals,
+positions, texture coordinates, texture lookup results and the like.
+Boolean vectors can be used for component-wise comparisons of numeric
+vectors.
+Some examples of vector declarations are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec2 texcoord1, texcoord2;
+vec3 position;
+vec4 myRGBA;
+ivec2 textureLookup;
+bvec3 less;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Initialization of vectors can be done with constructors.
+See &#8220;<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="matrices">4.1.10. Matrices</h4>
+<div class="paragraph">
+<p>The OpenGL Shading Language has built-in types for 2 × 2, 2 × 3, 2 × 4, 3
+× 2, 3 × 3, 3 × 4, 4 × 2, 4 × 3, and 4 ×
+4 matrices of floating-point numbers.
+Matrix types beginning with "<strong>mat</strong>" have single-precision components while
+matrix types beginning with "<strong>dmat</strong>" have double-precision components.
+The first number in the type is the number of columns, the second is the
+number of rows.
+If there is only one number, the matrix is square.
+Example matrix declarations:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2 mat2D;
+mat3 optMatrix;
+mat4 view, projection;
+mat4x4 view; <span class="comment">// an alternate way of declaring a mat4</span>
+mat3x2 m;    <span class="comment">// a matrix with 3 columns and 2 rows</span>
+dmat4 highPrecisionMVP;
+dmat2x4 dm;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Initialization of matrix values is done with constructors (described in
+&#8220;<a href="#vector-and-matrix-constructors">Vector and Matrix Constructors</a>&#8221;) in
+column-major order.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="opaque-types">4.1.11. Opaque Types</h4>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">Definition</dt>
+<dd>
+<p>An <em>opaque type</em> is a type where the internal structure of the type is
+hidden from the language.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The opaque types, as listed in the following sections, declare variables
+that are effectively opaque handles to other objects.
+These objects are accessed through built-in functions, not through direct
+reading or writing of the declared variable.
+They can only be declared as function parameters or in <strong>uniform</strong>-qualified
+variables (see &#8220;<a href="#uniform-variables">Uniform Variables</a>&#8221;).
+The only opaque types that take memory qualifiers are the image types.
+Except for array indexing, structure member selection, and parentheses,
+opaque variables are not allowed to be operands in expressions; such use
+results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>Opaque variables cannot be treated as l-values; hence cannot be used as
+<strong>out</strong> or <strong>inout</strong> function parameters, nor can they be assigned into.
+Any such use results in a compile-time error.
+However, they can be passed as <strong>in</strong> parameters with matching types and
+memory qualifiers.
+They cannot be declared with an initializer.</p>
+</div>
+<div class="paragraph">
+<p>Because a single opaque type declaration effectively declares two objects,
+the opaque handle itself and the object it is a handle to, there is room for
+both a storage qualifier and a memory qualifier.
+The storage qualifier will qualify the opaque handle, while the memory
+qualifier will qualify the object it is a handle to.</p>
+</div>
+<div class="sect4">
+<h5 id="samplers">Samplers</h5>
+<div class="paragraph">
+<p>Sampler types (e.g. <strong>sampler2D</strong>) are opaque types, declared and behaving as
+described above for opaque types.
+When aggregated into arrays within a shader, samplers can only be indexed
+with a dynamically uniform integral expression, otherwise results are
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>Sampler variables are handles to
+one-,
+two-, and three- dimensional textures, cube maps, depth textures (shadowing),
+etc., as enumerated in the basic types tables.
+There are distinct sampler types for each texture target, and for each of
+float, integer, and unsigned integer data types.
+Texture accesses are done through built-in texture functions (described in
+&#8220;<a href="#texture-functions">Texture Functions</a>&#8221;) and samplers are used to
+specify which texture to access and how it is to be filtered.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="images">Images</h5>
+<div class="paragraph">
+<p>Image types are opaque types, declared and behaving as described above for
+opaque types.
+They can be further qualified with memory qualifiers.
+When aggregated into arrays within a shader, images can only be indexed with
+a dynamically uniform integral expression, otherwise results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>Image variables are handles to
+one-,
+two-, or three-dimensional images
+corresponding to all or a portion of a single level of a texture image bound
+to an image unit.
+There are distinct image variable types for each texture target, and for
+each of float, integer, and unsigned integer data types.
+Image accesses should use an image type that matches the target of the
+texture whose level is bound to the image unit, or for non-layered bindings
+of 3D or array images should use the image type that matches the
+dimensionality of the layer of the image (i.e., a layer of 3D, 2DArray,
+Cube, or CubeArray should use
+<strong>image2D</strong>, a layer of 1DArray should use <strong>image1D</strong>, and a layer of 2DMSArray
+should use <strong>image2DMS</strong>).
+If the image target type does not match the bound image in this manner, if
+the data type does not match the bound image, or if the format layout
+qualifier does not match the image unit format as described in section
+8.25
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL Specification</a>, the
+results of image accesses are undefined but cannot include program
+termination.</p>
+</div>
+<div class="paragraph">
+<p>Image variables are used in the image load, store, and atomic functions
+described in &#8220;<a href="#image-functions">Image Functions</a>&#8221; to specify an image to
+access.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="atomic-counters">Atomic Counters</h5>
+<div class="paragraph">
+<p>Atomic counter types (e.g. <strong>atomic_uint</strong>) are opaque handles to counters,
+declared and behaving as described above for opaque types.
+The variables they declare specify which counter to access when using the
+built-in atomic counter functions as described in
+&#8220;<a href="#atomic-counter-functions">Atomic Counter Functions</a>&#8221;.
+They are bound to buffers as described in
+&#8220;<a href="#atomic-counter-layout-qualifiers">Atomic Counter Layout Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Atomic counters aggregated into arrays within a shader can only be indexed
+with dynamically uniform integral expressions, otherwise results are
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>Members of structures cannot be declared as atomic counter types.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="structures">4.1.12. Structures</h4>
+<div class="paragraph">
+<p>User-defined types can be created by aggregating other already defined types
+into a structure using the <strong>struct</strong> keyword.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light {
+    <span class="predefined-type">float</span> intensity;
+    vec3 position;
+} lightVar;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In this example, <em>light</em> becomes the name of the new type, and <em>lightVar</em>
+becomes a variable of type <em>light</em>.
+To declare variables of the new type, use its name (without the keyword
+<strong>struct</strong>).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">light lightVar2;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>More formally, structures are declared as follows.
+However, the definitive grammar is as given in
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221;.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>struct-definition</em> : </dt>
+<dd>
+<p><em>qualifier<sub>opt</sub></em> <strong>struct</strong> name<sub>opt</sub>_ <strong>{</strong> <em>member-list</em> <strong>}</strong>
+<em>declarators<sub>opt</sub></em> <strong>;</strong></p>
+</dd>
+<dt class="hdlist1"><em>member-list</em> : </dt>
+<dd>
+<p><em>member-declaration</em> <strong>;</strong><br>
+<em>member-declaration</em> <em>member-list</em> <strong>;</strong></p>
+</dd>
+<dt class="hdlist1"><em>member-declaration</em> : </dt>
+<dd>
+<p><em>basic-type</em> <em>declarators</em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>name</em> becomes the user-defined type, and can be used to declare
+variables to be of this new type.
+The <em>name</em> shares the same name space as other variables, types, and
+functions.
+All previously visible variables, types, constructors, or functions with
+that name are hidden.
+The optional <em>qualifier</em> only applies to any <em>declarators</em>, and is not part
+of the type being defined for <em>name</em>.</p>
+</div>
+<div class="paragraph">
+<p>Structures must have at least one member declaration.
+Member declarators may contain precision qualifiers, but use of any other
+qualifier results in a compile-time error.
+Bit fields are not supported.
+Member types must be already defined (there are no forward references).
+A compile-time error results if a member declaration contains an
+initializer.
+Member declarators can contain arrays.
+Such arrays must have a size specified, and the size must be a constant
+integral expression that&#8217;s greater than zero (see
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;).
+Each level of structure has its own name space for names given in member
+declarators; such names need only be unique within that name space.</p>
+</div>
+<div class="paragraph">
+<p>Anonymous structures are not supported.
+Embedded structure definitions are not supported.
+These result in compile-time errors.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> S { <span class="predefined-type">float</span> f; }; <span class="comment">// Allowed: S is defined as a structure.</span>
+
+<span class="keyword">struct</span> T {
+    S;              <span class="comment">// Error: anonymous structures disallowed</span>
+    <span class="keyword">struct</span> { ... }; <span class="comment">// Error: embedded structures disallowed</span>
+    S s;            <span class="comment">// Allowed: nested structure with a name.</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Structures can be initialized at declaration time using constructors, as
+discussed in &#8220;<a href="#structure-constructors">Structure Constructors</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Any restrictions on the usage of a type or qualifier also apply to any
+structure that contains a member of that type or qualifier.
+This also applies to structure members that are structures, recursively.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="arrays">4.1.13. Arrays</h4>
+<div class="paragraph">
+<p>Variables of the same type can be aggregated into arrays by declaring a name
+followed by brackets (<strong>[ ]</strong>) enclosing an optional size.
+When an array size is specified in a declaration, it must be an integral
+constant expression (see &#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;)
+greater than zero.
+Except for the last declared member of a shader storage block (see section
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221;), the size of an array must be
+declared (<em>explicitly sized</em>) before it is indexed with anything other than
+a constant integral expression.
+The size of any array must be declared before passing it as an argument to a
+function.
+Violation of any of these rules result in compile-time errors.
+It is legal to declare an array without a size (<em>unsized</em>) and then later
+redeclare the same name as an array of the same type and specify a size, or
+index it only with constant integral expressions (<em>implicitly sized</em>).
+However, unless noted otherwise, blocks cannot be redeclared; an unsized
+array member in a user-declared block cannot be sized by a block redeclaration.
+It is a compile-time error to declare an array with a size, and then later
+(in the same shader) index the same array with a constant integral
+expression greater than or equal to the declared size.
+It is a compile-time error to redeclare an unsized array with a size equal
+to or smaller than any index used earlier in the shader to index the array.
+It is also a compile-time error to index an array with a negative constant
+expression.
+Arrays declared as formal parameters in a function declaration must specify
+a size.
+Undefined behavior results from indexing an array with a non-constant
+expression that&#8217;s greater than or equal to the array&#8217;s size or less than 0.
+Arrays only have a single dimension (a single entry within "[ ]"), however,
+arrays of arrays can be declared.
+All types (basic types, structures, arrays) can be formed into an array.</p>
+</div>
+<div class="paragraph">
+<p>All arrays are inherently homogeneous; made of elements all having the same
+type and size, with one exception.
+The exception is a shader storage block having an unsized array as its last
+member (<em>run-time sized</em>); an array can be formed from such a shader storage
+block, even if the storage blocks have differing lengths for their last
+member.</p>
+</div>
+<div class="paragraph">
+<p>Some examples are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> frequencies[<span class="integer">3</span>];
+uniform vec4 lightPosition[<span class="integer">4</span>];
+light lights[];
+<span class="directive">const</span> <span class="predefined-type">int</span> numLights = <span class="integer">2</span>;
+light lights[numLights];
+
+<span class="comment">// a shader storage block, introduced in section 4.3.7 &quot;Buffer Variables&quot;</span>
+buffer b {
+    <span class="predefined-type">float</span> u[]; <span class="comment">// an error, unless u gets statically sized by link time</span>
+    vec4 v[];  <span class="comment">// okay, v will be sized dynamically, if not statically</span>
+} name[<span class="integer">3</span>];     <span class="comment">// when the block is arrayed, all u will be the same size,</span>
+               <span class="comment">// but not necessarily all v, if sized dynamically</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>An array type can be formed by specifying non-array type followed by an
+array specifier.
+All dimensions of such an array specifier must include a size.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>]    <span class="comment">// an array of size [5] of float</span>
+<span class="predefined-type">float</span>[<span class="integer">2</span>][<span class="integer">3</span>] <span class="comment">// an array of size [2][3] of float, not size [3] of float[2]</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This type can be used anywhere any other type can be used, including as the
+return value from a function</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] foo() { }</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>as a constructor of an array:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>as an unnamed parameter:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> foo(<span class="predefined-type">float</span>[<span class="integer">5</span>])</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and as an alternate way of declaring a variable or function parameter:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span>[<span class="integer">5</span>] a;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Arrays can have initializers formed from array constructors:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+<span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);  <span class="comment">// same thing</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>An array of arrays can be declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 a[<span class="integer">3</span>][<span class="integer">2</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>which declares a one-dimensional array of size 3 of one-dimensional arrays
+of size 2 of <strong>vec4</strong>.
+The following declarations do the same thing:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4[<span class="integer">2</span>] a[<span class="integer">3</span>]; <span class="comment">// size-3 array of size-2 array of vec4</span>
+vec4[<span class="integer">3</span>][<span class="integer">2</span>] a; <span class="comment">// size-3 array of size-2 array of vec4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When in transparent memory (like in a uniform block), the layout is that the
+inner-most (right-most in declaration) dimensions iterate faster than the
+outer dimensions.
+That is, for the above, the order in memory would be:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>Low address : a[0][0] : a[0][1] : a[1][0] : a[1][1] : a[2][0] : a[2][1]
+: High address</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The type of <em>a</em> needed for both constructors and nameless parameters is
+&#8220;vec4[3][2]&#8221;:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 b[<span class="integer">2</span>] = vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">0</span><span class="float">.1</span>));
+vec4[<span class="integer">3</span>][<span class="integer">2</span>] a = vec4[<span class="integer">3</span>][<span class="integer">2</span>](b, b, b);        <span class="comment">// constructor</span>
+<span class="directive">void</span> foo(vec4[<span class="integer">3</span>][<span class="integer">2</span>]); <span class="comment">// prototype with unnamed parameter</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Alternatively, the initializer-list syntax can be used to initialize an
+array of arrays:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 a[<span class="integer">3</span>][<span class="integer">2</span>] = { vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)),
+                 vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)),
+                 vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)) };</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Unsized arrays can be explicitly sized by an initializer at declaration
+time:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>];
+...
+<span class="predefined-type">float</span> b[] = a;  <span class="comment">// b is explicitly size 5</span>
+<span class="predefined-type">float</span> b[<span class="integer">5</span>] = a; <span class="comment">// means the same thing</span>
+<span class="predefined-type">float</span> b[] = <span class="predefined-type">float</span>[](<span class="integer">1</span>,<span class="integer">2</span>,<span class="integer">3</span>,<span class="integer">4</span>,<span class="integer">5</span>); <span class="comment">// also explicitly sizes to 5</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>However, it is a compile-time error to assign to an unsized array.
+Note, this is a rare case that initializers and assignments appear to have
+different semantics.
+For arrays of arrays, any unsized dimension is explicitly sized by the
+initializer:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 a[][] = { vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)), <span class="comment">// okay, size to a[3][2]</span>
+               vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)),
+               vec4[<span class="integer">2</span>](vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.0</span>)) };</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Arrays know the number of elements they contain.
+This can be obtained by using the <strong>length</strong>() method:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">5</span>];
+a.length(); <span class="comment">// returns 5</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This returns a type <strong>int</strong>.
+If an array has been explicitly sized, the value returned by the <strong>length</strong>()
+method is a constant expression.
+If an array has not been explicitly sized and is the last declared member of
+a shader storage block, the value returned will not be a constant expression
+and will be determined at runtime based on the size of the buffer object
+providing storage for the block.
+Such arrays are runtime sized.
+For runtime-sized arrays, the value returned by the <strong>length</strong>() method will be
+undefined if the array is contained in an array of shader storage blocks
+that is indexed with a non-constant expression less than zero or greater
+than or equal to the number of blocks in the array.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>length</strong>() method cannot be called on an array that is not runtime sized
+and also has not yet been explicitly sized;
+this results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>When the <strong>length</strong>() method returns a compile-time constant, the expression the
+<strong>length</strong>() method is applied to cannot contain any side effects, such as writes
+to l-values within the expression, or function calls that themselves have side
+effects: only the compile-time constant length itself need be computed.
+Behavior and results, including any compile-time error reporting,
+are undefined if the expression contains other effects.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a, b;
+<span class="directive">const</span> <span class="predefined-type">int</span> s = <span class="predefined-type">float</span>[<span class="integer">2</span>](a=<span class="float">3</span><span class="float">.0</span>, ++b).length(); <span class="comment">// illegal side effects</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>length</strong>() method works equally well for arrays of arrays:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 a[<span class="integer">3</span>][<span class="integer">2</span>];
+a.length()    <span class="comment">// this is 3</span>
+a[x].length() <span class="comment">// this is 2</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When the <strong>length</strong>() method returns a compile-time constant, the expression
+in brackets (<em>x</em> above) will be parsed and subjected to the rules required for
+array indexes, but the array will not be dereferenced.
+Thus, behavior is well defined even if the run-time value of the expression
+is out of bounds, as long as the expression contains no side effects.</p>
+</div>
+<div class="paragraph">
+<p>When the <strong>length</strong>() method returns a run-time value
+(not a compile-time constant), the array will be
+dereferenced.
+E.g., if <em>x</em> is not a compile-time constant and is out of range, an undefined
+value results.
+More generally, all involved expressions are fully evaluated and executed.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// for a compile time-sized array b containing a member array a:</span>
+b[x+<span class="integer">3</span>].a.length(); <span class="comment">// b is never dereferenced, x+3 is evaluated and checked</span>
+b[++x].a.length(); <span class="comment">// not allowed; results are undefined</span>
+
+<span class="comment">// for an array s of a shader storage object (run-time sized) containing a member array a:</span>
+s[++x].a.length(); <span class="comment">// s is dereferenced; ++x needs to be a valid index</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For implicitly-sized or run-time-sized arrays, only the outer-most dimension
+can be lacking a size.
+A type that includes an unknown array size cannot be formed into an array
+until it gets an explicit size, except for shader storage blocks where the
+only unsized array member is the last member of the block.</p>
+</div>
+<div class="paragraph">
+<p>In a shader storage block, the last member may be declared without an
+explicit size.
+In this case, the effective array size is inferred at run-time from the size
+of the data store backing the interface block.
+Such run-time-sized arrays may be indexed with general integer expressions.
+However, it is a compile-time error to pass them as an argument to a
+function or index them with a negative constant expression.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="implicit-conversions">4.1.14. Implicit Conversions</h4>
+<div class="paragraph">
+<p>In some situations, an expression and its type will be implicitly converted
+to a different type.
+The following table shows all allowed implicit conversions:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Type of expression</th>
+<th class="tableblock halign-left valign-top">Can be implicitly converted to</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uint</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong><br>
+  <strong>uint</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>float</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>int</strong><br>
+  <strong>uint</strong><br>
+  <strong>float</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>double</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uvec4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong><br>
+  <strong>uvec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong><br>
+  <strong>uvec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong><br>
+  <strong>uvec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vec4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec2</strong><br>
+  <strong>uvec2</strong><br>
+  <strong>vec2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec3</strong><br>
+  <strong>uvec3</strong><br>
+  <strong>vec3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>ivec4</strong><br>
+  <strong>uvec4</strong><br>
+  <strong>vec4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dvec4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2x3</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat2x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat2x4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3x2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat3x4</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat3x4</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x2</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4x2</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mat4x3</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>dmat4x3</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>There are no implicit array or structure conversions.
+For example, an array of <strong>int</strong> cannot be implicitly converted to an array of
+<strong>float</strong>.</p>
+</div>
+<div class="paragraph">
+<p>When an implicit conversion is done, it is the same conversion that would be
+done under explicit conversion, using a constructor.
+The explicit conversions via constructors are described in
+<a href="#conversion-and-scalar-constructors">Conversion and Scalar Constructors</a>.</p>
+</div>
+<div class="paragraph">
+<p>When performing implicit conversion for binary operators, there may be
+multiple data types to which the two operands can be converted.
+For example, when adding an <strong>int</strong> value to a <strong>uint</strong> value, both values can
+be implicitly converted to <strong>uint</strong>, <strong>float</strong>, and <strong>double</strong>.
+In such cases, a floating-point type is chosen if either operand has a
+floating-point type.
+Otherwise, an unsigned integer type is chosen if either operand has an
+unsigned integer type.
+Otherwise, a signed integer type is chosen.
+If operands can be implicitly converted to multiple data types deriving from
+the same base data type, the type with the smallest component size is used.</p>
+</div>
+<div class="paragraph">
+<p>The conversions in the table above are done only as indicated by other
+sections of this specification.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="initializers">4.1.15. Initializers</h4>
+<div class="paragraph">
+<p>At declaration, an initial value for a variable may be provided, specified
+as an equals (=) followed by an initializer.
+The initializer is either an <em>assignment-expression</em> or a list of
+initializers enclosed in curly braces.
+The grammar for the initializer is:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>initializer</em> : </dt>
+<dd>
+<p><em>assignment-expression</em><br>
+<strong>{</strong> <em>initializer-list</em> <strong>}</strong><br>
+<strong>{</strong> <em>initializer-list</em> <strong>,</strong> <strong>}</strong></p>
+</dd>
+<dt class="hdlist1"><em>initializer-list</em> : </dt>
+<dd>
+<p><em>initializer</em><br>
+<em>initializer-list</em> , <em>initializer</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <em>assignment-expression</em> is a normal expression except that a comma (<strong>,</strong>)
+outside parentheses is interpreted as the end of the initializer, not as the
+sequence operator.
+As explained in more detail below, this allows creation of nested
+initializers: The variable type and its initializer must exactly match in
+terms of nesting, number of components/elements/members present at each
+level, and types of components/elements/members.
+An <em>assignment-expression</em> at global scope can include calls to user-defined
+functions.</p>
+</div>
+<div class="paragraph">
+<p>An <em>assignment-expression</em> in an initializer must be either the same type as
+the object it initializes or be a type that can be converted to the object&#8217;s
+type according to &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221;.
+Since these include constructors, a composite variable can be initialized by
+either a constructor or an initializer list; and an element in an
+initializer list can be a constructor.</p>
+</div>
+<div class="paragraph">
+<p>If an initializer is a list of initializers enclosed in curly braces, the
+variable being declared must be a vector, a matrix, an array, or a
+structure.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> i = { <span class="integer">1</span> }; <span class="comment">// illegal, i is not a composite</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A list of initializers enclosed in a matching set of curly braces is applied
+to one composite.
+This may be the variable being declared or a composite contained in the
+variable being declared.
+Individual initializers from the initializer list are applied to the
+elements/members of the composite, in order.</p>
+</div>
+<div class="paragraph">
+<p>If the composite has a vector type, initializers from the list are applied
+to the components of the vector, in order, starting with component 0.
+The number of initializers must match the number of components.</p>
+</div>
+<div class="paragraph">
+<p>If the composite has a matrix type, initializers from the list must be
+vector initializers and are applied to the columns of the matrix, in order,
+starting with column 0.
+The number of initializers must match the number of columns.</p>
+</div>
+<div class="paragraph">
+<p>If the composite has a structure type, initializers from the list are
+applied to the members of the structure, in the order declared in the
+structure, starting with the first member.
+The number of initializers must match the number of members.</p>
+</div>
+<div class="paragraph">
+<p>Applying these rules, the following matrix declarations are equivalent:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2x2 a = mat2(  vec2( <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span> ), vec2( <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span> ) );
+mat2x2 b =      { vec2( <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span> ), vec2( <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span> ) };
+mat2x2 c =      {     { <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span> },     { <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span> } };</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>All of the following declarations result in a compile-time error.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[<span class="integer">2</span>] = { <span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span> };         <span class="comment">// illegal</span>
+vec2 b = { <span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span> };             <span class="comment">// illegal</span>
+mat3x3 c = { vec3(<span class="float">0</span><span class="float">.0</span>), vec3(<span class="float">1</span><span class="float">.0</span>), vec3(<span class="float">2</span><span class="float">.0</span>), vec3(<span class="float">3</span><span class="float">.0</span>) }; <span class="comment">// illegal</span>
+mat2x2 d = { <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span> };      <span class="comment">// illegal, can't flatten nesting</span>
+<span class="keyword">struct</span> {
+    <span class="predefined-type">float</span> a;
+    <span class="predefined-type">int</span> b;
+} e = { <span class="float">1</span><span class="float">.2</span>, <span class="integer">2</span>, <span class="integer">3</span> };                    <span class="comment">// illegal</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In all cases, the inner-most initializer (i.e., not a list of initializers
+enclosed in curly braces) applied to an object must have the same type as
+the object being initialized or be a type that can be converted to the
+object&#8217;s type according to &#8220;<a href="#implicit-conversions">Implicit
+Conversions</a>&#8221;.
+In the latter case, an implicit conversion will be done on the initializer
+before the assignment is done.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> {
+    <span class="predefined-type">float</span> a;
+    <span class="predefined-type">int</span> b;
+} e = { <span class="float">1</span><span class="float">.2</span>, <span class="integer">2</span> }; <span class="comment">// legal, all types match</span>
+<span class="keyword">struct</span> {
+    <span class="predefined-type">float</span> a;
+    <span class="predefined-type">int</span> b;
+} e = { <span class="integer">1</span>, <span class="integer">3</span> };   <span class="comment">// legal, first initializer is converted</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>All of the following declarations result in a compile-time error.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> a = <span class="predefined-constant">true</span>;                         <span class="comment">// illegal</span>
+vec4 b[<span class="integer">2</span>] = { vec4(<span class="float">0</span><span class="float">.0</span>), <span class="float">1</span><span class="float">.0</span> };       <span class="comment">// illegal</span>
+mat4x2 c = { vec3(<span class="float">0</span><span class="float">.0</span>), vec3(<span class="float">1</span><span class="float">.0</span>) };  <span class="comment">// illegal</span>
+
+<span class="keyword">struct</span> S1 {
+    vec4 a;
+    vec4 b;
+};
+
+<span class="keyword">struct</span> {
+    <span class="predefined-type">float</span> s;
+    <span class="predefined-type">float</span> t;
+} d[] = { S1(vec4(<span class="float">0</span><span class="float">.0</span>), vec4(<span class="float">1</span><span class="float">.1</span>)) }; <span class="comment">// illegal</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If an initializer (of either form) is provided for an unsized array, the
+size of the array is determined by the number of top-level (non-nested)
+initializers within the initializer.
+All of the following declarations create arrays explicitly sized with five
+elements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> a[] = <span class="predefined-type">float</span>[](<span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+<span class="predefined-type">float</span> b[] = { <span class="float">3</span><span class="float">.4</span>, <span class="float">4</span><span class="float">.2</span>, <span class="float">5</span><span class="float">.0</span>, <span class="float">5</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span> };
+<span class="predefined-type">float</span> c[] = a;                          <span class="comment">// c is explicitly size 5</span>
+<span class="predefined-type">float</span> d[<span class="integer">5</span>] = b;                         <span class="comment">// means the same thing</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to have too few or too many initializers in an
+initializer list for the composite being initialized.
+That is, all elements of an array, all members of a structure, all columns
+of a matrix, and all components of a vector must have exactly one
+initializer expression present, with no unconsumed initializers.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="scoping">4.2. Scoping</h3>
+<div class="paragraph">
+<p>The scope of a variable is determined by where it is declared.
+If it is declared outside all function definitions, it has global scope,
+which starts from where it is declared and persists to the end of the shader
+it is declared in.
+If it is declared in a <strong>while</strong> test or a <strong>for</strong> statement, then it is scoped
+to the end of the following sub-statement.
+If it is declared in an <strong>if</strong> or <strong>else</strong> statement, it is scoped to the end of
+that statement.
+(See &#8220;<a href="#selection">Selection</a>&#8221; and &#8220;<a href="#iteration">Iteration</a>&#8221; for the
+location of statements and sub-statements.) Otherwise, if it is declared as
+a statement within a compound statement, it is scoped to the end of that
+compound statement.
+If it is declared as a parameter in a function definition, it is scoped
+until the end of that function definition.
+A function&#8217;s parameter declarations and body together form a single scope
+nested in the global scope.
+The <strong>if</strong> statement&#8217;s expression does not allow new variables to be declared,
+hence does not form a new scope.</p>
+</div>
+<div class="paragraph">
+<p>Within a declaration, the scope of a name starts immediately after the
+initializer if present or immediately after the name being declared if not.
+Several examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> x = <span class="integer">1</span>;
+{
+    <span class="predefined-type">int</span> x = <span class="integer">2</span>, y = x; <span class="comment">// y is initialized to 2</span>
+}
+
+<span class="keyword">struct</span> S
+{
+    <span class="predefined-type">int</span> x;
+};
+
+{
+    S S = S(<span class="integer">0</span>); <span class="comment">// 'S' is only visible as a struct and constructor</span>
+    S;          <span class="comment">// 'S' is now visible as a variable</span>
+}
+
+<span class="predefined-type">int</span> x = x; <span class="comment">// Error if x has not been previously defined.</span>
+           <span class="comment">// If the previous definition of x was in this</span>
+           <span class="comment">// same scope, this causes a redeclaration error.</span>
+
+<span class="predefined-type">int</span> f( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> k)
+{
+    <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// redeclaration error of the name k</span>
+    ...
+}
+
+<span class="predefined-type">int</span> f(<span class="predefined-type">int</span> k)
+{
+    {
+        <span class="predefined-type">int</span> k = k + <span class="integer">3</span>; <span class="comment">// 2nd k is parameter, initializing nested first k</span>
+        <span class="predefined-type">int</span> m = k;     <span class="comment">// use of new k, which is hiding the parameter</span>
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For both <strong>for</strong> and <strong>while</strong> loops, the sub-statement itself does not
+introduce a new scope for variable names, so the following has a
+redeclaration compile-time error:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> ( <span class="comment">/* nested scope begins here */</span> <span class="predefined-type">int</span> i = <span class="integer">0</span>; i &lt; <span class="integer">10</span>; i++) {
+    <span class="predefined-type">int</span> i; <span class="comment">// redeclaration error</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The body of a <strong>do</strong>-<strong>while</strong> loop introduces a new scope lasting only between
+the <strong>do</strong> and <strong>while</strong> (not including the while test expression), whether or
+not the body is simple or compound:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span> i = <span class="integer">17</span>;
+<span class="keyword">do</span>
+    <span class="predefined-type">int</span> i = <span class="integer">4</span>;  <span class="comment">// okay, in nested scope_</span>
+<span class="keyword">while</span> (i == <span class="integer">0</span>); <span class="comment">// i is 17, scoped outside the do-while body</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The statement following a <strong>switch</strong> (&#8230;&#8203;) forms a nested scope.</p>
+</div>
+<div class="paragraph">
+<p>All variable names, structure type names, and function names in a given
+scope share the same name space.
+Function names can be redeclared in the same scope, with the same or
+different parameters, without error.
+An implicitly-sized array can be redeclared in the same scope as an array of
+the same base type.
+Otherwise, within one compilation unit, a declared name cannot be redeclared
+in the same scope; doing so results in a redeclaration compile-time error.
+If a nested scope redeclares a name used in an outer scope, it hides all
+existing uses of that name.
+There is no way to access the hidden name or make it unhidden, without
+exiting the scope that hid it.</p>
+</div>
+<div class="paragraph">
+<p>The built-in functions are scoped in a scope outside the global scope that
+users declare global variables in.
+That is, a shader&#8217;s global scope, available for user-defined functions and
+global variables, is nested inside the scope containing the built-in
+functions.
+When a function name is redeclared in a nested scope, it hides all functions
+declared with that name in the outer scope.
+Function declarations (prototypes) cannot occur inside of functions; they
+must be at global scope, or for the built-in functions, outside the global
+scope, otherwise a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>Shared globals are global variables declared with the same name in
+independently compiled units (shaders) within the same language (i.e., same
+stage, e.g. vertex) that are linked together when making a single program.
+(Globals forming the interface between two different shader languages are
+discussed in other sections.) Shared globals share the same name space, and
+must be declared with the same type.
+They will share the same storage.</p>
+</div>
+<div class="paragraph">
+<p>Shared global arrays must have the same base type and the same explicit
+size.
+An array implicitly sized in one shader can be explicitly sized by another
+shader in the same stage.
+If no shader in a stage has an explicit size for the array, the largest
+implicit size (one more than the largest index used) in that stage is used.
+There is no cross-stage array sizing.
+If there is no static access to an implicitly sized array within the stage
+declaring it, then the array is given a size of 1, which is relevant when
+the array is declared within an interface block that is shared with other
+stages or the application (other unused arrays might be eliminated by the
+optimizer).</p>
+</div>
+<div class="paragraph">
+<p>Shared global scalars must have exactly the same type name and type
+definition.
+Structures must have the same name, sequence of type names, and type
+definitions, and member names to be considered the same type.
+This rule applies recursively for nested or embedded types.
+If a shared global has multiple initializers, the initializers must all be
+constant expressions, and they must all have the same value.
+Otherwise, a link-time error will result.
+(A shared global having only one initializer does not require that
+initializer to be a constant expression.)</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="storage-qualifiers">4.3. Storage Qualifiers</h3>
+<div class="paragraph">
+<p>Variable declarations may have at most one storage qualifier specified in
+front of the type.
+These are summarized as</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Storage Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;none: default&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">local read/write memory, or an input parameter to a
+                      function</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>const</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">a variable whose value cannot be changed</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">linkage into a shader from a previous stage, variable
+                      is copied in</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">linkage out of a shader to a subsequent stage,
+                      variable is copied out</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>attribute</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compatibility profile only and vertex language only;
+                      same as <strong>in</strong> when in a vertex shader</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">value does not change across the primitive being
+                      processed, uniforms form the linkage between a shader,
+                      OpenGL, and the application</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>varying</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compatibility profile only and vertex and fragment
+                      languages only; same as <strong>out</strong> when in a vertex shader
+                      and same as <strong>in</strong> when in a fragment shader</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>buffer</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">value is stored in a buffer object, and can be read or
+                      written both by shader invocations and the OpenGL
+                      API</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>shared</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compute shader only; variable storage is shared across
+                      all work items in a workgroup</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Some input and output qualified variables can be qualified with at most one
+additional auxiliary storage qualifier:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Auxiliary Storage Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>centroid</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">centroid-based interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sample</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">per-sample interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>patch</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">per-tessellation-patch attributes</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Not all combinations of qualification are allowed.
+Auxiliary storage qualifiers can only be used with the <strong>in</strong> or <strong>out</strong> storage
+qualifiers.
+Additional qualifier rules are defined in upcoming sections.</p>
+</div>
+<div class="paragraph">
+<p>Local variables can only use the <strong>const</strong> storage qualifier (or use no
+storage qualifier).</p>
+</div>
+<div class="paragraph">
+<p>Note that function parameters can use <strong>const</strong>, <strong>in</strong>, and <strong>out</strong> qualifiers,
+but as <em>parameter qualifiers</em>.
+Parameter qualifiers are discussed in
+&#8220;<a href="#function-calling-conventions">Function Calling Conventions</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Function return types and structure members do not use storage qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Initializers in global declarations may only be used in declarations of
+global variables with no storage qualifier, with a <strong>const</strong> qualifier, or
+with a <strong>uniform</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>Global variables without storage qualifiers that are not initialized in
+their declaration or by the application will not be initialized by
+OpenGL, but rather will enter <em>main()</em> with undefined values.</p>
+</div>
+<div class="paragraph">
+<p>When comparing an output from one shader stage to an input of a subsequent
+shader stage, the input and output don&#8217;t match if their auxiliary qualifiers
+(or lack thereof) are not the same.</p>
+</div>
+<div class="sect3">
+<h4 id="default-storage-qualifier">4.3.1. Default Storage Qualifier</h4>
+<div class="paragraph">
+<p>If no qualifier is present on a global variable, then the variable has no
+linkage to the application or shaders running on other pipeline stages.
+For either global or local unqualified variables, the declaration will
+appear to allocate memory associated with the processor it targets.
+This variable will provide read/write access to this allocated memory.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="constant-qualifier">4.3.2. Constant Qualifier</h4>
+<div class="paragraph">
+<p>Named compile-time constants
+or read-only variables
+can be declared using
+the <strong>const</strong> qualifier.
+The <strong>const</strong> qualifier can be used with any of the non-void transparent basic
+data types, as well as with structures and arrays of these.
+It is a compile-time error to write to a <strong>const</strong> variable outside of its
+declaration, so they must be initialized when declared.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> vec3 zAxis = vec3 (<span class="float">0</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>);
+<span class="directive">const</span> <span class="predefined-type">float</span> ceiling = a + b; <span class="comment">// a and b not necessarily constants</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Structure members may not be qualified with <strong>const</strong>.
+Structure variables can be declared as <strong>const</strong>, and initialized with a
+structure
+constructor or initializer.</p>
+</div>
+<div class="paragraph">
+<p>Initializers for <strong>const</strong> declarations
+at global scope
+must be constant expressions, as defined in
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="constant-expressions">4.3.3. Constant Expressions</h4>
+<div class="paragraph">
+<p>SPIR-V specialization constants are expressed in GLSL as <strong>const</strong> with the
+layout qualifier <strong>constant_id</strong>, as described in
+&#8220;<a href="#specialization-constant-qualifier">Specialization-Constant
+Qualifier.</a>&#8221;</p>
+</div>
+<div class="paragraph">
+<p>A <em>constant expression</em> is one of</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A literal value (e.g. <strong>5</strong> or <strong>true</strong>).</p>
+</li>
+<li>
+<p>A variable declared with the <strong>const</strong> qualifier and an initializer, where
+the initializer is a constant expression.
+This includes both <strong>const</strong> declared with a specialization-constant
+layout qualifier, e.g. <strong>layout</strong>(<strong>constant_id</strong> = &#8230;&#8203;), and those declared
+without a specialization-constant layout qualifier.</p>
+</li>
+<li>
+<p>An expression formed by an operator on operands that are all constant
+expressions, including getting an element of a constant array, or a
+member of a constant structure, or components of a constant vector.
+However, the lowest precedence operators of the sequence operator (<strong>,</strong>)
+and the assignment operators (<strong>=</strong>, <strong>+=</strong>, <strong>&#8230;&#8203;</strong>) are not included in the
+operators that can create a constant expression.
+Also, an array access with a specialization constant as an index does
+not result in a constant expression.</p>
+</li>
+<li>
+<p>Valid use of the <strong>length</strong>() method on an explicitly sized object,
+whether or not the object itself is constant (implicitly sized or
+run-time sized arrays do not return a constant expression).</p>
+</li>
+<li>
+<p>A constructor whose arguments are all constant expressions.</p>
+</li>
+<li>
+<p>For non-specialization constants only: the value returned by certain
+built-in function calls whose arguments are all constant expressions,
+including at least the list below.
+Any other built-in function that does not access memory (not the texture
+lookup functions, image access, atomic counter, etc.), that has a
+non-<strong>void</strong> return type, that has no <strong>out</strong> parameter, and is not a noise
+function might also be considered a constant.
+When a function is called with an argument that is a specialization
+constant, the result is not a constant expression.</p>
+<div class="ulist">
+<ul>
+<li>
+<p>Angle and Trigonometric Functions</p>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>radians</strong></p>
+</li>
+<li>
+<p><strong>degrees</strong></p>
+</li>
+<li>
+<p><strong>sin</strong></p>
+</li>
+<li>
+<p><strong>cos</strong></p>
+</li>
+<li>
+<p><strong>asin</strong></p>
+</li>
+<li>
+<p><strong>acos</strong></p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Exponential Functions</p>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>pow</strong></p>
+</li>
+<li>
+<p><strong>exp</strong></p>
+</li>
+<li>
+<p><strong>log</strong></p>
+</li>
+<li>
+<p><strong>exp2</strong></p>
+</li>
+<li>
+<p><strong>log2</strong></p>
+</li>
+<li>
+<p><strong>sqrt</strong></p>
+</li>
+<li>
+<p><strong>inversesqrt</strong></p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Common Functions</p>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>abs</strong></p>
+</li>
+<li>
+<p><strong>sign</strong></p>
+</li>
+<li>
+<p><strong>floor</strong></p>
+</li>
+<li>
+<p><strong>trunc</strong></p>
+</li>
+<li>
+<p><strong>round</strong></p>
+</li>
+<li>
+<p><strong>ceil</strong></p>
+</li>
+<li>
+<p><strong>mod</strong></p>
+</li>
+<li>
+<p><strong>min</strong></p>
+</li>
+<li>
+<p><strong>max</strong></p>
+</li>
+<li>
+<p><strong>clamp</strong></p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Geometric Functions</p>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>length</strong></p>
+</li>
+<li>
+<p><strong>dot</strong></p>
+</li>
+<li>
+<p><strong>normalize</strong></p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Function calls to user-defined functions (non-built-in functions) cannot
+be used to form constant expressions.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>A <em>constant integral expression</em> is a constant expression that evaluates to
+a scalar signed or unsigned integer.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions will be evaluated in an invariant way so as to create
+the same value in multiple shaders when the same constant expressions appear
+in those shaders.
+See &#8220;<a href="#the-invariant-qualifier">The Invariant Qualifier</a>&#8221; for more details
+on how to create invariant expressions and
+&#8220;<a href="#precision-qualifiers">Precision Qualifiers</a>&#8221; for detail on how
+expressions are evaluated.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions respect the <strong>precise</strong> and <strong>invariant</strong> qualifiers but
+will be always be evaluated in an invariant way, independent of the use of
+such qualification, so as to create the same value in multiple shaders when
+the same constant expressions appear in those shaders.
+See &#8220;<a href="#the-invariant-qualifier">The Invariant Qualifier</a>&#8221; and
+&#8220;<a href="#the-precise-qualifier">The Precise Qualifier</a>&#8221; for more details on how
+to create invariant expressions.</p>
+</div>
+<div class="paragraph">
+<p>Non-specialization constant
+expressions may be evaluated by the compiler&#8217;s
+host platform, and are therefore not required to compute the same value that
+the same expression would evaluate to on the shader execution target.
+However, the host must use the same or greater precision than the target
+would use.</p>
+</div>
+<div class="paragraph">
+<p>Specialization-constant expressions are never evaluated by the compiler
+front end, but instead retain the expression&#8217;s operations needed to evaluate
+them later on the host.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="input-variables">4.3.4. Input Variables</h4>
+<div class="paragraph">
+<p>Shader input variables are declared with the <strong>in</strong> storage qualifier.
+They form the input interface between previous stages of the OpenGL
+pipeline and the declaring shader.
+Input variables must be declared at global scope.
+Values from the previous pipeline stage are copied into input variables at
+the beginning of shader execution.
+It is a compile-time error to write to a variable declared as an input.</p>
+</div>
+<div class="paragraph">
+<p>Only the input variables that are
+statically
+read need to be written by the
+previous stage; it is allowed to have superfluous declarations of input
+variables.
+This is shown in the following table.</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+<col>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top" colspan="2" rowspan="2"><p class="tableblock">Treatment of Mismatched Input Variables</p></td>
+<td class="tableblock halign-left valign-top" colspan="3"><p class="tableblock">Consuming Shader (input variables)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared but no Static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared and Static Use</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top" rowspan="3"><p class="tableblock">Generating Shader (output variables)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">No Declaration</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Link-Time Error</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared but no Static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are undefined)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Declared and Static Use</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Allowed (values are potentially undefined)</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Consumption errors are based on static use only.
+Compilation may generate a warning, but not an error, for any dynamic use
+the compiler can deduce that might cause consumption of undefined values.</p>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#built-in-variables">Built-In Variables</a>&#8221; for a list of the built-in
+input names.</p>
+</div>
+<div class="paragraph">
+<p>Vertex shader input variables (or attributes) receive per-vertex data.
+It is a compile-time error to use auxiliary storage or interpolation qualifiers
+on a vertex shader input.
+The values copied in are established by the OpenGL API or through the use
+of the layout identifier <strong>location</strong>.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a vertex shader input with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>A structure</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Example declarations in a vertex shader:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 position;
+in vec3 normal;
+in vec2 texCoord[<span class="integer">4</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is expected that graphics hardware will have a small number of fixed
+vector locations for passing vertex inputs.
+Therefore, the OpenGL Shading Language defines each non-matrix input variable as taking up
+one such vector location.
+There is an implementation-dependent limit on the number of locations that
+can be used, and if this is exceeded it will cause a link-time error.
+(Declared input variables that are not statically used do not count against
+this limit.) A scalar input counts the same amount against this limit as a
+<strong>vec4</strong>, so applications may want to consider packing groups of four
+unrelated float inputs together into a vector to better utilize the
+capabilities of the underlying hardware.
+A matrix input will use up multiple locations.
+The number of locations used will equal the number of columns in the matrix.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control, evaluation, and geometry shader input variables get
+the per-vertex values written out by output variables of the same names in
+the previous active shader stage.
+For these inputs, <strong>centroid</strong> and interpolation qualifiers are allowed, but
+have no effect.
+Since tessellation control, tessellation evaluation, and geometry shaders
+operate on a set of vertices, each input variable (or input block, see
+interface blocks below) needs to be declared as an array.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in <span class="predefined-type">float</span> foo[]; <span class="comment">// geometry shader input for vertex &quot;out float foo&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each element of such an array corresponds to one vertex of the primitive
+being processed.
+Each array can optionally have a size declared.
+For geometry shaders, the array size will be set by, (or if provided must be
+consistent with) the input <strong>layout</strong> declaration(s) establishing the type of
+input primitive, as described later in &#8220;<a href="#input-layout-qualifiers">Input
+Layout Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Some inputs and outputs are <em>arrayed</em>, meaning that for an interface between
+two shader stages either the input or output declaration requires an extra
+level of array indexing for the declarations to match.
+For example, with the interface between a vertex shader and a geometry
+shader, vertex shader output variables and geometry shader input variables
+of the same name must have matching types, except that the geometry shader
+will have one more array dimension than the vertex shader, to allow for
+vertex indexing.
+If such an arrayed interface variable is not declared with the necessary
+additional input or output array dimension, a link-time error will result.
+Geometry shader inputs, tessellation control shader inputs and outputs, and
+tessellation evaluation inputs all have an additional level of arrayness
+relative to other shader inputs and outputs.
+These inputs and outputs are known as <em>per-vertex-arrayed</em> inputs and
+outputs.
+Component limits for arrayed interfaces (e.g.
+<em>gl_MaxTessControlInputComponents</em>) are limits per vertex, not limits for
+the entire interface.</p>
+</div>
+<div class="paragraph">
+<p>For non-arrayed interfaces (meaning array dimensionally stays the same
+between stages), it is a link-time error if the input variable is not
+declared with the same type, including array dimensionality, as the matching
+output variable.</p>
+</div>
+<div class="paragraph">
+<p>The link-time type-matching rules apply to all declared input and output
+variables, whether or not they are used.</p>
+</div>
+<div class="paragraph">
+<p>Additionally, tessellation evaluation shaders support per-patch input
+variables declared with the <strong>patch</strong> and <strong>in</strong> qualifiers.
+Per-patch input variables are filled with the values of per-patch output
+variables written by the tessellation control shader.
+Per-patch inputs may be declared as one-dimensional arrays, but are not
+indexed by vertex number.
+Applying the <strong>patch</strong> qualifier to inputs can only be done in tessellation
+evaluation shaders.
+As with other input variables, per-patch inputs must be declared using the
+same type and qualification as per-patch outputs from the previous
+(tessellation control) shader stage.
+It is a compile-time error to use <strong>patch</strong> with inputs in any other stage.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a tessellation control, tessellation
+evaluation or geometry shader input with, or that contains, any of the
+following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment shader inputs get per-fragment values, typically interpolated from
+a previous stage&#8217;s outputs.
+The auxiliary storage qualifiers <strong>centroid</strong> and <strong>sample</strong> can also be
+applied, as well as the interpolation qualifiers <strong>flat</strong>, <strong>noperspective</strong>,
+and <strong>smooth.</strong></p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a fragment shader input with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment shader inputs that are, or contain, integral
+or double-precision floating-point
+types must be
+qualified with the interpolation qualifier <strong>flat</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Fragment inputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec3 normal;
+centroid in vec2 TexCoord;
+invariant centroid in vec4 Color;
+noperspective in <span class="predefined-type">float</span> temperature;
+flat in vec3 myColor;
+noperspective centroid in vec2 myTexCoord;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The fragment shader inputs form an interface with the last active shader in
+the vertex processing pipeline.
+For this interface, the last active shader stage output variables and
+fragment shader input variables of the same name must match in type and
+qualification, with a few exceptions: The storage qualifiers must, of
+course, differ (one is <strong>in</strong> and one is <strong>out</strong>).
+Also,
+interpolation qualification (e.g. <strong>flat</strong>) and
+auxiliary qualification (e.g. <strong>centroid</strong>) may differ.
+These mismatches are allowed between any pair of stages.
+When
+interpolation or
+auxiliary qualifiers do not match, those provided in
+the fragment shader supersede those provided in previous stages.
+If any such qualifiers are completely missing in the fragment shaders, then
+the default is used, rather than any qualifiers that may have been declared
+in previous stages.
+That is, what matters is what is declared in the fragment shaders, not what
+is declared in shaders in previous stages.</p>
+</div>
+<div class="paragraph">
+<p>When an interface between shader stages is formed using shaders from two
+separate program objects, it is not possible to detect mismatches between
+inputs and outputs when the programs are linked.
+When there are mismatches between inputs and outputs on such interfaces,
+the values passed across the interface will be partially or completely
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>Shaders can ensure matches across such interfaces either by using input and
+output layout qualifiers (sections &#8220;<a href="#input-layout-qualifiers">Input Layout
+Qualifiers</a>&#8221; and &#8220;<a href="#output-layout-qualifiers">Output Layout
+Qualifiers</a>&#8221;) or by using identical input and output declarations of
+blocks or variables.
+Complete rules for interface matching are found in section 7.4.1 &#8220;Shader
+Interface Matching&#8221; of the <a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>Compute shaders do not permit user-defined input variables and do not form a
+formal interface with any other shader stage.
+See &#8220;<a href="#compute-shader-special-variables">Compute Shader Special
+Variables</a>&#8221; for a description of built-in compute shader input variables.
+All other input to a compute shader is retrieved explicitly through image
+loads, texture fetches, loads from uniforms or uniform buffers, or other
+user supplied code.
+Redeclaration of built-in input variables in compute shaders is not
+permitted.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-variables">4.3.5. Uniform Variables</h4>
+<div class="paragraph">
+<p>The <strong>uniform</strong> qualifier is used to declare global variables whose values are
+the same across the entire primitive being processed.
+All <strong>uniform</strong> variables are read-only and are initialized externally either
+at link time or through the API.
+The link-time initial value is either the value of the variable&#8217;s
+initializer, if present, or 0 if no initializer is present.
+Opaque types cannot have initializers, or a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>Example declarations are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform vec4 lightPosition;
+uniform vec3 color = vec3(<span class="float">0</span><span class="float">.7</span>, <span class="float">0</span><span class="float">.7</span>, <span class="float">0</span><span class="float">.2</span>); <span class="comment">// value assigned at link time</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>uniform</strong> qualifier can be used with any of the basic data types, or
+when declaring a variable whose type is a structure, or an array of any of
+these.</p>
+</div>
+<div class="paragraph">
+<p>There is an implementation-dependent limit on the amount of storage for
+uniforms that can be used for each type of shader and if this is exceeded it
+will cause a compile-time or link-time error.
+Uniform variables that are declared but not
+used do not count against this limit.
+The number of user-defined uniform variables and the number of built-in
+uniform variables that are used within a shader are added together to
+determine whether available uniform storage has been exceeded.</p>
+</div>
+<div class="paragraph">
+<p>Uniforms in shaders all share a single global name space when linked into a
+program or separable program.
+Hence, the types,
+initializers,
+and any location specifiers of all statically used uniform variables with the
+same name must match across all shaders that are linked into a single program.
+However it is not required to repeat the
+initializer or
+location specifier in all the linked shaders.
+While this single uniform name space is cross stage, a uniform variable
+name&#8217;s scope is per stage: If a uniform variable name is declared in one
+stage (e.g. a vertex shader) but not in another (e.g. a fragment shader),
+then that name is still available in the other stage for a different use.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="output-variables">4.3.6. Output Variables</h4>
+<div class="paragraph">
+<p>Shader output variables are declared with the <strong>out</strong> storage qualifier.
+They form the output interface between the declaring shader and the
+subsequent stages of the OpenGL pipeline.
+Output variables must be declared at global scope.
+During shader execution they will behave as normal unqualified global
+variables.
+Their values are copied out to the subsequent pipeline stage on shader exit.
+Only output variables that are read by the subsequent pipeline stage need to
+be written; it is allowed to have superfluous declarations of output
+variables.</p>
+</div>
+<div class="paragraph">
+<p>There is <em>not</em> an <strong>inout</strong> storage qualifier for declaring a single variable
+name as both input and output to a shader.
+Also, a variable cannot be declared with both the <strong>in</strong> and the <strong>out</strong>
+qualifiers, this will result in a compile-time or link-time error.
+Output variables must be declared with different names than input variables.
+However, nesting an input or output inside an interface block with an
+instance name allows the same names with one referenced through a block
+instance name.</p>
+</div>
+<div class="paragraph">
+<p>Vertex, tessellation evaluation, and geometry output variables output
+per-vertex data and are declared using the <strong>out</strong> storage qualifier.
+Applying <strong>patch</strong> to an output can only be done in a tessellation control
+shader.
+It is a compile-time error to use <strong>patch</strong> on outputs in any other stage.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to declare a vertex, tessellation evaluation,
+tessellation control, or geometry shader output with, or that contains, any
+of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Individual outputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec3 normal;
+centroid out vec2 TexCoord;
+invariant centroid out vec4 Color;
+flat out vec3 myColor;
+sample out vec4 perSampleColor;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These can also appear in interface blocks, as described in
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221;.
+Interface blocks allow simpler addition of arrays to the interface from
+vertex to geometry shader.
+They also allow a fragment shader to have the same input interface as a
+geometry shader for a given vertex shader.</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control shader output variables are used to output
+per-vertex and per-patch data.
+Per-vertex output variables are arrayed (see <em>arrayed</em> under
+&#8220;<a href="#input-variables">Input Variables</a>&#8221;) and declared using the <strong>out</strong>
+qualifier without the <strong>patch</strong> qualifier.
+Per-patch output variables are declared using the <strong>patch</strong> and <strong>out</strong>
+qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Since tessellation control shaders produce an arrayed primitive comprising
+multiple vertices, each per-vertex output variable (or output block, see
+interface blocks below) needs to be declared as an array.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out <span class="predefined-type">float</span> foo[]; <span class="comment">// feeds next stage input &quot;in float foo[]&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each element of such an array corresponds to one vertex of the primitive
+being produced.
+Each array can optionally have a size declared.
+The array size will be set by (or if provided must be consistent with) the
+output layout declaration(s) establishing the number of vertices in the
+output patch, as described later in
+&#8220;<a href="#tessellation-control-outputs">Tessellation Control Outputs</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Each tessellation control shader invocation has a corresponding output patch
+vertex, and may assign values to per-vertex outputs only if they belong to
+that corresponding vertex.
+If a per-vertex output variable is used as an l-value, it is a compile-time
+or link-time error if the expression indicating the vertex index is not the
+identifier <em>gl_InvocationID</em>.</p>
+</div>
+<div class="paragraph">
+<p>The order of execution of a tessellation control shader invocation relative
+to the other invocations for the same input patch is undefined unless the
+built-in function <strong>barrier</strong>() is used.
+This provides some control over relative execution order.
+When a shader invocation calls <strong>barrier</strong>(), its execution pauses until all
+other invocations have reached the same point of execution.
+Output variable assignments performed by any invocation executed prior to
+calling <strong>barrier</strong>() will be visible to any other invocation after the call
+to <strong>barrier</strong>() returns.</p>
+</div>
+<div class="paragraph">
+<p>Because tessellation control shader invocations execute in undefined order
+between barriers, the values of per-vertex or per-patch output variables
+will sometimes be undefined.
+Consider the beginning and end of shader execution and each call to
+<strong>barrier</strong>() as synchronization points.
+The value of an output variable will be undefined in any of the three
+following cases:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>At the beginning of execution.</p>
+</li>
+<li>
+<p>At each synchronization point, unless</p>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p>the value was well-defined after the previous synchronization point and
+was not written by any invocation since, or</p>
+</li>
+<li>
+<p>the value was written by exactly one shader invocation since the previous
+synchronization point, or</p>
+</li>
+<li>
+<p>the value was written by multiple shader invocations since the previous
+synchronization point, and the last write performed by all such
+invocations wrote the same value.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</li>
+<li>
+<p>When read by a shader invocation, if</p>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p>the value was undefined at the previous synchronization point and has not
+been written by the same shader invocation since, or</p>
+</li>
+<li>
+<p>the output variable is written to by any other shader invocation between
+the previous and next synchronization points, even if that assignment
+occurs in code following the read.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Fragment outputs output per-fragment data and are declared using the <strong>out</strong>
+storage qualifier.
+It is a compile-time error to use auxiliary storage qualifiers or
+interpolation qualifiers in a fragment shader output declaration.
+It is a compile-time error to declare a fragment shader output with, or that
+contains, any of the following types:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>A <a href="#booleans">boolean type</a></p>
+</li>
+<li>
+<p>A double-precision scalar or vector (<strong>double</strong>, <strong>dvec2</strong>, <strong>dvec3</strong>,
+<strong>dvec4</strong>)</p>
+</li>
+<li>
+<p>An <a href="#opaque-types">opaque type</a></p>
+</li>
+<li>
+<p>A matrix type</p>
+</li>
+<li>
+<p>A structure</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Fragment outputs are declared as in the following examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec4 FragmentColor;
+out uint Luminosity;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Compute shaders have no built-in output variables, do not support
+user-defined output variables and do not form a formal interface with any
+other shader stage.
+All outputs from a compute shader take the form of the side effects such as
+image stores and operations on atomic counters.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="buffer-variables">4.3.7. Buffer Variables</h4>
+<div class="paragraph">
+<p>The <strong>buffer</strong> qualifier is used to declare global variables whose values are
+stored in the data store of a buffer object bound through the OpenGL API.
+Buffer variables can be read and written, with the underlying storage shared
+among all active shader invocations.
+Buffer variable memory reads and writes within a single shader invocation
+are processed in order.
+However, the order of reads and writes performed in one invocation relative
+to those performed by another invocation is largely undefined.
+Buffer variables may be qualified with memory qualifiers affecting how the
+underlying memory is accessed, as described in &#8220;<a href="#memory-qualifiers">Memory
+Qualifiers</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>buffer</strong> qualifier can be used to declare interface blocks (see
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221;), which are then referred to as
+shader storage blocks.
+It is a compile-time error to declare buffer variables outside a block.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// use buffer to create a buffer block (shader storage block)</span>
+buffer BufferName { <span class="comment">// externally visible name of buffer</span>
+    <span class="predefined-type">int</span> count;      <span class="comment">// typed, shared memory...</span>
+    ...             <span class="comment">// ...</span>
+    vec4 v[];       <span class="comment">// last member may be an array that is not sized</span>
+                    <span class="comment">// until after link time (dynamically sized)</span>
+} Name;             <span class="comment">// name of block within the shader</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There are implementation-dependent limits on the number of shader storage
+blocks used for each type of shader, the combined number of shader storage
+blocks used for a program, and the amount of storage required by each
+individual shader storage block.
+If any of these limits are exceeded, it will cause a compile-time or
+link-time error.</p>
+</div>
+<div class="paragraph">
+<p>If multiple shaders are linked together, then they will share a single
+global buffer variable name space.
+Hence, the types of all declared buffer variables with the same name must
+match across all shaders that are linked into a single program.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="shared-variables">4.3.8. Shared Variables</h4>
+<div class="paragraph">
+<p>The <strong>shared</strong> qualifier is used to declare global variables that have storage
+shared between all work items in a compute shader workgroup.
+Variables declared as <strong>shared</strong> may only be used in compute shaders (see
+&#8220;<a href="#compute-processor">Compute Processor</a>&#8221;).
+Any other declaration of a <strong>shared</strong> variable is a compile-time error.
+Shared variables are implicitly coherent (see
+&#8220;<a href="#memory-qualifiers">Memory Qualifiers</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>Variables declared as <strong>shared</strong> may not have initializers and their contents
+are undefined at the beginning of shader execution.
+Any data written to <strong>shared</strong> variables will be visible to other work items
+(executing the same shader) within the same workgroup.</p>
+</div>
+<div class="paragraph">
+<p>In the absence of synchronization, the order of reads and writes to the same
+<strong>shared</strong> variable by different invocations of a shader is not defined.</p>
+</div>
+<div class="paragraph">
+<p>In order to achieve ordering with respect to reads and writes to <strong>shared</strong>
+variables, control flow barriers must be employed using the <strong>barrier</strong>() function
+(see &#8220;<a href="#shader-invocation-control-functions">Shader Invocation Control
+Functions</a>&#8221;).</p>
+</div>
+<div class="paragraph">
+<p>There is a limit to the total size of all variables declared as <strong>shared</strong> in a
+single program.
+This limit, expressed in units of basic machine units may be determined by
+using the OpenGL API to query the value of
+MAX_COMPUTE_SHARED_MEMORY_SIZE.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="interface-blocks">4.3.9. Interface Blocks</h4>
+<div class="paragraph">
+<p>Input, output, uniform, and buffer variable declarations can be grouped into
+named interface blocks to provide coarser granularity backing than is
+achievable with individual declarations.
+They can have an optional instance name, used in the shader to reference
+their members.
+An output block of one programmable stage is backed by a corresponding input
+block in the subsequent programmable stage.
+A <em>uniform block</em> is backed by the application with a buffer object.
+A block of buffer variables, called a <em>shader storage block</em>, is also backed
+by the application with a buffer object.
+It is a compile-time error to have an input block in a vertex shader or an
+output block in a fragment shader.
+These uses are reserved for future use.</p>
+</div>
+<div class="paragraph">
+<p>An interface block is started by an <strong>in</strong>, <strong>out</strong>, <strong>uniform</strong>, or <strong>buffer</strong>
+keyword, followed by a block name, followed by an open curly brace (<strong>{</strong>) as
+follows:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>interface-block</em> : </dt>
+<dd>
+<p><em>layout-qualifier<sub>opt</sub></em> <em>interface-qualifier</em> <em>block-name</em> <strong>{</strong>
+<em>member-list</em> <strong>}</strong> <em>instance-name<sub>opt</sub></em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>interface-qualifier</em> : </dt>
+<dd>
+<p><strong>in</strong><br>
+<strong>out</strong><br>
+<strong>patch</strong> <strong>in</strong> // Note: Qualifiers can be in any order.<br>
+<strong>patch</strong> <strong>out</strong><br>
+<strong>uniform</strong><br>
+<strong>buffer</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>member-list</em> : </dt>
+<dd>
+<p><em>member-declaration</em><br>
+<em>member-declaration</em> <em>member-list</em></p>
+</dd>
+<dt class="hdlist1"><em>member-declaration</em> : </dt>
+<dd>
+<p><em>layout-qualifier<sub>opt</sub></em> <em>qualifiers<sub>opt</sub></em> <em>type</em> <em>declarators</em> <strong>;</strong></p>
+</dd>
+</dl>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>instance-name</em> : </dt>
+<dd>
+<p><em>identifier</em><br>
+<em>identifier</em> <strong>[</strong> <strong>]</strong><br>
+<em>identifier</em> <strong>[</strong> <em>constant-integral-expression</em> <strong>]</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Each of the above elements is discussed below, with the exception of layout
+qualifiers (<em>layout-qualifier</em>), which are defined in the next section.</p>
+</div>
+<div class="paragraph">
+<p>First, an example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform Transform {
+    mat4 ModelViewMatrix;
+    mat4 ModelViewProjectionMatrix;
+    uniform mat3 NormalMatrix;      <span class="comment">// allowed restatement of qualifier</span>
+    <span class="predefined-type">float</span> Deformation;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The above establishes a uniform block named &#8220;Transform&#8221; with four uniforms
+grouped inside it.</p>
+</div>
+<div class="paragraph">
+<p>Types and declarators are the same as for other input, output, uniform, and
+buffer variable declarations outside blocks, with these exceptions:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Initializers are not allowed</p>
+</li>
+<li>
+<p>Opaque types are not allowed</p>
+</li>
+<li>
+<p>Structure definitions cannot be nested inside a block</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Any of these would result in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>If no optional qualifier is used in a member-declaration, the qualification
+of the member includes all <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> as
+determined by <em>interface-qualifier</em>.
+If optional qualifiers are used, they can include interpolation qualifiers,
+auxiliary storage qualifiers,
+and storage qualifiers and they must declare
+an input, output, or uniform member consistent with the interface qualifier
+of the block: Input variables, output variables, uniform variables, and
+<strong>buffer</strong> members can only be in <strong>in</strong> blocks, <strong>out</strong> blocks, <strong>uniform</strong> blocks,
+and shader storage blocks, respectively.</p>
+</div>
+<div class="paragraph">
+<p>Repeating the <strong>in</strong>, <strong>out</strong>, <strong>patch</strong>, <strong>uniform</strong>, or <strong>buffer</strong> interface
+qualifier for a member&#8217;s storage qualifier is optional.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in Material {
+    smooth in vec4 Color1; <span class="comment">// legal, input inside in block</span>
+    smooth vec4 Color2;    <span class="comment">// legal, 'in' inherited from 'in Material'</span>
+    vec2 TexCoord;         <span class="comment">// legal, TexCoord is an input</span>
+    uniform <span class="predefined-type">float</span> Atten;   <span class="comment">// illegal, mismatched storage qualifier</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A <em>shader interface</em> is defined to be one of these:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>All the uniform variables and uniform blocks declared in a program.
+This spans all compilation units linked together within one program.</p>
+</li>
+<li>
+<p>All the <strong>buffer</strong> blocks declared in a program.</p>
+</li>
+<li>
+<p>The boundary between adjacent programmable pipeline stages: This spans
+all the outputs declared in all compilation units of the first stage and
+all the inputs declared in all compilation units of the second stage.
+Note that for the purposes of this definition, the fragment shader and
+the preceding shader are considered to have a shared boundary even
+though in practice, all values passed to the fragment shader first pass
+through the rasterizer and interpolator.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The block name (<em>block-name</em>) is used to match within shader interfaces: an
+output block of one pipeline stage will be matched to an input block with
+the same name in the subsequent pipeline stage.
+For uniform or shader storage blocks, the application uses the block name to
+identify the block.
+Block names have no other use within a shader beyond interface matching; it
+is a compile-time error
+to use a block name at global scope for anything other than as a
+block name (e.g. use of a block name for a global variable name or function
+name is currently reserved).
+It is a compile-time error to use the same block name for more than one
+block declaration in the same shader interface (as defined above) within one
+shader, even if the block contents are identical.</p>
+</div>
+<div class="paragraph">
+<p>Matched block names within a shader interface (as defined above) must match
+in terms of having the same number of declarations with the same sequence of
+types and the same sequence of member names, as well as having matching
+member-wise layout qualification
+(see next section).
+Matched uniform or shader storage block names (but not input or output block
+names) must also either all be lacking an instance name or all having an
+instance name, putting their members at the same scoping level.
+When instance names are present on matched block names, it is allowed for
+the instance names to differ; they need not match for the blocks to match.
+Furthermore, if a matching block is declared as an array, then the array
+sizes must also match (or follow array matching rules for the shader
+interface between consecutive shader stages).
+Any mismatch will generate a link-time error.
+A block name is allowed to have different definitions in different shader
+interfaces within the same shader, allowing, for example, an input block and
+output block to have the same name.</p>
+</div>
+<div class="paragraph">
+<p>If an instance name (<em>instance-name</em>) is not used, the names declared inside
+the block are scoped at the global level and accessed as if they were
+declared outside the block.
+If an instance name (<em>instance-name</em>) is used, then it puts all the members
+inside a scope within its own name space, accessed with the field selector
+(<strong>.</strong>) operator (analogously to structures).
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in Light {
+    vec4 LightPos;
+    vec3 LightColor;
+};
+in ColoredTexture {
+    vec4 Color;
+    vec2 TexCoord;
+} Material;           <span class="comment">// instance name</span>
+vec3 Color;           <span class="comment">// different Color than Material.Color</span>
+vec4 LightPos;        <span class="comment">// illegal, already defined</span>
+...
+... = LightPos;       <span class="comment">// accessing LightPos</span>
+... = Material.Color; <span class="comment">// accessing Color in ColoredTexture block</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Outside the shading language (i.e., in the API), members are similarly
+identified except the block name is always used in place of the instance
+name (API accesses are to shader interfaces, not to shaders).
+If there is no instance name, then the API does not use the block name to
+access a member, just the member name.</p>
+</div>
+<div class="paragraph">
+<p>Within a shader interface, all declarations of the same global name must be
+for the same object and must match in type and in whether they declare a
+variable or member of a block with no instance name.
+The API also needs this name to uniquely identify an object in the shader
+interface.
+It is a link-time error if any particular shader interface contains</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>two different blocks, each having no instance name, and each having a
+member of the same name, or</p>
+</li>
+<li>
+<p>a variable outside a block, and a block with no instance name, where the
+variable has the same name as a member in the block.</p>
+</li>
+</ul>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out Vertex {
+    vec4 Position;  <span class="comment">// API transform/feedback will use &quot;Vertex.Position&quot;</span>
+    vec2 Texture;
+} Coords;           <span class="comment">// shader will use &quot;Coords.Position&quot;</span>
+out Vertex2 {
+    vec4 Color;     <span class="comment">// API will use &quot;Color&quot;</span>
+    <span class="predefined-type">float</span> Color2;
+};
+
+<span class="comment">// in same program as Vertex2 above:</span>
+out Vertex3 {
+    <span class="predefined-type">float</span> Intensity;
+    vec4 Color;     <span class="comment">// ERROR, name collision with Color in Vertex2</span>
+};
+<span class="predefined-type">float</span> Color2;       <span class="comment">// ERROR, collides with Color2 in Vertex2</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For blocks declared as arrays, the array index must also be included when
+accessing members, as in this example</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">uniform Transform { <span class="comment">// API uses &quot;Transform[2]&quot; to refer to instance 2</span>
+    mat4 ModelViewMatrix;
+    mat4 ModelViewProjectionMatrix;
+    vec4 a[]; <span class="comment">// array will get implicitly sized</span>
+    <span class="predefined-type">float</span> Deformation;
+} transforms[<span class="integer">4</span>];
+...
+... = transforms[<span class="integer">2</span>].ModelViewMatrix; <span class="comment">// shader access of instance 2</span>
+<span class="comment">// API uses &quot;Transform.ModelViewMatrix&quot; to query an offset or other query</span>
+transforms[x].a.length(); <span class="comment">// same length for 'a' for all x</span>
+Transform[x];             <span class="comment">// illegal, must use 'transforms'</span>
+Transform.a.length();     <span class="comment">// illegal, must use 'transforms'</span>
+...transforms[<span class="integer">2</span>].a[<span class="integer">3</span>]...  <span class="comment">// if these are the only two dereferences of 'a',</span>
+...transforms[<span class="integer">3</span>].a[<span class="integer">7</span>]...  <span class="comment">// then 'a' must be size 8, for all</span>
+transforms[x]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For uniform or shader storage blocks declared as an array, each individual
+array element corresponds to a separate buffer object bind range, backing
+one instance of the block.
+As the array size indicates the number of buffer objects needed, uniform and
+shader storage block array declarations must specify an array size.
+A uniform or shader storage block array can only be indexed with a
+dynamically uniform integral expression, otherwise results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>When using OpenGL API entry points to identify the name of an individual
+block in an array of blocks, the name string may include an array index
+(e.g. <em>Transform[2]</em>).
+When using OpenGL API entry points to refer to offsets or other
+characteristics of a block member, an array index must not be specified
+(e.g. <em>Transform.ModelViewMatrix</em>).</p>
+</div>
+<div class="paragraph">
+<p>Tessellation control, tessellation evaluation and geometry shader input
+blocks must be declared as arrays and follow the array declaration and
+linking rules for all shader inputs for the respective stages.
+All other input and output block arrays must specify an array size.</p>
+</div>
+<div class="paragraph">
+<p>There are implementation-dependent limits on the number of uniform blocks
+and the number of shader storage blocks that can be used per stage.
+If either limit is exceeded, it will cause a link-time error.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="layout-qualifiers">4.4. Layout Qualifiers</h3>
+<div class="paragraph">
+<p>Layout qualifiers can appear in several forms of declaration.
+They can appear as part of an interface block definition or block member, as
+shown in the grammar in the previous section.
+They can also appear with just an <em>interface-qualifier</em> to establish layouts
+of other declarations made with that qualifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="paragraph">
+<p><em>layout-qualifier</em> <em>interface-qualifier</em> <strong>;</strong></p>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Or, they can appear with an individual variable declared with an interface
+qualifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="paragraph">
+<p><em>layout-qualifier</em> <em>interface-qualifier</em> <em>declaration</em> <strong>;</strong></p>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Declarations of layouts can only be made at global scope or block members,
+and only where indicated in the following subsections; their details are
+specific to what the interface qualifier is, and are discussed individually.</p>
+</div>
+<div class="paragraph">
+<p>The <em>layout-qualifier</em> expands to:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier</em> : </dt>
+<dd>
+<p><strong>layout</strong> <strong>(</strong> <em>layout-qualifier-id-list</em> <strong>)</strong></p>
+</dd>
+<dt class="hdlist1"><em>layout-qualifier-id-list</em> : </dt>
+<dd>
+<p><em>layout-qualifier-id</em><br>
+<em>layout-qualifier-id</em> <strong>,</strong> <em>layout-qualifier-id-list</em></p>
+</dd>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>layout-qualifier-name</em><br>
+<em>layout-qualifier-name</em> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>shared</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-value</em> : </dt>
+<dd>
+<p><em>integer-constant-expression</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The tokens used for <em>layout-qualifier-name</em> are identifiers, not keywords,
+however, the <strong>shared</strong> keyword is allowed as a <em>layout-qualifier-id</em>.
+Generally, they can be listed in any order.
+Order-dependent meanings exist only if explicitly called out below.
+Similarly, these identifiers are not case sensitive, unless explicitly noted
+otherwise.</p>
+</div>
+<div class="paragraph">
+<p>More than one layout qualifier may appear in a single declaration.
+Additionally, the same <em>layout-qualifier-name</em> can occur multiple times
+within a layout qualifier or across multiple layout qualifiers in the same
+declaration.
+When the same <em>layout-qualifier-name</em> occurs multiple times, in a single
+declaration, the last occurrence overrides the former occurrence(s).
+Further, if such a <em>layout-qualifier-name</em> will affect subsequent
+declarations or other observable behavior, it is only the last occurrence
+that will have any effect, behaving as if the earlier occurrence(s) within
+the declaration are not present.
+This is also true for overriding <em>layout-qualifier-name</em>, where one
+overrides the other (e.g. <strong>row_major</strong> vs.
+<strong>column_major</strong>); only the last occurrence has any effect.</p>
+</div>
+<div class="paragraph">
+<p><em>integer-constant-expression</em> is defined in
+&#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221; as &#8220;_constant integral
+expression_&#8221;, with it being a compile-time error for
+<em>integer-constant-expression</em> to be a specialization constant.</p>
+</div>
+<div class="paragraph">
+<p>The following table summarizes the use of layout qualifiers.
+It shows for each one what kinds of declarations it may be applied to.
+These are all discussed in detail in the following sections.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.6666%;">
+<col style="width: 16.667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Layout Qualifier</th>
+<th class="tableblock halign-left valign-top">Qualifier Only</th>
+<th class="tableblock halign-left valign-top">Individual Variable</th>
+<th class="tableblock halign-left valign-top">Block</th>
+<th class="tableblock halign-left valign-top">Block Member</th>
+<th class="tableblock halign-left valign-top">Allowed Interfaces</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>shared</strong><br>
+  <strong>packed</strong><br>
+  <strong>std140</strong><br>
+  <strong>std430</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top" rowspan="5"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>row_major</strong><br>
+  <strong>column_major</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>binding</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">opaque types only</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>offset</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">atomic counters only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>align</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong> / <strong>buffer</strong> and subroutine variables</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>location</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">all <strong>in</strong> / <strong>out</strong>, except for compute</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>component</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>index</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">fragment <strong>out</strong> and subroutine functions</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles</strong><br>
+  <strong>quads</strong><br>
+  <strong>isolines</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>equal_spacing</strong><br>
+  <strong>fractional_even_spacing</strong><br>
+  <strong>fractional_odd_spacing</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>cw</strong><br>
+  <strong>ccw</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>point_mode</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation evaluation <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>points</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong>/<strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ <strong>points</strong> ]<br>
+  <strong>lines</strong><br>
+  <strong>lines_adjacency</strong><br>
+  <strong>triangles</strong><br>
+  <strong>triangles_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>invocations</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">geometry <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>origin_upper_left</strong><br>
+  <strong>pixel_center_integer</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>gl_FragCoord</em> only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">fragment <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>early_fragment_tests</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>local_size_x</strong> =<br>
+  <strong>local_size_y</strong> =<br>
+  <strong>local_size_z</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compute <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>local_size_x_id</strong> =<br>
+  <strong>local_size_y_id</strong> =<br>
+  <strong>local_size_z_id</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compute <strong>in</strong> (SPIR-V generation only)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>xfb_buffer</strong> =<br>
+  <strong>xfb_stride</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top" rowspan="2"><p class="tableblock">vertex, tessellation, and geometry <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>xfb_offset</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>vertices</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">tessellation control <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ <strong>points</strong> ]<br>
+  <strong>line_strip</strong><br>
+  <strong>triangle_strip</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top" rowspan="3"><p class="tableblock">geometry <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>max_vertices</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>stream</strong> =</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>depth_any</strong><br>
+  <strong>depth_greater</strong><br>
+  <strong>depth_less</strong><br>
+  <strong>depth_unchanged</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>gl_FragDepth</em> only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">fragment <strong>out</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>constant_id</strong> =</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">scalar only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>const</strong> (SPIR-V generation only)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>rgba32f</strong><br>
+  <strong>rgba16f</strong><br>
+  <strong>rg32f</strong><br>
+  <strong>rg16f</strong><br>
+  <strong>r11f_g11f_b10f</strong><br>
+  <strong>r32f</strong><br>
+  <strong>r16f</strong><br>
+  <strong>rgba16</strong><br>
+  <strong>rgb10_a2</strong><br>
+  <strong>rgba8</strong><br>
+  <strong>rg16</strong><br>
+  <strong>rg8</strong><br>
+  <strong>r16</strong><br>
+  <strong>r8</strong><br>
+  <strong>rgba16_snorm</strong><br>
+  <strong>rgba8_snorm</strong><br>
+  <strong>rg16_snorm</strong><br>
+  <strong>rg8_snorm</strong><br>
+  <strong>r16_snorm</strong><br>
+  <strong>r8_snorm</strong><br>
+  <strong>rgba32i</strong><br>
+  <strong>rgba16i</strong><br>
+  <strong>rgba8i</strong><br>
+  <strong>rg32i</strong><br>
+  <strong>rg16i</strong><br>
+  <strong>rg8i</strong><br>
+  <strong>r32i</strong><br>
+  <strong>r16i</strong><br>
+  <strong>r8i</strong><br>
+  <strong>rgba32ui</strong><br>
+  <strong>rgba16ui</strong><br>
+<strong>rgb10_a2ui</strong><br>
+  <strong>rgba8ui</strong><br>
+  <strong>rg32ui</strong><br>
+  <strong>rg16ui</strong><br>
+  <strong>rg8ui</strong><br>
+  <strong>r32ui</strong><br>
+  <strong>r16ui</strong><br>
+  <strong>r8ui</strong></p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">image types only</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>uniform</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="sect3">
+<h4 id="input-layout-qualifiers">4.4.1. Input Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers specific to a particular shader language are discussed in
+separate sections below.</p>
+</div>
+<div class="paragraph">
+<p>All shaders except compute shaders allow <strong>location</strong> layout qualifiers on
+input variable declarations, input block declarations, and input block
+member declarations.
+Of these, variables and block members (but not blocks) additionally allow
+the <strong>component</strong> layout qualifier.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>component</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in vec4 normal;
+<span class="directive">const</span> <span class="predefined-type">int</span> start = <span class="integer">6</span>;
+layout(location = start + <span class="integer">2</span>) <span class="predefined-type">int</span> vec4 v;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the shader input <em>normal</em> is assigned to vector location
+number
+3 and <em>v</em> is assigned location number 8.
+For vertex shader inputs, the location specifies the number of the
+vertex attribute from which input values are taken.
+For inputs of all other shader types, the location specifies a vector number
+that can be used to match against outputs from a previous shader stage, even
+if that shader is in a different program object.</p>
+</div>
+<div class="paragraph">
+<p>The following language describes how many locations are consumed by a given
+type.
+However, geometry shader inputs, tessellation control shader inputs and
+outputs, and tessellation evaluation inputs all have an additional level of
+arrayness relative to other shader inputs and outputs.
+This outer array level is removed from the type before considering how many
+locations the type consumes.</p>
+</div>
+<div class="paragraph">
+<p>If a vertex shader input is any scalar or vector type, it will consume a
+single location.
+If a non-vertex shader input is a scalar or vector type other than <strong>dvec3</strong>
+or <strong>dvec4</strong>, it will consume a single location, while types <strong>dvec3</strong> or
+<strong>dvec4</strong> will consume two consecutive locations.
+Inputs of type <strong>double</strong> and <strong>dvec2</strong> will consume only a single location, in
+all stages.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input (after potentially removing an outer array level as
+just described above) is an array of size <em>n</em> and each of the elements takes
+<em>m</em> locations, it will be assigned <em>m</em> * <em>n</em> consecutive locations starting
+with the location specified.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">6</span>) in vec4 colors[<span class="integer">3</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the shader input <em>colors</em> is assigned to vector location
+numbers 6, 7, and 8.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input is an <em>n</em> × <em>m</em>
+matrix, it will be assigned multiple locations starting with the location
+specified.
+The number of locations assigned for each matrix will be the same as for an
+<em>n</em>-element array of <em>m</em>-component vectors.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">9</span>) in mat4 transforms[<span class="integer">2</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that shader input <em>transforms</em> is assigned to vector
+locations 9-16, with <em>transforms[0]</em> being assigned to locations 9-12, and
+<em>transforms[1]</em> being assigned to locations 13-16.</p>
+</div>
+<div class="paragraph">
+<p>If the declared input is a structure or block, its members will be assigned
+consecutive locations in their order of declaration, with the first member
+assigned the location provided in the layout qualifier.
+For a structure, this process applies to the entire structure.
+It is a compile-time error to use a <strong>location</strong> qualifier on a member of a
+structure.
+For a block, this process applies to the entire block, or until the first
+member is reached that has a <strong>location</strong> layout qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When a block member is declared with a <strong>location</strong> qualifier, its location
+comes from that qualifier; the member&#8217;s <strong>location</strong> qualifier overrides the
+block-level declaration.
+Subsequent members are again assigned consecutive locations, based on the
+newest location, until the next member declared with a <strong>location</strong> qualifier.
+The values used for locations do not have to be declared in increasing
+order.</p>
+</div>
+<div class="paragraph">
+<p>If a block has no block-level <strong>location</strong> layout qualifier, it is required
+that either all or none of its members have a <strong>location</strong> layout qualifier,
+or a compile-time error results.
+For some blocks declared as arrays, the <strong>location</strong> can only be applied at
+the block level: When a block is declared as an array where additional
+locations are needed for each member for each block array element, it is a
+compile-time error to specify locations on the block members.
+That is, when locations would be under specified by applying them on block
+members, they are not allowed on block members.
+For <em>arrayed</em> interfaces (those generally having an extra level of arrayness
+due to interface expansion), the outer array is stripped before applying
+this rule.</p>
+</div>
+<div class="paragraph">
+<p>When generating SPIR-V, all <strong>in</strong> and <strong>out</strong> qualified user-declared (non
+built-in) variables and blocks (or all their members) must have a
+shader-specified <strong>location</strong>.
+Otherwise, a compile-time error is generated.</p>
+</div>
+<div class="paragraph">
+<p>The locations consumed by block and structure members are determined by
+applying the rules above recursively as though the structure member were
+declared as an input variable of the same type.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) in <span class="keyword">struct</span> S
+{
+    vec3 a;                      <span class="comment">// gets location 3</span>
+    mat2 b;                      <span class="comment">// gets locations 4 and 5</span>
+    vec4 c[<span class="integer">2</span>];                   <span class="comment">// gets locations 6 and 7</span>
+    layout(location = <span class="integer">8</span>) vec2 A; <span class="comment">// ERROR, can't use on struct member</span>
+} s;
+layout(location = <span class="integer">4</span>) in block
+{
+    vec4 d;                      <span class="comment">// gets location 4</span>
+    vec4 e;                      <span class="comment">// gets location 5</span>
+    layout(location = <span class="integer">7</span>) vec4 f; <span class="comment">// gets location 7</span>
+    vec4 g;                      <span class="comment">// gets location 8</span>
+    layout(location = <span class="integer">1</span>) vec4 h; <span class="comment">// gets location 1</span>
+    vec4 i;                      <span class="comment">// gets location 2</span>
+    vec4 j;                      <span class="comment">// gets location 3</span>
+    vec4 k;                      <span class="comment">// ERROR, location 4 already used</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The number of input locations available to a shader is limited.
+For vertex shaders, the limit is the advertised number of vertex attributes.
+For all other shaders, the limit is implementation-dependent and must be no
+less than one fourth of the advertised maximum input component count.</p>
+</div>
+<div class="paragraph">
+<p>A program will fail to link if any attached shader uses a location greater
+than or equal to the number of supported locations, unless device-dependent
+optimizations are able to make the program fit within available hardware
+resources.</p>
+</div>
+<div class="paragraph">
+<p>A program will fail to link if explicit location assignments leave the
+linker unable to find space for other variables without explicit
+assignments.</p>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if a non-vertex input matches an output from
+a previous shader stage, the <strong>location</strong> layout qualifier (if any) must
+match.</p>
+</div>
+<div class="paragraph">
+<p>If a vertex shader input variable with no location assigned in the shader
+text has a location specified through the OpenGL API, the API-assigned
+location will be used.
+Otherwise, such variables will be assigned a location by the linker.
+See section 11.1.1 &#8220;Vertex Attributes&#8221; of the <a href="#references">OpenGL Specification</a> for
+more details.
+A link-time error will occur if an input variable is declared in multiple
+shaders of the same language with conflicting locations.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>component</strong> qualifier allows the location to be more finely specified
+for scalars and vectors, down to the individual components within a location
+that are consumed.
+It is a compile-time error to use <strong>component</strong> without also specifying the
+<strong>location</strong> qualifier (order does not matter).
+The components within a location are 0, 1, 2, and 3.
+A variable or block member starting at component <em>N</em> will consume components
+<em>N</em>, <em>N+1</em>, <em>N+2</em>, &#8230;&#8203;
+up through its size.
+It is a compile-time error if this sequence of components gets larger than
+3.
+A scalar <strong>double</strong> will consume two of these components, and a <strong>dvec2</strong> will
+consume all four components available within a location.
+A <strong>dvec3</strong> or <strong>dvec4</strong> can only be declared without specifying a <strong>component</strong>.
+A <strong>dvec3</strong> will consume all four components of the first location and
+components 0 and 1 of the second location.
+This leaves components 2 and 3 available for other component-qualified
+declarations.</p>
+</div>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// a consumes components 2 and 3 of location 4</span>
+layout(location = <span class="integer">4</span>, component = <span class="integer">2</span>) in vec2 a;
+
+<span class="comment">// b consumes component 1 of location 4</span>
+layout(location = <span class="integer">4</span>, component = <span class="integer">1</span>) in <span class="predefined-type">float</span> b;
+
+<span class="comment">// ERROR: c overflows component 3</span>
+layout(location = <span class="integer">3</span>, component = <span class="integer">2</span>) in vec3 c;
+
+<span class="comment">// d consumes components 2 and 3 of location 5</span>
+layout(location = <span class="integer">5</span>, component = <span class="integer">2</span>) in <span class="predefined-type">double</span> d;
+
+<span class="comment">// ERROR: e overflows component 3 of location 6</span>
+layout(location = <span class="integer">6</span>, component = <span class="integer">2</span>) in dvec2 e;
+
+<span class="comment">// ERROR: f overlaps with g</span>
+layout(location = <span class="integer">7</span>, component = <span class="integer">0</span>) <span class="predefined-type">double</span> f;
+layout(location = <span class="integer">7</span>, component = <span class="integer">1</span>) <span class="predefined-type">float</span> g;
+
+layout(location = <span class="integer">8</span>) in dvec3 h; <span class="comment">// components 0,1,2 and 3 of location 8</span>
+                                 <span class="comment">// and components 0 and 1 of location 9</span>
+layout(location = <span class="integer">9</span>, component = <span class="integer">2</span>) in <span class="predefined-type">float</span> i; <span class="comment">// okay, compts 2 and 3</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If the variable is an array, each element of the array, in order, is
+assigned to consecutive locations, but all at the same specified component
+within each location.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// component 3 in 6 locations are consumed</span>
+layout(location = <span class="integer">2</span>, component = <span class="integer">3</span>) in <span class="predefined-type">float</span> d[<span class="integer">6</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>That is, location 2 component 3 will hold <em>d[0]</em>, location 3 component 3
+will hold <em>d[1]</em>, &#8230;&#8203;, up through location 7 component 3 holding <em>d[5]</em>.</p>
+</div>
+<div class="paragraph">
+<p>This allows packing of two arrays into the same set of locations:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// e consumes beginning (components 0, 1 and 2) of each of 6 slots</span>
+layout(location = <span class="integer">0</span>, component = <span class="integer">0</span>) in vec3 e[<span class="integer">6</span>];
+
+<span class="comment">// f consumes last component of the same 6 slots</span>
+layout(location = <span class="integer">0</span>, component = <span class="integer">3</span>) in <span class="predefined-type">float</span> f[<span class="integer">6</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If applying this to an array of arrays, all levels of arrayness are removed
+to get to the elements that are assigned per location to the specified
+component.
+These non-arrayed elements will fill the locations in the order specified
+for arrays of arrays in &#8220;<a href="#arrays">Arrays</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to apply the <strong>component</strong> qualifier to a matrix, a
+structure, a block, or an array containing any of these.
+It is a compile-time error to use <strong>component</strong> 1 or 3 as the beginning of a
+<strong>double</strong> or <strong>dvec2</strong>.
+It is a link-time error to specify different components for the same
+variable within a program.</p>
+</div>
+<div class="paragraph">
+<p><em>Location aliasing</em> is causing two variables or block members to have the
+same location number.
+<em>Component aliasing</em> is assigning the same (or overlapping) component
+numbers for two location aliases.
+(Recall if <strong>component</strong> is not used, components are assigned starting with
+0.) With one exception, location aliasing is allowed only if it does not
+cause component aliasing; it is a compile-time or link-time error to cause
+component aliasing.
+Further, when location aliasing, the aliases sharing the location must have
+the same underlying numerical type and bit width  (floating-point or integer,
+32-bit versus 64-bit, etc.) and the same
+auxiliary storage and interpolation qualification.
+The one exception where component aliasing is permitted is for two input
+variables (not block members) to a vertex shader, which are allowed to have
+component aliasing.
+This vertex-variable component aliasing is intended only to support vertex
+shaders where each execution path accesses at most one input per each
+aliased component.
+Implementations are permitted, but not required, to generate link-time
+errors if they detect that every path through the vertex shader executable
+accesses multiple inputs aliased to any single component.</p>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-inputs">Tessellation Evaluation Inputs</h5>
+<div class="paragraph">
+<p>Additional input layout qualifier identifiers allowed for tessellation
+evaluation shaders are described below.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>primitive_mode</em><br>
+<em>vertex_spacing</em><br>
+<em>ordering</em><br>
+<em>point_mode</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>primitive-mode</strong> is used to specify a tessellation primitive mode to be
+used by the tessellation primitive generator.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>primitive-mode</em>: </dt>
+<dd>
+<p><strong>triangles</strong><br>
+<strong>quads</strong><br>
+<strong>isolines</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>If present, the <em>primitive-mode</em> specifies that the tessellation primitive
+generator should subdivide a triangle into smaller triangles, a quad into
+triangles, or a quad into a collection of lines, respectively.</p>
+</div>
+<div class="paragraph">
+<p>A second group of layout identifiers, <em>vertex spacing</em>, is used to specify
+the spacing used by the tessellation primitive generator when subdividing an
+edge.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>vertex-spacing</em>: </dt>
+<dd>
+<p><strong>equal_spacing</strong><br>
+<strong>fractional_even_spacing</strong><br>
+<strong>fractional_odd_spacing</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p><strong>equal_spacing</strong> specifies that edges should be divided into a collection of
+equal-sized segments;</p>
+</div>
+<div class="paragraph">
+<p><strong>fractional_even_spacing</strong> specifies that edges should be divided into an
+even number of equal-length segments plus two additional shorter
+&#8220;fractional&#8221; segments; or</p>
+</div>
+<div class="paragraph">
+<p><strong>fractional_odd_spacing</strong> specifies that edges should be divided into an odd
+number of equal-length segments plus two additional shorter &#8220;fractional&#8221;
+segments.</p>
+</div>
+<div class="paragraph">
+<p>A third group of layout identifiers, <em>ordering</em>, specifies whether the
+tessellation primitive generator produces triangles in clockwise or
+counter-clockwise order, according to the coordinate system depicted in the
+<a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>ordering</em>: </dt>
+<dd>
+<p><strong>cw</strong><br>
+<strong>ccw</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifiers <strong>cw</strong> and <strong>ccw</strong> indicate clockwise and counter-clockwise
+triangles, respectively.
+If the tessellation primitive generator does not produce triangles, the
+order is ignored.</p>
+</div>
+<div class="paragraph">
+<p>Finally, <em>point mode</em> indicates that the tessellation primitive generator
+should produce one point for each distinct vertex in the subdivided
+primitive, rather than generating lines or triangles.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>point-mode</em>: </dt>
+<dd>
+<p><strong>point_mode</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Any or all of these identifiers may be specified one or more times in a
+single input layout declaration.
+If primitive mode, vertex spacing, or ordering is declared more than once in
+the tessellation evaluation shaders of a program, all such declarations must
+use the same identifier.</p>
+</div>
+<div class="paragraph">
+<p>At least one tessellation evaluation shader (compilation unit) in a program
+must declare a primitive mode in its input layout.
+Declaring vertex spacing, ordering, or point mode identifiers is optional.
+It is not required that all tessellation evaluation shaders in a program
+declare a primitive mode.
+If spacing or vertex ordering declarations are omitted, the tessellation
+primitive generator will use equal spacing or counter-clockwise vertex
+ordering, respectively.
+If a point mode declaration is omitted, the tessellation primitive generator
+will produce lines or triangles according to the primitive mode.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-inputs">Geometry Shader Inputs</h5>
+<div class="paragraph">
+<p>Additional layout qualifier identifiers for geometry shader inputs include
+<em>primitive</em> identifiers and an <em>invocation count</em> identifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>points</strong><br>
+<strong>lines</strong><br>
+<strong>lines_adjacency</strong><br>
+<strong>triangles</strong><br>
+<strong>triangles_adjacency</strong><br>
+<strong>invocations</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifiers <strong>points</strong>, <strong>lines</strong>, <strong>lines_adjacency</strong>, <strong>triangles</strong>, and
+<strong>triangles_adjacency</strong> are used to specify the type of input primitive
+accepted by the geometry shader, and only one of these is accepted.
+At least one geometry shader (compilation unit) in a program must declare
+this input primitive layout, and all geometry shader input layout
+declarations in a program must declare the same layout.
+It is not required that all geometry shaders in a program declare an input
+primitive layout.</p>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>invocations</strong> is used to specify the number of times the
+geometry shader executable is invoked for each input primitive received.
+Invocation count declarations are optional.
+If no invocation count is declared in any geometry shader in a program, the
+geometry shader will be run once for each input primitive.
+If an invocation count is declared, all such declarations must specify the
+same count.
+If a shader specifies an invocation count greater than the
+implementation-dependent maximum, or less than or equal to zero,
+a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(triangles, invocations = <span class="integer">6</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that all inputs to the geometry shader are triangles and that
+the geometry shader executable is run six times for each triangle processed.</p>
+</div>
+<div class="paragraph">
+<p>All geometry shader input unsized array declarations will be sized by an
+earlier input primitive layout qualifier, when present, as per the following
+table.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Layout</th>
+<th class="tableblock halign-left valign-top">Size of Input Arrays</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>points</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lines_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>triangles_adjacency</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The intrinsically declared input array <em>gl_in[]</em> will also be sized by any
+input primitive-layout declaration.
+Hence, the expression</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_in.length()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will return the value from the table above.</p>
+</div>
+<div class="paragraph">
+<p>For inputs declared without an array size, including intrinsically declared
+inputs (i.e., <em>gl_in</em>), a layout must be declared before any use of the
+method <strong>length</strong>() or other any array use that requires the array size to be
+known.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error if a layout declaration&#8217;s array size (from the
+table above) does not match all the explicit array sizes specified in
+declarations of an input variables in the same shader.
+The following includes examples of compile-time errors:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// code sequence within one shader...</span>
+in vec4 Color1[];     <span class="comment">// legal, size still unknown</span>
+in vec4 Color2[<span class="integer">2</span>];    <span class="comment">// legal, size is 2</span>
+in vec4 Color3[<span class="integer">3</span>];    <span class="comment">// illegal, input sizes are inconsistent</span>
+layout(lines) in;     <span class="comment">// legal for Color2, input size is 2, matching Color2</span>
+in vec4 Color4[<span class="integer">3</span>];    <span class="comment">// illegal, contradicts layout of lines</span>
+layout(lines) in;     <span class="comment">// legal, matches other layout() declaration</span>
+layout(triangles) in; <span class="comment">// illegal, does not match earlier layout() declaration</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a link-time error if not all provided sizes (sized input arrays and
+layout size) match across all geometry shaders in a program.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="fragment-shader-inputs">Fragment Shader Inputs</h5>
+<div class="paragraph">
+<p>Additional fragment layout qualifier identifiers include the following for
+<em>gl_FragCoord</em> :</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>origin_upper_left</strong><br>
+<strong>pixel_center_integer</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>By default, <em>gl_FragCoord</em> assumes a lower-left origin for window
+coordinates and assumes pixel centers are located at half-pixel coordinates.
+For example, the (<em>x, y</em>) location (0.5, 0.5) is returned for the
+lower-left-most pixel in a window.
+The origin can be changed by redeclaring <em>gl_FragCoord</em> with the
+<strong>origin_upper_left</strong> qualifier, moving the origin of <em>gl_FragCoord</em> to the
+upper left of the window, with <em>y</em> increasing in value toward the bottom of
+the window.
+The values returned can also be shifted by half a pixel in both <em>x</em> and <em>y</em>
+by <strong>pixel_center_integer</strong> so it appears the pixels are centered at whole
+number pixel offsets.
+This moves the (<em>x</em>, <em>y</em>) value returned by <em>gl_FragCoord</em> of (0.5, 0.5) by
+default, to (0.0, 0.0) with <strong>pixel_center_integer</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Redeclarations are done as follows</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 gl_FragCoord; <span class="comment">// redeclaration that changes nothing is allowed</span>
+
+<span class="comment">// All the following are allowed redeclaration that change behavior</span>
+layout(origin_upper_left) in vec4 gl_FragCoord;
+layout(pixel_center_integer) in vec4 gl_FragCoord;
+layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If <em>gl_FragCoord</em> is redeclared in any fragment shader in a program, it must
+be redeclared in all the fragment shaders in that program that have a static
+use <em>gl_FragCoord</em>.
+All redeclarations of <em>gl_FragCoord in all fragment shaders in a single
+program must have the same set of qualifiers.
+Within any shader, the first redeclarations of _glFragCoord</em> must appear
+before any use of <em>gl_FragCoord</em>.
+The built-in <em>gl_FragCoord</em> is only predeclared in fragment shaders, so
+redeclaring it in any other shader language results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>Redeclaring <em>glFragCoord</em> with <strong>origin_upper_left</strong> and/or
+<strong>pixel_center_integer</strong> qualifiers only affects <em>gl_FragCoord.x</em> and
+<em>gl_FragCoord.y</em>.
+It has no effect on rasterization, transformation, or any other part of the
+OpenGL pipeline or language features.</p>
+</div>
+<div class="paragraph">
+<p>Fragment shaders allow the following layout qualifier on <strong>in</strong> only (not with
+variable declarations):</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>early_fragment_tests</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>to request that fragment tests be performed before fragment shader
+execution, as described in section 15.2.4 &#8220;Early Fragment Tests&#8221; of the
+<a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(early_fragment_tests) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Specifying this will make per-fragment tests be performed before fragment
+shader execution.
+If this is not declared, per-fragment tests will be performed after fragment
+shader execution.
+Only one fragment shader (compilation unit) need declare this, though more
+than one can.
+If at least one declares this, then it is enabled.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="compute-shader-inputs">Compute Shader Inputs</h5>
+<div class="paragraph">
+<p>There are no layout location qualifiers for compute shader inputs.</p>
+</div>
+<div class="paragraph">
+<p>Layout qualifier identifiers for compute shader inputs are the workgroup
+size qualifiers:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>local_size_x</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>local_size_y</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>local_size_z</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> qualifiers are used
+to declare a fixed workgroup size by the compute shader in the first,
+second, and third dimension, respectively.
+If a shader does not specify a size for one of the dimensions, that
+dimension will have a size of 1.</p>
+</div>
+<div class="paragraph">
+<p>For example, the following declaration in a compute shader</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">32</span>, local_size_y = <span class="integer">32</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is used to declare a two-dimensional compute shader with a workgroup size of 32
+X 32 elements, which is equivalent to a three-dimensional compute shader
+where the third dimension has size one.</p>
+</div>
+<div class="paragraph">
+<p>As another example, the declaration</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">8</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>effectively specifies that a one-dimensional compute shader is being
+compiled, and its size is 8 elements.</p>
+</div>
+<div class="paragraph">
+<p>If the fixed workgroup size of the shader in any dimension is less than
+or equal to zero or greater than the maximum size supported by the
+implementation for that dimension, a compile-time error results.
+Also, if such a layout qualifier is declared more than once in the same
+shader, all those declarations must set the same set of workgroup
+sizes and set them to the same values; otherwise a compile-time error
+results.
+If multiple compute shaders attached to a single program object declare a
+fixed workgroup size, the declarations must be identical; otherwise a
+link-time error results.</p>
+</div>
+<div class="paragraph">
+<p>Furthermore, if a program object contains any compute shaders, at least one
+must contain an input layout qualifier specifying a fixed workgroup size
+for the program, or a link-time error will occur.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="output-layout-qualifiers">4.4.2. Output Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Some output layout qualifiers apply to all shader stages and some apply only
+to specific stages.
+The latter are discussed in separate sections below.</p>
+</div>
+<div class="paragraph">
+<p>As with input layout qualifiers, all shaders except compute shaders allow
+<strong>location</strong> layout qualifiers on output variable declarations, output block
+declarations, and output block member declarations.
+Of these, variables and block members (but not blocks) additionally allow
+the <strong>component</strong> layout qualifier.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>component</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The usage and rules for applying the <strong>location</strong> qualifier
+and the <strong>component</strong> qualifier
+to blocks and structures are exactly as described in
+&#8220;<a href="#input-layout-qualifiers">Input Layout Qualifiers</a>&#8221;.
+Additionally, for fragment shader outputs, if two variables are placed
+within the same location, they must have the same underlying type
+(floating-point or integer).
+No component aliasing of output variables or members is allowed.</p>
+</div>
+<div class="paragraph">
+<p>Fragment shaders allow an additional <strong>index</strong> output layout qualifier:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>index</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Each of these qualifiers may appear at most once.
+If <strong>index</strong> is specified, <strong>location</strong> must also be specified.
+If <strong>index</strong> is not specified, the value 0 is used.
+For example, in a fragment shader,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>) out vec4 color;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the fragment shader output <em>color</em> is assigned to
+fragment color 3 as the first (index zero) input to the blend equation.
+And,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">3</span>, index = <span class="integer">1</span>) out vec4 factor;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the fragment shader output <em>factor</em> is assigned to
+fragment color 3 as the second (index one) input to the blend equation.</p>
+</div>
+<div class="paragraph">
+<p>For fragment shader outputs, the location
+and index specify
+the color output number
+and index
+receiving the values of the output.
+For outputs of all other shader stages, the location specifies a vector
+number that can be used to match against inputs in a subsequent shader
+stage, even if that shader is in a different program object.</p>
+</div>
+<div class="paragraph">
+<p>If a declared output is a scalar or vector type other than <strong>dvec3</strong> or
+<strong>dvec4</strong>, it will consume a single location.
+Outputs of type <strong>dvec3</strong> or <strong>dvec4</strong> will consume two consecutive locations.
+Outputs of type <strong>double</strong> and <strong>dvec2</strong> will consume only a single location, in
+all stages.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is an array, it will be assigned consecutive
+locations starting with the location specified.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(location = <span class="integer">2</span>) out vec4 colors[<span class="integer">3</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that <em>colors</em> is assigned to vector location numbers 2, 3,
+and 4.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is an <em>n</em> × <em>m</em>
+matrix, it will be assigned multiple locations starting with the location
+specified.
+The number of locations assigned will be the same as for an <em>n</em>-element
+array of <em>m</em>-component vectors.</p>
+</div>
+<div class="paragraph">
+<p>If the declared output is a structure, its members will be assigned
+consecutive locations in the order of declaration, with the first member
+assigned the location specified for the structure.
+The number of locations consumed by a structure member is determined by
+applying the rules above recursively as though the structure member were
+declared as an output variable of the same type.</p>
+</div>
+<div class="paragraph">
+<p><strong>location</strong> layout qualifiers may be used on output variables declared as
+structures.
+However, it is a compile-time error to use a <strong>location</strong> qualifier on a
+structure member.
+Location layout qualifiers may be used on output blocks and output block
+members.</p>
+</div>
+<div class="paragraph">
+<p>The number of output locations available to a shader is limited.
+For fragment shaders, the limit is the advertised number of draw buffers.</p>
+</div>
+<div class="paragraph">
+<p>For all other shaders, the limit is implementation-dependent and must be no
+less than one fourth of the advertised maximum output component count
+(compute shaders have no outputs).
+A program will fail to link if any attached shader uses a location greater
+than or equal to the number of supported locations, unless device-dependent
+optimizations are able to make the program fit within available hardware
+resources.</p>
+</div>
+<div class="paragraph">
+<p>Compile-time errors may also be given if at compile time it is known the
+link will fail.
+A negative output location will result in a compile-time error.
+It is also a compile-time error if a fragment shader sets a layout index to
+less than 0 or greater than 1.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error if any of the following occur:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>any two fragment shader output variables are assigned to the same
+location and index.</p>
+</li>
+<li>
+<p>if any two output variables from the same vertex, tessellation or
+geometry shader stage are assigned to the same location.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>For fragment shader outputs, locations can be assigned using either a
+<strong>layout</strong> qualifier or via the OpenGL API.</p>
+</div>
+<div class="paragraph">
+<p>For all shader types, a program will fail to link if explicit location
+assignments leave the linker unable to find space for other variables
+without explicit assignments.</p>
+</div>
+<div class="paragraph">
+<p>If an output variable with no location or index assigned in the shader text
+has a location specified through the OpenGL API, the API-assigned
+location will be used.
+Otherwise, such variables will be assigned a location by the linker.
+All such assignments will have a color index of zero.
+See section 15.2 &#8220;Shader Execution&#8221; of the <a href="#references">OpenGL Specification</a> for
+more details.
+A link-time error will occur if an output variable is declared in multiple
+shaders of the same language with conflicting location or index values.</p>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if a non-fragment output matches an input
+from a subsequent shader stage, the <strong>location</strong> layout qualifier (if any)
+must match.</p>
+</div>
+<div class="sect4">
+<h5 id="transform-feedback-layout-qualifiers">Transform Feedback Layout Qualifiers</h5>
+<div class="paragraph">
+<p>The vertex, tessellation, and geometry stages allow shaders to control
+transform feedback.
+When doing this, shaders will dictate which transform feedback buffers are
+in use, which output variables will be written to which buffers, and how
+each buffer is laid out.
+To accomplish this, shaders allow the following layout qualifier identifiers
+on output declarations:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>xfb_buffer</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>xfb_offset</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>xfb_stride</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Any shader making any static use (after preprocessing) of any of these
+<strong>xfb_</strong> qualifiers will cause the shader to be in a transform feedback
+capturing mode and hence responsible for describing the transform feedback
+setup.
+This mode will capture any output selected by <strong>xfb_offset</strong>, directly or
+indirectly, to a transform feedback buffer.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>xfb_buffer</strong> qualifier specifies which transform feedback buffer will
+capture outputs selected with <strong>xfb_offset</strong>.
+The <strong>xfb_buffer</strong> qualifier can be applied to the qualifier <strong>out</strong>, to output
+variables, to output blocks, and to output block members.
+Shaders in the transform feedback capturing mode have an initial global
+default of</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(xfb_buffer = <span class="integer">0</span>) out;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This default can be changed by declaring a different buffer with
+<strong>xfb_buffer</strong> on the interface qualifier <strong>out</strong>.
+This is the only way the global default can be changed.
+When a variable or output block is declared without an <strong>xfb_buffer</strong>
+qualifier, it inherits the global default buffer.
+When a variable or output block is declared with an <strong>xfb_buffer</strong> qualifier,
+it has that declared buffer.
+All members of a block inherit the block&#8217;s buffer.
+A member is allowed to declare an <strong>xfb_buffer</strong>, but it must match the buffer
+inherited from its block, or a compile-time error results.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(xfb_buffer=<span class="integer">2</span>, xfb_offset=<span class="integer">0</span>) out block { <span class="comment">// block's buffer is 2</span>
+    layout(xfb_buffer = <span class="integer">2</span>) vec4 v; <span class="comment">// okay, matches the inherited 2</span>
+    layout(xfb_buffer = <span class="integer">3</span>) vec4 u; <span class="comment">// ERROR, mismatched buffer</span>
+    vec4 w; <span class="comment">// inherited</span>
+};
+layout(xfb_offset=<span class="integer">16</span>) out vec4 t;  <span class="comment">// initial default is buffer 0</span>
+layout(xfb_buffer=<span class="integer">1</span>) out;          <span class="comment">// new global default of 1</span>
+out block {                        <span class="comment">// block has buffer 1</span>
+    vec4 x;                        <span class="comment">// x has buffer 1 (not captured)</span>
+    layout(xfb_buffer = <span class="integer">1</span>) vec4 y; <span class="comment">// okay (not captured)</span>
+    layout(xfb_buffer = <span class="integer">0</span>) vec4 z; <span class="comment">// ERROR, mismatched buffer</span>
+};
+layout(xfb_offset=<span class="integer">0</span>) out vec4 g;   <span class="comment">// g has buffer 1</span>
+layout(xfb_buffer=<span class="integer">2</span>) out vec4 h;   <span class="comment">// does not change global default</span>
+layout(xfb_offset=<span class="integer">16</span>) out vec4 j;  <span class="comment">// j has buffer 1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Note this means all members of a block that go to a transform feedback
+buffer will go to the same buffer.</p>
+</div>
+<div class="paragraph">
+<p>When a block is declared as an array, all members of block array-element 0
+are captured, as previously described, by the declared or inherited
+<strong>xfb_buffer</strong>.
+Generally, an array of size <em>N</em> of blocks is captured by <em>N</em> consecutive
+buffers, with all members of block array-element <em>E</em> captured by buffer <em>B</em>,
+where <em>B</em> equals the declared or inherited <strong>xfb_buffer</strong> plus <em>E</em>.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error to specify an <strong>xfb_buffer</strong>,
+including any additional buffers needed to capture an arrays of blocks, that
+is less than zero or greater than or equal to the implementation-dependent
+constant <em>gl_MaxTransformFeedbackBuffers</em>.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>xfb_offset</strong> qualifier assigns a byte offset within a transform feedback
+buffer.
+Only variables, block members, or blocks can be qualified with <strong>xfb_offset</strong>.
+If a block is qualified with <strong>xfb_offset</strong>, all its members are assigned
+transform feedback buffer offsets.
+If a block is not qualified with <strong>xfb_offset</strong>, any members of that block not
+qualified with an <strong>xfb_offset</strong> will not be assigned transform feedback
+buffer offsets.
+Only variables and block members that are assigned offsets will be captured
+(thus, a proper subset of a block can be captured).
+Each time such a variable or block member is written in a shader, the
+written value is captured at the assigned offset.
+If such a block member or variable is not written during a shader
+invocation, the buffer contents at the assigned offset will be undefined.
+Even if there are no static writes to a variable or member that is assigned
+a transform feedback offset, the space is still allocated in the buffer and
+still affects the stride.</p>
+</div>
+<div class="paragraph">
+<p>Variables and block members qualified with <strong>xfb_offset</strong> can be scalars,
+vectors, matrices, structures, and (sized) arrays of these.
+The offset must be a multiple of the size of the first component of the
+first qualified variable or block member, or a compile-time error results.
+Further, if applied to an aggregate containing a <strong>double</strong>, the offset must
+also be a multiple of 8, and the space taken in the buffer will be a
+multiple of 8.
+The given offset applies to the first component of the first member of the
+qualified entity.
+Then, within the qualified entity, subsequent components are each assigned,
+in order, to the next available offset aligned to a multiple of that
+component&#8217;s size.
+Aggregate types are flattened down to the component level to get this
+sequence of components.
+It is a compile-time error to apply <strong>xfb_offset</strong> to the declaration of an
+unsized array.</p>
+</div>
+<div class="paragraph">
+<p>No aliasing in output buffers is allowed: It is a compile-time or link-time
+error to specify variables with overlapping transform feedback offsets.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>xfb_stride</strong> qualifier specifies how many bytes are consumed by each
+captured vertex.
+It applies to the transform feedback buffer for that declaration, whether it
+is inherited or explicitly declared.
+It can be applied to variables, blocks, block members, or just the qualifier
+<strong>out</strong>.
+If the buffer is capturing any outputs with double-precision components, the
+stride must be a multiple of 8, otherwise it must be a multiple of 4, or a
+compile-time or link-time error results.
+It is a compile-time or link-time error to have any <strong>xfb_offset</strong> that
+overflows <strong>xfb_stride</strong>, whether stated on declarations before or after the
+<strong>xfb_stride</strong>, or in different compilation units.
+While <strong>xfb_stride</strong> can be declared multiple times for the same buffer, it is
+a compile-time or link-time error to have different values specified for the
+stride for the same buffer.</p>
+</div>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// buffer 1 has 32-byte stride</span>
+layout(xfb_buffer = <span class="integer">1</span>, xfb_stride = <span class="integer">32</span>) out;
+
+<span class="comment">// same as previous example; order within layout does not matter</span>
+layout(xfb_stride = <span class="integer">32</span>, xfb_buffer = <span class="integer">1</span>) out;
+
+<span class="comment">// everything in this block goes to buffer 0</span>
+layout(xfb_buffer = <span class="integer">0</span>, xfb_stride = <span class="integer">32</span>) out block1 {
+    layout(xfb_offset = <span class="integer">0</span>) vec4 a;  <span class="comment">// a goes to byte offset 0 of buffer 0</span>
+    layout(xfb_offset = <span class="integer">16</span>) vec4 b; <span class="comment">// b goes to offset 16 of buffer 0</span>
+};
+
+layout(xfb_buffer = <span class="integer">3</span>, xfb_offset = <span class="integer">12</span>) out block2 {
+    vec4 v;  <span class="comment">// v will be written to byte offsets 12 through 27 of buffer</span>
+    <span class="predefined-type">float</span> u; <span class="comment">// u will be written to offset 28</span>
+    layout(xfb_offset = <span class="integer">40</span>) vec4 w;
+    vec4 x;  <span class="comment">// x will be written to offset 56, the next available offset</span>
+};
+
+layout(xfb_buffer = <span class="integer">2</span>, xfb_stride = <span class="integer">32</span>) out block3 {
+    layout(xfb_offset = <span class="integer">12</span>) vec3 c;
+    layout(xfb_offset = <span class="integer">24</span>) vec3 d; <span class="comment">// ERROR, requires stride of 36</span>
+    layout(xfb_offset = <span class="integer">0</span>) vec3 g;  <span class="comment">// okay, increasing order not required</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When no <strong>xfb_stride</strong> is specified for a buffer, the stride of the buffer
+will be the smallest needed to hold the variable placed at the highest
+offset, including any required padding.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// if there no other declarations for buffer 3, it has stride 32</span>
+layout(xfb_buffer = <span class="integer">3</span>) out block4 {
+    layout(xfb_offset = <span class="integer">0</span>) vec4 e;
+    layout(xfb_offset = <span class="integer">16</span>) vec4 f;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The resulting stride (implicit or explicit), when divided by 4, must be less
+than or equal to the implementation-dependent constant
+<em>gl_MaxTransformFeedbackInterleavedComponents</em>.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-outputs">Tessellation Control Outputs</h5>
+<div class="paragraph">
+<p>Other than for the transform feedback layout qualifiers, tessellation
+control shaders allow output layout qualifiers only on the interface
+qualifier <strong>out</strong>, not on an output block, block member, or variable
+declaration.
+The output layout qualifier identifiers allowed for tessellation control
+shaders are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>vertices</strong> specifies the number of vertices in the output
+patch produced by the tessellation control shader, which also specifies the
+number of times the tessellation control shader is invoked.
+It is a compile- or link-time error for the output vertex count to be less
+than or equal to zero, or greater than the implementation-dependent maximum
+patch size.</p>
+</div>
+<div class="paragraph">
+<p>The intrinsically declared tessellation control output array <em>gl_out[]</em> will
+also be sized by any output layout declaration.
+Hence, the expression</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_out.length()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will return the output patch vertex count specified in a previous output
+layout qualifier.
+For outputs declared without an array size, including intrinsically declared
+outputs (i.e., <em>gl_out</em>), a layout must be declared before any use of the
+method <strong>length</strong>() or other array use that requires its size to be known.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error if the output patch vertex count specified in an
+output layout qualifier does not match the array size specified in any
+output variable declaration in the same shader.</p>
+</div>
+<div class="paragraph">
+<p>All tessellation control shader layout declarations in a program must
+specify the same output patch vertex count.
+There must be at least one layout qualifier specifying an output patch
+vertex count in any program containing tessellation control shaders;
+however, such a declaration is not required in all tessellation control
+shaders.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-outputs">Geometry Outputs</h5>
+<div class="paragraph">
+<p>Geometry shaders can have three additional types of output layout
+identifiers: an output <em>primitive type</em>, a maximum output <em>vertex count</em>,
+and per-output <em>stream</em> numbers.
+The primitive type and vertex count identifiers are allowed only on the
+interface qualifier <strong>out</strong>, not on an output block, block member, or variable
+declaration.
+The stream identifier is allowed on the interface qualifier <strong>out</strong>, on output
+blocks, and on variable declarations.</p>
+</div>
+<div class="paragraph">
+<p>The layout qualifier identifiers for geometry shader outputs are</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>points</strong><br>
+<strong>line_strip</strong><br>
+<strong>triangle_strip</strong><br>
+<strong>max_vertices</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>stream</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The primitive type identifiers <strong>points</strong>, <strong>line_strip</strong>, and <strong>triangle_strip</strong>
+are used to specify the type of output primitive produced by the geometry
+shader, and only one of these is accepted.
+At least one geometry shader (compilation unit) in a program must declare an
+output primitive type, and all geometry shader output primitive type
+declarations in a program must declare the same primitive type.
+It is not required that all geometry shaders in a program declare an output
+primitive type.</p>
+</div>
+<div class="paragraph">
+<p>The vertex count identifier <strong>max_vertices</strong> is used to specify the maximum
+number of vertices the shader will ever emit in a single invocation.
+At least one geometry shader (compilation unit) in a program must declare a
+maximum output vertex count, and all geometry shader output vertex count
+declarations in a program must declare the same count.
+It is not required that all geometry shaders in a program declare a count.</p>
+</div>
+<div class="paragraph">
+<p>In this example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(triangle_strip, max_vertices = <span class="integer">60</span>) out; <span class="comment">// order does not matter</span>
+layout(max_vertices = <span class="integer">60</span>) out;  <span class="comment">// redeclaration okay</span>
+layout(triangle_strip) out;     <span class="comment">// redeclaration okay</span>
+layout(points) out;             <span class="comment">// error, contradicts triangle_strip</span>
+layout(max_vertices = <span class="integer">30</span>) out;  <span class="comment">// error, contradicts 60</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>all outputs from the geometry shader are triangles and at most 60 vertices
+will be emitted by the shader.
+It is an error for the maximum number of vertices to be greater than
+<em>gl_MaxGeometryOutputVertices</em>.</p>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>stream</strong> is used to specify that a geometry shader output
+variable or block is associated with a particular vertex stream (numbered
+beginning with zero).
+A default stream number may be declared at global scope by qualifying
+interface qualifier <strong>out</strong> as in this example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(stream = <span class="integer">1</span>) out;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The stream number specified in such a declaration replaces any previous
+default and applies to all subsequent block and variable declarations until
+a new default is established.
+The initial default stream number is zero.</p>
+</div>
+<div class="paragraph">
+<p>Each output block or non-block output variable is associated with a vertex
+stream.
+If the block or variable is declared with the stream identifier, it is
+associated with the specified stream; otherwise, it is associated with the
+current default stream.
+A block member may be declared with a stream identifier, but the specified
+stream must match the stream associated with the containing block.
+One example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(stream=<span class="integer">1</span>) out;           <span class="comment">// default is now stream 1</span>
+out vec4 var1;                  <span class="comment">// var1 gets default stream (1)</span>
+layout(stream=<span class="integer">2</span>) out Block1 {   <span class="comment">// &quot;Block1&quot; belongs to stream 2</span>
+    layout(stream=<span class="integer">2</span>) vec4 var2; <span class="comment">// redundant block member stream decl</span>
+    layout(stream=<span class="integer">3</span>) vec2 var3; <span class="comment">// ILLEGAL (must match block stream)</span>
+    vec3 var4;                  <span class="comment">// belongs to stream 2</span>
+};
+layout(stream=<span class="integer">0</span>) out;           <span class="comment">// default is now stream 0</span>
+out vec4 var5;                  <span class="comment">// var5 gets default stream (0)</span>
+out Block2 {                    <span class="comment">// &quot;Block2&quot; gets default stream (0)</span>
+    vec4 var6;
+};
+layout(stream=<span class="integer">3</span>) out vec4 var7; <span class="comment">// var7 belongs to stream 3</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Each vertex emitted by the geometry shader is assigned to a specific stream,
+and the attributes of the emitted vertex are taken from the set of output
+blocks and variables assigned to the targeted stream.
+After each vertex is emitted, the values of all output variables become
+undefined.
+Additionally, the output variables associated with each vertex stream may
+share storage.
+Writing to an output variable associated with one stream may overwrite
+output variables associated with any other stream.
+When emitting each vertex, a geometry shader should write to all outputs
+associated with the stream to which the vertex will be emitted and to no
+outputs associated with any other stream.</p>
+</div>
+<div class="paragraph">
+<p>If a geometry shader output block or variable is declared more than once,
+all such declarations must associate the variable with the same vertex
+stream.
+If any stream declaration specifies a non-existent stream number, the shader
+will fail to compile.</p>
+</div>
+<div class="paragraph">
+<p>Built-in geometry shader outputs are always associated with vertex stream
+zero.</p>
+</div>
+<div class="paragraph">
+<p>All geometry shader output layout declarations in a program must declare the
+same layout and same value for <strong>max_vertices</strong>.
+If geometry shaders are in a program, there must be at least one geometry
+output layout declaration somewhere in that
+program, but not all geometry
+shaders (compilation units) are required to declare it.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="fragment-outputs">Fragment Outputs</h5>
+<div class="paragraph">
+<p>The built-in fragment shader variable <em>gl_FragDepth</em> may be redeclared using
+one of the following layout qualifiers.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>depth_any</strong><br>
+<strong>depth_greater</strong><br>
+<strong>depth_less</strong><br>
+<strong>depth_unchanged</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The layout qualifier for <em>gl_FragDepth</em> constrains intentions of the final
+value of <em>gl_FragDepth</em> written by any shader invocation.
+GL implementations are allowed to perform optimizations assuming that the
+depth test fails (or passes) for a given fragment if all values of
+<em>gl_FragDepth</em> consistent with the layout qualifier would fail (or pass).
+This potentially includes skipping shader execution if the fragment is
+discarded because it is occluded and the shader has no side effects.
+If the final value of <em>gl_FragDepth</em> is inconsistent with its layout
+qualifier, the result of the depth test for the corresponding fragment is
+undefined.
+However, no error will be generated in this case.
+If the depth test passes and depth writes are enabled, the value written to
+the depth buffer is always the value of <em>gl_FragDepth</em>, whether or not it is
+consistent with the layout qualifier.</p>
+</div>
+<div class="paragraph">
+<p>By default, <em>gl_FragDepth</em> is qualified as <em>depth_any</em>.
+When the layout qualifier for <em>gl_FragDepth</em> is <em>depth_any</em>, the shader
+compiler will note any assignment to <em>gl_FragDepth</em> modifying it in an
+unknown way, and depth testing will always be performed after the shader has
+executed.
+When the layout qualifier is <em>depth_greater</em>, the GL can assume that the
+final value of <em>gl_FragDepth</em> is greater than or equal to the fragment&#8217;s
+interpolated depth value, as given by the <em>z</em> component of <em>gl_FragCoord</em>.
+When the layout qualifier is <em>depth_less</em>, the GL can assume that any
+modification of <em>gl_FragDepth</em> will only decrease its value.
+When the layout qualifier is <em>depth_unchanged</em>, the shader compiler will
+honor any modification to <em>gl_FragDepth</em>, but the rest of the GL can assume
+that <em>gl_FragDepth</em> is not assigned a new value.</p>
+</div>
+<div class="paragraph">
+<p>Redeclarations of <em>gl_FragDepth</em> are performed as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// redeclaration that changes nothing is allowed +</span>
+out <span class="predefined-type">float</span> gl_FragDepth;
+
+<span class="comment">// assume it may be modified in any way</span>
+layout(depth_any) out <span class="predefined-type">float</span> gl_FragDepth;
+
+<span class="comment">// assume it may be modified such that its value will only increase</span>
+layout(depth_greater) out <span class="predefined-type">float</span> gl_FragDepth;
+
+<span class="comment">// assume it may be modified such that its value will only decrease</span>
+layout(depth_less) out <span class="predefined-type">float</span> gl_FragDepth;
+
+<span class="comment">// assume it will not be modified</span>
+layout(depth_unchanged) out <span class="predefined-type">float</span> gl_FragDepth;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If <em>gl_FragDepth</em> is redeclared in any fragment shader in a program, it must
+be redeclared in all fragment shaders in that program that have static
+assignments to <em>gl_FragDepth</em>.
+All redeclarations of <em>gl_FragDepth</em> in all fragment shaders in a single
+program must have the same set of qualifiers.
+Within any shader, the first redeclarations of <em>gl_FragDepth</em> must appear
+before any use of <em>gl_FragDepth</em>.
+The built-in <em>gl_FragDepth</em> is only predeclared in fragment shaders, so
+redeclaring it in any other shader language results in a compile-time error.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-variable-layout-qualifiers">4.4.3. Uniform Variable Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers can be used for uniform variables and subroutine uniforms.
+The layout qualifier identifiers for uniform variables and subroutine
+uniforms are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>location</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The location identifier can be used with default-block uniform variables and
+subroutine uniforms.
+The location specifies the location by which the OpenGL API can reference
+the uniform and update its value.
+Individual elements of a uniform array are assigned consecutive locations
+with the first element taking location <strong>location</strong>.
+No two default-block uniform variables in the program can have the same
+location, even if they are unused, otherwise a compile-time or link-time
+error will be generated.
+No two subroutine uniform variables can have the same location in the same
+shader stage, otherwise a compile-time or link-time error will be generated.
+Valid locations for default-block uniform variable locations are in the
+range of 0 to the implementation-defined maximum number of uniform locations
+minus one.
+Valid locations for subroutine uniforms are in the range of 0 to the
+implementation-defined per-stage maximum number of subroutine uniform
+locations minus one.</p>
+</div>
+<div class="paragraph">
+<p>Locations can be assigned to default-block uniform arrays and structures.
+The first inner-most scalar, vector or matrix member or element takes the
+specified <strong>location</strong> and the compiler assigns the next inner-most member or
+element the next incremental location value.
+Each subsequent inner-most member or element gets incremental locations for
+the entire structure or array.
+This rule applies to nested structures and arrays and gives each inner-most
+scalar, vector, or matrix member a unique location.
+For arrays without an explicit size, the size is calculated based on its
+static usage.
+When the linker generates locations for uniforms without an explicit
+location, it assumes for all uniforms with an explicit location all their
+array elements and structure members are used and the linker will not
+generate a conflicting location, even if that element or member is deemed
+unused.</p>
+</div>
+<div class="paragraph">
+<p>When generating SPIR-V for OpenGL, it is a compile-time error to not
+include a location for individual (default block) non-opaque uniform
+variables.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="subroutine-function-layout-qualifiers">4.4.4. Subroutine Function Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers can be used for subroutine functions.
+The layout qualifier identifiers for subroutine functions are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>index</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Each subroutine with an index qualifier in the shader must be given a unique
+index, otherwise a compile- or link-time error will be generated.
+The indices must be in the range of 0 to the implementation defined maximum
+number of subroutines minus one.
+It is recommended, but not required, that the shader assigns a range of
+tightly packed <em>index</em> values starting from zero so that the OpenGL
+subroutine function enumeration API returns a non-empty name for all active
+indices.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="uniform-and-shader-storage-block-layout-qualifiers">4.4.5. Uniform and Shader Storage Block Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Layout qualifiers can be used for uniform and shader storage blocks, but not
+for non-block uniform declarations.
+The layout qualifier identifiers (and <strong>shared</strong> keyword) for uniform and
+shader storage blocks are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>shared</strong><br>
+<strong>packed</strong><br>
+<strong>std140</strong><br>
+<strong>std430</strong><br>
+<strong>row_major</strong><br>
+<strong>column_major</strong><br>
+<strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>offset</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>align</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>None of these have any semantic effect at all on the usage of the variables
+being declared; they only describe how data is laid out in memory.
+For example, matrix semantics are always column-based, as described in the
+rest of this specification, no matter what layout qualifiers are being used.</p>
+</div>
+<div class="paragraph">
+<p>Uniform and shader storage block layout qualifiers can be declared for
+global scope, on a single uniform or shader storage block, or on a single
+block member declaration.</p>
+</div>
+<div class="paragraph">
+<p>Default layouts are established at global scope for uniform blocks as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) uniform;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and for shader storage blocks as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(layout-qualifier-id-list) buffer;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When this is done, the previous default qualification is first inherited and
+then overridden as per the override rules listed below for each qualifier
+listed in the declaration.
+The result becomes the new default qualification scoped to subsequent
+uniform or shader storage block definitions.</p>
+</div>
+<div class="paragraph">
+<p>The initial state of compilation
+when generating SPIR-V
+is as if the following were declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(std140, column_major) uniform;
+layout(std430, column_major) buffer;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The initial state of compilation when not generating SPIR-V is as if the
+following were declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(shared, column_major) uniform;
+layout(shared, column_major) buffer;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Uniform and shader storage blocks can be declared with optional layout
+qualifiers, and so can their individual member declarations.
+Such block layout qualification is scoped only to the content of the block.
+As with global layout declarations, block layout qualification first
+inherits from the current default qualification and then overrides it.
+Similarly, individual member layout qualification is scoped just to the
+member declaration, and inherits from and overrides the block&#8217;s
+qualification.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>shared</strong> qualifier overrides only the <strong>std140</strong>, <strong>std430</strong>, and <strong>packed</strong>
+qualifiers; other qualifiers are inherited.
+The compiler/linker will ensure that multiple programs and programmable
+stages containing this definition will share the same memory layout for this
+block, as long as all arrays are declared with explicit sizes and all
+matrices have matching <strong>row_major</strong> and/or <strong>column_major</strong> qualifications
+(which may come from a declaration outside the block definition).
+This allows use of the same buffer to back the same block definition across
+different programs.
+It is a compile-time error to use the <strong>shared</strong> qualifier when generating
+SPIR-V.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>packed</strong> qualifier overrides only <strong>std140</strong>, <strong>std430</strong>, and <strong>shared</strong>;
+other qualifiers are inherited.
+When <strong>packed</strong> is used, no shareable layout is guaranteed.
+The compiler and linker can optimize memory use based on what variables
+actively get used and on other criteria.
+Offsets must be queried, as there is no other way of guaranteeing where (and
+which) variables reside within the block.</p>
+</div>
+<div class="paragraph">
+<p>It is a link-time error to access the same packed uniform or shader storage
+block in multiple stages within a program.
+Attempts to access the same packed uniform or shader storage block across
+programs can result in conflicting member offsets and in undefined values
+being read.
+However, implementations may aid application management of packed blocks by
+using canonical layouts for packed blocks.
+It is a compile-time error to use the <strong>packed</strong> qualifier when generating
+SPIR-V.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>std140</strong> and <strong>std430</strong> qualifiers override only the <strong>packed</strong>, <strong>shared</strong>,
+<strong>std140</strong>, and <strong>std430</strong> qualifiers; other qualifiers are inherited.
+The <strong>std430</strong> qualifier is supported only for shader storage blocks; a shader
+using the <strong>std430</strong> qualifier on a uniform block will fail to compile.</p>
+</div>
+<div class="paragraph">
+<p>The layout is explicitly determined by this, as described in section 7.6.2.2
+&#8220;Standard Uniform Block Layout&#8221; of the <a href="#references">OpenGL Specification</a>.
+Hence, as in <strong>shared</strong> above, the resulting layout is shareable across
+programs.</p>
+</div>
+<div class="paragraph">
+<p>Layout qualifiers on member declarations cannot use the <strong>shared</strong>, <strong>packed</strong>,
+<strong>std140</strong>, or <strong>std430</strong> qualifiers.
+These can only be used at global scope (without an object) or on a block
+declaration, or a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>row_major</strong> and <strong>column_major</strong> qualifiers only affect the layout of
+matrices, including all matrices contained in structures and arrays they are
+applied to, to all depths of nesting.
+These qualifiers can be applied to other types, but will have no effect.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>row_major</strong> qualifier overrides only the <strong>column_major</strong> qualifier; other
+qualifiers are inherited.
+Elements within a matrix row will be contiguous in memory.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>column_major</strong> qualifier overrides only the <strong>row_major</strong> qualifier; other
+qualifiers are inherited.
+Elements within a matrix column will be contiguous in memory.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>binding</strong> qualifier specifies the uniform buffer binding point
+corresponding to the uniform or shader storage block, which will be used to
+obtain the values of the member variables of the block.
+It is a compile-time error to specify the <strong>binding</strong> qualifier for the global
+scope or for block member declarations.
+Any uniform or shader storage block declared without a <strong>binding</strong> qualifier
+is initially assigned to block binding point zero.
+After a program is linked, the binding points used for uniform
+and shader storage blocks
+declared with or without a <strong>binding</strong> qualifier can be updated
+by the OpenGL API.</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> qualifier is used with a uniform block or shader storage
+block instanced as an array, the first element of the array takes the
+specified block binding and each subsequent element takes the next
+consecutive binding point.
+For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a
+binding point, and they are ordered per the array of array ordering
+described in &#8220;<a href="#arrays.">Arrays.</a>&#8221;</p>
+</div>
+<div class="paragraph">
+<p>If the binding point for any uniform or shader storage block instance is
+less than zero, or greater than or equal to the corresponding
+implementation-dependent maximum number of buffer bindings, a compile-time
+error will occur.
+When the <strong>binding</strong> qualifier is used with a uniform or shader storage block
+instanced as an array of size <em>N</em>, all elements of the array from <strong>binding</strong>
+through <em>binding + N - 1</em> must be within this range.
+It is a compile-time or link-time error to use the same binding number for
+more than one uniform block or for more than one buffer block.</p>
+</div>
+<div class="paragraph">
+<p>When multiple arguments are listed in a <strong>layout</strong> declaration, the effect
+will be the same as if they were declared one at a time, in order from left
+to right, each in turn inheriting from and overriding the result from the
+previous qualification.</p>
+</div>
+<div class="paragraph">
+<p>For example</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(row_major, column_major)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>results in the qualification being <strong>column_major</strong>.
+Other examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(shared, row_major) uniform; <span class="comment">// default is now shared and row_major</span>
+
+layout(std140) uniform Transform { <span class="comment">// layout of this block is std140</span>
+    mat4 M1;                       <span class="comment">// row major</span>
+    layout(column_major) mat4 M2;  <span class="comment">// column major</span>
+    mat3 N1;                       <span class="comment">// row major</span>
+};
+
+uniform T2 {                       <span class="comment">// layout of this block is shared</span>
+    ...
+};
+
+layout(column_major) uniform T3 {  <span class="comment">// shared and column major</span>
+    mat4 M3;                       <span class="comment">// column major</span>
+    layout(row_major) mat4 m4;     <span class="comment">// row major</span>
+    mat3 N2;                       <span class="comment">// column major</span>
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>offset</strong> qualifier can only be used on block members of blocks declared
+with <strong>std140</strong> or <strong>std430</strong> layouts.
+The <strong>offset</strong> qualifier forces the qualified member to start at or after the
+specified <em>layout-qualifier-value</em>, which will be its byte offset from
+the beginning of the buffer.
+It is a compile-time error to have any offset, explicit or assigned, that
+lies within another member of the block.
+When not generating SPIR-V, it is a compile-time error to specify an offset
+that is smaller than the offset of the previous member in the block.
+Two blocks linked together in the same program with the same block name must
+have the exact same set of members qualified with <strong>offset</strong> and their
+<em>layout-qualifier-value</em> values must be the same, or a link-time error
+results.
+The specified offset must be a multiple of the base alignment of the type of
+the block member it qualifies, or a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>align</strong> qualifier can only be used on blocks or block members, and only
+for blocks declared with <strong>std140</strong> or <strong>std430</strong> layouts.
+The <strong>align</strong> qualifier makes the start of each block member have a minimum
+byte alignment.
+It does not affect the internal layout within each member, which will still
+follow the <strong>std140</strong> or <strong>std430</strong> rules.
+The specified alignment must be greater than 0 and a power of 2, or a
+compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>The <em>actual alignment</em> of a member will be the greater of the specified
+<strong>align</strong> alignment and the standard (e.g. <strong>std140</strong>) base alignment for the
+member&#8217;s type.
+The <em>actual offset</em> of a member is computed as follows: If <strong>offset</strong> was
+declared, start with that offset, otherwise start with the next available
+offset.
+If the resulting offset is not a multiple of the <em>actual alignment</em>,
+increase it to the first offset that is a multiple of the <em>actual
+alignment</em>.
+This results in the <em>actual offset</em> the member will have.</p>
+</div>
+<div class="paragraph">
+<p>When <strong>align</strong> is applied to an array, it affects only the start of the array,
+not the array&#8217;s internal stride.
+Both an <strong>offset</strong> and an <strong>align</strong> qualifier can be specified on a declaration.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>align</strong> qualifier, when used on a block, has the same effect as
+qualifying each member with the same <strong>align</strong> value as declared on the block,
+and gets the same compile-time results and errors as if this had been done.
+As described in general earlier, an individual member can specify its own
+<strong>align</strong>, which overrides the block-level <strong>align</strong>, but just for that member.</p>
+</div>
+<div class="paragraph">
+<p>Examples:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(std140) uniform block {
+ vec4 a;                         <span class="comment">// a takes offsets 0-15</span>
+ layout(offset = <span class="integer">32</span>) vec3 b;     <span class="comment">// b takes offsets 32-43</span>
+ layout(offset = <span class="integer">40</span>) vec2 c;     <span class="comment">// ERROR, lies within previous member</span>
+ layout(offset = <span class="integer">48</span>) vec2 d;     <span class="comment">// d takes offsets 48-55</span>
+ layout(align = <span class="integer">16</span>) <span class="predefined-type">float</span> e;     <span class="comment">// e takes offsets 64-67</span>
+ layout(align = <span class="integer">2</span>) <span class="predefined-type">double</span> f;     <span class="comment">// f takes offsets 72-79</span>
+ layout(align = <span class="integer">6</span>) <span class="predefined-type">double</span> g;     <span class="comment">// ERROR, 6 is not a power of 2</span>
+ layout(offset = <span class="integer">80</span>) <span class="predefined-type">float</span> h;    <span class="comment">// h takes offsets 80-83</span>
+ layout(align = <span class="integer">64</span>) dvec3 i;     <span class="comment">// i takes offsets 128-151</span>
+ layout(offset = <span class="integer">164</span>, align = <span class="integer">8</span>)
+ <span class="predefined-type">float</span> j;                        <span class="comment">// j takes offsets 168-171</span>
+};</code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="opaque-uniform-layout-qualifiers">4.4.6. Opaque Uniform Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Uniform layout qualifiers can be used to bind opaque uniform variables to
+specific buffers or units.
+Samplers can be bound to texture image units, images can be bound to image
+units, and atomic counters can be bound to buffers.</p>
+</div>
+<div class="paragraph">
+<p>Sampler, image and atomic counter types take the uniform layout qualifier
+identifier for binding:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The identifier <strong>binding</strong> specifies which unit will be bound.
+Any uniform sampler or image
+variable declared without a binding qualifier
+is initially bound to unit zero.
+After a program is linked, the unit referenced by a sampler
+or image
+uniform variable declared with or without a <strong>binding</strong> qualifier can be
+updated by the OpenGL API.</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> qualifier is used with an array, the first element of the
+array takes the specified unit and each subsequent element takes the next
+consecutive unit.
+For an array of arrays, each element (e.g. 6 elements for a[2][3]) gets a
+binding point, and they are ordered per the array of array ordering
+described in &#8220;<a href="#arrays.">Arrays.</a>&#8221;</p>
+</div>
+<div class="paragraph">
+<p>If the <strong>binding</strong> is less than zero, or greater than or equal to the
+implementation-dependent maximum supported number of units, a compile-time
+error will occur.
+When the <strong>binding</strong> qualifier is used with an array of size <em>N</em>, all elements
+of the array from <strong>binding</strong> through <em>binding + N - 1</em> must be within this
+range.
+It is a compile-time or link-time error to use the same <strong>binding</strong> number for
+more than one atomic counter, unless the <em>offset</em> for the atomic counters
+sharing the same binding are all different.</p>
+</div>
+<div class="paragraph">
+<p>A link-time error will result if two shaders in a program specify different
+<em>layout-qualifier-value</em> bindings for the same opaque-uniform name.
+However, it is not an error to specify a binding on some but not all
+declarations for the same name, as shown in the examples below.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// in one shader...</span>
+layout(binding=<span class="integer">3</span>) uniform sampler2D s; <span class="comment">// s bound to unit 3</span>
+
+<span class="comment">// in another shader...</span>
+uniform sampler2D s;                   <span class="comment">// okay, s still bound at 3</span>
+
+<span class="comment">// in another shader...</span>
+layout(binding=<span class="integer">4</span>) uniform sampler2D s; <span class="comment">// ERROR: contradictory bindings</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="atomic-counter-layout-qualifiers">4.4.7. Atomic Counter Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Atomic counter layout qualifiers can be used on atomic counter declarations.
+The atomic counter qualifiers are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em><br>
+<strong>offset</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint a;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the opaque handle to the atomic counter <em>a</em> will be
+bound to atomic counter buffer binding point 2 at an offset of 4 basic
+machine units into that buffer.
+The default <em>offset</em> for binding point 2 will be post incremented by 4 (the
+size of an atomic counter).</p>
+</div>
+<div class="paragraph">
+<p>A subsequent atomic counter declaration will inherit the previous (post
+incremented) offset.
+For example, a subsequent declaration of</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will establish that the atomic counter <em>bar</em> has a binding to buffer binding
+point 2 at an offset of 8 basic machine units into that buffer.
+The offset for binding point 2 will again be post-incremented by 4 (the size
+of an atomic counter).</p>
+</div>
+<div class="paragraph">
+<p>When multiple variables are listed in a layout declaration, the effect will
+be the same as if they were declared one at a time, in order from left to
+right.</p>
+</div>
+<div class="paragraph">
+<p>Binding points are not inherited, only offsets.
+Each binding point tracks its own current default <em>offset</em> for inheritance
+of subsequent variables using the same <strong>binding</strong>.
+The initial state of compilation is that all <strong>binding</strong> points have an
+<em>offset</em> of 0.
+The <em>offset</em> can be set per binding point at global scope (without declaring
+a variable).
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>, offset = <span class="integer">4</span>) uniform atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Establishes that the next <strong>atomic_uint</strong> declaration for binding point 2 will
+inherit <em>offset</em> 4 (but does not establish a default <strong>binding</strong>):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding = <span class="integer">2</span>) uniform atomic_uint bar; <span class="comment">// offset is 4</span>
+layout(offset = <span class="integer">8</span>) uniform atomic_uint bar;  <span class="comment">// error, no default binding</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Atomic counters may share the same binding point, but if a binding is
+shared, their offsets must be either explicitly or implicitly (from
+inheritance) unique and non overlapping.</p>
+</div>
+<div class="paragraph">
+<p>Example valid uniform declarations, assuming top of shader:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(binding=<span class="integer">3</span>, offset=<span class="integer">4</span>) uniform atomic_uint a; <span class="comment">// offset = 4</span>
+layout(binding=<span class="integer">2</span>) uniform atomic_uint b;           <span class="comment">// offset = 0</span>
+layout(binding=<span class="integer">3</span>) uniform atomic_uint c;           <span class="comment">// offset = 8</span>
+layout(binding=<span class="integer">2</span>) uniform atomic_uint d;           <span class="comment">// offset = 4</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Example of an invalid uniform declaration:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(offset=<span class="integer">4</span>) ...               <span class="comment">// error, must include binding</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... a; <span class="comment">// okay</span>
+layout(binding=<span class="integer">2</span>, offset=<span class="integer">0</span>) ... b; <span class="comment">// okay</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">0</span>) ... c; <span class="comment">// error, offsets must not be shared</span>
+                                   <span class="comment">// between a and c</span>
+layout(binding=<span class="integer">1</span>, offset=<span class="integer">2</span>) ... d; <span class="comment">// error, overlaps offset 0 of a</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to bind an atomic counter with a binding value
+greater than or equal to <em>gl_MaxAtomicCounterBindings</em>.
+It is a compile-time error to declare an unsized array of <strong>atomic_uint</strong>.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="format-layout-qualifiers">4.4.8. Format Layout Qualifiers</h4>
+<div class="paragraph">
+<p>Format layout qualifiers can be used on image variable declarations (those
+declared with a basic type having &#8220;<strong>image</strong>&#8221; in its keyword).
+The format layout qualifier identifiers for image variable declarations are:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>layout-qualifier-id</em> : </dt>
+<dd>
+<p><em>float-image-format-qualifier</em><br>
+<em>int-image-format-qualifier</em><br>
+<em>uint-image-format-qualifier</em><br>
+<strong>binding</strong> <strong>=</strong> <em>layout-qualifier-value</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>float-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32f</strong><br>
+<strong>rgba16f</strong><br>
+<strong>rg32f</strong><br>
+<strong>rg16f</strong><br>
+<strong>r11f_g11f_b10f</strong><br>
+<strong>r32f</strong><br>
+<strong>r16f</strong><br>
+<strong>rgba16</strong><br>
+<strong>rgb10_a2</strong><br>
+<strong>rgba8</strong><br>
+<strong>rg16</strong><br>
+<strong>rg8</strong><br>
+<strong>r16</strong><br>
+<strong>r8</strong><br>
+<strong>rgba16_snorm</strong><br>
+<strong>rgba8_snorm</strong><br>
+<strong>rg16_snorm</strong><br>
+<strong>rg8_snorm</strong><br>
+<strong>r16_snorm</strong><br>
+<strong>r8_snorm</strong></p>
+</dd>
+<dt class="hdlist1"><em>int-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32i</strong><br>
+<strong>rgba16i</strong><br>
+<strong>rgba8i</strong><br>
+<strong>rg32i</strong><br>
+<strong>rg16i</strong><br>
+<strong>rg8i</strong><br>
+<strong>r32i</strong><br>
+<strong>r16i</strong><br>
+<strong>r8i</strong></p>
+</dd>
+<dt class="hdlist1"><em>uint-image-format-qualifier</em> : </dt>
+<dd>
+<p><strong>rgba32ui</strong><br>
+<strong>rgba16ui</strong><br>
+<strong>rgb10_a2ui</strong><br>
+<strong>rgba8ui</strong><br>
+<strong>rg32ui</strong><br>
+<strong>rg16ui</strong><br>
+<strong>rg8ui</strong><br>
+<strong>r32ui</strong><br>
+<strong>r16ui</strong><br>
+<strong>r8ui</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>A format layout qualifier specifies the image format associated with a
+declared image variable.
+Only one format qualifier may be specified for any image variable
+declaration.
+For image variables with floating-point component types (keywords starting
+with &#8220;<strong>image</strong>&#8221;), signed integer component types (keywords starting with
+&#8220;<strong>iimage</strong>&#8221;), or unsigned integer component types (keywords starting with
+&#8220;<strong>uimage</strong>&#8221;), the format qualifier used must match the
+<em>float-image-format-qualifier</em>, <em>int-image-format-qualifier</em>, or
+<em>uint-image-format-qualifier</em> grammar rules, respectively.
+It is a compile-time error to declare an image variable where the format
+qualifier does not match the image variable type.</p>
+</div>
+<div class="paragraph">
+<p>Any image variable used for image loads or atomic operations must specify a
+format layout qualifier; it is a compile-time error to pass an image uniform
+variable or function parameter declared without a format layout qualifier to
+an image load or atomic function.</p>
+</div>
+<div class="paragraph">
+<p>Uniforms not qualified with <strong>writeonly</strong> must have a format layout qualifier.
+Note that an image variable passed to a function for read access cannot be
+declared as <strong>writeonly</strong> and hence must have been declared with a format
+layout qualifier.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>binding</strong> qualifier was described in
+&#8220;<a href="#opaque-uniform-layout-qualifiers">Opaque Uniform Layout Qualifiers</a>&#8221;.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="interpolation-qualifiers">4.5. Interpolation Qualifiers</h3>
+<div class="paragraph">
+<p>Inputs and outputs that could be interpolated can be further qualified by at
+most one of the following interpolation qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>smooth</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">perspective correct interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>flat</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">no interpolation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>noperspective</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">linear interpolation</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The presence of and type of interpolation is controlled by the above
+interpolation qualifiers as well as the auxiliary storage qualifiers
+<strong>centroid</strong> and <strong>sample</strong>.
+When no interpolation qualifier is present, smooth interpolation is used.
+It is a compile-time error to use more than one interpolation qualifier.
+The auxiliary storage qualifier <strong>patch</strong> is not used for interpolation; it is
+a compile-time error to use interpolation qualifiers with <strong>patch</strong>.</p>
+</div>
+<div class="paragraph">
+<p>A variable qualified as <strong>flat</strong> will not be interpolated.
+Instead, it will have the same value for every fragment within a primitive.
+This value will come from a single provoking vertex, as described by the
+<a href="#references">OpenGL Specification</a>.
+A variable qualified as <strong>flat</strong> may also be qualified as <strong>centroid</strong> or
+<strong>sample</strong>, which will mean the same thing as qualifying it only as <strong>flat</strong>.</p>
+</div>
+<div class="paragraph">
+<p>A variable qualified as <strong>smooth</strong> will be interpolated in a
+perspective-correct manner over the primitive being rendered.
+Interpolation in a perspective correct manner is specified in equation 14.7
+of the <a href="#references">OpenGL Specification</a>, section 14.5 &#8220;Line Segments&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>A variable qualified as <strong>noperspective</strong> must be interpolated linearly in
+screen space, as described in equation 3.7 of the <a href="#references">OpenGL Specification</a>,
+section 3.5 &#8220;Line Segments&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>When multisample rasterization is disabled, or for fragment shader input
+variables qualified with neither <strong>centroid</strong> nor <strong>sample</strong>, the value of the
+assigned variable may be interpolated anywhere within the pixel and a single
+value may be assigned to each sample within the pixel, to the extent
+permitted by the <a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>When multisample rasterization is enabled, <strong>centroid</strong> and <strong>sample</strong> may be
+used to control the location and frequency of the sampling of the qualified
+fragment shader input.
+If a fragment shader input is qualified with <strong>centroid</strong>, a single value may
+be assigned to that variable for all samples in the pixel, but that value
+must be interpolated at a location that lies in both the pixel and in the
+primitive being rendered, including any of the pixel&#8217;s samples covered by
+the primitive.
+Because the location at which the variable is interpolated may be different
+in neighboring pixels, and derivatives may be computed by computing
+differences between neighboring pixels, derivatives of centroid-sampled
+inputs may be less accurate than those for non-centroid interpolated
+variables.
+If a fragment shader input is qualified with <strong>sample</strong>, a separate value must
+be assigned to that variable for each covered sample in the pixel, and that
+value must be sampled at the location of the individual sample.</p>
+</div>
+<div class="paragraph">
+<p>It is a link-time error if, within the same stage, the interpolation
+qualifiers of variables of the same name do not match.</p>
+</div>
+<div class="sect3">
+<h4 id="redeclaring-built-in-interpolation-variables-in-the-compatibility-profile">4.5.1. Redeclaring Built-In Interpolation Variables in the Compatibility Profile</h4>
+<div class="paragraph">
+<p>The following predeclared variables can be redeclared with an interpolation
+qualifier when using the compatibility profile:</p>
+</div>
+<div class="paragraph">
+<p>Vertex, tessellation control, tessellation evaluation, and geometry
+languages:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_FrontColor
+gl_BackColor
+gl_FrontSecondaryColor
+gl_BackSecondaryColor</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Fragment language:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_Color
+gl_SecondaryColor</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 gl_Color;            <span class="comment">// predeclared by the fragment language</span>
+flat in vec4 gl_Color;       <span class="comment">// redeclared by user to be flat</span>
+flat in vec4 gl_FrontColor;  <span class="comment">// input to geometry shader, no &quot;gl_in[]&quot;</span>
+flat out vec4 gl_FrontColor; <span class="comment">// output from geometry shader</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Ideally, these are redeclared as part of the redeclaration of an interface
+block, as described in
+&#8220;<a href="#compatibility-profile-built-in-language-variables">Compatibility Profile
+Built-In Language Variables</a>&#8221;.
+However, for the above purpose, they can be redeclared as individual
+variables at global scope, outside an interface block.
+Such redeclarations also allow adding the transform-feedback qualifiers
+<strong>xfb_buffer</strong>, <strong>xfb_stride</strong>, and <strong>xfb_offset</strong> to output variables.
+(Using <strong>xfb_buffer</strong> on a variable does not change the global default
+buffer.) A compile-time error will result if a shader has both an interface
+block redeclaration and a separate redeclaration of a member of that
+interface block outside the interface block redeclaration.</p>
+</div>
+<div class="paragraph">
+<p>If <em>gl_Color</em> is redeclared with an interpolation qualifier, then
+<em>gl_FrontColor</em> and <em>gl_BackColor</em> (if they are written to) must also be
+redeclared with the same interpolation qualifier, and vice versa.
+If <em>gl_SecondaryColor</em> is redeclared with an interpolation qualifier, then
+<em>gl_FrontSecondaryColor</em> and _gl_BackSecondaryColor _(if they are written
+to) must also be redeclared with the same interpolation qualifier, and vice
+versa.
+This qualifier matching on predeclared variables is only required for
+variables that are statically used within the shaders in a program.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="parameter-qualifiers">4.6. Parameter Qualifiers</h3>
+<div class="paragraph">
+<p>In addition to precision qualifiers and memory qualifiers, parameters can
+have these parameter qualifiers.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;none: default&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">same as <strong>in</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>const</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters that cannot be written to</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>in</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed into a function</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>out</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed back out of a function,
+                   but not initialized for use when passed in</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inout</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">for function parameters passed both into and out of a
+                   function</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Parameter qualifiers are discussed in more detail in
+&#8220;<a href="#function-calling-conventions">Function Calling Conventions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="precision-and-precision-qualifiers">4.7. Precision and Precision Qualifiers</h3>
+<div class="paragraph">
+<p>Precision qualifiers are added for code portability with OpenGL ES, not for
+functionality.
+They have the same syntax as in OpenGL ES, as described below, but they have
+no semantic meaning, which includes no effect on the precision used to store
+or operate on variables.</p>
+</div>
+<div class="paragraph">
+<p>If an extension adds in the same semantics and functionality in the OpenGL
+ES 2.0 specification for precision qualifiers, then the extension is allowed
+to reuse the keywords below for that purpose.</p>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if an output from one shader stage matches
+an input of the next stage, the precision qualifier need not match.</p>
+</div>
+<div class="sect3">
+<h4 id="range-and-precision">4.7.1. Range and Precision</h4>
+<div class="paragraph">
+<p>The precision of stored single- and double-precision floating-point
+variables is defined by the IEEE 754 standard for 32-bit and 64-bit
+floating-point numbers.
+This includes support for NaNs (Not a Number) and Infs (positive or negative
+infinities) and positive and negative zeros.</p>
+</div>
+<div class="paragraph">
+<p>The following rules apply to
+both single and double-precision
+operations:
+Signed infinities and zeros are generated as dictated by IEEE, but subject
+to the precisions allowed in the following table.
+Any subnormal (denormalized) value input into a shader or potentially
+generated by any operation in a shader can be flushed to 0.
+The rounding mode cannot be set and is undefined but must not affect the
+result by more than 1 ULP.
+NaNs are not required to be generated.
+Support for signaling NaNs is not required and exceptions are never raised.
+Operations including built-in functions that operate on a NaN are not
+required to return a NaN as the result.
+However if NaNs are generated, <strong>isnan</strong>() must return the correct value.</p>
+</div>
+<div class="paragraph">
+<p>Precisions are expressed in terms of maximum relative error in units of ULP
+(units in the last place), unless otherwise noted.</p>
+</div>
+<div class="paragraph">
+<p>For single precision operations, precisions are required as follows:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Operation</th>
+<th class="tableblock halign-left valign-top">Precision</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> + <em>b</em>, <em>a</em> - <em>b</em>, <em>a</em> * <em>b</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;, &lt;=, ==, &gt;, &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correct result.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> / <em>b</em>, 1.0 / <em>b</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2.5 ULP for <span class="eq">|b|</span> in the range <span class="eq">[2<sup>-126</sup>, 2<sup>126</sup>]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>a</em> * <em>b</em> + <em>c</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded single operation or
+                                    sequence of two correctly rounded operations.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>fma</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <em>a</em> * <em>b</em> + <em>c</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>pow</strong>(<em>x</em>, <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from <strong>exp2</strong>(<em>y</em> * <strong>log2</strong>(<em>x</em>)).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>exp</strong>(<em>x</em>), <strong>exp2</strong>(<em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><span class="eq">(3 + 2 · |x|)</span> ULP.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>log</strong>(), <strong>log2</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3 ULP outside the range <span class="eq">[0.5,2.0]</span>.<br>
+                                    Absolute error &lt; 2<sup>-21</sup> inside the range
+                                    <span class="eq">[0.5,2.0]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>sqrt</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inherited from 1.0 / <strong>inversesqrt</strong>().</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>inversesqrt</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2 ULP.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">implicit and explicit
+  conversions between types</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Correctly rounded.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Built-in functions defined in the specification with an equation built from
+the above operations inherit the above errors.
+These include, for example, the geometric functions, the common functions,
+and many of the matrix functions.
+Built-in functions not listed above and not defined as equations of the
+above have undefined precision.
+These include, for example, the trigonometric functions and determinant.</p>
+</div>
+<div class="paragraph">
+<p>The precision of double-precision operations is at least that of single
+precision.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="precision-qualifiers">4.7.2. Precision Qualifiers</h4>
+<div class="paragraph">
+<p>Any
+single-precision
+floating-point, integer, or opaque-type declaration can have the type
+preceded by one of these precision qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>highp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">None.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>mediump</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">None.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>lowp</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">None.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">lowp <span class="predefined-type">float</span> color;
+out mediump vec2 P;
+lowp ivec2 foo(lowp mat3);
+highp mat4 m;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Literal constants do not have precision qualifiers.
+Neither do Boolean variables.
+Neither do constructors.</p>
+</div>
+<div class="paragraph">
+<p>Precision qualifiers, as with other qualifiers, do not affect the basic type
+of the variable.
+In particular, there are no constructors for precision conversions;
+constructors only convert types.
+Similarly, precision qualifiers, as with other qualifiers, do not contribute
+to function overloading based on parameter types.
+As discussed in &#8220;<a href="#function-calling-conventions">Function Calling
+Conventions</a>&#8221;, function input and output is done through copies, and
+therefore qualifiers do not have to match.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="default-precision-qualifiers">4.7.3. Default Precision Qualifiers</h4>
+<div class="paragraph">
+<p>The precision statement</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision precision-qualifier type;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>can be used to establish a default precision qualifier.
+The <em>type</em> field can be either <strong>int</strong>, <strong>float</strong>, or any of the opaque types,
+and the <em>precision-qualifier</em> can be <strong>lowp</strong>, <strong>mediump</strong>, or <strong>highp</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Any other types or qualifiers will result in a compile-time error.
+If <em>type</em> is <strong>float</strong>, the directive applies to non-precision-qualified
+single-precision
+floating-point type (scalar, vector, and matrix) declarations.
+If <em>type</em> is <strong>int</strong>, the directive applies to all non-precision-qualified
+integer type (scalar, vector, signed, and unsigned) declarations.
+This includes global variable declarations, function return declarations,
+function parameter declarations, and local variable declarations.</p>
+</div>
+<div class="paragraph">
+<p>Non-precision qualified declarations will use the precision qualifier
+specified in the most recent <strong>precision</strong> statement that is still in scope.
+The <strong>precision</strong> statement has the same scoping rules as variable
+declarations.
+If it is declared inside a compound statement, its effect stops at the end
+of the inner-most statement it was declared in.
+Precision statements in nested scopes override precision statements in outer
+scopes.
+Multiple precision statements for the same basic type can appear inside the
+same scope, with later statements overriding earlier statements within that
+scope.</p>
+</div>
+<div class="paragraph">
+<p>All languages except for the fragment language have the following
+predeclared globally scoped default precision statements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision highp <span class="predefined-type">float</span>;
+precision highp <span class="predefined-type">int</span>;
+precision highp atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The fragment language has the following predeclared globally scoped default
+precision statements:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precision mediump <span class="predefined-type">int</span>;
+precision highp <span class="predefined-type">float</span>;
+precision highp atomic_uint;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There are no errors for omission of a precision qualifier; so the above is
+just for reference of what may happen in OpenGL ES versions of the shading
+languages.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="available-precision-qualifiers">4.7.4. Available Precision Qualifiers</h4>
+<div class="paragraph">
+<p>The built-in macro GL_FRAGMENT_PRECISION_HIGH is defined to one:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#define</span> GL_FRAGMENT_PRECISION_HIGH <span class="integer">1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This macro is available in all languages except compute.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="variance-and-the-invariant-qualifier">4.8. Variance and the Invariant Qualifier</h3>
+<div class="paragraph">
+<p>In this section, <em>variance</em> refers to the possibility of getting different
+values from the same expression in different programs.
+For example, consider the situation where two vertex shaders, in different
+programs, each set <em>gl_Position</em> with the same expression, and the input
+values into that expression are the same when both shaders run.
+It is possible, due to independent compilation of the two shaders, that the
+values assigned to <em>gl_Position</em> are not exactly the same when the two
+shaders run.
+In this example, this can cause problems with alignment of geometry in a
+multi-pass algorithm.</p>
+</div>
+<div class="paragraph">
+<p>In general, such variance between shaders is allowed.
+When such variance does not exist for a particular output variable, that
+variable is said to be <em>invariant</em>.</p>
+</div>
+<div class="sect3">
+<h4 id="the-invariant-qualifier">4.8.1. The Invariant Qualifier</h4>
+<div class="paragraph">
+<p>To ensure that a particular output variable is invariant, it is necessary to
+use the <strong>invariant</strong> qualifier.
+It can either be used to qualify a previously declared variable as being
+invariant:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant gl_Position; <span class="comment">// make existing gl_Position be invariant</span>
+out vec3 Color;
+invariant Color;       <span class="comment">// make existing Color be invariant</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>or as part of a declaration when a variable is declared:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant centroid out vec3 Color;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Only variables output from a shader can be candidates for invariance.
+This includes user-defined output variables and the built-in output
+variables.
+As only outputs can be declared as invariant, an output from one shader
+stage will still match an input of a subsequent stage without the input
+being declared as invariant.</p>
+</div>
+<div class="paragraph">
+<p>Input or output instance names on blocks are not used when redeclaring
+built-in variables.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>invariant</strong> keyword can be followed by a comma separated list of
+previously declared identifiers.
+All uses of <strong>invariant</strong> must be at global scope or on block
+members, and before any use of the variables being declared as invariant.</p>
+</div>
+<div class="paragraph">
+<p>To guarantee invariance of a particular output variable across two programs,
+the following must also be true:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The output variable is declared as invariant in both programs.</p>
+</li>
+<li>
+<p>The same values must be input to all shader input variables consumed by
+expressions and control flow contributing to the value assigned to the
+output variable.</p>
+</li>
+<li>
+<p>The texture formats, texel values, and texture filtering are set the
+same way for any texture function calls contributing to the value of the
+output variable.</p>
+</li>
+<li>
+<p>All input values are all operated on in the same way.
+    All operations in the consuming expressions and any intermediate
+    expressions must be the same, with the same order of operands and same
+    associativity, to give the same order of evaluation.
+    Intermediate variables and functions must be declared as the same type
+    with the same explicit or implicit precision
+qualifiers.
+    Any control flow affecting the output value must be the same, and any
+    expressions consumed to determine this control flow must also follow
+    these invariance rules.</p>
+</li>
+<li>
+<p>All the data flow and control flow leading to setting the invariant
+output variable reside in a single compilation unit.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Essentially, all the data flow and control flow leading to an invariant
+output must match.</p>
+</div>
+<div class="paragraph">
+<p>Initially, by default, all output variables are allowed to be variant.
+To force all output variables to be invariant, use the pragma</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="preprocessor">#pragma</span> STDGL invariant(all)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>before all declarations in a shader.
+If this pragma is used after the declaration of any variables or functions,
+then the set of outputs that behave as invariant is undefined.</p>
+</div>
+<div class="paragraph">
+<p>Generally, invariance is ensured at the cost of flexibility in optimization,
+so performance can be degraded by use of invariance.
+Hence, use of this pragma is intended as a debug aid, to avoid individually
+declaring all output variables as invariant.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="invariance-of-constant-expressions">4.8.2. Invariance of Constant Expressions</h4>
+<div class="paragraph">
+<p>Invariance must be guaranteed for constant expressions.
+A particular constant expression must evaluate to the same result if it
+appears again in the same shader or a different shader.
+This includes the same expression appearing in two shaders of the same
+language or shaders of two different languages.</p>
+</div>
+<div class="paragraph">
+<p>Constant expressions must evaluate to the same result when operated on as
+already described above for invariant variables.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="the-precise-qualifier">4.9. The Precise Qualifier</h3>
+<div class="paragraph">
+<p>Some algorithms require floating-point computations to exactly follow the
+order of operations specified in the source code and to treat all operations
+consistently, even if the implementation supports optimizations that could
+produce nearly equivalent results with higher performance.
+For example, many GL implementations support a &#8220;multiply-add&#8221; instruction
+that can compute a floating-point expression such as</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">result = (a * b) + (c * d);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>in two operations instead of three operations; one multiply and one
+multiply-add instead of two multiplies and one add.
+The result of a floating-point multiply-add might not always be identical to
+first doing a multiply yielding a floating-point result and then doing a
+floating-point add.
+Hence, in this example, the two multiply operations would not be treated
+consistently; the two multiplies could effectively appear to have differing
+precisions.</p>
+</div>
+<div class="paragraph">
+<p>The key computation that needs to be made consistent appears when
+tessellating, where intermediate points for subdivision are synthesized in
+different directions, yet need to yield the same result, as shown in the
+diagram below.</p>
+</div>
+<div id="img-precise" class="imageblock">
+<div class="content">
+<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KCjxzdmcgdmVyc2lvbj0iMS4yIiBiYXNlUHJvZmlsZT0idGlueSIgd2lkdGg9IjIxMG1tIiBoZWlnaHQ9IjI5N21tIiB2aWV3Qm94PSIwIDAgMjEwMDAgMjk3MDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSIgc3Ryb2tlLXdpZHRoPSIyOC4yMjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6b29vPSJodHRwOi8veG1sLm9wZW5vZmZpY2Uub3JnL3N2Zy9leHBvcnQiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIj4KIDxkZWZzIGNsYXNzPSJDbGlwUGF0aEdyb3VwIj4KICA8Y2xpcFBhdGggaWQ9InByZXNlbnRhdGlvbl9jbGlwX3BhdGgiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIxMDAwIiBoZWlnaHQ9IjI5NzAwIi8+CiAgPC9jbGlwUGF0aD4KIDwvZGVmcz4KIDxkZWZzPgogIDxmb250IGlkPSJFbWJlZGRlZEZvbnRfMSIgaG9yaXotYWR2LXg9IjIwNDgiPgogICA8Zm9udC1mYWNlIGZvbnQtZmFtaWx5PSJMaWJlcmF0aW9uIFNhbnMgZW1iZWRkZWQiIHVuaXRzLXBlci1lbT0iMjA0OCIgZm9udC13ZWlnaHQ9Im5vcm1hbCIgZm9udC1zdHlsZT0ibm9ybWFsIiBhc2NlbnQ9IjE4NTIiIGRlc2NlbnQ9IjQyMyIvPgogICA8bWlzc2luZy1nbHlwaCBob3Jpei1hZHYteD0iMjA0OCIgZD0iTSAwLDAgTCAyMDQ3LDAgMjA0NywyMDQ3IDAsMjA0NyAwLDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idyIgaG9yaXotYWR2LXg9IjE1MDkiIGQ9Ik0gMTE3NCwwIEwgOTY1LDAgNzkyLDY5OCBDIDc4Nyw3MTYgNzgxLDczOCA3NzYsNzY1IDc3MCw3OTIgNzY0LDgxOCA3NTksODQzIDc1Miw4NzIgNzQ2LDkwMyA3NDAsOTM0IDczNCw5MDQgNzI4LDg3NCA3MjEsODQ1IDcxNiw4MjAgNzEwLDc5MyA3MDQsNzY2IDY5Nyw3MzkgNjkxLDcxNSA2ODYsNjk0IEwgNTA4LDAgMzAwLDAgLTMsMTA4MiAxNzUsMTA4MiAzNTgsMzQ3IEMgMzYzLDMzMiAzNjcsMzEzIDM3MiwyOTEgMzc3LDI2OCAzODEsMjQ2IDM4NiwyMjUgMzkxLDIwMCAzOTYsMTc1IDQwMSwxNDkgNDA2LDE3NCA0MTIsMTk5IDQxOCwyMjMgNDIzLDI0NCA0MjksMjY1IDQzNCwyODYgNDM5LDMwNyA0NDQsMzI1IDQ0OCwzMzkgTCA2NDQsMTA4MiA4MzcsMTA4MiAxMDI2LDMzOSBDIDEwMzEsMzIyIDEwMzYsMzAyIDEwNDEsMjgwIDEwNDYsMjU4IDEwNTEsMjM3IDEwNTYsMjE4IDEwNjEsMTk1IDEwNjcsMTcyIDEwNzIsMTQ5IDEwNzcsMTc0IDEwODMsMTk5IDEwODgsMjIzIDEwOTMsMjQ0IDEwOTgsMjY1IDExMDMsMjg4IDExMDgsMzEwIDExMTIsMzMwIDExMTcsMzQ3IEwgMTMwOCwxMDgyIDE0ODQsMTA4MiAxMTc0LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0idiIgaG9yaXotYWR2LXg9IjEwMzMiIGQ9Ik0gNjEzLDAgTCA0MDAsMCA3LDEwODIgMTk5LDEwODIgNDM3LDM3OCBDIDQ0MiwzNjMgNDQ3LDM0NiA0NTQsMzI1IDQ2MCwzMDQgNDY2LDI4MiA0NzMsMjU5IDQ4MCwyMzYgNDg2LDIxNSA0OTIsMTk0IDQ5NywxNzMgNTAyLDE1NSA1MDYsMTQxIDUxMCwxNTUgNTE1LDE3MyA1MjIsMTk0IDUyOCwyMTUgNTM0LDIzNiA1NDEsMjU4IDU0OCwyODAgNTU1LDMwMiA1NjIsMzIzIDU2OSwzNDQgNTc1LDM2MSA1ODAsMzc2IEwgODI2LDEwODIgMTAxNywxMDgyIDYxMywwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InUiIGhvcml6LWFkdi14PSI4NzQiIGQ9Ik0gMzE0LDEwODIgTCAzMTQsMzk2IEMgMzE0LDM0MyAzMTgsMjk5IDMyNiwyNjQgMzMzLDIyOSAzNDYsMjAwIDM2MywxNzkgMzgwLDE1NyA0MDMsMTQyIDQzMiwxMzMgNDYwLDEyNCA0OTUsMTE5IDUzNywxMTkgNTgwLDExOSA2MTgsMTI3IDY1MywxNDIgNjg3LDE1NyA3MTYsMTc4IDc0MSwyMDcgNzY1LDIzNSA3ODQsMjcwIDc5NywzMTIgODEwLDM1MyA4MTcsNDAxIDgxNyw0NTUgTCA4MTcsMTA4MiA5OTcsMTA4MiA5OTcsMjMxIEMgOTk3LDIwOCA5OTcsMTg1IDk5OCwxNjAgOTk4LDEzNSA5OTgsMTExIDk5OSw4OSAxMDAwLDY2IDEwMDAsNDcgMTAwMSwzMSAxMDAyLDE1IDEwMDIsNSAxMDAzLDAgTCA4MzMsMCBDIDgzMiwzIDgzMiwxMiA4MzEsMjcgODMwLDQyIDgzMCw1OSA4MjksNzggODI4LDk3IDgyNywxMTYgODI2LDEzNiA4MjUsMTU1IDgyNSwxNzIgODI1LDE4NSBMIDgyMiwxODUgQyA4MDUsMTU0IDc4NiwxMjUgNzY1LDEwMCA3NDQsNzUgNzIwLDUzIDY5MywzNiA2NjYsMTggNjM0LDQgNTk5LC02IDU2NCwtMTUgNTIzLC0yMCA0NzYsLTIwIDQxNiwtMjAgMzY0LC0xMyAzMjEsMiAyNzgsMTcgMjQyLDM5IDIxNCw3MCAxODYsMTAxIDE2NiwxNDAgMTUzLDE4OCAxNDAsMjM2IDEzMywyOTQgMTMzLDM2MSBMIDEzMywxMDgyIDMxNCwxMDgyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InQiIGhvcml6LWFkdi14PSI1MzEiIGQ9Ik0gNTU0LDggQyA1MjcsMSA0OTksLTUgNDcxLC0xMCA0NDIsLTE0IDQwOSwtMTYgMzcyLC0xNiAyMjgsLTE2IDE1Niw2NiAxNTYsMjI5IEwgMTU2LDk1MSAzMSw5NTEgMzEsMTA4MiAxNjMsMTA4MiAyMTYsMTMyNCAzMzYsMTMyNCAzMzYsMTA4MiA1MzYsMTA4MiA1MzYsOTUxIDMzNiw5NTEgMzM2LDI2OCBDIDMzNiwyMTYgMzQ1LDE4MCAzNjIsMTU5IDM3OSwxMzggNDA4LDEyNyA0NTAsMTI3IDQ2NywxMjcgNDg0LDEyOCA1MDEsMTMxIDUxNywxMzQgNTM1LDEzNyA1NTQsMTQxIEwgNTU0LDggWiIvPgogICA8Z2x5cGggdW5pY29kZT0icyIgaG9yaXotYWR2LXg9IjkwMSIgZD0iTSA5NTAsMjk5IEMgOTUwLDI0OCA5NDAsMjAzIDkyMSwxNjQgOTAxLDEyNCA4NzIsOTEgODM1LDY0IDc5OCwzNyA3NTIsMTYgNjk4LDIgNjQzLC0xMyA1ODEsLTIwIDUxMSwtMjAgNDQ4LC0yMCAzOTIsLTE1IDM0MiwtNiAyOTEsNCAyNDcsMjAgMjA5LDQxIDE3MSw2MiAxMzksOTEgMTE0LDEyNiA4OCwxNjEgNjksMjAzIDU3LDI1NCBMIDIxNiwyODUgQyAyMzEsMjI3IDI2MywxODUgMzExLDE1OCAzNTksMTMxIDQyNiwxMTcgNTExLDExNyA1NTAsMTE3IDU4NSwxMjAgNjE4LDEyNSA2NTAsMTMwIDY3OCwxNDAgNzAxLDE1MyA3MjQsMTY2IDc0MywxODMgNzU2LDIwNSA3NjksMjI2IDc3NSwyNTMgNzc1LDI4NSA3NzUsMzE4IDc2NywzNDUgNzUyLDM2NiA3MzcsMzg3IDcxNSw0MDQgNjg4LDQxOCA2NjEsNDMyIDYyOCw0NDQgNTg5LDQ1NSA1NTAsNDY1IDUwNyw0NzYgNDYwLDQ4OSA0MTcsNTAwIDM3NCw1MTMgMzMxLDUyNyAyODgsNTQxIDI1MCw1NjAgMjE2LDU4MyAxODEsNjA2IDE1Myw2MzQgMTMyLDY2OCAxMTEsNzAyIDEwMCw3NDUgMTAwLDc5NiAxMDAsODk1IDEzNSw5NzAgMjA2LDEwMjIgMjc2LDEwNzMgMzc4LDEwOTkgNTEzLDEwOTkgNjMyLDEwOTkgNzI3LDEwNzggNzk4LDEwMzYgODY4LDk5NCA5MTIsOTI3IDkzMSw4MzQgTCA3NjksODE0IEMgNzYzLDg0MiA3NTIsODY2IDczNiw4ODUgNzIwLDkwNCA3MDEsOTE5IDY3OCw5MzEgNjU1LDk0MiA2MzAsOTUxIDYwMiw5NTYgNTczLDk2MSA1NDQsOTYzIDUxMyw5NjMgNDMyLDk2MyAzNzIsOTUxIDMzMyw5MjYgMjk0LDkwMSAyNzUsODY0IDI3NSw4MTQgMjc1LDc4NSAyODIsNzYxIDI5Nyw3NDIgMzExLDcyMyAzMzEsNzA3IDM1Nyw2OTQgMzgyLDY4MSA0MTMsNjY5IDQ0OSw2NjAgNDg1LDY1MCA1MjUsNjQwIDU2OCw2MjkgNTk3LDYyMiA2MjYsNjE0IDY1Niw2MDYgNjg2LDU5NyA3MTUsNTg3IDc0NCw1NzYgNzcyLDU2NCA3OTksNTUwIDgyNCw1MzUgODQ5LDUxOSA4NzAsNTAwIDg4OSw0NzggOTA4LDQ1NiA5MjMsNDMwIDkzNCw0MDEgOTQ1LDM3MiA5NTAsMzM4IDk1MCwyOTkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iciIgaG9yaXotYWR2LXg9IjUzMCIgZD0iTSAxNDIsMCBMIDE0Miw4MzAgQyAxNDIsODUzIDE0Miw4NzYgMTQyLDkwMCAxNDEsOTIzIDE0MSw5NDYgMTQwLDk2OCAxMzksOTkwIDEzOSwxMDExIDEzOCwxMDMwIDEzNywxMDQ5IDEzNywxMDY3IDEzNiwxMDgyIEwgMzA2LDEwODIgQyAzMDcsMTA2NyAzMDgsMTA0OSAzMDksMTAzMCAzMTAsMTAxMCAzMTEsOTkwIDMxMiw5NjkgMzEzLDk0OCAzMTMsOTI5IDMxNCw5MTAgMzE0LDg5MSAzMTQsODc0IDMxNCw4NjEgTCAzMTgsODYxIEMgMzMxLDkwMiAzNDQsOTM4IDM1OSw5NjkgMzczLDk5OSAzOTAsMTAyNCA0MDksMTA0NCA0MjgsMTA2MyA0NTEsMTA3OCA0NzgsMTA4OCA1MDUsMTA5NyA1MzcsMTEwMiA1NzUsMTEwMiA1OTAsMTEwMiA2MDQsMTEwMSA2MTcsMTA5OSA2MzAsMTA5NiA2NDEsMTA5NCA2NDgsMTA5MiBMIDY0OCw5MjcgQyA2MzYsOTMwIDYyMiw5MzMgNjA2LDkzNSA1OTAsOTM2IDU3Miw5MzcgNTUyLDkzNyA1MTEsOTM3IDQ3Niw5MjggNDQ3LDkwOSA0MTgsODkwIDM5NCw4NjUgMzc2LDgzMiAzNTcsNzk5IDM0NCw3NTkgMzM1LDcxNCAzMjYsNjY4IDMyMiw2MTggMzIyLDU2NCBMIDMyMiwwIDE0MiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9InAiIGhvcml6LWFkdi14PSI5NTMiIGQ9Ik0gMTA1Myw1NDYgQyAxMDUzLDQ2NCAxMDQ2LDM4OCAxMDMzLDMxOSAxMDIwLDI1MCA5OTgsMTkwIDk2NywxNDAgOTM2LDkwIDg5NSw1MSA4NDQsMjMgNzkzLC02IDczMCwtMjAgNjU1LC0yMCA1NzgsLTIwIDUxMCwtNSA0NTIsMjQgMzk0LDUzIDM1MCwxMDEgMzE5LDE2OCBMIDMxNCwxNjggQyAzMTUsMTY3IDMxNSwxNjEgMzE2LDE1MCAzMTYsMTM5IDMxNiwxMjYgMzE3LDExMCAzMTcsOTQgMzE3LDc2IDMxOCw1NyAzMTgsMzcgMzE4LDE3IDMxOCwtMiBMIDMxOCwtNDI1IDEzOCwtNDI1IDEzOCw4NjEgQyAxMzgsODg3IDEzOCw5MTIgMTM4LDkzNiAxMzcsOTYwIDEzNyw5ODIgMTM2LDEwMDIgMTM1LDEwMjEgMTM1LDEwMzggMTM0LDEwNTIgMTMzLDEwNjYgMTMzLDEwNzYgMTMyLDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDgwIDMwOCwxMDczIDMwOSwxMDYxIDMxMCwxMDQ5IDMxMSwxMDM1IDMxMiwxMDE4IDMxMywxMDAxIDMxNCw5ODIgMzE1LDk2MyAzMTYsOTQ0IDMxNiw5MjUgMzE2LDkwOCBMIDMyMCw5MDggQyAzMzcsOTQzIDM1Niw5NzIgMzc3LDk5NyAzOTgsMTAyMSA0MjMsMTA0MSA0NTAsMTA1NyA0NzcsMTA3MiA1MDgsMTA4NCA1NDIsMTA5MSA1NzUsMTA5OCA2MTMsMTEwMSA2NTUsMTEwMSA3MzAsMTEwMSA3OTMsMTA4OCA4NDQsMTA2MSA4OTUsMTAzNCA5MzYsOTk3IDk2Nyw5NDkgOTk4LDkwMCAxMDIwLDg0MiAxMDMzLDc3NCAxMDQ2LDcwNSAxMDUzLDYyOSAxMDUzLDU0NiBaIE0gODY0LDU0MiBDIDg2NCw2MDkgODYwLDY2OCA4NTIsNzIwIDg0NCw3NzIgODMwLDgxNiA4MTEsODUyIDc5MSw4ODggNzY1LDkxNSA3MzIsOTM0IDY5OSw5NTMgNjU4LDk2MiA2MDksOTYyIDU2OSw5NjIgNTMxLDk1NiA0OTYsOTQ1IDQ2MSw5MzQgNDMwLDkxMiA0MDQsODgwIDM3Nyw4NDggMzU2LDgwNCAzNDEsNzQ4IDMyNiw2OTEgMzE4LDYxOCAzMTgsNTI4IDMxOCw0NTEgMzI0LDM4NyAzMzcsMzM0IDM1MCwyODEgMzY4LDIzOCAzOTMsMjA1IDQxNywxNzIgNDQ3LDE0OSA0ODMsMTM1IDUxOSwxMjAgNTYwLDExMyA2MDcsMTEzIDY1NywxMTMgNjk5LDEyMyA3MzIsMTQyIDc2NSwxNjEgNzkxLDE4OSA4MTEsMjI2IDgzMCwyNjMgODQ0LDMwOCA4NTIsMzYxIDg2MCw0MTQgODY0LDQ3NCA4NjQsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9Im8iIGhvcml6LWFkdi14PSI5ODAiIGQ9Ik0gMTA1Myw1NDIgQyAxMDUzLDM1MyAxMDExLDIxMiA5MjgsMTE5IDg0NSwyNiA3MjQsLTIwIDU2NSwtMjAgNDkwLC0yMCA0MjIsLTkgMzYzLDE0IDMwNCwzNyAyNTQsNzEgMjEzLDExOCAxNzIsMTY1IDE0MCwyMjMgMTE5LDI5NCA5NywzNjQgODYsNDQ3IDg2LDU0MiA4Niw5MTUgMjQ4LDExMDIgNTcxLDExMDIgNjU1LDExMDIgNzI4LDEwOTAgNzg5LDEwNjcgODUwLDEwNDQgOTAwLDEwMDkgOTM5LDk2MiA5NzgsOTE1IDEwMDYsODU3IDEwMjUsNzg3IDEwNDQsNzE3IDEwNTMsNjM1IDEwNTMsNTQyIFogTSA4NjQsNTQyIEMgODY0LDYyNiA4NTgsNjk1IDg0NSw3NTAgODMyLDgwNSA4MTMsODQ4IDc4OCw4ODEgNzYzLDkxNCA3MzIsOTM3IDY5Niw5NTAgNjYwLDk2MyA2MTksOTY5IDU3NCw5NjkgNTI4LDk2OSA0ODcsOTYyIDQ1MCw5NDkgNDEzLDkzNSAzODEsOTEyIDM1NSw4NzkgMzI5LDg0NiAzMDksODAyIDI5Niw3NDcgMjgyLDY5MiAyNzUsNjI0IDI3NSw1NDIgMjc1LDQ1OCAyODIsMzg5IDI5NywzMzQgMzEyLDI3OSAzMzIsMjM1IDM1OCwyMDIgMzgzLDE2OSA0MTQsMTQ2IDQ0OSwxMzMgNDg0LDEyMCA1MjIsMTEzIDU2MywxMTMgNjA5LDExMyA2NTEsMTIwIDY4OCwxMzMgNzI1LDE0NiA3NTcsMTY4IDc4MywyMDEgODA5LDIzNCA4MjksMjc4IDg0MywzMzMgODU3LDM4OCA4NjQsNDU4IDg2NCw1NDIgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibiIgaG9yaXotYWR2LXg9Ijg3NCIgZD0iTSA4MjUsMCBMIDgyNSw2ODYgQyA4MjUsNzM5IDgyMSw3ODMgODE0LDgxOCA4MDYsODUzIDc5Myw4ODIgNzc2LDkwNCA3NTksOTI1IDczNiw5NDEgNzA4LDk1MCA2NzksOTU5IDY0NCw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTYgNDg3LDk0MSA0NTIsOTI2IDQyMyw5MDQgMzk5LDg3NiAzNzQsODQ3IDM1NSw4MTIgMzQyLDc3MSAzMjksNzI5IDMyMiw2ODEgMzIyLDYyNyBMIDMyMiwwIDE0MiwwIDE0Miw4NTEgQyAxNDIsODc0IDE0Miw4OTggMTQyLDkyMyAxNDEsOTQ4IDE0MSw5NzEgMTQwLDk5NCAxMzksMTAxNiAxMzksMTAzNSAxMzgsMTA1MSAxMzcsMTA2NyAxMzcsMTA3NyAxMzYsMTA4MiBMIDMwNiwxMDgyIEMgMzA3LDEwNzkgMzA3LDEwNzAgMzA4LDEwNTUgMzA5LDEwNDAgMzEwLDEwMjQgMzExLDEwMDUgMzEyLDk4NiAzMTIsOTY2IDMxMyw5NDcgMzE0LDkyNyAzMTQsOTEwIDMxNCw4OTcgTCAzMTcsODk3IEMgMzM0LDkyOCAzNTMsOTU3IDM3NCw5ODIgMzk1LDEwMDcgNDE5LDEwMjkgNDQ2LDEwNDcgNDczLDEwNjQgNTA1LDEwNzggNTQwLDEwODggNTc1LDEwOTcgNjE2LDExMDIgNjYzLDExMDIgNzIzLDExMDIgNzc1LDEwOTUgODE4LDEwODAgODYxLDEwNjUgODk3LDEwNDMgOTI1LDEwMTIgOTUzLDk4MSA5NzQsOTQyIDk4Nyw4OTQgMTAwMCw4NDUgMTAwNiw3ODggMTAwNiw3MjEgTCAxMDA2LDAgODI1LDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0ibSIgaG9yaXotYWR2LXg9IjE0NTciIGQ9Ik0gNzY4LDAgTCA3NjgsNjg2IEMgNzY4LDczOSA3NjUsNzgzIDc1OCw4MTggNzUxLDg1MyA3NDAsODgyIDcyNSw5MDQgNzA5LDkyNSA2ODgsOTQxIDY2Myw5NTAgNjM4LDk1OSA2MDcsOTYzIDU3MCw5NjMgNTMyLDk2MyA0OTgsOTU2IDQ2Nyw5NDEgNDM2LDkyNiA0MTAsOTA0IDM4OSw4NzYgMzY3LDg0NyAzNTAsODEyIDMzOSw3NzEgMzI3LDcyOSAzMjEsNjgxIDMyMSw2MjcgTCAzMjEsMCAxNDIsMCAxNDIsODUxIEMgMTQyLDg3NCAxNDIsODk4IDE0Miw5MjMgMTQxLDk0OCAxNDEsOTcxIDE0MCw5OTQgMTM5LDEwMTYgMTM5LDEwMzUgMTM4LDEwNTEgMTM3LDEwNjcgMTM3LDEwNzcgMTM2LDEwODIgTCAzMDYsMTA4MiBDIDMwNywxMDc5IDMwNywxMDcwIDMwOCwxMDU1IDMwOSwxMDQwIDMxMCwxMDI0IDMxMSwxMDA1IDMxMiw5ODYgMzEyLDk2NiAzMTMsOTQ3IDMxNCw5MjcgMzE0LDkxMCAzMTQsODk3IEwgMzE3LDg5NyBDIDMzMyw5MjggMzUwLDk1NyAzNjksOTgyIDM4OCwxMDA3IDQxMCwxMDI5IDQzNSwxMDQ3IDQ2MCwxMDY0IDQ4OCwxMDc4IDUyMSwxMDg4IDU1MywxMDk3IDU5MCwxMTAyIDYzMywxMTAyIDcxNSwxMTAyIDc4MCwxMDg2IDgyOCwxMDUzIDg3NSwxMDIwIDkwOCw5NjggOTI3LDg5NyBMIDkzMCw4OTcgQyA5NDYsOTI4IDk2NCw5NTcgOTg0LDk4MiAxMDA0LDEwMDcgMTAyNywxMDI5IDEwNTQsMTA0NyAxMDgxLDEwNjQgMTExMSwxMDc4IDExNDQsMTA4OCAxMTc3LDEwOTcgMTIxNSwxMTAyIDEyNTgsMTEwMiAxMzEzLDExMDIgMTM2MCwxMDk1IDE0MDAsMTA4MCAxNDM5LDEwNjUgMTQ3MiwxMDQzIDE0OTcsMTAxMiAxNTIyLDk4MSAxNTQxLDk0MiAxNTUzLDg5NCAxNTY1LDg0NSAxNTcxLDc4OCAxNTcxLDcyMSBMIDE1NzEsMCAxMzkzLDAgMTM5Myw2ODYgQyAxMzkzLDczOSAxMzkwLDc4MyAxMzgzLDgxOCAxMzc2LDg1MyAxMzY1LDg4MiAxMzUwLDkwNCAxMzM0LDkyNSAxMzEzLDk0MSAxMjg4LDk1MCAxMjYzLDk1OSAxMjMyLDk2MyAxMTk1LDk2MyAxMTU3LDk2MyAxMTIzLDk1NiAxMDkyLDk0MiAxMDYxLDkyNyAxMDM1LDkwNiAxMDE0LDg3OCA5OTIsODUwIDk3NSw4MTUgOTY0LDc3MyA5NTIsNzMxIDk0Niw2ODIgOTQ2LDYyNyBMIDk0NiwwIDc2OCwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImwiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM4LDAgTCAxMzgsMTQ4NCAzMTgsMTQ4NCAzMTgsMCAxMzgsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJrIiBob3Jpei1hZHYteD0iOTAxIiBkPSJNIDgxNiwwIEwgNDUwLDQ5NCAzMTgsMzg1IDMxOCwwIDEzOCwwIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCw1NTcgNzkzLDEwODIgMTAwNCwxMDgyIDU2NSw2MTcgMTAyNywwIDgxNiwwIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImkiIGhvcml6LWFkdi14PSIxODciIGQ9Ik0gMTM3LDEzMTIgTCAxMzcsMTQ4NCAzMTcsMTQ4NCAzMTcsMTMxMiAxMzcsMTMxMiBaIE0gMTM3LDAgTCAxMzcsMTA4MiAzMTcsMTA4MiAzMTcsMCAxMzcsMCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJoIiBob3Jpei1hZHYteD0iODc0IiBkPSJNIDMxNyw4OTcgQyAzMzcsOTM0IDM1OSw5NjUgMzgyLDk5MSA0MDUsMTAxNiA0MzEsMTAzNyA0NTksMTA1NCA0ODcsMTA3MSA1MTgsMTA4MyA1NTEsMTA5MSA1ODQsMTA5OCA2MjIsMTEwMiA2NjMsMTEwMiA3MzIsMTEwMiA3ODksMTA5MyA4MzQsMTA3NCA4NzgsMTA1NSA5MTMsMTAyOSA5MzksOTk2IDk2NCw5NjIgOTgyLDkyMiA5OTIsODc1IDEwMDEsODI4IDEwMDYsNzc3IDEwMDYsNzIxIEwgMTAwNiwwIDgyNSwwIDgyNSw2ODYgQyA4MjUsNzMyIDgyMiw3NzIgODE3LDgwNyA4MTEsODQyIDgwMCw4NzEgNzg0LDg5NCA3NjgsOTE3IDc0NSw5MzQgNzE2LDk0NiA2ODcsOTU3IDY0OSw5NjMgNjAyLDk2MyA1NTksOTYzIDUyMSw5NTUgNDg3LDk0MCA0NTIsOTI1IDQyMyw5MDMgMzk5LDg3NSAzNzQsODQ3IDM1NSw4MTMgMzQyLDc3MyAzMjksNzMzIDMyMiw2ODggMzIyLDYzOCBMIDMyMiwwIDE0MiwwIDE0MiwxNDg0IDMyMiwxNDg0IDMyMiwxMDk4IEMgMzIyLDEwNzYgMzIyLDEwNTQgMzIxLDEwMzIgMzIwLDEwMTAgMzIwLDk5MCAzMTksOTcxIDMxOCw5NTIgMzE3LDkzNyAzMTYsOTI0IDMxNSw5MTEgMzE1LDkwMiAzMTQsODk3IEwgMzE3LDg5NyBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJnIiBob3Jpei1hZHYteD0iOTI3IiBkPSJNIDU0OCwtNDI1IEMgNDg2LC00MjUgNDMxLC00MTkgMzgzLC00MDYgMzM1LC0zOTMgMjk0LC0zNzUgMjYwLC0zNTIgMjI2LC0zMjggMTk4LC0zMDAgMTc3LC0yNjcgMTU2LC0yMzQgMTQwLC0xOTggMTMxLC0xNTggTCAzMTIsLTEzMiBDIDMyNCwtMTgyIDM1MSwtMjIwIDM5MiwtMjQ4IDQzMywtMjc0IDQ4NiwtMjg4IDU1MywtMjg4IDU5NCwtMjg4IDYzMSwtMjgyIDY2NCwtMjcxIDY5NywtMjYwIDcyNiwtMjQxIDc0OSwtMjE3IDc3MiwtMTkxIDc5MCwtMTU5IDgwMywtMTE5IDgxNiwtNzkgODIyLC0zMCA4MjIsMjcgTCA4MjIsMjAxIDgyMCwyMDEgQyA4MDcsMTc0IDc5MCwxNDggNzcxLDEyMyA3NTEsOTggNzI3LDc1IDY5OSw1NiA2NzAsMzcgNjM3LDIxIDYwMCwxMCA1NjMsLTIgNTIwLC04IDQ3MiwtOCA0MDMsLTggMzQ1LDQgMjk2LDI3IDI0Nyw1MCAyMDcsODQgMTc2LDEzMCAxNDUsMTc2IDEyMiwyMzMgMTA4LDMwMiA5MywzNzAgODYsNDQ5IDg2LDUzOSA4Niw2MjYgOTMsNzA0IDEwOCw3NzMgMTIyLDg0MiAxNDUsOTAxIDE3OCw5NTAgMjEwLDk5OCAyNTIsMTAzNSAzMDQsMTA2MSAzNTUsMTA4NiA0MTgsMTA5OSA0OTIsMTA5OSA1NjksMTA5OSA2MzUsMTA4MiA2OTIsMTA0NyA3NDgsMTAxMiA3OTEsOTYyIDgyMiw4OTcgTCA4MjQsODk3IEMgODI0LDkxNCA4MjUsOTMyIDgyNiw5NTMgODI3LDk3NCA4MjgsOTkzIDgyOSwxMDEyIDgzMCwxMDMwIDgzMSwxMDQ2IDgzMiwxMDU5IDgzMywxMDcyIDgzNSwxMDgwIDgzNiwxMDgyIEwgMTAwNywxMDgyIEMgMTAwNiwxMDc2IDEwMDYsMTA2NiAxMDA1LDEwNTIgMTAwNCwxMDM3IDEwMDQsMTAyMCAxMDAzLDEwMDAgMTAwMiw5ODAgMTAwMiw5NTggMTAwMiw5MzQgMTAwMSw5MDkgMTAwMSw4ODQgMTAwMSw4NTggTCAxMDAxLDMxIEMgMTAwMSwtMTIwIDk2NCwtMjM0IDg5MCwtMzExIDgxNSwtMzg3IDcwMSwtNDI1IDU0OCwtNDI1IFogTSA4MjIsNTQxIEMgODIyLDYxNiA4MTQsNjgxIDc5OCw3MzUgNzgxLDc4OCA3NjAsODMyIDczMyw4NjYgNzA2LDkwMCA2NzYsOTI1IDY0Miw5NDEgNjA3LDk1NyA1NzIsOTY1IDUzNiw5NjUgNDkwLDk2NSA0NTEsOTU3IDQxOCw5NDEgMzg1LDkyNSAzNTcsOTAwIDMzNiw4NjYgMzE0LDgzMSAyOTgsNzg3IDI4OCw3MzQgMjc3LDY4MCAyNzIsNjE2IDI3Miw1NDEgMjcyLDQ2MyAyNzcsMzk4IDI4OCwzNDUgMjk4LDI5MiAzMTQsMjQ5IDMzNSwyMTYgMzU2LDE4MyAzODMsMTYwIDQxNiwxNDYgNDQ5LDEzMiA0ODgsMTI1IDUzMywxMjUgNTY5LDEyNSA2MDQsMTMzIDYzOSwxNDggNjczLDE2MyA3MDQsMTg4IDczMSwyMjEgNzU4LDI1NCA3ODAsMjk3IDc5NywzNTAgODE0LDQwMyA4MjIsNDY2IDgyMiw1NDEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iZiIgaG9yaXotYWR2LXg9IjU1NyIgZD0iTSAzNjEsOTUxIEwgMzYxLDAgMTgxLDAgMTgxLDk1MSAyOSw5NTEgMjksMTA4MiAxODEsMTA4MiAxODEsMTIwNCBDIDE4MSwxMjQzIDE4NSwxMjgwIDE5MiwxMzE0IDE5OSwxMzQ3IDIxMywxMzc3IDIzMywxNDAyIDI1MiwxNDI3IDI3OSwxNDQ2IDMxMywxNDYxIDM0NywxNDc1IDM5MSwxNDgyIDQ0NSwxNDgyIDQ2NiwxNDgyIDQ4OSwxNDgxIDUxMiwxNDc5IDUzNSwxNDc3IDU1NSwxNDc0IDU3MiwxNDcwIEwgNTcyLDEzMzMgQyA1NjEsMTMzNSA1NDgsMTMzNyA1MzMsMTMzOSA1MTgsMTM0MCA1MDQsMTM0MSA0OTIsMTM0MSA0NjUsMTM0MSA0NDQsMTMzNyA0MjcsMTMzMCA0MTAsMTMyMyAzOTYsMTMxMiAzODcsMTI5OSAzNzcsMTI4NSAzNzAsMTI2OCAzNjcsMTI0OCAzNjMsMTIyOCAzNjEsMTIwNSAzNjEsMTE3OSBMIDM2MSwxMDgyIDU3MiwxMDgyIDU3Miw5NTEgMzYxLDk1MSBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJlIiBob3Jpei1hZHYteD0iOTgwIiBkPSJNIDI3Niw1MDMgQyAyNzYsNDQ2IDI4MiwzOTQgMjk0LDM0NyAzMDUsMjk5IDMyMywyNTggMzQ4LDIyNCAzNzIsMTg5IDQwMywxNjMgNDQxLDE0NCA0NzksMTI1IDUyNSwxMTUgNTc4LDExNSA2NTYsMTE1IDcxOSwxMzEgNzY2LDE2MiA4MTMsMTkzIDg0NCwyMzMgODYxLDI4MSBMIDEwMTksMjM2IEMgMTAwOCwyMDYgOTkyLDE3NiA5NzIsMTQ2IDk1MSwxMTUgOTI0LDg4IDg5MCw2NCA4NTYsMzkgODE0LDE5IDc2Myw0IDcxMiwtMTIgNjUwLC0yMCA1NzgsLTIwIDQxOCwtMjAgMjk2LDI4IDIxMywxMjMgMTI5LDIxOCA4NywzNjAgODcsNTQ4IDg3LDY0OSAxMDAsNzM1IDEyNSw4MDYgMTUwLDg3NiAxODUsOTMzIDIyOSw5NzcgMjczLDEwMjEgMzI0LDEwNTMgMzgzLDEwNzMgNDQyLDEwOTIgNTA0LDExMDIgNTcxLDExMDIgNjYyLDExMDIgNzM4LDEwODcgNzk5LDEwNTggODYwLDEwMjkgOTA5LDk4OCA5NDYsOTM3IDk4Myw4ODUgMTAwOSw4MjQgMTAyNSw3NTQgMTA0MCw2ODQgMTA0OCw2MDggMTA0OCw1MjcgTCAxMDQ4LDUwMyAyNzYsNTAzIFogTSA4NjIsNjQxIEMgODUyLDc1NSA4MjMsODM4IDc3NSw4OTEgNzI3LDk0MyA2NTgsOTY5IDU2OCw5NjkgNTM4LDk2OSA1MDcsOTY0IDQ3NCw5NTUgNDQxLDk0NSA0MTAsOTI4IDM4Miw5MDMgMzU0LDg3OCAzMzAsODQ1IDMxMSw4MDMgMjkyLDc2MCAyODEsNzA2IDI3OCw2NDEgTCA4NjIsNjQxIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImQiIGhvcml6LWFkdi14PSI5MjciIGQ9Ik0gODIxLDE3NCBDIDc4OCwxMDUgNzQ0LDU1IDY4OSwyNSA2MzQsLTUgNTY1LC0yMCA0ODQsLTIwIDM0NywtMjAgMjQ3LDI2IDE4MywxMTggMTE4LDIxMCA4NiwzNDkgODYsNTM2IDg2LDkxMyAyMTksMTEwMiA0ODQsMTEwMiA1NjYsMTEwMiA2MzQsMTA4NyA2ODksMTA1NyA3NDQsMTAyNyA3ODgsOTc5IDgyMSw5MTQgTCA4MjMsOTE0IEMgODIzLDkyMSA4MjMsOTMxIDgyMyw5NDYgODIyLDk2MCA4MjIsOTc1IDgyMiw5OTEgODIxLDEwMDYgODIxLDEwMjEgODIxLDEwMzUgODIxLDEwNDkgODIxLDEwNTkgODIxLDEwNjUgTCA4MjEsMTQ4NCAxMDAxLDE0ODQgMTAwMSwyMjMgQyAxMDAxLDE5NyAxMDAxLDE3MiAxMDAyLDE0OCAxMDAyLDEyNCAxMDAyLDEwMiAxMDAzLDgyIDEwMDQsNjIgMTAwNCw0NSAxMDA1LDMxIDEwMDYsMTYgMTAwNiw2IDEwMDcsMCBMIDgzNSwwIEMgODM0LDcgODMzLDE2IDgzMiwyOSA4MzEsNDEgODMwLDU1IDgyOSw3MSA4MjgsODcgODI3LDEwNCA4MjYsMTIyIDgyNSwxMzkgODI1LDE1NyA4MjUsMTc0IEwgODIxLDE3NCBaIE0gMjc1LDU0MiBDIDI3NSw0NjcgMjgwLDQwMyAyODksMzUwIDI5OCwyOTcgMzEzLDI1MyAzMzQsMjE5IDM1NSwxODQgMzgxLDE1OSA0MTMsMTQzIDQ0NSwxMjcgNDg0LDExOSA1MzAsMTE5IDU3NywxMTkgNjE5LDEyNyA2NTYsMTQyIDY5MiwxNTcgNzIyLDE4MiA3NDcsMjE3IDc3MSwyNTEgNzg5LDI5NiA4MDIsMzUxIDgxNSw0MDYgODIxLDQ3NCA4MjEsNTU0IDgyMSw2MzEgODE1LDY5NiA4MDIsNzQ5IDc4OSw4MDIgNzcxLDg0NCA3NDYsODc3IDcyMSw5MTAgNjkxLDkzMyA2NTYsOTQ4IDYyMCw5NjIgNTc5LDk2OSA1MzIsOTY5IDQ4OCw5NjkgNDUwLDk2MSA0MTgsOTQ2IDM4Niw5MzEgMzU5LDkwNiAzMzgsODcyIDMxNyw4MzggMzAxLDc5NCAyOTEsNzQwIDI4MCw2ODUgMjc1LDYxOSAyNzUsNTQyIFoiLz4KICAgPGdseXBoIHVuaWNvZGU9ImMiIGhvcml6LWFkdi14PSI5MDEiIGQ9Ik0gMjc1LDU0NiBDIDI3NSw0ODQgMjgwLDQyNyAyODksMzc1IDI5OCwzMjMgMzEzLDI3OCAzMzQsMjQxIDM1NSwyMDMgMzg0LDE3NCA0MTksMTUzIDQ1NCwxMzIgNDk3LDEyMiA1NDgsMTIyIDYxMiwxMjIgNjY2LDEzOSA3MDksMTczIDc1MiwyMDYgNzc4LDI1OCA3ODgsMzI4IEwgOTcwLDMyOCBDIDk2NCwyODMgOTUxLDIzOSA5MzEsMTk3IDkxMSwxNTUgODg0LDExOCA4NTAsODYgODE1LDU0IDc3MywyOCA3MjQsOSA2NzUsLTEwIDYxOCwtMjAgNTUzLC0yMCA0NjgsLTIwIDM5NiwtNiAzMzcsMjMgMjc4LDUyIDIzMCw5MSAxOTMsMTQyIDE1NiwxOTIgMTI5LDI1MSAxMTIsMzIwIDk1LDM4OCA4Nyw0NjIgODcsNTQyIDg3LDYxNSA5Myw2NzkgMTA1LDczNSAxMTcsNzkwIDEzNCw4MzkgMTU2LDg4MSAxNzcsOTIyIDIwMyw5NTcgMjMyLDk4NiAyNjEsMTAxNCAyOTMsMTAzNyAzMjgsMTA1NCAzNjIsMTA3MSAzOTgsMTA4MyA0MzYsMTA5MSA0NzQsMTA5OCA1MTIsMTEwMiA1NTEsMTEwMiA2MTIsMTEwMiA2NjYsMTA5NCA3MTMsMTA3NyA3NjAsMTA2MCA4MDEsMTAzOCA4MzYsMTAwOSA4NzAsOTgwIDg5OCw5NDUgOTE5LDkwNiA5NDAsODY3IDk1NSw4MjQgOTY0LDc3OSBMIDc3OSw3NjUgQyA3NzAsODI1IDc0Niw4NzMgNzA4LDkwOCA2NzAsOTQzIDYxNiw5NjEgNTQ2LDk2MSA0OTUsOTYxIDQ1Miw5NTMgNDE4LDkzNiAzODMsOTE5IDM1NSw4OTMgMzM0LDg1OSAzMTMsODI0IDI5OCw3ODEgMjg5LDcyOSAyODAsNjc3IDI3NSw2MTYgMjc1LDU0NiBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSJiIiBob3Jpei1hZHYteD0iOTUzIiBkPSJNIDEwNTMsNTQ2IEMgMTA1MywxNjkgOTIwLC0yMCA2NTUsLTIwIDU3MywtMjAgNTA1LC01IDQ1MSwyNSAzOTYsNTQgMzUyLDEwMiAzMTgsMTY4IEwgMzE2LDE2OCBDIDMxNiwxNTEgMzE2LDEzMyAzMTUsMTE0IDMxNCw5NSAzMTMsNzggMzEyLDYyIDMxMSw0NiAzMTAsMzIgMzA5LDIxIDMwOCwxMCAzMDcsMyAzMDYsMCBMIDEzMiwwIEMgMTMzLDYgMTMzLDE2IDEzNCwzMSAxMzUsNDUgMTM1LDYyIDEzNiw4MiAxMzcsMTAyIDEzNywxMjQgMTM4LDE0OCAxMzgsMTcyIDEzOCwxOTcgMTM4LDIyMyBMIDEzOCwxNDg0IDMxOCwxNDg0IDMxOCwxMDYxIEMgMzE4LDEwNDEgMzE4LDEwMjIgMzE4LDEwMDQgMzE3LDk4NSAzMTcsOTY5IDMxNiw5NTUgMzE1LDkzOCAzMTUsOTIzIDMxNCw5MDggTCAzMTgsOTA4IEMgMzUxLDk3NyAzOTYsMTAyNyA0NTEsMTA1NyA1MDYsMTA4NyA1NzQsMTEwMiA2NTUsMTEwMiA3OTIsMTEwMiA4OTIsMTA1NiA5NTcsOTY0IDEwMjEsODcyIDEwNTMsNzMzIDEwNTMsNTQ2IFogTSA4NjQsNTQwIEMgODY0LDYxNSA4NTksNjc5IDg1MCw3MzIgODQxLDc4NSA4MjYsODI5IDgwNSw4NjQgNzg0LDg5OCA3NTgsOTIzIDcyNiw5MzkgNjk0LDk1NSA2NTUsOTYzIDYwOSw5NjMgNTYyLDk2MyA1MjAsOTU1IDQ4NCw5NDAgNDQ3LDkyNSA0MTcsOTAwIDM5Myw4NjYgMzY4LDgzMiAzNTAsNzg3IDMzNyw3MzIgMzI0LDY3NyAzMTgsNjA5IDMxOCw1MjkgMzE4LDQ1MiAzMjQsMzg3IDMzNywzMzQgMzUwLDI4MSAzNjgsMjM5IDM5MywyMDYgNDE3LDE3MyA0NDcsMTQ5IDQ4MywxMzUgNTE5LDEyMCA1NjAsMTEzIDYwNywxMTMgNjUxLDExMyA2ODksMTIxIDcyMSwxMzYgNzUzLDE1MSA3ODAsMTc2IDgwMSwyMTAgODIyLDI0NCA4MzgsMjg4IDg0OSwzNDMgODU5LDM5NyA4NjQsNDYzIDg2NCw1NDAgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iYSIgaG9yaXotYWR2LXg9IjEwNjAiIGQ9Ik0gNDE0LC0yMCBDIDMwNSwtMjAgMjI0LDkgMTY5LDY2IDExNCwxMjQgODcsMjAzIDg3LDMwMyA4NywzNzUgMTAxLDQzNCAxMjgsNDgwIDE1NSw1MjYgMTkwLDU2MiAyMzQsNTg4IDI3Nyw2MTQgMzI3LDYzMiAzODMsNjQyIDQzOSw2NTIgNDk2LDY1NyA1NTQsNjU3IEwgNzk3LDY1NyA3OTcsNzE3IEMgNzk3LDc2MiA3OTIsODAwIDc4Myw4MzIgNzc0LDg2MyA3NTksODg5IDc0MCw5MDggNzIxLDkyOCA2OTcsOTQyIDY2OCw5NTEgNjM5LDk2MCA2MDQsOTY1IDU2NSw5NjUgNTMwLDk2NSA0OTksOTYzIDQ3MSw5NTggNDQzLDk1MyA0MTksOTQ0IDM5OCw5MzEgMzc3LDkxOCAzNjEsOTAwIDM0OCw4NzggMzM1LDg1NSAzMjcsODI3IDMyMyw3OTMgTCAxMzUsODEwIEMgMTQyLDg1MyAxNTQsODkyIDE3Myw5MjggMTkyLDk2MyAyMTgsOTk0IDI1MywxMDIwIDI4NywxMDQ2IDMzMCwxMDY2IDM4MiwxMDgxIDQzMywxMDk1IDQ5NiwxMTAyIDU2OSwxMTAyIDcwNSwxMTAyIDgwNywxMDcxIDg3NiwxMDA5IDk0NSw5NDYgOTc5LDg1NiA5NzksNzM4IEwgOTc5LDI3MiBDIDk3OSwyMTkgOTg2LDE3OSAxMDAwLDE1MiAxMDE0LDEyNSAxMDQxLDExMSAxMDgwLDExMSAxMDkwLDExMSAxMTAwLDExMiAxMTEwLDExMyAxMTIwLDExNCAxMTMwLDExNiAxMTM5LDExOCBMIDExMzksNiBDIDExMTYsMSAxMDk0LC0zIDEwNzIsLTYgMTA0OSwtOSAxMDI1LC0xMCAxMDAwLC0xMCA5NjYsLTEwIDkzNywtNSA5MTMsNCA4ODgsMTMgODY4LDI2IDg1Myw0NSA4MzgsNjMgODI2LDg2IDgxOCwxMTMgODEwLDE0MCA4MDUsMTcxIDgwMywyMDcgTCA3OTcsMjA3IEMgNzc4LDE3MiA3NTcsMTQxIDczNCwxMTMgNzExLDg1IDY4NCw2MSA2NTMsNDIgNjIyLDIyIDU4OCw3IDU0OSwtNCA1MTAsLTE1IDQ2NSwtMjAgNDE0LC0yMCBaIE0gNDU1LDExNSBDIDUxMiwxMTUgNTYzLDEyNSA2MDYsMTQ2IDY0OSwxNjcgNjg0LDE5NCA3MTMsMjI2IDc0MSwyNTkgNzYyLDI5NCA3NzYsMzMyIDc5MCwzNzEgNzk3LDQwOCA3OTcsNDQzIEwgNzk3LDUzMSA2MDAsNTMxIEMgNTU2LDUzMSA1MTQsNTI4IDQ3NSw1MjIgNDM1LDUxNyA0MDAsNTA2IDM3MCw0ODkgMzQwLDQ3MiAzMTYsNDQ5IDI5OSw0MTggMjgxLDM4OCAyNzIsMzQ5IDI3MiwzMDAgMjcyLDI0MSAyODgsMTk1IDMyMCwxNjMgMzUxLDEzMSAzOTYsMTE1IDQ1NSwxMTUgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iUyIgaG9yaXotYWR2LXg9IjExOTIiIGQ9Ik0gMTI3MiwzODkgQyAxMjcyLDMzMCAxMjYxLDI3NSAxMjM4LDIyNSAxMjE1LDE3NSAxMTc5LDEzMiAxMTMxLDk2IDEwODMsNTkgMTAyMywzMSA5NTAsMTEgODc3LC0xMCA3OTAsLTIwIDY5MCwtMjAgNTE1LC0yMCAzNzgsMTEgMjgwLDcyIDE4MiwxMzMgMTIwLDIyMiA5MywzMzggTCAyNzgsMzc1IEMgMjg3LDMzOCAzMDIsMzA1IDMyMSwyNzUgMzQwLDI0NSAzNjcsMjE5IDQwMCwxOTggNDMzLDE3NiA0NzMsMTU5IDUyMiwxNDcgNTcxLDEzNSA2MjksMTI5IDY5NywxMjkgNzU0LDEyOSA4MDYsMTM0IDg1MywxNDQgOTAwLDE1MyA5NDEsMTY4IDk3NSwxODggMTAwOSwyMDggMTAzNiwyMzQgMTA1NSwyNjYgMTA3NCwyOTcgMTA4MywzMzUgMTA4MywzNzkgMTA4Myw0MjUgMTA3Myw0NjIgMTA1Miw0OTEgMTAzMSw1MjAgMTAwMSw1NDMgOTYzLDU2MiA5MjUsNTgxIDg4MCw1OTYgODI3LDYwOSA3NzQsNjIyIDcxNiw2MzUgNjUyLDY1MCA2MTMsNjU5IDU3Myw2NjggNTM0LDY3OSA0OTQsNjg5IDQ1Niw3MDEgNDIwLDcxNiAzODMsNzMwIDM0OSw3NDcgMzE3LDc2NiAyODUsNzg1IDI1Nyw4MDkgMjM0LDgzNiAyMTEsODYzIDE5Miw4OTQgMTc5LDkzMCAxNjYsOTY1IDE1OSwxMDA2IDE1OSwxMDUzIDE1OSwxMTIwIDE3MywxMTc3IDIwMCwxMjI1IDIyNywxMjcyIDI2NCwxMzExIDMxMiwxMzQyIDM2MCwxMzczIDQxNywxMzk1IDQ4MiwxNDA5IDU0NywxNDIzIDYxOCwxNDMwIDY5NCwxNDMwIDc4MSwxNDMwIDg1NiwxNDIzIDkxOCwxNDEwIDk4MCwxMzk2IDEwMzIsMTM3NSAxMDc1LDEzNDggMTExOCwxMzIxIDExNTIsMTI4NyAxMTc4LDEyNDcgMTIwMywxMjA2IDEyMjQsMTE1OSAxMjM5LDExMDYgTCAxMDUxLDEwNzMgQyAxMDQyLDExMDcgMTAyOCwxMTM3IDEwMTEsMTE2NCA5OTMsMTE5MSA5NzAsMTIxMyA5NDEsMTIzMSA5MTIsMTI0OSA4NzgsMTI2MyA4MzcsMTI3MiA3OTYsMTI4MSA3NDcsMTI4NiA2OTIsMTI4NiA2MjcsMTI4NiA1NzIsMTI4MCA1MjgsMTI2OSA0ODMsMTI1NyA0NDgsMTI0MSA0MjEsMTIyMSAzOTQsMTIwMSAzNzQsMTE3OCAzNjMsMTE1MSAzNTEsMTEyNCAzNDUsMTA5NCAzNDUsMTA2MyAzNDUsMTAyMSAzNTYsOTg3IDM3Nyw5NjAgMzk4LDkzMyA0MjYsOTEwIDQ2Miw4OTIgNDk4LDg3NCA1NDAsODU5IDU4Nyw4NDcgNjM0LDgzNSA2ODUsODIzIDczOCw4MTEgNzgxLDgwMSA4MjUsNzkxIDg2OCw3ODEgOTExLDc3MCA5NTIsNzU4IDk5MSw3NDQgMTAzMCw3MjkgMTA2Nyw3MTIgMTEwMiw2OTMgMTEzNiw2NzQgMTE2Niw2NTAgMTE5MSw2MjIgMTIxNiw1OTQgMTIzNiw1NjEgMTI1MSw1MjMgMTI2NSw0ODUgMTI3Miw0NDAgMTI3MiwzODkgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iTyIgaG9yaXotYWR2LXg9IjE0MzAiIGQ9Ik0gMTQ5NSw3MTEgQyAxNDk1LDYwMSAxNDc5LDUwMSAxNDQ4LDQxMSAxNDE2LDMyMSAxMzcwLDI0NCAxMzEwLDE4MCAxMjUwLDExNiAxMTc3LDY3IDEwOTAsMzIgMTAwMywtMyA5MDUsLTIwIDc5NSwtMjAgNjc5LC0yMCA1NzcsLTIgNDkwLDM1IDQwMyw3MSAzMzAsMTIyIDI3MiwxODcgMjE0LDI1MiAxNzAsMzI5IDE0MSw0MTggMTEyLDUwNyA5Nyw2MDUgOTcsNzExIDk3LDgyMSAxMTIsOTIwIDE0MywxMDA5IDE3NCwxMDk4IDIxOSwxMTczIDI3OCwxMjM2IDMzNywxMjk4IDQxMSwxMzQ2IDQ5OCwxMzgwIDU4NSwxNDEzIDY4NCwxNDMwIDc5NywxNDMwIDkwOSwxNDMwIDEwMDksMTQxMyAxMDk2LDEzNzkgMTE4MywxMzQ1IDEyNTYsMTI5NyAxMzE1LDEyMzQgMTM3NCwxMTcxIDE0MTgsMTA5NiAxNDQ5LDEwMDcgMTQ4MCw5MTggMTQ5NSw4MjAgMTQ5NSw3MTEgWiBNIDEzMDAsNzExIEMgMTMwMCw3OTYgMTI4OSw4NzMgMTI2OCw5NDIgMTI0NiwxMDExIDEyMTQsMTA3MSAxMTcyLDExMjAgMTEyOSwxMTY5IDEwNzcsMTIwNyAxMDE0LDEyMzQgOTUxLDEyNjEgODc5LDEyNzQgNzk3LDEyNzQgNzEzLDEyNzQgNjM5LDEyNjEgNTc2LDEyMzQgNTEzLDEyMDcgNDYwLDExNjkgNDE4LDExMjAgMzc1LDEwNzEgMzQ0LDEwMTEgMzIzLDk0MiAzMDIsODczIDI5MSw3OTYgMjkxLDcxMSAyOTEsNjI2IDMwMiw1NDkgMzI0LDQ3OSAzNDUsNDA4IDM3NywzNDggNDIwLDI5NyA0NjIsMjQ2IDUxNSwyMDYgNTc4LDE3OCA2NDEsMTQ5IDcxMywxMzUgNzk1LDEzNSA4ODMsMTM1IDk1OSwxNDkgMTAyMywxNzggMTA4NiwyMDcgMTEzOSwyNDcgMTE4MCwyOTggMTIyMSwzNDkgMTI1MSw0MDkgMTI3MSw0ODAgMTI5MCw1NTEgMTMwMCw2MjggMTMwMCw3MTEgWiIvPgogICA8Z2x5cGggdW5pY29kZT0iQyIgaG9yaXotYWR2LXg9IjEzMjQiIGQ9Ik0gNzkyLDEyNzQgQyA3MTIsMTI3NCA2NDEsMTI2MSA1ODAsMTIzNCA1MTgsMTIwNyA0NjYsMTE2OSA0MjUsMTEyMCAzODMsMTA3MSAzNTEsMTAxMSAzMzAsOTQyIDMwOSw4NzMgMjk4LDc5NiAyOTgsNzExIDI5OCw2MjYgMzEwLDU0OSAzMzMsNDc5IDM1Niw0MDggMzg5LDM0OCA0MzIsMjk3IDQ3NSwyNDYgNTI3LDIwNyA1OTAsMTc5IDY1MiwxNTEgNzIyLDEzNyA4MDAsMTM3IDg1NSwxMzcgOTA1LDE0NCA5NTAsMTU5IDk5NSwxNzMgMTAzNSwxOTMgMTA3MiwyMTkgMTEwOCwyNDUgMTE0MCwyNzYgMTE2OSwzMTIgMTE5OCwzNDcgMTIyMywzODcgMTI0NSw0MzAgTCAxNDAxLDM1MiBDIDEzNzYsMjk5IDEzNDQsMjUwIDEzMDcsMjA1IDEyNzAsMTYwIDEyMjYsMTIwIDExNzYsODcgMTEyNSw1NCAxMDY4LDI4IDEwMDUsOSA5NDEsLTEwIDg3MCwtMjAgNzkxLC0yMCA2NzcsLTIwIDU3NywtMiA0OTIsMzUgNDA2LDcxIDMzNCwxMjIgMjc3LDE4NyAyMTksMjUyIDE3NiwzMjkgMTQ3LDQxOCAxMTgsNTA3IDEwNCw2MDUgMTA0LDcxMSAxMDQsODIxIDExOSw5MjAgMTUwLDEwMDkgMTgwLDEwOTggMjI0LDExNzMgMjgzLDEyMzYgMzQxLDEyOTggNDEzLDEzNDYgNDk4LDEzODAgNTgzLDE0MTMgNjgxLDE0MzAgNzkwLDE0MzAgOTQwLDE0MzAgMTA2NSwxNDAxIDExNjYsMTM0MiAxMjY3LDEyODMgMTM0MSwxMTk2IDEzODgsMTA4MSBMIDEyMDcsMTAyMSBDIDExOTQsMTA1NCAxMTc2LDEwODYgMTE1MywxMTE3IDExMzAsMTE0NyAxMTAyLDExNzQgMTA2OCwxMTk3IDEwMzQsMTIyMCA5OTQsMTIzOSA5NDksMTI1MyA5MDMsMTI2NyA4NTEsMTI3NCA3OTIsMTI3NCBaIi8+CiAgIDxnbHlwaCB1bmljb2RlPSIgIiBob3Jpei1hZHYteD0iNTU2Ii8+CiAgPC9mb250PgogPC9kZWZzPgogPGRlZnMgY2xhc3M9IlRleHRTaGFwZUluZGV4Ij4KICA8ZyBvb286c2xpZGU9ImlkMSIgb29vOmlkLWxpc3Q9ImlkMyBpZDQgaWQ1IGlkNiBpZDcgaWQ4IGlkOSBpZDEwIGlkMTEgaWQxMiBpZDEzIGlkMTQgaWQxNSBpZDE2IGlkMTcgaWQxOCBpZDE5Ii8+CiA8L2RlZnM+CiA8ZGVmcyBjbGFzcz0iRW1iZWRkZWRCdWxsZXRDaGFycyI+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDU3MzU2KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gNTgwLDExNDEgTCAxMTYzLDU3MSA1ODAsMCAtNCw1NzEgNTgwLDExNDEgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoNTczNTQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSA4LDExMjggTCAxMTM3LDExMjggMTEzNywwIDgsMCA4LDExMjggWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAxNDYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAxNzQsMCBMIDYwMiw3MzkgMTc0LDE0ODEgMTQ1Niw3MzkgMTc0LDAgWiBNIDEzNTgsNzM5IEwgMzA5LDEzNDYgNjU5LDczOSAxMzU4LDczOSBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSgxMDEzMikiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIDIwMTUsNzM5IEwgMTI3NiwwIDcxNywwIDEyNjAsNTQzIDE3NCw1NDMgMTc0LDkzNiAxMjYwLDkzNiA3MTcsMTQ4MSAxMjc0LDE0ODEgMjAxNSw3MzkgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDcpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAwLC0yIEMgLTcsMTQgLTE2LDI3IC0yNSwzNyBMIDM1Niw1NjcgQyAyNjIsODIzIDIxNSw5NTIgMjE1LDk1NCAyMTUsOTc5IDIyOCw5OTIgMjU1LDk5MiAyNjQsOTkyIDI3Niw5OTAgMjg5LDk4NyAzMTAsOTkxIDMzMSw5OTkgMzU0LDEwMTIgTCAzODEsOTk5IDQ5Miw3NDggNzcyLDEwNDkgODM2LDEwMjQgODYwLDEwNDkgQyA4ODEsMTAzOSA5MDEsMTAyNSA5MjIsMTAwNiA4ODYsOTM3IDgzNSw4NjMgNzcwLDc4NCA3NjksNzgzIDcxMCw3MTYgNTk0LDU4NCBMIDc3NCwyMjMgQyA3NzQsMTk2IDc1MywxNjggNzExLDEzOSBMIDcyNywxMTkgQyA3MTcsOTAgNjk5LDc2IDY3Miw3NiA2NDEsNzYgNTcwLDE3OCA0NTcsMzgxIEwgMTY0LC03NiBDIDE0MiwtMTEwIDExMSwtMTI3IDcyLC0xMjcgMzAsLTEyNyA5LC0xMTAgOCwtNzYgMSwtNjcgLTIsLTUyIC0yLC0zMiAtMiwtMjMgLTEsLTEzIDAsLTIgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoMTAwMDQpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAyODUsLTMzIEMgMTgyLC0zMyAxMTEsMzAgNzQsMTU2IDUyLDIyOCA0MSwzMzMgNDEsNDcxIDQxLDU0OSA1NSw2MTYgODIsNjcyIDExNiw3NDMgMTY5LDc3OCAyNDAsNzc4IDI5Myw3NzggMzI4LDc0NyAzNDYsNjg0IEwgMzY5LDUwOCBDIDM3Nyw0NDQgMzk3LDQxMSA0MjgsNDEwIEwgMTE2MywxMTE2IEMgMTE3NCwxMTI3IDExOTYsMTEzMyAxMjI5LDExMzMgMTI3MSwxMTMzIDEyOTIsMTExOCAxMjkyLDEwODcgTCAxMjkyLDk2NSBDIDEyOTIsOTI5IDEyODIsOTAxIDEyNjIsODgxIEwgNDQyLDQ3IEMgMzkwLC02IDMzOCwtMzMgMjg1LC0zMyBaIi8+CiAgPC9nPgogIDxnIGlkPSJidWxsZXQtY2hhci10ZW1wbGF0ZSg5Njc5KSIgdHJhbnNmb3JtPSJzY2FsZSgwLjAwMDQ4ODI4MTI1LC0wLjAwMDQ4ODI4MTI1KSI+CiAgIDxwYXRoIGQ9Ik0gODEzLDAgQyA2MzIsMCA0ODksNTQgMzgzLDE2MSAyNzYsMjY4IDIyMyw0MTEgMjIzLDU5MiAyMjMsNzczIDI3Niw5MTYgMzgzLDEwMjMgNDg5LDExMzAgNjMyLDExODQgODEzLDExODQgOTkyLDExODQgMTEzNiwxMTMwIDEyNDUsMTAyMyAxMzUzLDkxNiAxNDA3LDc3MiAxNDA3LDU5MiAxNDA3LDQxMiAxMzUzLDI2OCAxMjQ1LDE2MSAxMTM2LDU0IDk5MiwwIDgxMywwIFoiLz4KICA8L2c+CiAgPGcgaWQ9ImJ1bGxldC1jaGFyLXRlbXBsYXRlKDgyMjYpIiB0cmFuc2Zvcm09InNjYWxlKDAuMDAwNDg4MjgxMjUsLTAuMDAwNDg4MjgxMjUpIj4KICAgPHBhdGggZD0iTSAzNDYsNDU3IEMgMjczLDQ1NyAyMDksNDgzIDE1NSw1MzUgMTAxLDU4NiA3NCw2NDkgNzQsNzIzIDc0LDc5NiAxMDEsODU5IDE1NSw5MTEgMjA5LDk2MyAyNzMsOTg5IDM0Niw5ODkgNDE5LDk4OSA0ODAsOTYzIDUzMSw5MTAgNTgyLDg1OSA2MDgsNzk2IDYwOCw3MjMgNjA4LDY0OCA1ODMsNTg2IDUzMiw1MzUgNDgyLDQ4MyA0MjAsNDU3IDM0Niw0NTcgWiIvPgogIDwvZz4KICA8ZyBpZD0iYnVsbGV0LWNoYXItdGVtcGxhdGUoODIxMSkiIHRyYW5zZm9ybT0ic2NhbGUoMC4wMDA0ODgyODEyNSwtMC4wMDA0ODgyODEyNSkiPgogICA8cGF0aCBkPSJNIC00LDQ1OSBMIDExMzUsNDU5IDExMzUsNjA2IC00LDYwNiAtNCw0NTkgWiIvPgogIDwvZz4KIDwvZGVmcz4KIDxkZWZzIGNsYXNzPSJUZXh0RW1iZWRkZWRCaXRtYXBzIi8+CiA8Zz4KICA8ZyBpZD0iaWQyIiBjbGFzcz0iTWFzdGVyX1NsaWRlIj4KICAgPGcgaWQ9ImJnLWlkMiIgY2xhc3M9IkJhY2tncm91bmQiLz4KICAgPGcgaWQ9ImJvLWlkMiIgY2xhc3M9IkJhY2tncm91bmRPYmplY3RzIi8+CiAgPC9nPgogPC9nPgogPGcgY2xhc3M9IlNsaWRlR3JvdXAiPgogIDxnPgogICA8ZyBpZD0iaWQxIiBjbGFzcz0iU2xpZGUiIGNsaXAtcGF0aD0idXJsKCNwcmVzZW50YXRpb25fY2xpcF9wYXRoKSI+CiAgICA8ZyBjbGFzcz0iUGFnZSI+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMyI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MCw3MDAwIEwgNzAwMCw3MDAwIDcwMDAsMzAwMCA5OTAwLDMwMDAgOTkwMCw3MDAwIDg0NTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLlJlY3RhbmdsZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTIwNTAsNzAwMCBMIDEwMTAwLDcwMDAgMTAxMDAsMzAwMCAxNDAwMCwzMDAwIDE0MDAwLDcwMDAgMTIwNTAsNzAwMCBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkVsbGlwc2VTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDUiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDg5OTksMzMwMCBDIDkxMDUsMzMxMiA5MTk1LDMzODMgOTI4OCwzNTMxIDkzODcsMzY5MCA5NDU5LDM4ODkgOTUxNiw0MTY1IDk1NzQsNDQ0MSA5NjAwLDQ3MTIgOTYwMCw1MDMxIDk2MDAsNTM1MCA5NTc0LDU2MjEgOTUxNiw1ODk3IDk0NTksNjE3MyA5NDAyLDYzMjggOTMxOSw2NDc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiIGQ9Ik0gOTE0MSw2NzAxIEwgOTQwNSw2NTI2IDkyNDgsNjQwMyA5MTQxLDY3MDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5FbGxpcHNlU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ2Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDc5NCw2NzEwIEMgMTA3NDgsNjY2OSAxMDcxMCw2NjE4IDEwNjY4LDY1NDAgMTA1ODMsNjM4MCAxMDUyMSw2MTgxIDEwNDcyLDU5MDUgMTA0MjIsNTYyOCAxMDQwMCw1MzU2IDEwNDAwLDUwMzYgMTA0MDAsNDcxNiAxMDQyMiw0NDQ0IDEwNDcyLDQxNjggMTA1MjEsMzg5MSAxMDU4MywzNjkyIDEwNjY4LDM1MzIgMTA3NDgsMzM4MyAxMDY5MCwzNDkyIDEwNzAxLDM0NzQiLz4KICAgICAgIDxwYXRoIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSIgZD0iTSAxMDkxNiwzMzAwIEwgMTA2MjIsMzQxNiAxMDc1MCwzNTY5IDEwOTE2LDMzMDAgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDciPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4OTksNjkwMCBDIDk5NTUsNjkwMCA5OTk5LDY5NDMgOTk5OSw2OTk5IDk5OTksNzA1NSA5OTU1LDcwOTkgOTg5OSw3MDk5IDk4NDMsNzA5OSA5ODAwLDcwNTUgOTgwMCw2OTk5IDk4MDAsNjk0MyA5ODQzLDY5MDAgOTg5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODAwLDY5MDAgTCA5ODAwLDY5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAxLDcxMDEgTCAxMDAwMSw3MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQ4Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDA5OSwyOTAwIEMgMTAxNTUsMjkwMCAxMDE5OSwyOTQzIDEwMTk5LDI5OTkgMTAxOTksMzA1NSAxMDE1NSwzMDk5IDEwMDk5LDMwOTkgMTAwNDMsMzA5OSAxMDAwMCwzMDU1IDEwMDAwLDI5OTkgMTAwMDAsMjk0MyAxMDA0MywyOTAwIDEwMDk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDAwLDI5MDAgTCAxMDAwMCwyOTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMSwzMTAxIEwgMTAyMDEsMzEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkOSI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTg5OSwyOTAwIEMgOTk1NSwyOTAwIDk5OTksMjk0MyA5OTk5LDI5OTkgOTk5OSwzMDU1IDk5NTUsMzA5OSA5ODk5LDMwOTkgOTg0MywzMDk5IDk4MDAsMzA1NSA5ODAwLDI5OTkgOTgwMCwyOTQzIDk4NDMsMjkwMCA5ODk5LDI5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDk4MDAsMjkwMCBMIDk4MDAsMjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDEsMzEwMSBMIDEwMDAxLDMxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEwIj4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSA5ODk5LDQ5MDAgQyA5OTU1LDQ5MDAgOTk5OSw0OTQzIDk5OTksNDk5OSA5OTk5LDUwNTUgOTk1NSw1MDk5IDk4OTksNTA5OSA5ODQzLDUwOTkgOTgwMCw1MDU1IDk4MDAsNDk5OSA5ODAwLDQ5NDMgOTg0Myw0OTAwIDk4OTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTgwMCw0OTAwIEwgOTgwMCw0OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMSw1MTAxIEwgMTAwMDEsNTEwMSBaIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTEiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMDk5LDQ5MDAgQyAxMDE1NSw0OTAwIDEwMTk5LDQ5NDMgMTAxOTksNDk5OSAxMDE5OSw1MDU1IDEwMTU1LDUwOTkgMTAwOTksNTA5OSAxMDA0Myw1MDk5IDEwMDAwLDUwNTUgMTAwMDAsNDk5OSAxMDAwMCw0OTQzIDEwMDQzLDQ5MDAgMTAwOTksNDkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwMDAsNDkwMCBMIDEwMDAwLDQ5MDAgWiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjAxLDUxMDEgTCAxMDIwMSw1MTAxIFoiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuQ3VzdG9tU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxMiI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAwOTksNjkwMCBDIDEwMTU1LDY5MDAgMTAxOTksNjk0MyAxMDE5OSw2OTk5IDEwMTk5LDcwNTUgMTAxNTUsNzA5OSAxMDA5OSw3MDk5IDEwMDQzLDcwOTkgMTAwMDAsNzA1NSAxMDAwMCw2OTk5IDEwMDAwLDY5NDMgMTAwNDMsNjkwMCAxMDA5OSw2OTAwIFoiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDAwMCw2OTAwIEwgMTAwMDAsNjkwMCBaIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAyMDEsNzEwMSBMIDEwMjAxLDcxMDEgWiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5DdXN0b21TaGFwZSI+CiAgICAgIDxnIGlkPSJpZDEzIj4KICAgICAgIDxwYXRoIGZpbGw9InJnYigyNTUsMjU1LDI1NSkiIHN0cm9rZT0ibm9uZSIgZD0iTSA1MTAwLDUyMDAgTCAzNTAwLDUyMDAgMzUwMCwzMDAwIDY3MDAsMzAwMCA2NzAwLDUyMDAgNTEwMCw1MjAwIFoiLz4KICAgICAgIDx0ZXh0IGNsYXNzPSJUZXh0U2hhcGUiPjx0c3BhbiBjbGFzcz0iVGV4dFBhcmFncmFwaCIgZm9udC1mYW1pbHk9IkxpYmVyYXRpb24gU2Fucywgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNTNweCIgZm9udC13ZWlnaHQ9IjQwMCI+PHRzcGFuIGNsYXNzPSJUZXh0UG9zaXRpb24iIHg9IjM3NTAiIHk9IjM0MzMiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPlN1YmRpdmlzaW9uIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iMzgyNyI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+cG9pbnRzIG5lZWQgdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI0MjIxIj48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5sYW5kIG9uIHRoZSBzYW1lIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMzc1MCIgeT0iNDYxNSI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+bG9jYXRpb24gdG8gPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIzNzUwIiB5PSI1MDA5Ij48dHNwYW4gZmlsbD0icmdiKDAsMCwwKSIgc3Ryb2tlPSJub25lIj5wcmV2ZW50IGNyYWNraW5nPC90c3Bhbj48L3RzcGFuPjwvdHNwYW4+PC90ZXh0PgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGNsYXNzPSJjb20uc3VuLnN0YXIuZHJhd2luZy5MaW5lU2hhcGUiPgogICAgICA8ZyBpZD0iaWQxNCI+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjYwMCw0MjAwIEwgNjY1MSw0MjEzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjcwMyw0MjI3IEwgNjc1NCw0MjQwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjgwNiw0MjUzIEwgNjg1Nyw0MjY2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNjkwOCw0MjgwIEwgNjk2MCw0MjkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzAxMSw0MzA2IEwgNzA2Myw0MzE5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzExNCw0MzMzIEwgNzE2NSw0MzQ2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzIxNyw0MzU5IEwgNzI2OCw0MzcyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzMyMCw0Mzg2IEwgNzM3MSw0Mzk5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzQyMyw0NDEyIEwgNzQ3NCw0NDI2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzUyNSw0NDM5IEwgNzU3Nyw0NDUyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzYyOCw0NDY1IEwgNzY4MCw0NDc5Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzczMSw0NDkyIEwgNzc4Miw0NTA1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzgzNCw0NTE4IEwgNzg4NSw0NTMyIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gNzkzNyw0NTQ1IEwgNzk4OCw0NTU4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODAzOSw0NTcxIEwgODA5MSw0NTg1Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODE0Miw0NTk4IEwgODE5NCw0NjExIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODI0NSw0NjI1IEwgODI5Niw0NjM4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODM0OCw0NjUxIEwgODM5OSw0NjY0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODQ1MSw0Njc4IEwgODUwMiw0NjkxIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODU1Myw0NzA0IEwgODYwNSw0NzE3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODY1Niw0NzMxIEwgODcwOCw0NzQ0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODc1OSw0NzU3IEwgODgxMSw0NzcwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODg2Miw0Nzg0IEwgODkxMyw0Nzk3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gODk2NSw0ODEwIEwgOTAxNiw0ODI0Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTA2OCw0ODM3IEwgOTExOSw0ODUwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTE3MCw0ODYzIEwgOTIyMiw0ODc3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTI3Myw0ODkwIEwgOTMyNSw0OTAzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTM3Niw0OTE2IEwgOTQyNyw0OTMwIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTQ3OSw0OTQzIEwgOTUzMCw0OTU2Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTU4Miw0OTY5IEwgOTYzMyw0OTgzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gOTY4NCw0OTk2IEwgOTcwMCw1MDAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTUiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNjUwLDI3MDAgTCAxMDcwMCwyNzAwIDEwNzAwLDE1MDAgMTQ2MDAsMTUwMCAxNDYwMCwyNzAwIDEyNjUwLDI3MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTA5NTAiIHk9IjIwMjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMDk1MCIgeT0iMjQxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTYiPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyODUwLDg1MDAgTCAxMDkwMCw4NTAwIDEwOTAwLDczMDAgMTQ4MDAsNzMwMCAxNDgwMCw4NTAwIDEyODUwLDg1MDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9Ijc4MjQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPkNvcm5lciBwb2ludHMgc3RhcnQgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iODIxOCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+d2l0aCB0aGUgc2FtZSB2YWx1ZXM8L3RzcGFuPjwvdHNwYW4+PC90c3Bhbj48L3RleHQ+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkN1c3RvbVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTciPgogICAgICAgPHBhdGggZmlsbD0icmdiKDI1NSwyNTUsMjU1KSIgc3Ryb2tlPSJub25lIiBkPSJNIDEyNDAwLDUyMDAgTCAxMDkwMCw1MjAwIDEwOTAwLDMzMDAgMTM5MDAsMzMwMCAxMzkwMCw1MjAwIDEyNDAwLDUyMDAgWiIvPgogICAgICAgPHRleHQgY2xhc3M9IlRleHRTaGFwZSI+PHRzcGFuIGNsYXNzPSJUZXh0UGFyYWdyYXBoIiBmb250LWZhbWlseT0iTGliZXJhdGlvbiBTYW5zLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjM1M3B4IiBmb250LXdlaWdodD0iNDAwIj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjM3ODAiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPk9wcG9zaW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQxNzQiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmRpcmVjdGlvbnMgb2YgPC90c3Bhbj48L3RzcGFuPjx0c3BhbiBjbGFzcz0iVGV4dFBvc2l0aW9uIiB4PSIxMTE1MCIgeT0iNDU2OCI+PHRzcGFuIGZpbGw9InJnYigwLDAsMCkiIHN0cm9rZT0ibm9uZSI+ZWRnZSB3YWxraW5nIDwvdHNwYW4+PC90c3Bhbj48dHNwYW4gY2xhc3M9IlRleHRQb3NpdGlvbiIgeD0iMTExNTAiIHk9IjQ5NjIiPjx0c3BhbiBmaWxsPSJyZ2IoMCwwLDApIiBzdHJva2U9Im5vbmUiPmZvciBzdWJkaXZpc2lvbjwvdHNwYW4+PC90c3Bhbj48L3RzcGFuPjwvdGV4dD4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBjbGFzcz0iY29tLnN1bi5zdGFyLmRyYXdpbmcuTGluZVNoYXBlIj4KICAgICAgPGcgaWQ9ImlkMTgiPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMzAwLDI5MDAgTCAxMDM0MSwyODY3Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzODMsMjgzNCBMIDEwNDI0LDI4MDEiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ2NiwyNzY3IEwgMTA1MDcsMjczNCIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ5LDI3MDEgTCAxMDU5MCwyNjY4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsMjYzNSBMIDEwNjczLDI2MDIiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxNSwyNTY4IEwgMTA3NTYsMjUzNSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNzk3LDI1MDIgTCAxMDgwMCwyNTAwIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgY2xhc3M9ImNvbS5zdW4uc3Rhci5kcmF3aW5nLkxpbmVTaGFwZSI+CiAgICAgIDxnIGlkPSJpZDE5Ij4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDIwMCw3MTAwIEwgMTAyNDMsNzEzMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwMjg2LDcxNjIgTCAxMDMzMCw3MTkzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTAzNzMsNzIyMyBMIDEwNDE2LDcyNTQiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDQ1OSw3Mjg1IEwgMTA1MDIsNzMxNiIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwNTQ2LDczNDcgTCAxMDU4OSw3Mzc4Ii8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA2MzIsNzQwOSBMIDEwNjc1LDc0MzkiLz4KICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsMCwwKSIgZD0iTSAxMDcxOCw3NDcwIEwgMTA3NjIsNzUwMSIvPgogICAgICAgPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBkPSJNIDEwODA1LDc1MzIgTCAxMDg0OCw3NTYzIi8+CiAgICAgICA8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLDAsMCkiIGQ9Ik0gMTA4OTEsNzU5NCBMIDEwOTAwLDc2MDAiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgPC9nPgogIDwvZz4KIDwvZz4KPC9zdmc+" alt="precise">
+</div>
+</div>
+<div class="paragraph">
+<p>Without any qualifiers, implementations are permitted to perform
+optimizations that effectively modify the order or number of operations used
+to evaluate an expression, even if those optimizations may produce slightly
+different results relative to unoptimized code.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>precise</strong> qualifier ensures that operations contributing to a
+variable&#8217;s value are done in their stated order and with operator consistency.
+The order is determined by operator precedence and parenthesis, as described in
+&#8220;<a href="#operators">Operators</a>&#8221;.
+Operator consistency means for each particular operator, for example the
+multiply operator (<strong>*</strong>), its operation is always computed with the same
+precision.
+Specifically, values computed by compiler-generated code must adhere to the
+following identities:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>a + b = b + a</p>
+</li>
+<li>
+<p>a * b = b * a</p>
+</li>
+<li>
+<p>a * b + c * d = b * a + c* d = d * c + b * a = &lt;any other mathematically
+valid combination&gt;</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>While the following are prevented:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>a + (b + c) is not allowed to become (a + b) + c</p>
+</li>
+<li>
+<p>a * (b * c) is not allowed to become (a * b) * c</p>
+</li>
+<li>
+<p>a * b + c is not allowed to become a single operation <strong>fma</strong>(a, b, c)</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Where <em>a</em>, <em>b</em>, <em>c</em>, and <em>d</em>, are scalars or vectors, not matrices.
+(Matrix multiplication generally does not commute.) It is the shader
+writer&#8217;s responsibility to express the computation in terms of these rules
+and the compiler&#8217;s responsibility to follow these rules.
+See the description of <em>gl_TessCoord</em> for the rules the tessellation stages
+are responsible for following, which in conjunction with the above allow
+avoiding cracking when subdividing.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">precise out vec4 position;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>declares that operations used to produce the value of <em>position</em> must be
+performed in exactly the order specified in the source code and with all
+operators being treated consistently.
+As with the <strong>invariant</strong> qualifier (see &#8220;<a href="#the-invariant-qualifier">The
+Invariant Qualifier</a>&#8221;), the <strong>precise</strong> qualifier may be used to qualify a
+built-in or previously declared user-defined variable as being precise:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec3 Color;
+precise Color; <span class="comment">// make existing Color be precise</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When applied to a block, a structure type, or a variable of structure type,
+<strong>precise</strong> applies to each contained member, recursively.</p>
+</div>
+<div class="paragraph">
+<p>This qualifier will affect the evaluation of an r-value in a particular
+function if and only if the result is eventually consumed in the same
+function by an l-value qualified as <strong>precise</strong>.
+Any other expressions within a function are not affected, including return
+values and output parameters not declared as <strong>precise</strong> but that are
+eventually consumed outside the function by a variable qualified as
+<strong>precise</strong>. Unaffected expressions also include the controlling expressions
+in selection and iteration statements and the condition in ternary
+operators (<strong>?:</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Some examples of the use of <strong>precise</strong>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 a, b, c, d;
+precise out vec4 v;
+
+<span class="predefined-type">float</span> func(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h)
+{
+    <span class="keyword">return</span> (e*f) + (g*h); <span class="comment">// no constraint on order or operator consistency</span>
+}
+
+<span class="predefined-type">float</span> func2(<span class="predefined-type">float</span> e, <span class="predefined-type">float</span> f, <span class="predefined-type">float</span> g, <span class="predefined-type">float</span> h)
+{
+    precise <span class="predefined-type">float</span> result = (e*f) + (g*h); <span class="comment">// ensures same precision for the two multiplies</span>
+    <span class="keyword">return</span> result;
+}
+
+<span class="predefined-type">float</span> func3(<span class="predefined-type">float</span> i, <span class="predefined-type">float</span> j, precise out <span class="predefined-type">float</span> k)
+{
+    k = i * i + j;        <span class="comment">// precise, due to &lt;k&gt; declaration</span>
+}
+
+<span class="directive">void</span> main()
+{
+    vec3 r = vec3(a * b);             <span class="comment">// precise, used to compute v.xyz</span>
+    vec3 s = vec3(c * d);             <span class="comment">// precise, used to compute v.xyz</span>
+    v.xyz = r + s;                    <span class="comment">// precise</span>
+    v.w = (a.w * b.w) + (c.w * d.w);  <span class="comment">// precise</span>
+    v.x = func(a.x, b.x, c.x, d.x);   <span class="comment">// values computed in func() are NOT precise</span>
+    v.x = func2(a.x, b.x, c.x, d.x);  <span class="comment">// precise!</span>
+    func3(a.x * b.x, c.x * d.x, v.x); <span class="comment">// precise!</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>For the purposes of determining if an output from one shader stage matches
+an input of the next stage, the <strong>precise</strong> qualifier need not match between
+the input and the output.</p>
+</div>
+<div class="paragraph">
+<p>All constant expressions are evaluated as if <strong>precise</strong> was present, whether
+or not it is present.
+However, as described in &#8220;<a href="#constant-expressions">Constant Expressions</a>&#8221;,
+there is no requirement that a compile-time constant expression evaluates to
+the same value as a corresponding non-constant expression.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="memory-qualifiers">4.10. Memory Qualifiers</h3>
+<div class="paragraph">
+<p>Shader storage blocks, variables declared within shader storage blocks and
+variables declared as image types (the basic opaque types with &#8220;<strong>image</strong>&#8221;
+in their keyword), can be further qualified with one or more of the
+following memory qualifiers:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Qualifier</th>
+<th class="tableblock halign-left valign-top">Meaning</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>coherent</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where reads and writes are coherent with
+                reads and writes from other shader invocations</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>volatile</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable whose underlying value may be changed at any
+                point during shader execution by some source other than the
+                current shader invocation</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>restrict</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable where use of that variable is the only way
+                to read and write the underlying memory in the relevant
+                shader stage</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>readonly</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to read the underlying
+                memory, but cannot be used to write the underlying memory</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>writeonly</strong></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">memory variable that can be used to write the underlying
+                memory, but cannot be used to read the underlying memory</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>coherent</strong> qualifier
+are performed coherently with accesses to the same location from other
+shader invocations.
+In particular, when reading a variable declared as <strong>coherent</strong>, the values
+returned will reflect the results of previously completed writes performed
+by other shader invocations.
+When writing a variable declared as <strong>coherent</strong>, the values written will be
+reflected in subsequent coherent reads performed by other shader
+invocations.</p>
+</div>
+<div class="paragraph">
+<p>As described in section
+7.12
+&#8220;Shader Memory Access&#8221; of the
+<a href="#references">OpenGL Specification</a>, shader memory reads and writes complete in a
+largely undefined order.
+The built-in function <strong>memoryBarrier</strong>() can be used if needed to guarantee
+the completion and relative ordering of memory accesses performed by a
+single shader invocation.</p>
+</div>
+<div class="paragraph">
+<p>When accessing memory using variables not declared as <strong>coherent</strong>, the memory
+accessed by a shader may be cached by the implementation to service future
+accesses to the same address.
+Memory stores may be cached in such a way that the values written may not be
+visible to other shader invocations accessing the same memory.
+The implementation may cache the values fetched by memory reads and return
+the same values to any shader invocation accessing the same memory, even if
+the underlying memory has been modified since the first memory read.
+While variables not declared as <strong>coherent</strong> may not be useful for
+communicating between shader invocations, using non-coherent accesses may
+result in higher performance.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>volatile</strong> qualifier
+must treat the underlying memory as though it could be read or written at
+any point during shader execution by some source other than the executing
+shader invocation.
+When a volatile variable is read, its value must be re-fetched from the
+underlying memory, even if the shader invocation performing the read had
+previously fetched its value from the same memory.
+When a volatile variable is written, its value must be written to the
+underlying memory, even if the compiler can conclusively determine that its
+value will be overwritten by a subsequent write.
+Since the external source reading or writing a <strong>volatile</strong> variable may be
+another shader invocation, variables declared as <strong>volatile</strong> are
+automatically treated as coherent.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>restrict</strong> qualifier
+may be compiled assuming that the variable used to perform the memory access
+is the only way to access the underlying memory using the shader stage in
+question.
+This allows the compiler to coalesce or reorder loads and stores using
+<strong>restrict</strong>-qualified image variables in ways that wouldn&#8217;t be permitted
+for image variables not so qualified, because the compiler can assume that
+the underlying image won&#8217;t be read or written by other code.
+Applications are responsible for ensuring that image memory referenced by
+variables qualified with <strong>restrict</strong> will not be referenced using other
+variables in the same scope; otherwise, accesses to <strong>restrict</strong>-qualified
+variables will have undefined results.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>readonly</strong> qualifier
+may only read the underlying memory, which is treated as read-only memory
+and cannot be written to.
+It is a compile-time error to pass an image variable qualified with
+<strong>readonly</strong> to <strong>imageStore</strong>() or other built-in functions that modify image
+memory.</p>
+</div>
+<div class="paragraph">
+<p>Memory accesses to image variables declared using the <strong>writeonly</strong> qualifier
+may only write the underlying memory; the underlying memory cannot be read.
+It is a compile-time error to pass an image variable qualified with
+<strong>writeonly</strong> to <strong>imageLoad</strong>() or other built-in functions that read image
+memory.</p>
+</div>
+<div class="paragraph">
+<p>A variable could be qualified as both <strong>readonly</strong> and <strong>writeonly</strong>, disallowing
+both read and write. Such variables can still be used with some queries, for
+example <strong>imageSize</strong>() and <strong>.length</strong>().</p>
+</div>
+<div class="paragraph">
+<p>The memory qualifiers <strong>coherent</strong>, <strong>volatile</strong>, <strong>restrict</strong>, <strong>readonly</strong>, and
+<strong>writeonly</strong> may be used in the declaration of buffer variables (i.e.,
+members of shader storage blocks).
+When a buffer variable is declared with a memory qualifier, the behavior
+specified for memory accesses involving image variables described above
+applies identically to memory accesses involving that buffer variable.
+It is a compile-time error to assign to a buffer variable qualified with
+<strong>readonly</strong> or to read from a buffer variable qualified with <strong>writeonly</strong>.
+The combination <strong>readonly</strong> <strong>writeonly</strong> is allowed.</p>
+</div>
+<div class="paragraph">
+<p>Additionally, memory qualifiers may be used at the block-level declaration
+of a shader storage block, including the combination <strong>readonly</strong> <strong>writeonly</strong>.
+When a block declaration is qualified with a memory qualifier, it is as if
+all of its members were declared with the same memory qualifier.
+For example, the block declaration</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">coherent buffer Block {
+    readonly vec4 member1;
+    vec4 member2;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">buffer Block {
+    coherent readonly vec4 member1;
+    coherent vec4 member2;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Memory qualifiers are only supported in the declarations of image variables,
+buffer variables, and shader storage blocks; it is an error to use such
+qualifiers in any other declarations.</p>
+</div>
+<div class="paragraph">
+<p>When calling user-defined functions, variables qualified with <strong>coherent</strong>,
+<strong>volatile</strong>, <strong>readonly</strong>, or <strong>writeonly</strong> may not be passed to functions whose
+formal parameters lack such qualifiers.
+(See &#8220;<a href="#function-definitions">Function Definitions</a>&#8221; for more detail on
+function calling.) It is legal to have any additional memory qualifiers on a
+formal parameter, but only <strong>restrict</strong> can be taken away from a calling
+argument, by a formal parameter that lacks the <strong>restrict</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When a built-in function is called, the code generated is to be based on the
+actual qualification of the calling argument, not on the list of memory
+qualifiers specified on the formal parameter in the prototype.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 funcA(restrict image2D a) { ... }
+vec4 funcB(image2D a) { ... }
+layout(rgba32f) uniform image2D img1;
+layout(rgba32f) coherent uniform image2D img2;
+
+funcA(img1);        <span class="comment">// OK, adding &quot;restrict&quot; is allowed</span>
+funcB(img2);        <span class="comment">// illegal, stripping &quot;coherent&quot; is not</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Layout qualifiers cannot be used on formal function parameters, and layout
+qualification is not included in parameter matching.</p>
+</div>
+<div class="paragraph">
+<p>Note that the use of <strong>const</strong> in an image variable declaration is qualifying
+the const-ness of the variable being declared, not the image it refers to.
+The qualifier <strong>readonly</strong> qualifies the image memory (as accessed through
+that variable) while <strong>const</strong> qualifies the variable itself.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="specialization-constant-qualifier">4.11. Specialization-Constant Qualifier</h3>
+<div class="paragraph">
+<p>Specialization constants are used only for SPIR-V and declared using the
+<strong>constant_id</strong> layout qualifier.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">17</span>) <span class="directive">const</span> <span class="predefined-type">int</span> arraySize = <span class="integer">12</span>;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The above makes a specialization constant with a default value of 12.
+The number 17 is an example author-chosen id by which the API or other tools
+can later refer to this specific specialization constant.
+If it is never changed before final lowering, it will retain the value of
+12.
+It is a compile-time error to use the <strong>constant_id</strong> qualifier on anything
+but SPIR-V generation of a scalar <strong>bool</strong>, <strong>int</strong>, <strong>uint</strong>, <strong>float</strong>, or
+<strong>double</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Built-in constants can be declared to be specialization constants.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">31</span>) gl_MaxClipDistances; <span class="comment">// add specialization_id</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The declaration uses just the name of the previously declared built-in
+variable, with a <strong>constant_id</strong> layout-qualifier declaration.
+It is a compile-time error to do this after the constant has been used:
+Constants are strictly either non-specialization constants or specialization
+constants, not both.</p>
+</div>
+<div class="paragraph">
+<p>The built-in constant vector <em>gl_WorkGroupSize</em> can be specialized using the
+<strong>local_size_{xyz}_id</strong> qualifiers, to individually give the components an id.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x_id = <span class="integer">18</span>, local_size_z_id = <span class="integer">19</span>) in;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This leaves <em>gl_WorkGroupSize.y</em> as a non-specialization constant, with
+<em>gl_WorkGroupSize</em> being a partially specialized vector.
+Its <em>x</em> and <em>z</em> components can be later specialized, after generating
+SPIR-V, using the ids 18 and 19.
+These ids are declared independently from declaring the workgroup size:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(local_size_x = <span class="integer">32</span>, local_size_y = <span class="integer">32</span>) in;   <span class="comment">// size is (32,32,1)</span>
+layout(local_size_x_id = <span class="integer">18</span>) in;                   <span class="comment">// constant_id for x</span>
+layout(local_size_z_id = <span class="integer">19</span>) in;                   <span class="comment">// constant_id for z</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Existing rules for declaring <strong>local_size_x</strong>, <strong>local_size_y</strong>, and
+<strong>local_size_z</strong> are not changed.
+For the local-size ids, it is a compile-time error to provide different id
+values for the same local-size id, or to provide them after any use.
+Otherwise, order, placement, number of statements, and replication do not
+cause errors.</p>
+</div>
+<div class="paragraph">
+<p>Two arrays sized with specialization constants are the same type only if
+sized with the same symbol, and involving no operations.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">layout(constant_id = <span class="integer">51</span>) <span class="directive">const</span> <span class="predefined-type">int</span> aSize = <span class="integer">20</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> pad = <span class="integer">2</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> total = aSize + pad; <span class="comment">// specialization constant</span>
+<span class="predefined-type">int</span> a[total], b[total];        <span class="comment">// a and b have the same type</span>
+<span class="predefined-type">int</span> c[<span class="integer">22</span>];                     <span class="comment">// different type than a or b</span>
+<span class="predefined-type">int</span> d[aSize + pad];            <span class="comment">// different type than a, b, or c</span>
+<span class="predefined-type">int</span> e[aSize + <span class="integer">2</span>];              <span class="comment">// different type than a, b, c, or d</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Types containing arrays sized with a specialization constant cannot be
+compared, assigned as aggregates, declared with an initializer, or used as
+an initializer.
+They can, however, be passed as arguments to functions having formal
+parameters of the same type.
+Only the outer-most dimension of a variable declared as an array of arrays
+can be a specialization constant, otherwise a compile-time error results.</p>
+</div>
+<div class="paragraph">
+<p>Arrays inside a block may be sized with a specialization constant, but the
+block will have a static layout.
+Changing the specialized size will not re-layout the block.
+In the absence of explicit offsets, the layout will be based on the default
+size of the array.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="order-of-qualification">4.12. Order and Repetition of Qualification</h3>
+<div class="paragraph">
+<p>When multiple qualifiers are present in a declaration, they may appear in
+any order, but they must all appear before the type.
+The <strong>layout</strong> qualifier is the only qualifier that can appear more than once.
+Further, a declaration can have at most one storage qualifier, at most one
+auxiliary storage qualifier, and at most one interpolation qualifier.
+If <strong>inout</strong> is used, neither <strong>in</strong> nor <strong>out</strong> may be used.
+Multiple memory qualifiers can be used.
+Any violation of these rules will cause a compile-time error.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="empty-declarations">4.13. Empty Declarations</h3>
+<div class="paragraph">
+<p><em>Empty declarations</em> are declarations without a variable name, meaning no
+object is instantiated by the declaration.
+Generally, empty declarations are allowed.
+Some are useful when declaring structures, while many others have no effect.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>;               <span class="comment">// No effect</span>
+<span class="keyword">struct</span> S {<span class="predefined-type">int</span> x;}; <span class="comment">// Defines a struct S</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The combinations of qualifiers that cause compile-time or link-time errors
+are the same whether or not the declaration is empty, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">invariant in <span class="predefined-type">float</span> x; <span class="comment">// Error. An input cannot be invariant.</span>
+invariant in <span class="predefined-type">float</span>;   <span class="comment">// Error even though no variable is declared.</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="operators-and-expressions">5. Operators and Expressions</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="operators">5.1. Operators</h3>
+<div class="paragraph">
+<p>The OpenGL Shading Language has the following operators.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Precedence</th>
+<th class="tableblock halign-left valign-top">Operator Class</th>
+<th class="tableblock halign-left valign-top">Operators</th>
+<th class="tableblock halign-left valign-top">Associativity</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1 (highest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">parenthetical grouping</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">( )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">NA</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">array subscript<br>
+                 function call and constructor structure<br>
+                 field or method selector, swizzle<br>
+                 post fix increment and decrement</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">[ ]<br>
+                                                  ( )<br>
+                                                  .<br>
+                                                  ++ --</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">prefix increment and decrement<br>
+                 unary</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">++ --<br>
+                                                  + - ~ !</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">multiplicative</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">* / %</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">additive</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">+ -</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">6</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise shift</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;&lt; &gt;&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">7</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">relational</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&lt; &gt; &lt;= &gt;=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">8</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">== !=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">9</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">10</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">11</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bit-wise inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">|</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">12</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical and</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">&amp;&amp;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">13</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical exclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">^^</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">14</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">logical inclusive or</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">||</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">selection</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">? :</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">16</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Assignment<br>
+                 arithmetic assignments</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">=<br>
+                                                  += -=<br>
+                                                  *= /=<br>
+                                                  %= &lt;&lt;= &gt;&gt;=<br>
+                                                  &amp;= ^= |=</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Right to Left</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">17 (lowest)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">sequence</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">,</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Left to Right</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>There is no address-of operator nor a dereference operator.
+There is no typecast operator; constructors are used instead.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="array-operations">5.2. Array Operations</h3>
+<div class="paragraph">
+<p>These are now described in &#8220;<a href="#structure-and-array-operations">Structure and
+Array Operations</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="function-calls">5.3. Function Calls</h3>
+<div class="paragraph">
+<p>If a function returns a value, then a call to that function may be used as
+an expression, whose type will be the type that was used to declare or
+define the function.</p>
+</div>
+<div class="paragraph">
+<p>Function definitions and calling conventions are discussed in
+&#8220;<a href="#function-definitions">Function Definitions</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="constructors">5.4. Constructors</h3>
+<div class="paragraph">
+<p>Constructors use the function call syntax, where the function name is a
+type, and the call makes an object of that type.
+Constructors are used the same way in both initializers and expressions.
+(See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for details.)
+The parameters are used to initialize the constructed value.
+Constructors can be used to request a data type conversion to change from
+one scalar type to another scalar type, or to build larger types out of
+smaller types, or to reduce a larger type to a smaller type.</p>
+</div>
+<div class="paragraph">
+<p>In general, constructors are not built-in functions with predetermined
+prototypes.
+For arrays and structures, there must be exactly one argument in the
+constructor for each element or member.
+For the other types, the arguments must provide a sufficient number of
+components to perform the initialization, and it is a compile-time error to
+include so many arguments that they cannot all be used.
+Detailed rules follow.
+The prototypes actually listed below are merely a subset of examples.</p>
+</div>
+<div class="sect3">
+<h4 id="conversion-and-scalar-constructors">5.4.1. Conversion and Scalar Constructors</h4>
+<div class="paragraph">
+<p>Converting between scalar types is done as the following prototypes
+indicate:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">int</span>(uint)     <span class="comment">// converts an unsigned integer to a signed integer</span>
+<span class="predefined-type">int</span>(<span class="predefined-type">bool</span>)     <span class="comment">// converts a Boolean value to an int</span>
+<span class="predefined-type">int</span>(<span class="predefined-type">float</span>)    <span class="comment">// converts a float value to an int</span>
+<span class="predefined-type">int</span>(<span class="predefined-type">double</span>)   <span class="comment">// converts a double value to a signed integer</span>
+uint(<span class="predefined-type">int</span>)     <span class="comment">// converts a signed integer value to an unsigned integer</span>
+uint(<span class="predefined-type">bool</span>)    <span class="comment">// converts a Boolean value to an unsigned integer</span>
+uint(<span class="predefined-type">float</span>)   <span class="comment">// converts a float value to an unsigned integer</span>
+uint(<span class="predefined-type">double</span>)  <span class="comment">// converts a double value to an unsigned integer</span>
+<span class="predefined-type">bool</span>(<span class="predefined-type">int</span>)     <span class="comment">// converts a signed integer value to a Boolean</span>
+<span class="predefined-type">bool</span>(uint)    <span class="comment">// converts an unsigned integer value to a Boolean value</span>
+<span class="predefined-type">bool</span>(<span class="predefined-type">float</span>)   <span class="comment">// converts a float value to a Boolean</span>
+<span class="predefined-type">bool</span>(<span class="predefined-type">double</span>)  <span class="comment">// converts a double value to a Boolean</span>
+<span class="predefined-type">float</span>(<span class="predefined-type">int</span>)    <span class="comment">// converts a signed integer value to a float</span>
+<span class="predefined-type">float</span>(uint)   <span class="comment">// converts an unsigned integer value to a float value</span>
+<span class="predefined-type">float</span>(<span class="predefined-type">bool</span>)   <span class="comment">// converts a Boolean value to a float</span>
+<span class="predefined-type">float</span>(<span class="predefined-type">double</span>) <span class="comment">// converts a double value to a float</span>
+<span class="predefined-type">double</span>(<span class="predefined-type">int</span>)   <span class="comment">// converts a signed integer value to a double</span>
+<span class="predefined-type">double</span>(uint)  <span class="comment">// converts an unsigned integer value to a double</span>
+<span class="predefined-type">double</span>(<span class="predefined-type">bool</span>)  <span class="comment">// converts a Boolean value to a double</span>
+<span class="predefined-type">double</span>(<span class="predefined-type">float</span>) <span class="comment">// converts a float value to a double</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When constructors are used to convert a floating-point type to an integer
+type, the fractional part of the floating-point value is dropped.
+It is undefined to convert a negative floating-point value to an <strong>uint</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Integer values having more bits of precision than a single-precision
+floating-point mantissa will lose precision when converted to <strong>float</strong>.</p>
+</div>
+<div class="paragraph">
+<p>When a constructor is used to convert any integer or floating-point type to
+a <strong>bool</strong>, 0 and 0.0 are converted to <strong>false</strong>, and non-zero values are
+converted to <strong>true</strong>.
+When a constructor is used to convert a <strong>bool</strong> to any integer or
+floating-point type, <strong>false</strong> is converted to 0 or 0.0, and <strong>true</strong> is
+converted to 1 or 1.0.</p>
+</div>
+<div class="paragraph">
+<p>The constructor <strong>int</strong>(<strong>uint</strong>) preserves the bit pattern in the argument,
+which will change the argument&#8217;s value if its sign bit is set.
+The constructor <strong>uint</strong>(<strong>int</strong>) preserves the bit pattern in the argument,
+which will change its value if it is negative.</p>
+</div>
+<div class="paragraph">
+<p>Identity constructors, like <strong>float</strong>(<strong>float</strong>) are also legal, but of little
+use.</p>
+</div>
+<div class="paragraph">
+<p>Scalar constructors with non-scalar parameters can be used to take the first
+element from a non-scalar.
+For example, the constructor <strong>float</strong>(<strong>vec3</strong>) will select the first component
+of the <strong>vec3</strong> parameter.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="vector-and-matrix-constructors">5.4.2. Vector and Matrix Constructors</h4>
+<div class="paragraph">
+<p>Constructors can be used to create vectors or matrices from a set of
+scalars, vectors, or matrices.
+This includes the ability to shorten vectors.</p>
+</div>
+<div class="paragraph">
+<p>If there is a single scalar parameter to a vector constructor, it is used to
+initialize all components of the constructed vector to that scalar&#8217;s value.
+If there is a single scalar parameter to a matrix constructor, it is used to
+initialize all the components on the matrix&#8217;s diagonal, with the remaining
+components initialized to 0.0.</p>
+</div>
+<div class="paragraph">
+<p>If a vector is constructed from multiple scalars, one or more vectors, or
+one or more matrices, or a mixture of these, the vector&#8217;s components will be
+constructed in order from the components of the arguments.
+The arguments will be consumed left to right, and each argument will have
+all its components consumed, in order, before any components from the next
+argument are consumed.
+Similarly for constructing a matrix from multiple scalars or vectors, or a
+mixture of these.
+Matrix components will be constructed and consumed in column major order.
+In these cases, there must be enough components provided in the arguments to
+provide an initializer for every component in the constructed value.
+It is a compile-time error to provide extra arguments beyond this last used
+argument.</p>
+</div>
+<div class="paragraph">
+<p>If a matrix is constructed from a matrix, then each component (column <em>i</em>,
+row <em>j</em>) in the result that has a corresponding component (column <em>i</em>, row
+<em>j</em>) in the argument will be initialized from there.
+All other components will be initialized to the identity matrix.
+If a matrix argument is given to a matrix constructor, it is
+a compile-time error to have any other arguments.</p>
+</div>
+<div class="paragraph">
+<p>If the basic type (<strong>bool</strong>, <strong>int</strong>,
+<strong>float</strong>, or <strong>double</strong>)
+of a parameter to a
+constructor does not match the basic type of the object being constructed,
+the scalar construction rules (above) are used to convert the parameters.</p>
+</div>
+<div class="paragraph">
+<p>Some useful vector constructors are as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3(<span class="predefined-type">float</span>)          <span class="comment">// initializes each component of the vec3 with the float</span>
+vec4(ivec4)          <span class="comment">// makes a vec4 with component-wise conversion</span>
+vec4(mat2)           <span class="comment">// the vec4 is column 0 followed by column 1</span>
+vec2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>)   <span class="comment">// initializes a vec2 with 2 floats</span>
+ivec3(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">int</span>) <span class="comment">// initializes an ivec3 with 3 ints</span>
+bvec4(<span class="predefined-type">int</span>, <span class="predefined-type">int</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>) <span class="comment">// uses 4 Boolean conversions</span>
+vec2(vec3)           <span class="comment">// drops the third component of a vec3</span>
+vec3(vec4)           <span class="comment">// drops the fourth component of a vec4</span>
+vec3(vec2, <span class="predefined-type">float</span>)    <span class="comment">// vec3.x = vec2.x, vec3.y = vec2.y, vec3.z = float</span>
+vec3(<span class="predefined-type">float</span>, vec2)    <span class="comment">// vec3.x = float, vec3.y = vec2.x, vec3.z = vec2.y</span>
+vec4(vec3, <span class="predefined-type">float</span>)
+vec4(<span class="predefined-type">float</span>, vec3)
+vec4(vec2, vec2)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Some examples of these are:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 color = vec4(<span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>, <span class="float">0</span><span class="float">.0</span>, <span class="float">1</span><span class="float">.0</span>);
+vec4 rgba = vec4(<span class="float">1</span><span class="float">.0</span>);      <span class="comment">// sets each component to 1.0</span>
+vec3 rgb = vec3(color);     <span class="comment">// drop the 4th component</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To initialize the diagonal of a matrix with all other elements set to zero:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2(<span class="predefined-type">float</span>)
+mat3(<span class="predefined-type">float</span>)
+mat4(<span class="predefined-type">float</span>)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>That is, <em>result[i][j]</em> is set to the <em>float</em> argument for all \(i
+= j\) and set to 0 for all \(i \neq j\).</p>
+</div>
+<div class="paragraph">
+<p>To initialize a matrix by specifying vectors or scalars, the components are
+assigned to the matrix elements in column-major order.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat2(vec2, vec2);                 <span class="comment">// one column per argument</span>
+mat3(vec3, vec3, vec3);           <span class="comment">// one column per argument</span>
+mat4(vec4, vec4, vec4, vec4);     <span class="comment">// one column per argument</span>
+mat3x2(vec2, vec2, vec2);         <span class="comment">// one column per argument</span>
+dmat2(dvec2, dvec2);
+dmat3(dvec3, dvec3, dvec3);
+dmat4(dvec4, dvec4, dvec4, dvec4);
+mat2(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>,                <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>);               <span class="comment">// second column</span>
+mat3(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,         <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,         <span class="comment">// second column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>);        <span class="comment">// third column</span>
+mat4(<span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// first column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// second column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>,  <span class="comment">// third column</span>
+     <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>, <span class="predefined-type">float</span>); <span class="comment">// fourth column</span>
+mat2x3(vec2, <span class="predefined-type">float</span>,               <span class="comment">// first column</span>
+       vec2, <span class="predefined-type">float</span>);              <span class="comment">// second column</span>
+dmat2x4(dvec3, <span class="predefined-type">double</span>,            <span class="comment">// first column</span>
+        <span class="predefined-type">double</span>, dvec3);           <span class="comment">// second column</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A wide range of other possibilities exist, to construct a matrix from
+vectors and scalars, as long as enough components are present to initialize
+the matrix.
+To construct a matrix from a matrix:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat3x3(mat4x4); <span class="comment">// takes the upper-left 3x3 of the mat4x4</span>
+mat2x3(mat4x2); <span class="comment">// takes the upper-left 2x2 of the mat4x4, last row is 0,0</span>
+mat4x4(mat3x3); <span class="comment">// puts the mat3x3 in the upper-left, sets the lower right</span>
+                <span class="comment">// component to 1, and the rest to 0</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="structure-constructors">5.4.3. Structure Constructors</h4>
+<div class="paragraph">
+<p>Once a structure is defined, and its type is given a name, a constructor is
+available with the same name to construct instances of that structure.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">struct</span> light {
+    <span class="predefined-type">float</span> intensity;
+    vec3 position;
+};
+
+light lightVar = light(<span class="float">3</span><span class="float">.0</span>, vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>));</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The arguments to the constructor will be used to set the structure&#8217;s
+members, in order, using one argument per member.
+Each argument must be the same type as the member it
+sets, or be a type that can be converted to the member&#8217;s type according to
+section &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Structure constructors can be used as initializers or in expressions.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="array-constructors">5.4.4. Array Constructors</h4>
+<div class="paragraph">
+<p>Array types can also be used as constructor names, which can then be used in
+expressions or initializers.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> <span class="predefined-type">float</span> c[<span class="integer">3</span>] = <span class="predefined-type">float</span>[<span class="integer">3</span>](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+<span class="directive">const</span> <span class="predefined-type">float</span> d[<span class="integer">3</span>] = <span class="predefined-type">float</span>[](<span class="float">5</span><span class="float">.0</span>, <span class="float">7</span><span class="float">.2</span>, <span class="float">1</span><span class="float">.1</span>);
+
+<span class="predefined-type">float</span> g;
+...
+<span class="predefined-type">float</span> a[<span class="integer">5</span>] = <span class="predefined-type">float</span>[<span class="integer">5</span>](g, <span class="integer">1</span>, g, <span class="float">2</span><span class="float">.3</span>, g);
+<span class="predefined-type">float</span> b[<span class="integer">3</span>];
+
+b = <span class="predefined-type">float</span>[<span class="integer">3</span>](g, g + <span class="float">1</span><span class="float">.0</span>, g + <span class="float">2</span><span class="float">.0</span>);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There must be exactly the same number of arguments as the size of the array
+being constructed.
+If no size is present in the constructor, then the array is explicitly sized
+to the number of arguments provided.
+The arguments are assigned in order, starting at element 0, to the elements
+of the constructed array.
+Each argument must be the same type as the element type of the
+array, or be
+a type that can be converted to the element type of the array according to
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>Arrays of arrays are similarly constructed, and the size for any dimension
+is <strong class="purple">optional</strong></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 b[<span class="integer">2</span>] = ...;
+vec4[<span class="integer">3</span>][<span class="integer">2</span>](b, b, b);    <span class="comment">// constructor</span>
+vec4[][<span class="integer">2</span>](b, b, b);     <span class="comment">// constructor, valid, size deduced</span>
+vec4[<span class="integer">3</span>][](b, b, b);     <span class="comment">// constructor, valid, size deduced</span>
+vec4[][](b, b, b);      <span class="comment">// constructor, valid, both sizes deduced</span></code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="vector-components">5.5. Vector and Scalar Components and Length</h3>
+<div class="paragraph">
+<p>The names of the components of a vector
+or scalar
+are denoted by a single letter.
+As a notational convenience, several letters are associated with each
+component based on common usage of position, color or texture coordinate
+vectors.
+The individual components can be selected by following the variable name
+with period (<strong>.</strong>) and then the component name.</p>
+</div>
+<div class="paragraph">
+<p>The component names supported are:</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ x, y, z, w }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent points or normals</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ r, g, b, a }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent colors</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><em>{ s, t, p, q }</em></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Useful when accessing vectors that represent texture coordinates</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The component names <em>x</em>, <em>r</em>, and <em>s</em> are, for example, synonyms for the
+same (first) component in a vector.
+They are also the names of the only component in a scalar.</p>
+</div>
+<div class="paragraph">
+<p>Note that the third component of the texture coordinate set, <em>r</em> in
+OpenGL, has been renamed <em>p</em> so as to avoid the confusion with <em>r</em> (for
+red) in a color.</p>
+</div>
+<div class="paragraph">
+<p>Accessing components beyond those declared for the type is
+a compile-time error so, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec2 pos;
+<span class="predefined-type">float</span> height;
+pos.x       <span class="comment">// is legal</span>
+pos.z       <span class="comment">// is illegal</span>
+height.x    <span class="comment">// is legal</span>
+height.y    <span class="comment">// is illegal</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The component selection syntax allows multiple components to be selected by
+appending their names (from the same name set) after the period (<strong>.</strong>).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 v4;
+v4.rgba;    <span class="comment">// is a vec4 and the same as just using v4,</span>
+v4.rgb;     <span class="comment">// is a vec3,</span>
+v4.b;       <span class="comment">// is a float,</span>
+v4.xy;      <span class="comment">// is a vec2,</span>
+v4.xgba;    <span class="comment">// is illegal - the component names do not come from the same set</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>No more than 4 components can be selected.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 v4;
+v4.xyzwxy;      <span class="comment">// is illegal since it has 6 components</span>
+(v4.xyzwxy).xy; <span class="comment">// is illegal since the intermediate value has 6</span>
+components</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The order of the components can be different to swizzle them, or replicated:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);
+vec4 swiz = pos.wzyx;   <span class="comment">// swiz = (4.0, 3.0, 2.0, 1.0)</span>
+vec4 dup = pos.xxyy;    <span class="comment">// dup = (1.0, 1.0, 2.0, 2.0)</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This notation is more concise than the constructor syntax.
+To form an r-value, it can be applied to any expression that results in a
+vector or scalar r-value.</p>
+</div>
+<div class="paragraph">
+<p>The component group notation can occur on the left hand side of an
+expression.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos = vec4(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);
+pos.xw = vec2(<span class="float">5</span><span class="float">.0</span>, <span class="float">6</span><span class="float">.0</span>);        <span class="comment">// pos = (5.0, 2.0, 3.0, 6.0)</span>
+pos.wx = vec2(<span class="float">7</span><span class="float">.0</span>, <span class="float">8</span><span class="float">.0</span>);        <span class="comment">// pos = (8.0, 2.0, 3.0, 7.0)</span>
+pos.xx = vec2(<span class="float">3</span><span class="float">.0</span>, <span class="float">4</span><span class="float">.0</span>);        <span class="comment">// illegal - 'x' used twice</span>
+pos.xy = vec3(<span class="float">1</span><span class="float">.0</span>, <span class="float">2</span><span class="float">.0</span>, <span class="float">3</span><span class="float">.0</span>);   <span class="comment">// illegal - mismatch between vec2 and vec3</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To form an l-value, swizzling must further be applied to an l-value and
+contain no duplicate components. It results in an l-value of scalar or
+vector type, depending on number of components specified.</p>
+</div>
+<div class="paragraph">
+<p>Array subscripting syntax can also be applied to vectors (but not to
+scalars) to provide numeric indexing.
+So in</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 pos;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><em>pos[2]</em> refers to the third element of <em>pos</em> and is equivalent to <em>pos.z</em>.
+This allows variable indexing into a vector, as well as a generic way of
+accessing components.
+Any integer expression can be used as the subscript.
+The first component is at index zero.
+Reading from or writing to a vector using a constant integral expression
+with a value that is negative or greater than or equal to the size of the
+vector results in a compile-time error.
+When indexing with non-constant expressions, behavior is undefined if the
+index is negative, or greater than or equal to the size of the vector.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>length</strong>() method may be applied to vectors (but not scalars).
+The result is the number of components in the vector.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v;
+<span class="directive">const</span> <span class="predefined-type">int</span> L = v.length();</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>sets the constant <em>L</em> to 3.
+The type returned by <strong>.length</strong>() on a vector is <strong>int</strong>, and the value
+returned is a constant expression.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="matrix-components">5.6. Matrix Components</h3>
+<div class="paragraph">
+<p>The components of a matrix can be accessed using array subscripting syntax.
+Applying a single subscript to a matrix treats the matrix as an array of
+column vectors, and selects a single column, whose type is a vector of the
+same size as the (column size of the) matrix.
+The leftmost column is column 0.
+A second subscript would then operate on the resulting vector, as defined
+earlier for vectors.
+Hence, two subscripts select a column and then a row.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat4 m;
+m[<span class="integer">1</span>] = vec4(<span class="float">2</span><span class="float">.0</span>);   <span class="comment">// sets the second column to all 2.0</span>
+m[<span class="integer">0</span>][<span class="integer">0</span>] = <span class="float">1</span><span class="float">.0</span>;      <span class="comment">// sets the upper left element to 1.0</span>
+m[<span class="integer">2</span>][<span class="integer">3</span>] = <span class="float">2</span><span class="float">.0</span>;      <span class="comment">// sets the 4th element of the third column to 2.0</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Behavior is undefined when accessing a component outside the bounds of a
+matrix with a non-constant expression.
+It is a compile-time error to access a matrix with a constant expression
+that is outside the bounds of the matrix.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>length</strong>() method may be applied to matrices.
+The result is the number of columns of the matrix.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat3x4 v;
+<span class="directive">const</span> <span class="predefined-type">int</span> L = v.length();</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>sets the constant <em>L</em> to 3.
+The type returned by <strong>.length</strong>() on a matrix is <strong>int</strong>, and the value
+returned is a constant expression.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="structure-and-array-operations">5.7. Structure and Array Operations</h3>
+<div class="paragraph">
+<p>The members of a structure and the <strong>length</strong>() method of an array are
+selected using the period (<strong>.</strong>).</p>
+</div>
+<div class="paragraph">
+<p>In total, only the following operators are allowed to operate on arrays and
+structures as whole entities:</p>
+</div>
+<table class="tableblock frame-all grid-all fit-content">
+<colgroup>
+<col>
+<col>
+</colgroup>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">field selector</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>.</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">equality</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>==</strong> <strong>!=</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">assignment</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>=</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Ternary operator</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>?:</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Sequence operator</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>,</strong></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">indexing (arrays only)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>[</strong> <strong>]</strong></p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The equality operators and assignment operator are only allowed if the two
+operands are same size and type.
+The operands cannot contain any opaque types.
+Structure types must be of the same declared structure.
+Both array operands must be
+explicitly
+sized.
+When using the equality operators, two structures are equal if and only if
+all the members are component-wise equal, and two arrays are equal if and
+only if all the elements are element-wise equal.</p>
+</div>
+<div class="paragraph">
+<p>Array elements are accessed using the array subscript operator (<strong>[ ]</strong>).
+An example of accessing an array element is</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">diffuseColor += lightIntensity[<span class="integer">3</span>] * NdotL;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Array indices start at zero.
+Array elements are accessed using an expression whose type is <strong>int</strong> or
+<strong>uint</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Behavior is undefined if a shader subscripts an array with an index less
+than 0 or greater than or equal to the size the array was declared with.</p>
+</div>
+<div class="paragraph">
+<p>Arrays can also be accessed with the method operator (<strong>.</strong>) and the <strong>length</strong>
+method to query the size of the array:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">lightIntensity.length() <span class="comment">// return the size of the array</span></code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="assignments">5.8. Assignments</h3>
+<div class="paragraph">
+<p>Assignments of values to variable names are done with the assignment
+operator (<strong>=</strong>):</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue-expression</em> = <em>rvalue-expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>The <em>lvalue-expression</em> evaluates to an l-value.
+The assignment operator stores the value of <em>rvalue-expression</em> into the
+l-value and returns an r-value with the type and precision of
+<em>lvalue-expression</em>.
+The <em>lvalue-expression</em> and <em>rvalue-expression</em> must have the same
+type, or the expression must have a type in the table in section
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; that converts to the type
+of <em>lvalue-expression</em>, in which case an implicit conversion will be done on
+the <em>rvalue-expression</em> before the assignment is done.
+Any other desired type-conversions must be specified explicitly via a
+constructor.
+It is a compile-time error if the l-value is not writable.
+Variables that are built-in types, entire structures or arrays, structure
+members, l-values with the field selector (<strong>.</strong>) applied to select components
+or swizzles without repeated fields, l-values within parentheses, and
+l-values dereferenced with the array subscript operator (<strong>[ ]</strong>) are all
+l-values.
+Other binary or unary expressions, function names, swizzles with repeated
+fields, and constants cannot be l-values.
+The ternary operator (<strong>?:</strong>) is also not allowed as an l-value.
+Using an incorrect expression as an l-value results in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>Expressions on the left of an assignment are evaluated before expressions on
+the right of the assignment.</p>
+</div>
+<div class="paragraph">
+<p>The other assignment operators are</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>add into (<strong>+=</strong>)</p>
+</li>
+<li>
+<p>subtract from (<strong>-=</strong>)</p>
+</li>
+<li>
+<p>multiply into (<strong>*=</strong>)</p>
+</li>
+<li>
+<p>divide into (<strong>/=</strong>)</p>
+</li>
+<li>
+<p>modulus into (<strong>%=</strong>)</p>
+</li>
+<li>
+<p>left shift by (<strong>&lt;&lt;=</strong>)</p>
+</li>
+<li>
+<p>right shift by (<strong>&gt;&gt;=</strong>)</p>
+</li>
+<li>
+<p>and into (<strong>&amp;=</strong>)</p>
+</li>
+<li>
+<p>inclusive-or into (<strong>|=</strong>)</p>
+</li>
+<li>
+<p>exclusive-or into (<strong>^=</strong>)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>where the general expression</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue</em> <em>op</em>= <em>expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>lvalue</em> = <em>lvalue</em> <em>op</em> <em>expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>where <em>lvalue</em> is the value returned by <em>lvalue-expression</em>, <em>op</em> is as
+described below, and the <em>lvalue-expression</em> and <em>expression</em> must satisfy
+the semantic requirements of both <em>op</em> and equals (<strong>=</strong>).</p>
+</div>
+<div class="paragraph">
+<p>Reading a variable before writing (or initializing) it is legal, however the
+value is undefined.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="expressions">5.9. Expressions</h3>
+<div class="paragraph">
+<p>Expressions in the shading language are built from the following:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Constants of type <strong>bool</strong>, all integral types, all floating-point types,
+all vector types, and all matrix types.</p>
+</li>
+<li>
+<p>Constructors of all types.</p>
+</li>
+<li>
+<p>Variable names of all types.</p>
+</li>
+<li>
+<p>An array, vector, or matrix expression with the <strong>length</strong>() method
+applied.</p>
+</li>
+<li>
+<p>Subscripted arrays.</p>
+</li>
+<li>
+<p>Function calls that return values.
+In some cases, function calls returning <strong>void</strong> are also allowed in
+expressions as specified below.</p>
+</li>
+<li>
+<p>Component field selectors and array subscript results.</p>
+</li>
+<li>
+<p>Parenthesized expressions.
+Any expression, including expressions with void type can be
+parenthesized.
+Parentheses can be used to group operations.
+Operations within parentheses are done before operations across
+parentheses.</p>
+</li>
+<li>
+<p>The arithmetic binary operators add (<strong>+</strong>), subtract (<strong>-</strong>), multiply
+(<strong>*</strong>), and divide (<strong>/</strong>) operate on integer and floating-point scalars,
+vectors, and matrices.
+If the fundamental types in the operands do not match, then the
+conversions from &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; are
+applied to create matching types.
+All arithmetic binary operators result in the same fundamental type
+(signed integer, unsigned integer, single-precision floating-point, or
+double-precision floating-point) as the operands they operate on, after
+operand type conversion.
+After conversion, the following cases are valid</p>
+<div class="ulist">
+<ul>
+<li>
+<p>The two operands are scalars.
+In this case the operation is applied, resulting in a scalar.</p>
+</li>
+<li>
+<p>One operand is a scalar, and the other is a vector or matrix.
+In this case, the scalar operation is applied independently to each
+component of the vector or matrix, resulting in the same size vector or
+matrix.</p>
+</li>
+<li>
+<p>The two operands are vectors of the same size.
+In this case, the operation is done component-wise resulting in the
+same size vector.</p>
+</li>
+<li>
+<p>The operator is add (<strong>+</strong>), subtract (<strong>-</strong>), or divide (<strong>/</strong>), and the
+operands are matrices with the same number of rows and the same number
+of columns.
+In this case, the operation is done component-wise resulting in the
+same size matrix.</p>
+</li>
+<li>
+<p>The operator is multiply (<strong>*</strong>), where both operands are matrices or one
+operand is a vector and the other a matrix.
+A right vector operand is treated as a column vector and a left vector
+operand as a row vector.
+In all these cases, it is required that the number of columns of the
+left operand is equal to the number of rows of the right operand.
+Then, the multiply (<strong>*</strong>) operation does a linear algebraic multiply,
+yielding an object that has the same number of rows as the left operand
+and the same number of columns as the right operand.
+&#8220;<a href="#vector-and-matrix-operations">Vector and Matrix Operations</a>&#8221;
+explains in more detail how vectors and matrices are operated on.</p>
+<div class="openblock">
+<div class="content">
+<div class="paragraph">
+<p>All other cases result in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>Use the built-in functions <strong>dot</strong>, <strong>cross</strong>, <strong>matrixCompMult</strong>, and
+<strong>outerProduct</strong>, to get, respectively, vector dot product, vector cross
+product, matrix component-wise multiplication, and the matrix product of a
+column vector times a row vector.</p>
+</div>
+</div>
+</div>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>The operator modulus (<strong>%</strong>) operates on signed or unsigned integers or
+integer vectors.
+If the fundamental types in the operands do not match, then the
+conversions from &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; are
+applied to create matching types.
+The operands cannot be vectors of differing size; this is
+a compile-time error.
+If one operand is a scalar and the other vector, then the scalar is
+applied component-wise to the vector, resulting in the same type as the
+vector.
+If both are vectors of the same size, the result is computed
+component-wise.
+The resulting value is undefined for any component computed with a
+second operand that is zero, while results for other components with
+non-zero second operands remain defined.
+If both operands are non-negative, then the remainder is non-negative.
+Results are undefined if one or both operands are negative.
+The operator modulus (<strong>%</strong>) is not defined for any other data types
+(non-integer types).</p>
+</li>
+<li>
+<p>The arithmetic unary operators negate (<strong>-</strong>), post- and pre-increment and
+decrement (<strong>--</strong> and <strong>++</strong>) operate on integer or floating-point values
+(including vectors and matrices).
+All unary operators work component-wise on their operands.
+These result with the same type they operated on.
+For post- and pre-increment and decrement, the expression must be a writable
+l-value.
+Pre-increment and pre-decrement add or subtract 1 or 1.0 to the contents
+of the expression they operate on, and the value of the pre-increment or
+pre-decrement expression is the resulting value of that modification.
+Post-increment and post-decrement expressions add or subtract 1 or 1.0
+to the contents of the expression they operate on, but the resulting
+expression has the expression&#8217;s value before the post-increment or
+post-decrement was executed.</p>
+</li>
+<li>
+<p>The relational operators greater than (<strong>&gt;</strong>), less than (<strong>&lt;</strong>), greater
+than or equal (<strong>&gt;=</strong>), and less than or equal (<strong>&lt;=</strong>) operate only on
+scalar integer and scalar floating-point expressions.
+The result is scalar Boolean.
+Either the operands' types must match, or the conversions from section
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; will be applied to
+obtain matching types.
+To do component-wise relational comparisons on vectors, use the built-in
+functions <strong>lessThan</strong>, <strong>lessThanEqual</strong>, <strong>greaterThan</strong>, and
+<strong>greaterThanEqual.</strong></p>
+</li>
+<li>
+<p>The equality operators <strong>equal</strong> (<strong>==</strong>), and not equal (<strong>!=</strong>) operate on
+all types except opaque types, aggregates that contain opaque types,
+subroutine uniforms, and aggregates that contain subroutine uniforms.
+They result in a scalar Boolean.
+If the operand types do not match, then there must be a conversion from
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; applied to one operand
+that can make them match, in which case this conversion is done.
+For vectors, matrices, structures, and arrays, all components, members,
+or elements of one operand must equal the corresponding components,
+members, or elements in the other operand for the operands to be
+considered equal.
+To get a vector of component-wise equality results for vectors, use the
+built-in functions <strong>equal</strong> and <strong>notEqual</strong>.</p>
+</li>
+<li>
+<p>The logical binary operators and (<strong>&amp;&amp;</strong>), or (<strong>||</strong>), and exclusive or
+(<strong>^^</strong>) operate only on two Boolean expressions and result in a Boolean
+expression.
+And (<strong>&amp;&amp;</strong>) will only evaluate the right hand operand if the left hand
+operand evaluated to <strong>true</strong>.
+Or (<strong>||</strong>) will only evaluate the right hand operand if the left hand
+operand evaluated to <strong>false</strong>.
+Exclusive or (<strong>^^</strong>) will always evaluate both operands.</p>
+</li>
+<li>
+<p>The logical unary operator not (<strong>!</strong>).
+It operates only on a Boolean expression and results in a Boolean
+expression.
+To operate on a vector, use the built-in function <strong>not</strong>.</p>
+</li>
+<li>
+<p>The sequence (<strong>,</strong>) operator that operates on expressions by returning
+the type and value of the right-most expression in a comma separated
+list of expressions.
+All expressions are evaluated, in order, from left to right.
+The operands to the sequence operator may have <strong>void</strong> type.</p>
+</li>
+<li>
+<p>The ternary selection operator (<strong>?:</strong>).
+It operates on three expressions (<em>exp1</em> <strong>?</strong> <em>exp2</em> <strong>:</strong> <em>exp3</em>).
+This operator evaluates the first expression, which must result in a
+scalar Boolean.
+If the result is true, it selects to evaluate the second expression,
+otherwise it selects to evaluate the third expression.
+Only one of the second and third expressions is evaluated.
+The second and third expressions can be any type, including <strong>void</strong>, as
+long their types match, or there is a conversion in section
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; that can be applied to
+one of the expressions to make their types match.
+This resulting matching type is the type of the entire expression.</p>
+</li>
+<li>
+<p>The one&#8217;s complement operator (<strong>~</strong>).
+The operand must be of type signed or unsigned integer or integer
+vector, and the result is the one&#8217;s complement of its operand; each bit
+of each component is complemented, including any sign bits.</p>
+</li>
+<li>
+<p>The shift operators (<strong>&lt;&lt;</strong>) and (<strong>&gt;&gt;</strong>).
+For both operators, the operands must be signed or unsigned integers or
+integer vectors.
+One operand can be signed while the other is unsigned.
+In all cases, the resulting type will be the same type as the left
+operand.
+If the first operand is a scalar, the second operand has to be a scalar
+as well.
+If the first operand is a vector, the second operand must be a scalar or
+a vector with the same size as the first operand, and the result is
+computed component-wise.
+The result is undefined if the right operand is negative, or greater
+than or equal to the number of bits in the left expression&#8217;s base type.
+The value of E1 &lt;&lt; E2 is E1 (interpreted as a bit pattern) left-shifted
+by E2 bits.
+The value of E1 &gt;&gt; E2 is E1 right-shifted by E2 bit positions.
+If E1 is a signed integer, the right-shift will extend the sign bit.
+If E1 is an unsigned integer, the right-shift will zero-extend.</p>
+</li>
+<li>
+<p>The bitwise operators and (<strong>&amp;</strong>), exclusive-or (<strong>^</strong>), and inclusive-or
+(<strong>|</strong>).
+The operands must be of type signed or unsigned integers or integer
+vectors.
+The operands cannot be vectors of differing size; this is a compile-time error.
+If one operand is a scalar and the other a vector, the scalar is applied
+component-wise to the vector, resulting in the same type as the vector.
+If the fundamental types in the operands do not match, then the
+conversions from &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; are
+applied to create matching types, and this will be the resulting
+fundamental type.
+For and (<strong>&amp;</strong>), the result is the bitwise-and function of the operands.
+For exclusive-or (<strong>^</strong>), the result is the bitwise exclusive-or function
+of the operands.
+For inclusive-or (<strong>|</strong>), the result is the bitwise inclusive-or function
+of the operands.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>For a complete specification of the syntax of expressions, see
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221;.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="vector-and-matrix-operations">5.10. Vector and Matrix Operations</h3>
+<div class="paragraph">
+<p>With a few exceptions, operations are component-wise.
+Usually, when an operator operates on a vector or matrix, it is operating
+independently on each component of the vector or matrix, in a component-wise
+fashion.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u;
+<span class="predefined-type">float</span> f;
+v = u + f;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will be equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">v.x = u.x + f;
+v.y = u.y + f;
+v.z = u.z + f;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u, w;
+w = v + u;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>will be equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">w.x = v.x + u.x;
+w.y = v.y + u.y;
+w.z = v.z + u.z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and likewise for most operators and all integer and floating-point vector
+and matrix types.
+The exceptions are matrix multiplied by vector, vector multiplied by matrix,
+and matrix multiplied by matrix.
+These do not operate component-wise, but rather perform the correct linear
+algebraic multiply.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec3 v, u;
+mat3 m;
+u = v * m;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u.x = dot(v, m[<span class="integer">0</span>]); <span class="comment">// m[0] is the left column of m</span>
+u.y = dot(v, m[<span class="integer">1</span>]); <span class="comment">// dot(a,b) is the inner (dot) product of a and b</span>
+u.z = dot(v, m[<span class="integer">2</span>]);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u = m * v;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">u.x = m[<span class="integer">0</span>].x * v.x + m[<span class="integer">1</span>].x * v.y + m[<span class="integer">2</span>].x * v.z;
+u.y = m[<span class="integer">0</span>].y * v.x + m[<span class="integer">1</span>].y * v.y + m[<span class="integer">2</span>].y * v.z;
+u.z = m[<span class="integer">0</span>].z * v.x + m[<span class="integer">1</span>].z * v.y + m[<span class="integer">2</span>].z * v.z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>And</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">mat3 m, n, r;
+r = m * n;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>is equivalent to</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">r[<span class="integer">0</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].x = m[<span class="integer">0</span>].x * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].x * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].x * n[<span class="integer">2</span>].z;
+r[<span class="integer">0</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].y = m[<span class="integer">0</span>].y * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].y * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].y * n[<span class="integer">2</span>].z;
+r[<span class="integer">0</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">0</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">0</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">0</span>].z;
+r[<span class="integer">1</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">1</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">1</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">1</span>].z;
+r[<span class="integer">2</span>].z = m[<span class="integer">0</span>].z * n[<span class="integer">2</span>].x + m[<span class="integer">1</span>].z * n[<span class="integer">2</span>].y + m[<span class="integer">2</span>].z * n[<span class="integer">2</span>].z;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and similarly for other sizes of vectors and matrices.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="out-of-bounds-accesses">5.11. Out-of-Bounds Accesses</h3>
+<div class="paragraph">
+<p>In the subsections described above for array, vector, matrix and structure
+accesses, any out-of-bounds access produced undefined behavior.
+However, if robust buffer access is enabled via the OpenGL API, such
+accesses will be bound within the memory extent of the active program.
+It will not be possible to access memory from other programs, and accesses
+will not result in abnormal program termination.
+Out-of-bounds reads return undefined values, which include values from other
+variables of the active program or zero.
+Out-of-bounds writes may be discarded or overwrite other variables of the
+active program, depending on the value of the computed index and how this
+relates to the extent of the active program&#8217;s memory.
+Applications that require defined behavior for out-of-bounds accesses should
+range check all computed indices before dereferencing an array.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="specialization-constant-operations">5.12. Specialization Constant Operations</h3>
+<div class="paragraph">
+<p>Only some operations discussed in this section may be applied to a
+specialization constant and still yield a result that is a specialization
+constant.
+The operations that do so are listed below.
+When a specialization constant is operated on with one of these operators
+and with another constant or specialization constant, the result is
+implicitly a specialization constant.</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>int</strong>(), <strong>uint</strong>(), and <strong>bool</strong>() constructors for type conversions from
+any of the following types to any of the following types:</p>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>int</strong></p>
+</li>
+<li>
+<p><strong>uint</strong></p>
+</li>
+<li>
+<p><strong>bool</strong></p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>vector versions of the above conversion constructors</p>
+</li>
+<li>
+<p>allowed implicit conversions of the above</p>
+</li>
+<li>
+<p>swizzles (e.g. <code>foo.yx</code>)</p>
+</li>
+<li>
+<p>the following when applied to integer or unsigned integer types:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>unary negative (<strong>-</strong>)</p>
+</li>
+<li>
+<p>binary operations (<strong>+</strong>, <strong>-</strong>, <strong>*</strong>, <strong>/</strong>, <strong>%</strong>)</p>
+</li>
+<li>
+<p>shift (<strong>&lt;&lt;</strong>, <strong>&gt;&gt;</strong>)</p>
+</li>
+<li>
+<p>bitwise operations (<strong>&amp;</strong>, <strong>|</strong>, <strong>^</strong>)</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>the following when applied to integer or unsigned integer scalar types:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>comparison (<strong>==</strong>, <strong>!=</strong>, <strong>&gt;</strong>, <strong>&gt;=</strong>, <strong>&lt;</strong>, <strong>&#8656;</strong>)</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>The following when applied to the Boolean scalar type:</p>
+<div class="ulist">
+<ul>
+<li>
+<p>not (<strong>!</strong>)</p>
+</li>
+<li>
+<p>logical operations (<strong>&amp;&amp;</strong>, <strong>||</strong>, <strong>^^</strong>)</p>
+</li>
+<li>
+<p>comparison (<strong>==</strong>, <strong>!=</strong>)</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>the ternary operator (<strong>?:</strong>)</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="statements-and-structure">6. Statements and Structure</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The fundamental building blocks of the OpenGL Shading Language are:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>statements and declarations</p>
+</li>
+<li>
+<p>function definitions</p>
+</li>
+<li>
+<p>selection (<strong>if</strong>-<strong>else</strong> and <strong>switch</strong>-<strong>case</strong>-<strong>default</strong>)</p>
+</li>
+<li>
+<p>iteration (<strong>for</strong>, <strong>while</strong>, and <strong>do</strong>-<strong>while</strong>)</p>
+</li>
+<li>
+<p>jumps (<strong>discard</strong>, <strong>return</strong>, <strong>break</strong>, and <strong>continue</strong>)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The overall structure of a shader is as follows</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>translation-unit</em> : </dt>
+<dd>
+<p><em>global-declaration</em><br>
+<em>translation-unit</em> <em>global-declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>global-declaration</em> : </dt>
+<dd>
+<p><em>function-definition</em><br>
+<em>declaration</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>That is, a shader is a sequence of declarations and function bodies.
+Function bodies are defined as</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function-definition</em> : </dt>
+<dd>
+<p><em>function-prototype</em> <strong>{</strong> <em>statement-list</em> <strong>}</strong></p>
+</dd>
+<dt class="hdlist1"><em>statement-list</em> : </dt>
+<dd>
+<p><em>statement</em><br>
+<em>statement-list</em> <em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>statement</em> : </dt>
+<dd>
+<p><em>compound-statement</em><br>
+<em>simple-statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Curly braces are used to group sequences of statements into compound
+statements.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>compound-statement</em> : </dt>
+<dd>
+<p><strong>{</strong> <em>statement-list</em> <strong>}</strong></p>
+</dd>
+<dt class="hdlist1"><em>simple-statement</em> : </dt>
+<dd>
+<p><em>declaration-statement</em><br>
+<em>expression-statement</em><br>
+<em>selection-statement</em><br>
+<em>iteration-statement</em><br>
+<em>jump-statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Simple declaration, expression, and jump statements end in a semi-colon.</p>
+</div>
+<div class="paragraph">
+<p>This above is slightly simplified, and the complete grammar specified in
+&#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; should be used as
+the definitive specification.</p>
+</div>
+<div class="paragraph">
+<p>Declarations and expressions have already been discussed.</p>
+</div>
+<div class="sect2">
+<h3 id="function-definitions">6.1. Function Definitions</h3>
+<div class="paragraph">
+<p>As indicated by the grammar above, a valid shader is a sequence of global
+declarations and function definitions.
+A function is declared as the following example shows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// prototype</span>
+returnType functionName (type0 arg0, type1 arg1, ..., typen argn);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>and a function is defined like</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// definition</span>
+returnType functionName (type0 arg0, type1 arg1, ..., typen argn)
+{
+    <span class="comment">// do some computation</span>
+    <span class="keyword">return</span> returnValue;
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>where <em>returnType</em> must be present and cannot be void, or:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> functionName (type0 arg0, type1 arg1, ..., typen argn)
+{
+    <span class="comment">// do some computation</span>
+    <span class="keyword">return</span>; <span class="comment">// optional</span>
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If the type of <em>returnValue</em> does not match <em>returnType</em>, there must be an
+implicit conversion in &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221;
+that converts the type of <em>returnValue</em> to <em>returnType</em>, or a compile-time
+error will result.</p>
+</div>
+<div class="paragraph">
+<p>Each of the <em>typeN</em> must include a type and can optionally include parameter
+qualifiers.
+The formal argument names (<em>args</em> above) in the declarations are optional
+for both the declaration and definition forms.</p>
+</div>
+<div class="paragraph">
+<p>A function is called by using its name followed by a list of arguments in
+parentheses.</p>
+</div>
+<div class="paragraph">
+<p>Arrays are allowed as arguments and as the return type.
+In both cases, the array must be
+explicitly
+sized.
+An array is passed or returned by using just its name, without brackets, and
+the size of the array must match the size specified in the function&#8217;s
+declaration.</p>
+</div>
+<div class="paragraph">
+<p>Structures are also allowed as argument types.
+The return type can also be a structure.</p>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for the
+definitive reference on the syntax to declare and define functions.</p>
+</div>
+<div class="paragraph">
+<p>All functions must be either declared with a prototype or defined with a
+body before they are called.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> myfunc (<span class="predefined-type">float</span> f,      <span class="comment">// f is an input parameter</span>
+              out <span class="predefined-type">float</span> g); <span class="comment">// g is an output parameter</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Functions that return no value must be declared as <strong>void</strong>.
+A <strong>void</strong> function can only use <strong>return</strong> without a return argument, even if
+the return argument has <strong>void</strong> type.
+Return statements only accept values:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> func1() { }
+<span class="directive">void</span> func2() { <span class="keyword">return</span> func1(); } <span class="comment">// illegal return statement</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Only a precision qualifier is allowed on the return type of a function.
+Formal parameters can have parameter, precision, and memory qualifiers, but
+no other qualifiers.</p>
+</div>
+<div class="paragraph">
+<p>Functions that accept no input arguments need not use <strong>void</strong> in the argument
+list because prototypes (or definitions) are required and therefore there is
+no ambiguity when an empty argument list &#8220;( )&#8221; is declared.
+The idiom &#8220;(<strong>void</strong>)&#8221; as a parameter list is provided for convenience.</p>
+</div>
+<div class="paragraph">
+<p>Function names can be overloaded.
+The same function name can be used for multiple functions, as long as the
+parameter types differ.
+If a function name is declared twice with the same parameter types, then the
+return types and all qualifiers must also match, and it is the same function
+being declared.</p>
+</div>
+<div class="paragraph">
+<p>For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4 f(in vec4 x, out vec4 y);       <span class="comment">// (A)</span>
+vec4 f(in vec4 x, out uvec4 y);      <span class="comment">// (B) okay, different argument type</span>
+vec4 f(in ivec4 x, out dvec4 y);     <span class="comment">// (C) okay, different argument type</span>
+<span class="predefined-type">int</span> f(in vec4 x, out vec4 y);        <span class="comment">// error, only return type differs</span>
+vec4 f(in vec4 x, in vec4 y);        <span class="comment">// error, only qualifier differs</span>
+vec4 f(<span class="directive">const</span> in vec4 x, out vec4 y); <span class="comment">// error, only qualifier differs</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>When function calls are resolved, an exact type match for all the arguments
+is sought.
+If an exact match is found, all other functions are ignored, and the exact
+match is used.
+If no exact match is found, then the implicit conversions in section
+&#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221; will be applied to find a
+match.
+Mismatched types on input parameters (<strong>in</strong> or <strong>inout</strong> or default) <strong>must</strong>
+have a conversion from the calling argument type to the formal parameter
+type.
+Mismatched types on output parameters (<strong>out</strong> or <strong>inout</strong>) must have a
+conversion from the formal parameter type to the calling argument type.</p>
+</div>
+<div class="paragraph">
+<p>If implicit conversions can be used to find more than one matching function,
+a single best-matching function is sought.
+To determine a best match, the conversions between calling argument and
+formal parameter types are compared for each function argument and pair of
+matching functions.
+After these comparisons are performed, each pair of matching functions are
+compared.
+A function declaration <em>A</em> is considered a better match than function
+declaration <em>B</em> if</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>for at least one function argument, the conversion for that argument in
+<em>A</em> is better than the corresponding conversion in <em>B</em>; and</p>
+</li>
+<li>
+<p>there is no function argument for which the conversion in <em>B</em> is better
+than the corresponding conversion in <em>A</em>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>If a single function declaration is considered a better match than every
+other matching function declaration, it will be used.
+Otherwise, a compile-time semantic error for an ambiguous overloaded
+function call occurs.</p>
+</div>
+<div class="paragraph">
+<p>To determine whether the conversion for a single argument in one match is
+better than that for another match, the following rules are applied, in
+order:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>An exact match is better than a match involving any implicit conversion.</p>
+</li>
+<li>
+<p>A match involving an implicit conversion from <strong>float</strong> to <strong>double</strong> is
+better than a match involving any other implicit conversion.</p>
+</li>
+<li>
+<p>A match involving an implicit conversion from either <strong>int</strong> or <strong>uint</strong> to
+<strong>float</strong> is better than a match involving an implicit conversion from
+either <strong>int</strong> or <strong>uint</strong> to <strong>double</strong>.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>If none of the rules above apply to a particular pair of conversions,
+neither conversion is considered better than the other.</p>
+</div>
+<div class="paragraph">
+<p>For the example function prototypes (A), (B), and &#169; above, the following
+examples show how the rules apply to different sets of calling argument
+types:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">f(vec4, vec4)   <span class="comment">// exact match of vec4 f(in vec4 x, out vec4 y)</span>
+f(vec4, uvec4)  <span class="comment">// exact match of vec4 f(in vec4 x, out uvec4 y)</span>
+f(vec4, ivec4)  <span class="comment">// matched to vec4 f(in vec4 x, out vec4 y)</span>
+                <span class="comment">// (C) not relevant, can't convert vec4 to</span>
+                <span class="comment">// ivec4. (A) better than (B) for 2nd</span>
+                <span class="comment">// argument (rule 3), same on first argument.</span>
+f(ivec4, vec4); <span class="comment">// NOT matched. All three match by implicit</span>
+                <span class="comment">// conversion. (C) is better than (A) and (B)</span>
+                <span class="comment">// on the first argument. (A) is better than</span>
+                <span class="comment">// (B) and (C).</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>User-defined functions can have multiple declarations, but only one
+definition.</p>
+</div>
+<div class="paragraph">
+<p>A shader can redefine built-in functions.
+If a built-in function is redeclared in a shader (i.e., a prototype is
+visible) before a call to it, then the linker will only attempt to resolve
+that call within the set of shaders that are linked with it.</p>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> is used as the entry point to a shader executable.
+A shader need not contain a function named <em>main</em>, but one shader in a set
+of shaders linked together to form a single shader executable must, or a
+link-time error results.
+This function takes no arguments, returns no value, and must be declared as
+type <strong>void</strong>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">void</span> main()
+{
+    ...
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> can contain uses of <strong>return</strong>.
+See &#8220;<a href="#jumps">Jumps</a>&#8221; for more details.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error to declare or define a function
+<strong>main</strong> with any other parameters or return type.</p>
+</div>
+<div class="sect3">
+<h4 id="function-calling-conventions">6.1.1. Function Calling Conventions</h4>
+<div class="paragraph">
+<p>Functions are called by value-return.
+This means input arguments are copied into the function at call time, and
+output arguments are copied back to the caller before function exit.
+Because the function works with local copies of parameters, there are no
+issues regarding aliasing of variables within a function.
+To control what parameters are copied in and/or out through a function
+definition or declaration:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>The keyword <strong>in</strong> is used as a qualifier to denote a parameter is to be
+copied in, but not copied out.</p>
+</li>
+<li>
+<p>The keyword <strong>out</strong> is used as a qualifier to denote a parameter is to be
+copied out, but not copied in.
+This should be used whenever possible to avoid unnecessarily copying
+parameters in.</p>
+</li>
+<li>
+<p>The keyword <strong>inout</strong> is used as a qualifier to denote the parameter is to
+be both copied in and copied out.
+It means the same thing as specifying both <strong>in</strong> and <strong>out</strong>.</p>
+</li>
+<li>
+<p>A function parameter declared with no such qualifier means the same
+thing as specifying <strong>in</strong>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>All arguments are evaluated at call time, exactly once, in order, from left
+to right.
+Evaluation of an <strong>in</strong> parameter results in a value that is copied to the
+formal parameter.
+Evaluation of an <strong>out</strong> parameter results in an l-value that is used to copy
+out a value when the function returns.
+Evaluation of an <strong>inout</strong> parameter results in both a value and an l-value;
+the value is copied to the formal parameter at call time and the l-value is
+used to copy out a value when the function returns.</p>
+</div>
+<div class="paragraph">
+<p>The order in which output parameters are copied back to the caller is
+undefined.</p>
+</div>
+<div class="paragraph">
+<p>If the function matching described in the previous section required argument
+type conversions, these conversions are applied at copy-in and copy-out
+times.</p>
+</div>
+<div class="paragraph">
+<p>In a function, writing to an input-only parameter is allowed.
+Only the function&#8217;s copy is modified.
+This can be prevented by declaring a parameter with the <strong>const</strong> qualifier.</p>
+</div>
+<div class="paragraph">
+<p>When calling a function, expressions that do not evaluate to l-values cannot
+be passed to parameters declared as <strong>out</strong> or <strong>inout</strong>, or a compile-time error
+results.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function-prototype</em> : </dt>
+<dd>
+<p><em>precision-qualifier</em> <em>type</em> <em>function-name</em> <strong>(</strong> <em>parameter-qualifiers</em>
+<em>precision-qualifier</em> <em>type</em> <em>name</em> <em>array-specifier</em> <strong>,</strong> &#8230;&#8203;
+<strong>)</strong></p>
+</dd>
+<dt class="hdlist1"><em>type</em> : </dt>
+<dd>
+<p>any basic type, array type, structure name, or structure definition</p>
+</dd>
+<dt class="hdlist1"><em>parameter-qualifiers</em> : </dt>
+<dd>
+<p><em>empty</em><br>
+list of <em>parameter-qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter-qualifier</em> : </dt>
+<dd>
+<p><strong>const</strong><br>
+<strong>in</strong><br>
+<strong>out</strong><br>
+<strong>inout</strong><br>
+<strong>precise</strong><br>
+<em>memory-qualifier</em><br>
+<em>precision-qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>name</em> : </dt>
+<dd>
+<p>empty<br>
+identifier</p>
+</dd>
+<dt class="hdlist1"><em>array-specifier</em> : </dt>
+<dd>
+<p>empty<br>
+<strong>[</strong> <em>integral-constant-expression</em> <strong>]</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>The <strong>const</strong> qualifier cannot be used with <strong>out</strong> or <strong>inout</strong>, or
+a compile-time error results.
+The above is used both for function declarations (i.e., prototypes) and for
+function definitions.
+Hence, function definitions can have unnamed arguments.</p>
+</div>
+<div class="paragraph">
+<p>Recursion is not allowed, not even statically.
+Static recursion is present if the static function-call graph of a program
+contains cycles.
+This includes all potential function calls through variables declared as
+<strong>subroutine</strong> <strong>uniform</strong> (described below).
+It is a compile-time or link-time error if a single compilation unit
+(shader) contains either static recursion or the potential for recursion
+through subroutine variables.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="subroutines">6.1.2. Subroutines</h4>
+<div class="paragraph">
+<p>Subroutines provide a mechanism allowing shaders to be compiled in a manner
+where the target of one or more function calls can be changed at run-time
+without requiring any shader recompilation.
+For example, a single shader may be compiled with support for multiple
+illumination algorithms to handle different kinds of lights or surface
+materials.
+An application using such a shader may switch illumination algorithms by
+changing the value of its subroutine uniforms.
+To use subroutines, a subroutine type is declared, one or more functions are
+associated with that subroutine type, and a subroutine variable of that type
+is declared.
+The function currently assigned to the variable function is then called by
+using function calling syntax replacing a function name with the name of the
+subroutine variable.
+Subroutine variables are uniforms, and are assigned to specific functions
+only through commands (<strong>UniformSubroutinesuiv</strong>) in the OpenGL API.</p>
+</div>
+<div class="paragraph">
+<p>Subroutine functionality is not available when generating SPIR-V.</p>
+</div>
+<div class="paragraph">
+<p>Subroutine types are declared using a statement similar to a function
+declaration, with the <strong>subroutine</strong> keyword, as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">subroutine returnType subroutineTypeName(type0 arg0, type1 arg1,
+                                         ..., typen argn);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>As with function declarations, the formal argument names (<em>args</em> above) are
+optional.
+Functions are associated with subroutine types of matching declarations by
+defining the function with the <strong>subroutine</strong> keyword and a list of subroutine
+types the function matches:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">subroutine(subroutineTypeName0, ..., subroutineTypeNameN)
+returnType functionName(type0 arg0, type1 arg1, ..., typen argn)
+{ ... } <span class="comment">// function body</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error if arguments and return type don&#8217;t match between
+the function and each associated subroutine type.</p>
+</div>
+<div class="paragraph">
+<p>Functions declared with <strong>subroutine</strong> must include a body.
+An overloaded function cannot be declared with <strong>subroutine</strong>; a program will
+fail to compile or link if any shader or stage contains two or more
+functions with the same name if the name is associated with a subroutine
+type.</p>
+</div>
+<div class="paragraph">
+<p>A function declared with <strong>subroutine</strong> can also be called directly with a
+static use of <em>functionName</em>, as is done with non-subroutine function
+declarations and calls.</p>
+</div>
+<div class="paragraph">
+<p>Subroutine type variables are required to be <em>subroutine uniforms</em>, and are
+declared with a specific subroutine type in a subroutine uniform variable
+declaration:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">subroutine uniform subroutineTypeName subroutineVarName;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Subroutine uniform variables are called the same way functions are called.
+When a subroutine variable (or an element of a subroutine variable array) is
+associated with a particular function, all function calls through that
+variable will call that particular function.</p>
+</div>
+<div class="paragraph">
+<p>Unlike other uniform variables, subroutine uniform variables are scoped to
+the shader execution stage the variable is declared in.</p>
+</div>
+<div class="paragraph">
+<p>Subroutine variables may be declared as explicitly-sized arrays, which can
+be indexed only with dynamically uniform expressions.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time error to use the <strong>subroutine</strong> keyword in any places
+other than (as shown above) to</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>declare a subroutine type at global scope,</p>
+</li>
+<li>
+<p>declare a function as a subroutine, or</p>
+</li>
+<li>
+<p>declare a subroutine variable at global scope.</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="selection">6.2. Selection</h3>
+<div class="paragraph">
+<p>Conditional control flow in the shading language is done by either <strong>if</strong>,
+<strong>if</strong>-<strong>else</strong>, or <strong>switch</strong> statements:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>selection-statement</em> : </dt>
+<dd>
+<p><strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em><br>
+<strong>if</strong> <strong>(</strong> <em>bool-expression</em> <strong>)</strong> <em>statement</em> <strong>else</strong> <em>statement</em><br>
+<strong>switch</strong> <strong>(</strong> <em>init-expression</em> <strong>)</strong> <strong>{</strong> <em>switch-statement-list<sub>opt</sub></em> <strong>}</strong></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Where <em>switch-statement-list</em> is a nested scope containing a list of zero or
+more <em>switch-statement</em> and other statements defined by the language, where
+<em>switch-statement</em> adds some forms of labels.
+That is</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>switch-statement-list</em> : </dt>
+<dd>
+<p><em>switch-statement</em><br>
+<em>switch-statement-list</em> <em>switch-statement</em></p>
+</dd>
+<dt class="hdlist1"><em>switch-statement</em> : </dt>
+<dd>
+<p><strong>case</strong> <em>constant-expression</em> <strong>:</strong><br>
+<strong>default</strong> <strong>:</strong> <em>statement</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>Note the above grammar&#8217;s purpose is to aid discussion in this section; the
+normative grammar is in &#8220;<a href="#shading-language-grammar">Shading Language
+Grammar</a>&#8221;.</p>
+</div>
+<div class="paragraph">
+<p>If an <strong>if</strong>-expression evaluates to <strong>true</strong>, then the first <em>statement</em> is
+executed.
+If it evaluates to <strong>false</strong> and there is an <strong>else</strong> part then the second
+<em>statement</em> is executed.</p>
+</div>
+<div class="paragraph">
+<p>Any expression whose type evaluates to a Boolean can be used as the
+conditional expression <em>bool-expression</em>.
+Vector types are not accepted as the expression to <strong>if</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Conditionals can be nested.</p>
+</div>
+<div class="paragraph">
+<p>The type of <em>init-expression</em> in a <strong>switch</strong> statement must be a scalar
+integer.
+The type of the <em>constant-expression</em> value in a case label also must be a
+scalar integer.
+When any pair of these values is tested for &#8220;equal value&#8221; and the types do
+not match, an implicit conversion will be done to convert the <strong>int</strong> to a
+<strong>uint</strong> (see &#8220;<a href="#implicit-conversions">Implicit Conversions</a>&#8221;) before the
+compare is done.
+If a <strong>case</strong> label has a <em>constant-expression</em> of equal value to
+<em>init-expression</em>, execution will continue after that label.
+Otherwise, if there is a <strong>default</strong> label, execution will continue after that
+label.
+Otherwise, execution skips the rest of the switch statement.
+It is a compile-time error to have more than one <strong>default</strong> or a replicated
+<em>constant-expression</em>.
+A <strong>break</strong> statement not nested in a loop or other switch statement (either
+not nested or nested only in <strong>if</strong> or <strong>if</strong>-<strong>else</strong> statements) will also skip
+the rest of the switch statement.
+Fall through labels are allowed, but it is a compile-time error to have no
+statement between a label and the end of the switch statement.
+No statements are allowed in a switch statement before the first <strong>case</strong>
+statement.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>case</strong> and <strong>default</strong> labels can only appear within a <strong>switch</strong> statement.
+No <strong>case</strong> or <strong>default</strong> labels can be nested inside other statements or
+compound statements within their corresponding <strong>switch</strong>.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="iteration">6.3. Iteration</h3>
+<div class="paragraph">
+<p>For, while, and do loops are allowed as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">for</span> (init-expression; condition-expression; loop-expression)
+    sub-statement
+<span class="keyword">while</span> (condition-expression)
+    sub-statement
+<span class="keyword">do</span>
+    statement
+<span class="keyword">while</span> (condition-expression)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>See &#8220;<a href="#shading-language-grammar">Shading Language Grammar</a>&#8221; for the
+definitive specification of loops.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>for</strong> loop first evaluates the <em>init-expression</em>, then the
+<em>condition-expression</em>.
+If the <em>condition-expression</em> evaluates to <strong>true</strong>, then the body of the loop
+is executed.
+After the body is executed, a <strong>for</strong> loop will then evaluate the
+<em>loop-expression</em>, and then loop back to evaluate the
+<em>condition-expression</em>, repeating until the <em>condition-expression</em> evaluates
+to <strong>false</strong>.
+The loop is then exited, skipping its body and skipping its
+<em>loop-expression</em>.
+Variables modified by the <em>loop-expression</em> maintain their value after the
+loop is exited, provided they are still in scope.
+Variables declared in <em>init-expression</em> or <em>condition-expression</em> are only
+in scope until the end of the sub-statement of the <strong>for</strong> loop.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>while</strong> loop first evaluates the <em>condition-expression</em>.
+If <strong>true</strong>, then the body is executed.
+This is then repeated, until the <em>condition-expression</em> evaluates to
+<strong>false</strong>, exiting the loop and skipping its body.
+Variables declared in the <em>condition-expression</em> are only in scope until the
+end of the sub-statement of the <strong>while</strong> loop.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>do</strong>-<strong>while</strong> loop first executes the body, then executes the
+<em>condition-expression</em>.
+This is repeated until <em>condition-expression</em> evaluates to <strong>false</strong>, and then
+the loop is exited.</p>
+</div>
+<div class="paragraph">
+<p>Expressions for <em>condition-expression</em> must evaluate to a Boolean.</p>
+</div>
+<div class="paragraph">
+<p>Both the <em>condition-expression</em> and the <em>init-expression</em> can declare and
+initialize a variable, except in the <strong>do</strong>-<strong>while</strong> loop, which cannot declare
+a variable in its <em>condition-expression</em>.
+The variable&#8217;s scope lasts only until the end of the sub-statement that
+forms the body of the loop.</p>
+</div>
+<div class="paragraph">
+<p>Loops can be nested.</p>
+</div>
+<div class="paragraph">
+<p>Non-terminating loops are allowed.
+The consequences of very long or non-terminating loops are platform
+dependent.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="jumps">6.4. Jumps</h3>
+<div class="paragraph">
+<p>These are the jumps:</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>jump_statement</em> : </dt>
+<dd>
+<p><strong>continue</strong> <strong>;</strong><br>
+<strong>break</strong> <strong>;</strong><br>
+<strong>return</strong> <strong>;</strong><br>
+<strong>return</strong> <em>expression</em> <strong>;</strong><br>
+<strong>discard</strong> <strong>;</strong> // in the fragment shader language only</p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>There is no &#8220;goto&#8221; or other non-structured flow of control.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>continue</strong> jump is used only in loops.
+It skips the remainder of the body of the inner-most loop of which it is
+inside.
+For <strong>while</strong> and <strong>do</strong>-<strong>while</strong> loops, this jump is to the next evaluation of
+the loop <em>condition-expression</em> from which the loop continues as previously
+defined.
+For <strong>for</strong> loops, the jump is to the <em>loop-expression</em>, followed by the
+<em>condition-expression</em>.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>break</strong> jump can also be used only in loops and <strong>switch</strong> statements.
+It is simply an immediate exit of the inner-most loop or <strong>switch</strong> statements
+containing the <strong>break</strong>.
+No further execution of <em>condition-expression</em>, <em>loop-expression</em>, or
+<em>switch-statement</em> is done.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>discard</strong> keyword is only allowed within fragment shaders.
+It can be used within a fragment shader to abandon the operation on the
+current fragment.
+This keyword causes the fragment to be discarded and no updates to any
+buffers will occur.
+Any prior writes to other buffers such as shader storage buffers are
+unaffected.
+Control flow exits the shader, and subsequent implicit or explicit
+derivatives are undefined when this control flow is non-uniform (meaning
+different fragments within the primitive take different control paths).
+It would typically be used within a conditional statement, for example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="keyword">if</span> (intensity &lt; <span class="float">0</span><span class="float">.0</span>)
+    discard;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A fragment shader may test a fragment&#8217;s alpha value and discard the fragment
+based on that test.
+However, it should be noted that coverage testing occurs after the fragment
+shader runs, and the coverage test can change the alpha value.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>return</strong> jump causes immediate exit of the current function.
+If it has <em>expression</em> then that is the return value for the function.</p>
+</div>
+<div class="paragraph">
+<p>The function <em>main</em> can use <strong>return</strong>.
+This simply causes <em>main</em> to exit in the same way as when the end of the
+function had been reached.
+It does not imply a use of <strong>discard</strong> in a fragment shader.
+Using <strong>return</strong> in <em>main</em> before defining outputs will have the same behavior
+as reaching the end of <em>main</em> before defining outputs.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="built-in-variables">7. Built-In Variables</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="built-in-language-variables">7.1. Built-In Language Variables</h3>
+<div class="paragraph">
+<p>Some OpenGL operations occur in fixed functionality and need to provide
+values to or receive values from shader executables.
+Shaders communicate with fixed-function OpenGL pipeline stages, and
+optionally with other shader executables, through the use of built-in input
+and output variables.</p>
+</div>
+<div class="sect3">
+<h4 id="vertex-shader-special-variables">7.1.1. Vertex Shader Special Variables</h4>
+<div class="paragraph">
+<p>The built-in vertex shader variables are intrinsically declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in <span class="predefined-type">int</span> gl_VertexID;
+in <span class="predefined-type">int</span> gl_InstanceID;
+in <span class="predefined-type">int</span> gl_DrawID;
+in <span class="predefined-type">int</span> gl_BaseVertex;
+in <span class="predefined-type">int</span> gl_BaseInstance;
+
+out gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_Position</em> is intended for writing the homogeneous vertex
+position.
+It can be written at any time during shader execution.
+This value will be used by primitive assembly, clipping, culling, and other
+fixed functionality operations, if present, that operate on primitives after
+vertex processing has occurred.
+Its value is undefined after the vertex processing stage if the vertex
+shader executable does not write <em>gl_Position</em>.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_PointSize</em> is intended for a shader to write the size of
+the point to be rasterized.
+It is measured in pixels.
+If <em>gl_PointSize</em> is not written to, its value is undefined in subsequent
+pipe stages.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_ClipDistance</em> is intended for writing clip distances, and
+provides the forward compatible mechanism for controlling user clipping.
+The element <em>gl_ClipDistance[i]</em> specifies a clip distance for each plane
+<em>i</em>.
+A distance of 0 means the vertex is on the plane, a positive distance means
+the vertex is inside the clip plane, and a negative distance means the point
+is outside the clip plane.
+The clip distances will be linearly interpolated across the primitive and
+the portion of the primitive with interpolated distances less than 0 will be
+clipped.</p>
+</div>
+<div class="paragraph">
+<p>The <em>gl_ClipDistance</em> array is predeclared as unsized and must be explicitly
+sized by the shader either redeclaring it with a size or implicitly sized by
+indexing it only with constant integral expressions.
+This needs to size the array to include all the clip planes that are enabled
+via the OpenGL API; if the size does not include all enabled planes,
+results are undefined.
+The size can be at most <em>gl_MaxClipDistances</em>.
+The number of varying components (see <em>gl_MaxVaryingComponents)</em> consumed by
+<em>gl_ClipDistance</em> will match the size of the array, no matter how many
+planes are enabled.
+The shader must also set all values in <em>gl_ClipDistance</em> that have been
+enabled via the OpenGL API, or results are undefined.
+Values written into <em>gl_ClipDistance</em> for planes that are not enabled have
+no effect.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_CullDistance</em> provides a mechanism for controlling user
+culling.
+The element <em>gl_CullDistance[i]</em> specifies a cull distance for plane <em>i</em>.
+A distance of 0 means the vertex is on the plane, a positive distance means
+the vertex is inside the cull volume, and a negative distance means the
+point is outside the cull volume.
+Primitives whose vertices all have a negative cull distance for plane <em>i</em>
+will be discarded.</p>
+</div>
+<div class="paragraph">
+<p>The <em>gl_CullDistance</em> array is predeclared as unsized and must be sized by
+the shader either redeclaring it with a size or indexing it only with
+constant integral expressions.
+The size determines the number and set of enabled cull distances and can be
+at most <em>gl_MaxCullDistances</em>.
+The number of varying components (see <em>gl_MaxVaryingComponents</em>) consumed by
+<em>gl_CullDistance</em> will match the size of the array.
+Shaders writing <em>gl_CullDistance</em> must write all enabled distances, or
+culling results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>As an output variable, <em>gl_CullDistance</em> provides the place for the shader
+to write these distances.
+As an input in all but the fragment language, it reads the values written in
+the previous shader stage.
+In the fragment language, <em>gl_CullDistance</em> array contains linearly
+interpolated values for the vertex values written by a shader to the
+<em>gl_CullDistance</em> vertex output variable.</p>
+</div>
+<div class="paragraph">
+<p>It is a compile-time or link-time error for the set of shaders forming a
+program to have the sum of the sizes of the <em>gl_ClipDistance</em> and
+<em>gl_CullDistance</em> arrays to be larger than
+<em>gl_MaxCombinedClipAndCullDistances</em>.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_VertexID</em> is a vertex shader input variable that holds an
+integer index for the vertex, as defined under &#8220;Shader Inputs&#8221; in section
+11.1.3.9 &#8220;Shader Inputs&#8221; of the <a href="#references">OpenGL Specification</a>.
+While the variable <em>gl_VertexID</em> is always present, its value is not always
+defined.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_InstanceID</em> is a vertex shader input variable that holds
+the instance number of the current primitive in an instanced draw call (see
+&#8220;Shader Inputs&#8221; in section 11.1.3.9 &#8220;Shader Inputs&#8221; of the
+<a href="#references">OpenGL Specification</a>).
+If the current primitive does not come from an instanced draw call, the
+value of <em>gl_InstanceID</em> is zero.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_DrawID</em> is a vertex shader input variable that holds the
+integer index of the drawing command to which the current vertex belongs
+(see &#8220;Shader Inputs&#8221; in section 11.1.3.9 of the <a href="#references">OpenGL Specification</a>).
+If the vertex is not invoked by a <strong>Multi</strong>* form of a draw command, then the
+value of <em>gl_DrawID</em> is zero.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_BaseVertex</em> is a vertex shader input variable that holds
+the integer value passed to the baseVertex parameter of the command that
+resulted in the current shader invocation (see &#8220;Shader Inputs&#8221; in section
+11.1.3.9 of the <a href="#references">OpenGL Specification</a>).</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_BaseInstance</em> is a vertex shader input variable that holds
+the integer value passed to the baseInstance parameter of the command that
+resulted in the current shader invocation (see &#8220;Shader Inputs&#8221; in section
+11.1.3.9 of the <a href="#references">OpenGL Specification</a>).</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="tessellation-control-shader-special-variables">7.1.2. Tessellation Control Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the tessellation control shader, built-in variables are intrinsically
+declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+} gl_in[gl_MaxPatchVertices];
+
+in <span class="predefined-type">int</span> gl_PatchVerticesIn;
+in <span class="predefined-type">int</span> gl_PrimitiveID;
+in <span class="predefined-type">int</span> gl_InvocationID;
+
+out gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+} gl_out[];
+
+patch out <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>];
+patch out <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>];</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-input-variables">Tessellation Control Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em>
+contain the values written in the previous shader stage to the corresponding
+outputs.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PatchVerticesIn</em> contains the number of vertices in the input patch
+being processed by the shader.
+A single shader can read patches of differing sizes, so the value of
+<em>gl_PatchVerticesIn</em> may differ between patches.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveID</em> contains the number of primitives processed by the shader
+since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_InvocationID</em> contains the number of the output patch vertex assigned to
+the tessellation control shader invocation.
+It is assigned integer values in the range [0, N-1], where N is the number
+of output patch vertices per primitive.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-control-output-variables">Tessellation Control Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em> are
+used in the same fashion as the corresponding output variables in the vertex
+shader.</p>
+</div>
+<div class="paragraph">
+<p>The values written to <em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are
+assigned to the corresponding outer and inner tessellation levels of the
+output patch.
+They are used by the tessellation primitive generator to control primitive
+tessellation and may be read by tessellation evaluation shaders.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="tessellation-evaluation-shader-special-variables">7.1.3. Tessellation Evaluation Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the tessellation evaluation shader, built-in variables are intrinsically
+declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+} gl_in[gl_MaxPatchVertices];
+
+in <span class="predefined-type">int</span> gl_PatchVerticesIn;
+in <span class="predefined-type">int</span> gl_PrimitiveID;
+in vec3 gl_TessCoord;
+patch in <span class="predefined-type">float</span> gl_TessLevelOuter[<span class="integer">4</span>];
+patch in <span class="predefined-type">float</span> gl_TessLevelInner[<span class="integer">2</span>];
+
+out gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+};</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-input-variables">Tessellation Evaluation Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em>
+contain the values written in the previous shader stage to the corresponding
+outputs.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PatchVerticesIn</em> and <em>gl_PrimitiveID</em> are defined in the same fashion as
+the corresponding input variables in the tessellation control shader.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_TessCoord</em> specifies a three-component <em>(u,v,w)</em> vector identifying the
+position of the vertex being processed by the shader relative to the
+primitive being tessellated.
+Its values will obey the properties</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_TessCoord.x == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.x) <span class="comment">// two operations performed</span>
+gl_TessCoord.y == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.y) <span class="comment">// two operations performed</span>
+gl_TessCoord.z == <span class="float">1</span><span class="float">.0</span> - (<span class="float">1</span><span class="float">.0</span> - gl_TessCoord.z) <span class="comment">// two operations performed</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>to aid in replicating subdivision computations.</p>
+</div>
+<div class="paragraph">
+<p>If a tessellation control shader is active, the input variables
+<em>gl_TessLevelOuter</em> and <em>gl_TessLevelInner</em> are filled with the
+corresponding outputs written by the tessellation control shader.
+Otherwise, they are assigned with default tessellation levels specified in
+section 11.2.3.3 &#8220;Tessellation Evaluation Shader Inputs&#8221; of the
+<a href="#references">OpenGL Specification</a>.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="tessellation-evaluation-output-variables">Tessellation Evaluation Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em> are
+used in the same fashion as the corresponding output variables in the vertex
+shader.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="geometry-shader-special-variables">7.1.4. Geometry Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the geometry shader, built-in variables are intrinsically declared as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+} gl_in[];
+
+in <span class="predefined-type">int</span> gl_PrimitiveIDIn;
+in <span class="predefined-type">int</span> gl_InvocationID;
+
+out gl_PerVertex {
+    vec4 gl_Position;
+    <span class="predefined-type">float</span> gl_PointSize;
+    <span class="predefined-type">float</span> gl_ClipDistance[];
+    <span class="predefined-type">float</span> gl_CullDistance[];
+};
+
+out <span class="predefined-type">int</span> gl_PrimitiveID;
+out <span class="predefined-type">int</span> gl_Layer;
+out <span class="predefined-type">int</span> gl_ViewportIndex;</code></pre>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-input-variables">Geometry Shader Input Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em>
+contain the values written in the previous shader stage to the corresponding
+outputs.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveIDIn</em> contains the number of primitives processed by the shader
+since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_InvocationID</em> contains the invocation number assigned to the geometry
+shader invocation.
+It is assigned integer values in the range [0, N-1], where N is the number
+of geometry shader invocations per primitive.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="geometry-shader-output-variables">Geometry Shader Output Variables</h5>
+<div class="paragraph">
+<p><em>gl_Position</em>, <em>gl_PointSize</em>, <em>gl_ClipDistance</em>, and <em>gl_CullDistance</em> are
+used in the same fashion as the corresponding output variables in the vertex
+shader.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_PrimitiveID</em> is filled with a single integer that serves as a primitive
+identifier to the fragment shader.
+This is then available to fragment shaders, which will select the written
+primitive ID from the provoking vertex of the primitive being shaded.
+If a fragment shader using <em>gl_PrimitiveID</em> is active and a geometry shader
+is also active, the geometry shader must write to <em>gl_PrimitiveID</em> or the
+fragment shader input <em>gl_PrimitiveID</em> is undefined.
+See section 11.3.4.5 &#8220;Geometry Shader Outputs&#8221; of the
+<a href="#references">OpenGL Specification</a> for more information.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_Layer</em> is used to select a specific layer (or face and layer of a cube
+map) of a multi-layer framebuffer attachment.
+The actual layer used will come from one of the vertices in the primitive
+being shaded.
+Which vertex the layer comes from is determined as discussed in section
+11.3.4.6 &#8220;Layer and Viewport Selection&#8221; of the <a href="#references">OpenGL Specification</a>
+but may be undefined, so it is best to write the same layer value for all
+vertices of a primitive.
+If a shader statically assigns a value to <em>gl_Layer</em>, layered rendering mode
+is enabled.
+See section 11.3.4.5 &#8220;Geometry Shader Outputs&#8221; and section 9.4.9 &#8220;Layered
+Framebuffers&#8221; of the <a href="#references">OpenGL Specification</a> for more information.
+If a shader statically assigns a value to <em>gl_Layer</em>, and there is an
+execution path through the shader that does not set <em>gl_Layer</em>, then the
+value of <em>gl_Layer</em> is undefined for executions of the shader that take that
+path.</p>
+</div>
+<div class="paragraph">
+<p>The output variable <em>gl_Layer</em> takes on a special value when used with an
+array of cube map textures.
+Instead of only referring to the layer, it is used to select a cube map face
+and a layer.
+Setting <em>gl_Layer</em> to the value <em>layer*6+face</em> will render to face <em>face</em> of
+the cube defined in layer <em>layer</em>.
+The face values are defined in table 9.3 of section 9.4.9 &#8220;Layered
+Framebuffers&#8221; of the <a href="#references">OpenGL Specification</a>,
+but repeated below for clarity.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Face Value</th>
+<th class="tableblock halign-left valign-top">Resulting Target</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_X</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Y</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">3</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Y</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">4</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_POSITIVE_Z</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">TEXTURE_CUBE_MAP_NEGATIVE_Z</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>For example, to render to the positive <em>y</em> cube map face located in the 5th
+layer of the cube map array, <em>gl_Layer</em> should be set to <em>5 * 6 + 2</em>.</p>
+</div>
+<div class="paragraph">
+<p>The output variable <em>gl_ViewportIndex</em> provides the index of the viewport to
+which the next primitive emitted from the geometry shader should be drawn.
+Primitives generated by the geometry shader will undergo viewport
+transformation and scissor testing using the viewport transformation and
+scissor rectangle selected by the value of <em>gl_ViewportIndex</em>.
+The viewport index used will come from one of the vertices in the primitive
+being shaded.
+However, which vertex the viewport index comes from is
+implementation-dependent, so it is best to use the same viewport index for
+all vertices of the primitive.
+If a geometry shader does not assign a value to <em>gl_ViewportIndex</em>, viewport
+transform and scissor rectangle zero will be used.
+If a geometry shader statically assigns a value to <em>gl_ViewportIndex</em> and
+there is a path through the shader that does not assign a value to
+<em>gl_ViewportIndex</em>, the value of <em>gl_ViewportIndex</em> is undefined for
+executions of the shader that take that path.
+See section 11.3.4.6 &#8220;Layer and Viewport Selection&#8221; of the
+<a href="#references">OpenGL Specification</a> for more information.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="fragment-shader-special-variables">7.1.5. Fragment Shader Special Variables</h4>
+<div class="paragraph">
+<p>The built-in special variables that are accessible from a fragment shader
+are intrinsically declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 gl_FragCoord;
+in <span class="predefined-type">bool</span> gl_FrontFacing;
+in <span class="predefined-type">float</span> gl_ClipDistance[];
+in <span class="predefined-type">float</span> gl_CullDistance[];
+in vec2 gl_PointCoord;
+in <span class="predefined-type">int</span> gl_PrimitiveID;
+in <span class="predefined-type">int</span> gl_SampleID;
+in vec2 gl_SamplePosition;
+in <span class="predefined-type">int</span> gl_SampleMaskIn[];
+in <span class="predefined-type">int</span> gl_Layer;
+in <span class="predefined-type">int</span> gl_ViewportIndex;
+in <span class="predefined-type">bool</span> gl_HelperInvocation;
+
+out <span class="predefined-type">float</span> gl_FragDepth;
+out <span class="predefined-type">int</span> gl_SampleMask[];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The output of the fragment shader executable is processed by the fixed
+function operations at the back end of the OpenGL pipeline.</p>
+</div>
+<div class="paragraph">
+<p>The fixed functionality computed depth for a fragment may be obtained by
+reading <em>gl_FragCoord.z</em>, described below.</p>
+</div>
+<div class="paragraph">
+<p>Writing to <em>gl_FragDepth</em> will establish the depth value for the fragment
+being processed.
+If depth buffering is enabled, and no shader writes <em>gl_FragDepth</em>, then the
+fixed function value for depth will be used as the fragment&#8217;s depth value.
+If a shader statically assigns a value to <em>gl_FragDepth</em>, and there is an
+execution path through the shader that does not set <em>gl_FragDepth</em>, then the
+value of the fragment&#8217;s depth may be undefined for executions of the shader
+that take that path.
+That is, if the set of linked fragment shaders statically contain a write to
+<em>gl_FragDepth</em>, then it is responsible for always writing it.</p>
+</div>
+<div class="paragraph">
+<p>If a shader executes the <strong>discard</strong> keyword, the fragment is discarded, and
+the values of any user-defined fragment outputs, <em>gl_FragDepth</em>, and
+<em>gl_SampleMask</em> become irrelevant.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_FragCoord</em> is available as an input variable from within
+fragment shaders and it holds the window relative coordinates (<em>x</em>, <em>y</em>,
+<em>z</em>, <em>1/w</em>) values for the fragment.
+If multi-sampling, this value can be for any location within the pixel, or
+one of the fragment samples.
+The use of <strong>centroid</strong> does not further restrict this value to be inside the
+current primitive.
+This value is the result of the fixed functionality that interpolates
+primitives after vertex processing to generate fragments.
+The <em>z</em> component is the depth value that would be used for the fragment&#8217;s
+depth if no shader contained any writes to <em>gl_FragDepth</em>.
+This is useful for invariance if a shader conditionally computes
+<em>gl_FragDepth</em> but otherwise wants the fixed functionality fragment depth.</p>
+</div>
+<div class="paragraph">
+<p>Fragment shaders have access to the input built-in variable
+<em>gl_FrontFacing</em>, whose value is <strong>true</strong> if the fragment belongs to a
+front-facing primitive.
+One use of this is to emulate two-sided lighting by selecting one of two
+colors calculated by a vertex or geometry shader.</p>
+</div>
+<div class="paragraph">
+<p>The values in <em>gl_PointCoord</em> are two-dimensional coordinates indicating
+where within a point primitive the current fragment is located, when point
+sprites are enabled.
+They range from 0.0 to 1.0 across the point.
+If the current primitive is not a point, or if point sprites are not
+enabled, then the values read from <em>gl_PointCoord</em> are undefined.</p>
+</div>
+<div class="paragraph">
+<p>For both the input array <em>gl_SampleMaskIn[]</em> and the output array
+<em>gl_SampleMask[]</em>, bit <em>B</em> of mask <em>M</em> (<em>gl_SampleMaskIn[M]</em> or
+<em>gl_SampleMask[M]</em>) corresponds to sample <em>32*M+B</em>.
+These arrays have <strong>ceil</strong>(<em>s</em>/32) elements, where <em>s</em> is the maximum number
+of color samples supported by the implementation.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SampleMaskIn</em> indicates the set of samples covered by
+the primitive generating the fragment during multisample rasterization.
+It has a sample bit set if and only if the sample is considered covered for
+this fragment shader invocation.</p>
+</div>
+<div class="paragraph">
+<p>The output array <em>gl_SampleMask[]</em> sets the sample mask for the fragment
+being processed.
+Coverage for the current fragment will become the logical AND of the
+coverage mask and the output <em>gl_SampleMask</em>.
+This array must be sized in the fragment shader either implicitly or
+explicitly, to be no larger than the implementation-dependent maximum
+sample-mask (as an array of 32bit elements), determined by the maximum
+number of samples..
+If the fragment shader statically assigns a value to <em>gl_SampleMask</em>, the
+sample mask will be undefined for any array elements of any fragment shader
+invocations that fail to assign a value.
+If a shader does not statically assign a value to <em>gl_SampleMask</em>, the
+sample mask has no effect on the processing of a fragment.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SampleID</em> is filled with the sample number of the
+sample currently being processed.
+This variable is in the range <em>0</em> to <em>gl_NumSamples-1</em>, where
+<em>gl_NumSamples</em> is the total number of samples in the framebuffer, or 1 if
+rendering to a non-multisample framebuffer.
+Any static use of this variable in a fragment shader causes the entire
+shader to be evaluated per-sample.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_SamplePosition</em> contains the position of the current
+sample within the multisample draw buffer.
+The <em>x</em> and <em>y</em> components of <em>gl_SamplePosition</em> contain the sub-pixel
+coordinate of the current sample and will have values in the range 0.0 to
+1.0.
+Any static use of this variable in a fragment shader causes the entire
+shader to be evaluated per sample.</p>
+</div>
+<div class="paragraph">
+<p>The value <em>gl_HelperInvocation</em> is <strong>true</strong> if the fragment shader invocation
+is considered a <em>helper invocation</em> and is <strong>false</strong> otherwise.
+A helper invocation is a fragment shader invocation that is created solely
+for the purposes of evaluating derivatives for use in non-helper fragment
+shader invocations.
+Such derivatives are computed implicitly in the built-in function
+<strong>texture</strong>() (see &#8220;<a href="#texture-functions">Texture Functions</a>&#8221;), and
+explicitly in the derivative functions in
+&#8220;<a href="#derivative-functions">Derivative Functions</a>&#8221;, for example <strong>dFdx</strong>() and
+<strong>dFdy</strong>().</p>
+</div>
+<div class="paragraph">
+<p>Fragment shader helper invocations execute the same shader code as
+non-helper invocations, but will not have side effects that modify the
+framebuffer or other shader-accessible memory.
+In particular:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Fragments corresponding to helper invocations are discarded when shader
+execution is complete, without updating the framebuffer.</p>
+</li>
+<li>
+<p>Stores to image and buffer variables performed by helper invocations
+have no effect on the underlying image or buffer memory.</p>
+</li>
+<li>
+<p>Atomic operations to image, buffer, or atomic counter variables
+performed by helper invocations have no effect on the underlying image
+or buffer memory.
+The values returned by such atomic operations are undefined.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Helper invocations may be generated for pixels not covered by a primitive
+being rendered.
+While fragment shader inputs qualified with <strong>centroid</strong> are normally required
+to be sampled in the intersection of the pixel and the primitive, the
+requirement is ignored for such pixels since there is no intersection
+between the pixel and primitive.</p>
+</div>
+<div class="paragraph">
+<p>Helper invocations may also be generated for fragments that are covered by a
+primitive being rendered when the fragment is killed by early fragment tests
+(using the <strong>early_fragment_tests</strong> qualifier) or where the implementation is
+able to determine that executing the fragment shader would have no effect
+other than assisting in computing derivatives for other fragment shader
+invocations.</p>
+</div>
+<div class="paragraph">
+<p>The set of helper invocations generated when processing any set of
+primitives is implementation-dependent.</p>
+</div>
+<div class="paragraph">
+<p><em>gl_ClipDistance</em> contains linearly interpolated values for the vertex-
+pipeline values written by a shader to the <em>gl_ClipDistance</em> output
+variable. Only elements in this array that have clipping enabled will
+have defined values.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_PrimitiveID</em> is filled with the value written to the
+<em>gl_PrimitiveID</em> geometry shader output, if a geometry shader is present.
+Otherwise, it is filled with the number of primitives processed by the
+shader since the current set of rendering primitives was started.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_Layer</em> is filled with the value written to the
+<em>gl_Layer</em> geometry shader output, if a geometry shader is present.
+If the geometry stage does not dynamically assign a value to <em>gl_Layer</em>, the
+value of <em>gl_Layer</em> in the fragment stage will be undefined.
+If the geometry stage makes no static assignment to <em>gl_Layer</em>, the input
+value in the fragment stage will be zero.
+Otherwise, the fragment stage will read the same value written by the
+geometry stage, even if that value is out of range.
+If a fragment shader contains a static access to <em>gl_Layer</em>, it will count
+against the implementation defined limit for the maximum number of inputs to
+the fragment stage.</p>
+</div>
+<div class="paragraph">
+<p>The input variable <em>gl_ViewportIndex</em> is filled with the value written to
+the output variable <em>gl_ViewportIndex</em> in the geometry stage, if a geometry
+shader is present.
+If the geometry stage does not dynamically assign a value to
+<em>gl_ViewportIndex</em>, the value of <em>gl_ViewportIndex</em> in the fragment shader
+will be undefined.
+If the geometry stage makes no static assignment to <em>gl_ViewportIndex</em>, the
+fragment stage will read zero.
+Otherwise, the fragment stage will read the same value written by the
+geometry stage, even if that value is out of range.
+If a fragment shader contains a static access to <em>gl_ViewportIndex</em>, it will
+count against the implementation defined limit for the maximum number of
+inputs to the fragment stage.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="compute-shader-special-variables">7.1.6. Compute Shader Special Variables</h4>
+<div class="paragraph">
+<p>In the compute shader, built-in variables are declared as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">// workgroup dimensions</span>
+in uvec3 gl_NumWorkGroups;
+<span class="directive">const</span> uvec3 gl_WorkGroupSize;
+
+<span class="comment">// workgroup and invocation IDs</span>
+in uvec3 gl_WorkGroupID;
+in uvec3 gl_LocalInvocationID;
+
+<span class="comment">// derived variables</span>
+in uvec3 gl_GlobalInvocationID;
+in uint gl_LocalInvocationIndex;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_NumWorkGroups</em> is a compute-shader input variable
+containing the number of workgroups in each dimension of the dispatch that
+will execute the compute shader.
+Its content is equal to the values specified in the <em>num_groups_x</em>,
+<em>num_groups_y</em>, and <em>num_groups_z</em> parameters passed to the
+<em>DispatchCompute</em> API entry point.</p>
+</div>
+<div class="paragraph">
+<p>The built-in constant <em>gl_WorkGroupSize</em> is a compute-shader constant
+containing the workgroup size of the shader.
+The size of the workgroup in the <em>X</em>, <em>Y</em>, and <em>Z</em> dimensions is stored in
+the <em>x</em>, <em>y</em>, and <em>z</em> components.
+The constants values in <em>gl_WorkGroupSize</em> will match those specified in the
+required <strong>local_size_x</strong>, <strong>local_size_y</strong>, and <strong>local_size_z</strong> layout
+qualifiers for the current shader.
+This is a constant so that it can be used to size arrays of memory that can
+be shared within the workgroup.
+It is a compile-time error to use <em>gl_WorkGroupSize</em> in a shader that does
+not declare a fixed workgroup size, or before that shader has declared a
+fixed workgroup size, using <strong>local_size_x</strong>, <strong>local_size_y</strong>, and
+<strong>local_size_z</strong>.</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_WorkGroupID</em> is a compute-shader input variable
+containing the three-dimensional index of the workgroup that the
+current invocation is executing in.
+The possible values range across the parameters passed into
+<em>DispatchCompute</em>, i.e., from (0, 0, 0) to (<em>gl_NumWorkGroups.x</em> - 1,
+<em>gl_NumWorkGroups.y</em> - 1, <em>gl_NumWorkGroups.z</em> -1).</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_LocalInvocationID</em> is a compute-shader input
+variable containing the three-dimensional index of the current work item
+within the workgroup.
+The possible values for this variable range across the workgroup
+size, i.e., (0,0,0) to (<em>gl_WorkGroupSize.x</em> - 1, <em>gl_WorkGroupSize.y</em> - 1,
+<em>gl_WorkGroupSize.z</em> - 1).</p>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_GlobalInvocationID</em> is a compute shader input
+variable containing the global index of the current work item.
+This value uniquely identifies this invocation from all other invocations
+across all workgroups initiated by the current <em>DispatchCompute</em> call.
+This is computed as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_GlobalInvocationID =
+    gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The built-in variable <em>gl_LocalInvocationIndex</em> is a compute shader input
+variable that contains the one-dimensional representation of the
+<em>gl_LocalInvocationID</em>.
+This is computed as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">gl_LocalInvocationIndex =
+    gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
+    gl_LocalInvocationID.y * gl_WorkGroupSize.x +
+    gl_LocalInvocationID.x;</code></pre>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="compatibility-profile-built-in-language-variables">7.1.7. Compatibility Profile Built-In Language Variables</h4>
+<div class="paragraph">
+<p>When using the compatibility profile, the GL can provide fixed functionality
+behavior for the vertex and fragment programmable pipeline stages.
+For example, mixing a fixed functionality vertex stage with a programmable
+fragment stage.</p>
+</div>
+<div class="paragraph">
+<p>The following built-in vertex, tessellation control, tessellation
+evaluation, and geometry output variables are available to specify inputs
+for the subsequent programmable shader stage or the fixed functionality
+fragment stage.
+A particular one should be written to if any functionality in a
+corresponding fragment shader or fixed pipeline uses it or state derived
+from it.
+Otherwise, behavior is undefined.
+The following members are added to the output <em>gl_PerVertex</em> block in these
+languages:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out gl_PerVertex { <span class="comment">// part of the gl_PerVertex block described in 7.1</span>
+    <span class="comment">// in addition to other gl_PerVertex members...</span>
+    vec4  gl_ClipVertex;
+    vec4  gl_FrontColor;
+    vec4  gl_BackColor;
+    vec4  gl_FrontSecondaryColor;
+    vec4  gl_BackSecondaryColor;
+    vec4  gl_TexCoord[];
+    <span class="predefined-type">float</span> gl_FogFragCoord;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The output variable <em>gl_ClipVertex</em> provides a place for vertex and geometry
+shaders to write the coordinate to be used with the user clipping planes.
+Writing to <em>gl_ClipDistance</em> is the preferred method for user clipping.
+It is a compile-time or link-time error for the set of shaders forming a
+program to statically read or write both <em>gl_ClipVertex</em> and either
+<em>gl_ClipDistance</em> or <em>gl_CullDistance</em>.
+If neither <em>gl_ClipVertex</em> nor <em>gl_ClipDistance</em> is written, their values
+are undefined and any clipping against user clip planes is also undefined.</p>
+</div>
+<div class="paragraph">
+<p>Similarly to what was previously described for the core profile, the
+<em>gl_PerVertex</em> block can be redeclared in a shader to explicitly include
+these additional members.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out gl_PerVertex {
+    vec4 gl_Position;    <span class="comment">// will use gl_Position</span>
+    vec4 gl_FrontColor;  <span class="comment">// will consume gl_color in the fragment shader</span>
+    vec4 gl_BackColor;
+    vec4 gl_TexCoord[<span class="integer">3</span>]; <span class="comment">// 3 elements of gl_TexCoord will be used</span>
+}; <span class="comment">// no other aspects of the fixed interface will be used</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The user must ensure the clip vertex and user clipping planes are defined in
+the same coordinate space.
+User clip planes work properly only under linear transform.
+It is undefined what happens under non-linear transform.</p>
+</div>
+<div class="paragraph">
+<p>The output variables <em>gl_FrontColor</em>, <em>glFrontSecondaryColor</em>,
+<em>gl_BackColor</em>, and <em>glBackSecondaryColor</em> assign primary and secondary
+colors for front and back faces of primitives containing the vertex being
+processed.
+The output variable <em>gl_TexCoord</em> assigns texture coordinates for the vertex
+being processed.</p>
+</div>
+<div class="paragraph">
+<p>For <em>gl_FogFragCoord</em>, the value written will be used as the &#8220;c&#8221; value in
+section 16.4 &#8220;Fog&#8221; of the Compatibility profile of the
+<a href="#references">OpenGL Specification</a>, by the fixed functionality pipeline.
+For example, if the z-coordinate of the fragment in eye space is desired as
+&#8220;c&#8221;, then that&#8217;s what the vertex shader executable should write into
+<em>gl_FogFragCoord</em>.</p>
+</div>
+<div class="paragraph">
+<p>As with all arrays, indices used to subscript <em>gl_TexCoord</em> must either be a
+constant integral expressions, or this array must be redeclared by the
+shader with a size.
+The size can be at most <em>gl_MaxTextureCoords</em>.
+Using indexes close to 0 may aid the implementation in preserving varying
+resources.
+The redeclaration of <em>gl_TexCoord</em> can also be done at global scope as, for
+example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 gl_TexCoord[<span class="integer">3</span>];
+out vec4 gl_TexCoord[<span class="integer">4</span>];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>(This treatment is a special case for <em>gl_TexCoord[]</em>, not a general method
+for redeclaring members of blocks.) It is a compile-time error to redeclare
+<em>gl_TexCoord[]</em> at global scope if there is a redeclaration of the
+corresponding built-in block; only one form of redeclaration is allowed
+within a shader (and hence within a stage, as block redeclarations must
+match across all shaders using it).</p>
+</div>
+<div class="paragraph">
+<p>In the tessellation control, evaluation, and geometry shaders, the outputs
+of the previous stage described above are also available in the input
+<em>gl_PerVertex</em> block in these languages.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex { <span class="comment">// part of the gl_PerVertex block described in 7.1</span>
+    <span class="comment">// in addition to other gl_PerVertex members...</span>
+    vec4  gl_ClipVertex;
+    vec4  gl_FrontColor;
+    vec4  gl_BackColor;
+    vec4  gl_FrontSecondaryColor;
+    vec4  gl_BackSecondaryColor;
+    vec4  gl_TexCoord[];
+    <span class="predefined-type">float</span> gl_FogFragCoord;
+} gl_in[];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These can be redeclared to establish an explicit pipeline interface, the
+same way as described above for the output block <em>gl_PerVertex</em>, and the
+input redeclaration must match the output redeclaration of the previous
+stage.
+However, when a built-in interface block with an instance name is redeclared
+(e.g. <em>gl_in</em>), the instance name must be included in the redeclaration.
+It is a compile-time error to not include the built-in instance name or to
+change its name.
+For example,</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerVertex {
+    vec4 gl_ClipVertex;
+    vec4 gl_FrontColor;
+} gl_in[]; <span class="comment">// must be present and must be &quot;gl_in[]&quot;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Built-in block arrays predeclared with a size can be redeclared with unsized syntax.
+This keeps their size equal to the original predeclared size.</p>
+</div>
+<div class="paragraph">
+<p>Treatment of <em>gl_TexCoord[]</em> redeclaration is also identical to that
+described for the output block <em>gl_TexCoord[]</em> redeclaration.</p>
+</div>
+<div class="paragraph">
+<p>The following fragment input block is also available in a fragment shader
+when using the compatibility profile:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in gl_PerFragment {
+    in <span class="predefined-type">float</span> gl_FogFragCoord;
+    in vec4  gl_TexCoord[];
+    in vec4  gl_Color;
+    in vec4  gl_SecondaryColor;
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The values in <em>gl_Color</em> and <em>gl_SecondaryColor</em> will be derived
+automatically by the system from <em>gl_FrontColor</em>, <em>gl_BackColor</em>,
+<em>gl_FrontSecondaryColor</em>, and <em>gl_BackSecondaryColor</em> based on which face is
+visible in the primitive producing the fragment.
+If fixed functionality is used for vertex processing, then <em>gl_FogFragCoord</em>
+will either be the z-coordinate of the fragment in eye space, or the
+interpolation of the fog coordinate, as described in section 16.4 &#8220;Fog&#8221; of
+the Compatibility profile of the <a href="#references">OpenGL Specification</a>.
+The <em>gl_TexCoord[]</em> values are the interpolated <em>gl_TexCoord[]</em> values from
+a vertex shader or the texture coordinates of any fixed pipeline based
+vertex functionality.</p>
+</div>
+<div class="paragraph">
+<p>Indices to the fragment shader <em>gl_TexCoord</em> array are as described above in
+the vertex shader text.</p>
+</div>
+<div class="paragraph">
+<p>As described above for the input and output <em>gl_PerVertex</em> blocks, the
+<em>gl_PerFragment</em> block can be redeclared to create an explicit interface to
+another program.
+When matching these interfaces between separate programs, members in the
+<em>gl_PerVertex</em> output block must be declared if and only if the
+corresponding fragment shader members generated from them are present in the
+<em>gl_PerFragment</em> input block.
+These matches are described in detail in section 7.4.1 &#8220;Shader Interface
+Matching&#8221; of the <a href="#references">OpenGL Specification</a>.
+If they don&#8217;t match within a program, a link-time error will result.
+If the mismatch is between two programs, values passed between programs are
+undefined.
+Unlike with all other block matching, the order of declaration within
+<em>gl_PerFragment</em> does not have to match across shaders and does not have to
+correspond with order of declaration in a matching <em>gl_PerVertex</em>
+redeclaration.</p>
+</div>
+<div class="paragraph">
+<p>The following fragment output variables are available in a fragment shader
+when using the compatibility profile:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out vec4 gl_FragColor;
+out vec4 gl_FragData[gl_MaxDrawBuffers];</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Writing to <em>gl_FragColor</em> specifies the fragment color that will be used by
+the subsequent fixed functionality pipeline.
+If subsequent fixed functionality consumes fragment color and an execution
+of the fragment shader executable does not write a value to <em>gl_FragColor</em>
+then the fragment color consumed is undefined.</p>
+</div>
+<div class="paragraph">
+<p>The variable <em>gl_FragData</em> is an array.
+Writing to <em>gl_FragData[n]</em> specifies the fragment data that will be used by
+the subsequent fixed functionality pipeline for data <em>n</em>.
+If subsequent fixed functionality consumes fragment data and an execution of
+a fragment shader executable does not write a value to it, then the fragment
+data consumed is undefined.</p>
+</div>
+<div class="paragraph">
+<p>If a shader statically assigns a value to <em>gl_FragColor</em>, it may not assign
+a value to any element of <em>gl_FragData</em>.
+If a shader statically writes a value to any element of <em>gl_FragData</em>, it
+may not assign a value to <em>gl_FragColor</em>.
+That is, a shader may assign values to either <em>gl_FragColor</em> or
+<em>gl_FragData</em>, but not both.
+Multiple shaders linked together must also consistently write just one of
+these variables.
+Similarly, if user-declared output variables are in use (statically assigned
+to), then the built-in variables <em>gl_FragColor</em> and <em>gl_FragData</em> may not be
+assigned to.
+These incorrect usages all generate compile-time or link-time errors.</p>
+</div>
+<div class="paragraph">
+<p>If a shader executes the <strong>discard</strong> keyword, the fragment is discarded, and
+the values of <em>gl_FragDepth</em> and <em>gl_FragColor</em> become irrelevant.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="compatibility-profile-vertex-shader-built-in-inputs">7.2. Compatibility Profile Vertex Shader Built-In Inputs</h3>
+<div class="paragraph">
+<p>The following predeclared input names can be used from within a vertex
+shader to access the current values of OpenGL state when using the
+compatibility profile.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">in vec4 gl_Color;
+in vec4 gl_SecondaryColor;
+in vec3 gl_Normal;
+in vec4 gl_Vertex;
+in vec4 gl_MultiTexCoord0;
+in vec4 gl_MultiTexCoord1;
+in vec4 gl_MultiTexCoord2;
+in vec4 gl_MultiTexCoord3;
+in vec4 gl_MultiTexCoord4;
+in vec4 gl_MultiTexCoord5;
+in vec4 gl_MultiTexCoord6;
+in vec4 gl_MultiTexCoord7;
+in <span class="predefined-type">float</span> gl_FogCoord;</code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="built-in-constants">7.3. Built-In Constants</h3>
+<div class="paragraph">
+<p>The following built-in constants are provided to all shaders.
+The actual values used are implementation-dependent, but must be at least
+the value shown.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span>
+<span class="comment">// Implementation-dependent constants. The example values below</span>
+<span class="comment">// are the minimum values allowed for these maximums.</span>
+<span class="comment">//</span></code></pre>
+</div>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexAttribs = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexUniformVectors = <span class="integer">256</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexOutputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVaryingComponents = <span class="integer">60</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVaryingVectors = <span class="integer">15</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVertexAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessPatchComponents = <span class="integer">120</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxPatchVertices = <span class="integer">32</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessGenLevel = <span class="integer">64</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlInputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlOutputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlTotalOutputComponents = <span class="integer">4096</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessControlAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationInputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationOutputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTessEvaluationAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryInputComponents = <span class="integer">64</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryOutputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryImageUniforms = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryOutputVertices = <span class="integer">256</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryTotalOutputComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryVaryingComponents = <span class="integer">64</span>;            <span class="comment">// deprecated</span>
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounters = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxGeometryAtomicCounterBuffers = <span class="integer">0</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentImageUniforms = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentInputComponents = <span class="integer">128</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentUniformVectors = <span class="integer">256</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxFragmentAtomicCounterBuffers = <span class="integer">1</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxDrawBuffers = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MinProgramTexelOffset = -<span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxProgramTexelOffset = <span class="integer">7</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxImageUnits = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxSamples = <span class="integer">4</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxImageSamples = <span class="integer">0</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxClipDistances = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCullDistances = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxViewports = <span class="integer">16</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxComputeImageUniforms = <span class="integer">8</span>;
+<span class="directive">const</span> ivec3 gl_MaxComputeWorkGroupCount = { <span class="integer">65535</span>, <span class="integer">65535</span>, <span class="integer">65535</span> };
+<span class="directive">const</span> ivec3 gl_MaxComputeWorkGroupSize = { <span class="integer">1024</span>, <span class="integer">1024</span>, <span class="integer">64</span> };
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxComputeUniformComponents = <span class="integer">1024</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxComputeTextureImageUnits = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxComputeAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxComputeAtomicCounterBuffers = <span class="integer">8</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedTextureImageUnits = <span class="integer">96</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedImageUniforms = <span class="integer">48</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedImageUnitsAndFragmentOutputs = <span class="integer">8</span>;  <span class="comment">// deprecated</span>
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedShaderOutputResources = <span class="integer">16</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounters = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedAtomicCounterBuffers = <span class="integer">1</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxCombinedClipAndCullDistances = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxAtomicCounterBindings = <span class="integer">1</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxAtomicCounterBufferSize = <span class="integer">32</span>;
+
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTransformFeedbackBuffers = <span class="integer">4</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTransformFeedbackInterleavedComponents = <span class="integer">64</span>;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The constant <em>gl_MaxVaryingFloats</em> is removed in the core profile, use
+<em>gl_MaxVaryingComponents</em> instead.</p>
+</div>
+<div class="sect3">
+<h4 id="compatibility-profile-built-in-constants">7.3.1. Compatibility Profile Built-In Constants</h4>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTextureUnits = <span class="integer">2</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxTextureCoords = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxClipPlanes = <span class="integer">8</span>;
+<span class="directive">const</span> <span class="predefined-type">int</span> gl_MaxVaryingFloats = <span class="integer">60</span>;</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="built-in-uniform-state">7.4. Built-In Uniform State</h3>
+<div class="paragraph">
+<p>Built-in uniform state is not available when generating SPIR-V.</p>
+</div>
+<div class="paragraph">
+<p>Otherwise, as an aid to accessing OpenGL processing state, the following
+uniform variables are built into the OpenGL Shading Language.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span>
+<span class="comment">// Depth range in window coordinates,</span>
+<span class="comment">// section 13.6.1 &quot;Controlling the Viewport&quot; in the</span>
+<span class="comment">// OpenGL Specification.</span>
+<span class="comment">//</span>
+<span class="comment">// Note: Depth-range state is only for viewport 0.</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_DepthRangeParameters {
+    <span class="predefined-type">float</span> near; <span class="comment">// n</span>
+    <span class="predefined-type">float</span> far;  <span class="comment">// f</span>
+    <span class="predefined-type">float</span> diff; <span class="comment">// f - n</span>
+};
+uniform gl_DepthRangeParameters gl_DepthRange;
+uniform <span class="predefined-type">int</span> gl_NumSamples;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These variables are only guaranteed to be available in the fragment stage.
+In other stages, their presence and function is implementation-defined.</p>
+</div>
+<div class="sect3">
+<h4 id="compatibility-profile-state">7.4.1. Compatibility Profile State</h4>
+<div class="paragraph">
+<p>These variables are present only in the compatibility profile.
+They are not available to compute shaders, but are available to all other
+shaders.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+uniform mat4 gl_ModelViewMatrix;
+uniform mat4 gl_ProjectionMatrix;
+uniform mat4 gl_ModelViewProjectionMatrix;
+uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+uniform mat3 gl_NormalMatrix; <span class="comment">// transpose of the inverse of the</span>
+                              <span class="comment">// upper leftmost 3x3 of gl_ModelViewMatrix</span>
+
+uniform mat4 gl_ModelViewMatrixInverse;
+uniform mat4 gl_ProjectionMatrixInverse;
+uniform mat4 gl_ModelViewProjectionMatrixInverse;
+uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords];
+
+uniform mat4 gl_ModelViewMatrixTranspose;
+uniform mat4 gl_ProjectionMatrixTranspose;
+uniform mat4 gl_ModelViewProjectionMatrixTranspose;
+uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords];
+
+uniform mat4 gl_ModelViewMatrixInverseTranspose;
+uniform mat4 gl_ProjectionMatrixInverseTranspose;
+uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose;
+uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+uniform <span class="predefined-type">float</span> gl_NormalScale;
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+uniform vec4 gl_ClipPlane[gl_MaxClipPlanes];
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_PointParameters {
+    <span class="predefined-type">float</span> size;
+    <span class="predefined-type">float</span> sizeMin;
+    <span class="predefined-type">float</span> sizeMax;
+    <span class="predefined-type">float</span> fadeThresholdSize;
+    <span class="predefined-type">float</span> distanceConstantAttenuation;
+    <span class="predefined-type">float</span> distanceLinearAttenuation;
+    <span class="predefined-type">float</span> distanceQuadraticAttenuation;
+};
+
+uniform gl_PointParameters gl_Point;
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_MaterialParameters {
+ vec4 emission;   <span class="comment">// Ecm</span>
+ vec4 ambient;    <span class="comment">// Acm</span>
+ vec4 diffuse;    <span class="comment">// Dcm</span>
+ vec4 specular;   <span class="comment">// Scm</span>
+ <span class="predefined-type">float</span> shininess; <span class="comment">// Srm</span>
+};
+uniform gl_MaterialParameters gl_FrontMaterial;
+uniform gl_MaterialParameters gl_BackMaterial;
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_LightSourceParameters {
+    vec4 ambient;               <span class="comment">// Acli</span>
+    vec4 diffuse;               <span class="comment">// Dcli</span>
+    vec4 specular;              <span class="comment">// Scli</span>
+    vec4 position;              <span class="comment">// Ppli</span>
+    vec4 halfVector;            <span class="comment">// Derived: Hi</span>
+    vec3 spotDirection;         <span class="comment">// Sdli</span>
+    <span class="predefined-type">float</span> spotExponent;         <span class="comment">// Srli</span>
+    <span class="predefined-type">float</span> spotCutoff;           <span class="comment">// Crli</span>
+                                <span class="comment">// (range: [0.0,90.0], 180.0)</span>
+    <span class="predefined-type">float</span> spotCosCutoff;        <span class="comment">// Derived: cos(Crli)</span>
+                                <span class="comment">// (range: [1.0,0.0],-1.0)</span>
+    <span class="predefined-type">float</span> constantAttenuation;  <span class="comment">// K0</span>
+    <span class="predefined-type">float</span> linearAttenuation;    <span class="comment">// K1</span>
+    <span class="predefined-type">float</span> quadraticAttenuation; <span class="comment">// K2</span>
+};
+
+uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
+
+<span class="keyword">struct</span> gl_LightModelParameters {
+    vec4 ambient;                  <span class="comment">// Acs</span>
+};
+
+uniform gl_LightModelParameters gl_LightModel;
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+<span class="comment">// Derived state from products of light and material.</span>
+<span class="comment">//</span>
+
+<span class="keyword">struct</span> gl_LightModelProducts {
+    vec4 sceneColor; <span class="comment">// Derived. Ecm + Acm * Acs</span>
+};
+
+uniform gl_LightModelProducts gl_FrontLightModelProduct;
+uniform gl_LightModelProducts gl_BackLightModelProduct;
+
+<span class="keyword">struct</span> gl_LightProducts {
+    vec4 ambient; <span class="comment">// Acm * Acli</span>
+    vec4 diffuse; <span class="comment">// Dcm * Dcli</span>
+    vec4 specular; <span class="comment">// Scm * Scli</span>
+};
+
+uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];
+uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+uniform vec4 gl_TextureEnvColor[gl_MaxTextureUnits];
+uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords];
+uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords];
+uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords];
+uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords];
+uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords];
+uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords];
+uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords];
+uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords];
+
+<span class="comment">//</span>
+<span class="comment">// compatibility profile only</span>
+<span class="comment">//</span>
+<span class="keyword">struct</span> gl_FogParameters {
+    vec4 color;
+    <span class="predefined-type">float</span> density;
+    <span class="predefined-type">float</span> start;
+    <span class="predefined-type">float</span> end;
+    <span class="predefined-type">float</span> scale; <span class="comment">// Derived: 1.0 / (end - start)</span>
+};
+
+uniform gl_FogParameters gl_Fog;</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="redeclaring-built-in-blocks">7.5. Redeclaring Built-In Blocks</h3>
+<div class="paragraph">
+<p>The <em>gl_PerVertex</em> block can be redeclared in a shader to explicitly
+indicate what subset of the fixed pipeline interface will be used.
+This is necessary to establish the interface between multiple programs.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out gl_PerVertex {
+    vec4 gl_Position;   <span class="comment">// will use gl_Position</span>
+    <span class="predefined-type">float</span> gl_PointSize; <span class="comment">// will use gl_PointSize</span>
+    vec4 t;             <span class="comment">// error, only gl_PerVertex members allowed</span>
+}; <span class="comment">// no other members of gl_PerVertex will be used</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This establishes the output interface the shader will use with the
+subsequent pipeline stage.
+It must be a subset of the built-in members of <em>gl_PerVertex</em>.
+Such a redeclaration can also add the <strong>invariant</strong> qualifier, interpolation
+qualifiers, and the layout qualifiers <strong>xfb_offset</strong>, <strong>xfb_buffer</strong>, and
+<strong>xfb_stride</strong>.
+It can also add an array size for unsized arrays.
+For example:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">out layout(xfb_buffer = <span class="integer">1</span>, xfb_stride = <span class="integer">16</span>) gl_PerVertex {
+    vec4 gl_Position;
+    layout(xfb_offset = <span class="integer">0</span>) <span class="predefined-type">float</span> gl_ClipDistance[<span class="integer">4</span>];
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Other layout qualifiers, like <strong>location</strong>, cannot be added to such a
+redeclaration, unless specifically stated.</p>
+</div>
+<div class="paragraph">
+<p>If a built-in interface block is redeclared, it must appear in the shader
+before any use of any member included in the built-in declaration, or a
+compile-time error will result.
+It is also a compile-time error to redeclare the block more than once or to
+redeclare a built-in block and then use a member from that built-in block
+that was not included in the redeclaration.
+Also, if a built-in interface block is redeclared, no member of the built-in
+declaration can be redeclared outside the block redeclaration.
+If multiple shaders using members of a built-in block belonging to the same
+interface are linked together in the same program, they must all redeclare
+the built-in block in the same way, as described in
+&#8220;<a href="#interface-blocks">Interface Blocks</a>&#8221; for interface block matching, or a
+link-time error will result.
+It will also be a link-time error if some shaders in a program redeclare a
+specific built-in interface block while another shader in that program does
+not redeclare that interface block yet still uses a member of that interface
+block.
+If a built-in block interface is formed across shaders in different
+programs, the shaders must all redeclare the built-in block in the same way
+(as described for a single program), or the values passed along the
+interface are undefined.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="built-in-functions">8. Built-In Functions</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The OpenGL Shading Language defines an assortment of built-in convenience functions for
+scalar and vector operations.
+Many of these built-in functions can be used in more than one type of
+shader, but some are intended to provide a direct mapping to hardware and so
+are available only for a specific type of shader.</p>
+</div>
+<div class="paragraph">
+<p>The built-in functions basically fall into three categories:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>They expose some necessary hardware functionality in a convenient way
+such as accessing a texture map.
+There is no way in the language for these functions to be emulated by a
+shader.</p>
+</li>
+<li>
+<p>They represent a trivial operation (clamp, mix, etc.) that is very
+simple for the user to write, but they are very common and may have
+direct hardware support.
+It is a very hard problem for the compiler to map expressions to complex
+assembler instructions.</p>
+</li>
+<li>
+<p>They represent an operation graphics hardware is likely to accelerate at
+some point.
+The trigonometry functions fall into this category.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Many of the functions are similar to the same named ones in common C
+libraries, but they support vector input as well as the more traditional
+scalar input.</p>
+</div>
+<div class="paragraph">
+<p>Applications should be encouraged to use the built-in functions rather than
+do the equivalent computations in their own shader code since the built-in
+functions are assumed to be optimal (e.g. perhaps supported directly in
+hardware).</p>
+</div>
+<div class="paragraph">
+<p>User code can replace built-in functions with their own if they choose, by
+simply redeclaring and defining the same name and argument list.
+Because built-in functions are in a more outer scope than user built-in
+functions, doing this will hide all built-in functions with the same name as
+the redeclared function.</p>
+</div>
+<div class="paragraph">
+<p>When the built-in functions are specified below, where the input arguments
+(and corresponding output) can be <strong>float</strong>, <strong>vec2</strong>, <strong>vec3</strong>, or <strong>vec4</strong>,
+<em>genFType</em> is used as the argument.
+Where the input arguments (and corresponding output) can be <strong>int</strong>, <strong>ivec2</strong>,
+<strong>ivec3</strong>, or <strong>ivec4</strong>, <em>genIType</em> is used as the argument.
+Where the input arguments (and corresponding output) can be <strong>uint</strong>, <strong>uvec2</strong>,
+<strong>uvec3</strong>, or <strong>uvec4</strong>, <em>genUType</em> is used as the argument.
+Where the input arguments (or corresponding output) can be <strong>bool</strong>, <strong>bvec2</strong>,
+<strong>bvec3</strong>, or <strong>bvec4</strong>, <em>genBType</em> is used as the argument.
+Where the input arguments (and corresponding output) can be <strong>double</strong>,
+<strong>dvec2</strong>, <strong>dvec3</strong>, <strong>dvec4</strong>, <em>genDType</em> is used as the argument.
+For any specific use of a function, the actual types substituted for
+<em>genFType</em>, <em>genIType</em>, <em>genUType</em>, or <em>genBType</em> have to have the same
+number of components for all arguments and for the return type.
+Similarly, <em>mat</em> is used for any matrix basic
+type with single-precision
+components and <em>dmat</em> is used for any matrix basic type with
+double-precision components.</p>
+</div>
+<div class="sect2">
+<h3 id="angle-and-trigonometry-functions">8.1. Angle and Trigonometry Functions</h3>
+<div class="paragraph">
+<p>Function parameters specified as <em>angle</em> are assumed to be in units of
+radians.
+In no case will any of these functions result in a divide by zero error.
+If the divisor of a ratio is 0, then results will be undefined.</p>
+</div>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>radians</strong>(genFType <em>degrees</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>degrees</em> to radians, i.e.,
+      <span class="eq">(π / 180) · degrees</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>degrees</strong>(genFType <em>radians</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Converts <em>radians</em> to degrees, i.e.,
+      <span class="eq">(180 / π) · radians</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sin</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric sine function.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cos</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric cosine function.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tan</strong>(genFType <em>angle</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">The standard trigonometric tangent.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asin</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc sine.
+      Returns an angle whose sine is <em>x</em>.
+      The range of values returned by this function is
+      <span class="eq">[-π / 2, π / 2]</span>.
+      Results are undefined if <span class="eq">|x| &gt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acos</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc cosine.
+      Returns an angle whose cosine is <em>x</em>.
+      The range of values returned by this function is <span class="eq">[0,π]</span>.
+      Results are undefined if <span class="eq">|x| &gt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y</em>, genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent.
+      Returns an angle whose tangent is <span class="eq">y / x</span>.
+      The signs of <em>x</em> and <em>y</em> are used to determine what quadrant the angle
+      is in.
+      The range of values returned by this function is <span class="eq">[-π, π</span>.
+      Results are undefined if <em>x</em> and <em>y</em> are both 0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atan</strong>(genFType <em>y_over_x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc tangent.
+      Returns an angle whose tangent is <em>y_over_x</em>.
+      The range of values returned by this function is
+      <span class="eq">[-π / 2, π / 2]</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sinh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic sine function <span class="eq">(e<sup>x</sup> - e<sup>-x</sup>) / 2</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>cosh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic cosine function <span class="eq">(e<sup>x</sup> + e<sup>-x</sup>) / 2</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>tanh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the hyperbolic tangent function <span class="eq">sinh(x) / cosh(x)</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>asinh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic sine; returns the inverse of <strong>sinh</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>acosh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic cosine; returns the non-negative inverse of <strong>cosh</strong>.
+      Results are undefined if <span class="eq">x &lt; 1</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>atanh</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Arc hyperbolic tangent; returns the inverse of <strong>tanh</strong>.
+      Results are undefined if <span class="eq">x ≥ 1</span>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="exponential-functions">8.2. Exponential Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>pow</strong>(genFType <em>x</em>, genFType <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> raised to the <em>y</em> power, i.e., <span class="eq">x<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x &lt; 0</span>.
+      Results are undefined if <span class="eq">x = 0</span> and <span class="eq">y ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural exponentiation of <em>x</em>, i.e., <span class="eq">e<sup>x</sup></span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the natural logarithm of <em>x</em>, i.e., returns the value <em>y</em>
+      which satisfies the equation <span class="eq">x = e<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>exp2</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 2 raised to the <em>x</em> power, i.e., <span class="eq">2<sup>x</sup></span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>log2</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the base 2 logarithm of <em>x</em>, i.e., returns the value <em>y</em> which
+      satisfies the equation <span class="eq">x = 2<sup>y</sup></span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sqrt</strong>(genFType <em>x</em>)<br>
+  genDType <strong>sqrt</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">sqrt(x)</span>.
+      Results are undefined if <span class="eq">x &lt; 0</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>inversesqrt</strong>(genFType <em>x</em>)<br>
+  genDType <strong>inversesqrt</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <span class="eq">1 / sqrt(x)</span>.
+      Results are undefined if <span class="eq">x ≤ 0</span>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="common-functions">8.3. Common Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>abs</strong>(genFType <em>x</em>)<br>
+  genIType <strong>abs</strong>(genIType <em>x</em>)<br>
+  genDType <strong>abs</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> if <span class="eq">x ≥ 0</span>; otherwise it returns -<em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>sign</strong>(genFType <em>x</em>)<br>
+  genIType <strong>sign</strong>(genIType <em>x</em>)<br>
+  genDType <strong>sign</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 1.0 if <em>x</em> &gt; 0, 0.0 if <em>x</em> = 0, or -1.0 if <em>x</em> &lt; 0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>floor</strong>(genFType <em>x</em>)<br>
+  genDType <strong>floor</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is less than or
+      equal to <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>trunc</strong>(genFType <em>x</em>)<br>
+  genDType <strong>trunc</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em> whose absolute
+      value is not larger than the absolute value of <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>round</strong>(genFType <em>x</em>)<br>
+  genDType <strong>round</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>.
+      The fraction 0.5 will round in a direction chosen by the
+      implementation, presumably the direction that is fastest.
+      This includes the possibility that <strong>round</strong>(<em>x</em>) returns the same value
+      as <strong>roundEven</strong>(<em>x</em>) for all values of <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>roundEven</strong>(genFType <em>x</em>)<br>
+  genDType <strong>roundEven</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer to <em>x</em>.
+      A fractional part of 0.5 will round toward the nearest even integer.
+      (Both 3.5 and 4.5 for x will return 4.0.)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ceil</strong>(genFType <em>x</em>)<br>
+  genDType <strong>ceil</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a value equal to the nearest integer that is greater than or
+      equal to <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fract</strong>(genFType <em>x</em>)<br>
+  genDType <strong>fract</strong>(genDType <em>x</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>x</em> - <strong>floor</strong>(<em>x</em>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mod</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genFType <strong>mod</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  genDType <strong>mod</strong>(genDType <em>x</em>, double <em>y</em>)<br>
+  genDType <strong>mod</strong>(genDType <em>x</em>, genDType <em>y</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Modulus.
+      Returns <span class="eq">x - y · <strong>floor</strong>(x / y)</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>modf</strong>(genFType <em>x</em>, out genFType <em>i</em>)<br>
+  genDType <strong>modf</strong>(genDType <em>x</em>, out genDType <em>i</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the fractional part of <em>x</em> and sets <em>i</em> to the integer part (as
+      a whole number floating-point value).
+      Both the return value and the output parameter will have the same sign
+      as <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>min</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  genFType <strong>min</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genDType <strong>min</strong>(genDType <em>x</em>, genDType <em>y</em>)<br>
+  genDType <strong>min</strong>(genDType <em>x</em>, double <em>y</em>)<br>
+  genIType <strong>min</strong>(genIType <em>x</em>, genIType <em>y</em>)<br>
+  genIType <strong>min</strong>(genIType <em>x</em>, int <em>y</em>)<br>
+  genUType <strong>min</strong>(genUType <em>x</em>, genUType <em>y</em>)<br>
+  genUType <strong>min</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>y</em> &lt; <em>x;</em> otherwise it returns <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>max</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  genFType <strong>max</strong>(genFType <em>x</em>, float <em>y</em>)<br>
+  genDType <strong>max</strong>(genDType <em>x</em>, genDType <em>y</em>)<br>
+  genDType <strong>max</strong>(genDType <em>x</em>, double <em>y</em>)<br>
+  genIType <strong>max</strong>(genIType <em>x</em>, genIType <em>y</em>)<br>
+  genIType <strong>max</strong>(genIType <em>x</em>, int <em>y</em>)<br>
+  genUType <strong>max</strong>(genUType <em>x</em>, genUType <em>y</em>)<br>
+  genUType <strong>max</strong>(genUType <em>x</em>, uint <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <em>y</em> if <em>x</em> &lt; <em>y;</em> otherwise it returns <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>clamp</strong>(genFType <em>x</em>, genFType <em>minVal</em>, genFType <em>maxVal</em>)<br>
+  genFType <strong>clamp</strong>(genFType <em>x</em>, float <em>minVal</em>, float <em>maxVal</em>)<br>
+  genDType <strong>clamp</strong>(genDType <em>x</em>, genDType <em>minVal</em>, genDType <em>maxVal</em>)<br>
+  genDType <strong>clamp</strong>(genDType <em>x</em>, double <em>minVal</em>, double <em>maxVal</em>)<br>
+  genIType <strong>clamp</strong>(genIType <em>x</em>, genIType <em>minVal</em>, genIType <em>maxVal</em>)<br>
+  genIType <strong>clamp</strong>(genIType <em>x</em>, int <em>minVal</em>, int <em>maxVal</em>)<br>
+  genUType <strong>clamp</strong>(genUType <em>x</em>, genUType <em>minVal</em>, genUType <em>maxVal</em>)<br>
+  genUType <strong>clamp</strong>(genUType <em>x</em>, uint <em>minVal</em>, uint <em>maxVal</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>min</strong>(<strong>max</strong>(<em>x</em>, <em>minVal</em>), <em>maxVal</em>).
+      Results are undefined if <em>minVal</em> &gt; <em>maxVal</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType <em>a</em>)<br>
+  genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, float <em>a</em>)<br>
+  genDType <strong>mix</strong>(genDType <em>x</em>, genDType <em>y</em>, genDType <em>a</em>)<br>
+  genDType <strong>mix</strong>(genDType <em>x</em>, genDType <em>y</em>, double <em>a</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the linear blend of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">x · (1 - a) + y · a</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>,  genBType <em>a</em>)<br>
+  genDType <strong>mix</strong>(genDType <em>x</em>, genDType <em>y</em>, genBType <em>a</em>)<br>
+  genIType <strong>mix</strong>(genIType <em>x</em>, genIType <em>y</em>, genBType <em>a</em>)<br>
+  genUType <strong>mix</strong>(genUType <em>x</em>, genUType <em>y</em>, genBType <em>a</em>)<br>
+  genBType <strong>mix</strong>(genBType <em>x</em>, genBType <em>y</em>, genBType <em>a</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Selects which vector each returned component comes from.
+      For a component of <em>a</em> that is <strong>false</strong>, the corresponding component of
+      <em>x</em> is returned.
+      For a component of <em>a</em> that is <strong>true</strong>, the corresponding component of
+      <em>y</em> is returned.
+      Components of <em>x</em> and <em>y</em> that are not selected are allowed to be
+      invalid floating-point values and will have no effect on the results.
+      Thus, this provides different functionality than, for example,<br>
+      genFType <strong>mix</strong>(genFType <em>x</em>, genFType <em>y</em>, genFType(<em>a</em>))<br>
+      where <em>a</em> is a Boolean vector.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>step</strong>(genFType <em>edge</em>, genFType <em>x</em>)<br>
+  genFType <strong>step</strong>(float <em>edge</em>, genFType <em>x</em>)<br>
+  genDType <strong>step</strong>(genDType <em>edge</em>, genDType <em>x</em>)<br>
+  genDType <strong>step</strong>(double <em>edge</em>, genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns 0.0 if <em>x</em> &lt; <em>edge;</em> otherwise it returns 1.0.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>smoothstep</strong>(genFType <em>edge0</em>, genFType <em>edge1</em>, genFType <em>x</em>)<br>
+  genFType <strong>smoothstep</strong>(float <em>edge0</em>, float <em>edge1</em>, genFType <em>x</em>)<br>
+  genDType <strong>smoothstep</strong>(genDType <em>edge0</em>, genDType <em>edge1</em>, genDType <em>x</em>)<br>
+  genDType <strong>smoothstep</strong>(double <em>edge0</em>, double <em>edge1</em>, genDType <em>x</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns 0.0 if <span class="eq">x ≤ edge0</span> and 1.0 if <span class="eq">x ≥ edge1</span>, and
+      performs smooth Hermite interpolation between 0 and 1 when <span class="eq">edge0
+      &lt; x &lt; edge1</span>.
+      This is useful in cases where you would want a threshold function with
+      a smooth transition.
+      This is equivalent to:</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">genFType t;
+t = clamp ((x - edge0) / (edge1 - edge0), <span class="integer">0</span>, <span class="integer">1</span>);
+<span class="keyword">return</span> t * t * (<span class="integer">3</span> - <span class="integer">2</span> * t);</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>(And similarly for doubles.) Results are undefined if <span class="eq">edge0 ≥
+edge1</span>.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isnan</strong>(genFType <em>x</em>)<br>
+  genBType <strong>isnan</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a NaN.
+      Returns <strong>false</strong> otherwise.
+      Always returns <strong>false</strong> if NaNs are not implemented.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genBType <strong>isinf</strong>(genFType <em>x</em>)<br>
+  genBType <strong>isinf</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>x</em> holds a positive infinity or negative infinity.
+      Returns <strong>false</strong> otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>floatBitsToInt</strong>( genFType <em>value</em>)<br>
+  genUType <strong>floatBitsToUint</strong>( genFType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a signed or unsigned integer value representing the encoding
+      of a floating-point value.
+      The <strong>float</strong> value&#8217;s bit-level representation is preserved.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>intBitsToFloat</strong>( genIType <em>value</em>)<br>
+  genFType <strong>uintBitsToFloat</strong>( genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a floating-point value corresponding to a signed or unsigned
+      integer encoding of a floating-point value.
+      If a NaN is passed in, it will not signal, and the resulting value is
+      unspecified.
+      If an Inf is passed in, the resulting value is the corresponding Inf.
+      Otherwise, the bit-level representation is preserved.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fma</strong>(genFType <em>a</em>, genFType <em>b</em>, genFType <em>c</em>)<br>
+  genDType <strong>fma</strong>(genDType <em>a</em>, genDType <em>b</em>, genDType <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Computes and returns <span class="eq">a * b + c</span>.
+      In uses where the return value is eventually consumed by a variable
+      declared as <strong>precise</strong>:</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="ulist">
+<ul>
+<li>
+<p><strong>fma</strong>() is considered a single operation, whereas the expression &#8220;a * b
++ c&#8221; consumed by a variable declared <strong>precise</strong> is considered two
+operations.</p>
+</li>
+<li>
+<p>The precision of <strong>fma</strong>() can differ from the precision of the expression
+&#8220;a * b + c&#8221;.</p>
+</li>
+<li>
+<p><strong>fma</strong>() will be computed with the same precision as any other <strong>fma</strong>()
+consumed by a precise variable, giving invariant results for the same
+input values of <em>a</em>, <em>b</em>, and <em>c</em>.</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Otherwise, in the absence of <strong>precise</strong> consumption, there are no special
+constraints on the number of operations or difference in precision between
+<strong>fma</strong>() and the expression &#8220;_a_ * <em>b</em> + <em>c</em>&#8221;.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>frexp</strong>( genFType <em>x</em>, out  genIType <em>exp</em>)
+  genDType <strong>frexp</strong>(genDType <em>x</em>, out genIType <em>exp</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Splits <em>x</em> into a floating-point significand in the range
+      <span class="eq">[0.5,1.0]</span>, and an integral exponent of two, such that</p>
+<p class="tableblock">      <span class="eq">x = significant · 2<sup>exponent</sup></span></p>
+<p class="tableblock">      The significand is returned by the function and the exponent is
+      returned in the parameter <em>exp</em>.
+      For a floating-point value of zero, the significand and exponent are
+      both zero.</p>
+<p class="tableblock">      If an implementation supports signed zero, an input value of minus
+      zero should return a significand of minus zero.
+      For a floating-point value that is an infinity or is not a number, the
+      results are undefined.</p>
+<p class="tableblock">      If the input <em>x</em> is a vector, this operation is performed in a
+      component-wise manner; the value returned by the function and the
+      value written to <em>exp</em> are vectors with the same number of components
+      as <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>ldexp</strong>( genFType <em>x</em>,  genIType <em>exp</em>)<br>
+  genDType <strong>ldexp</strong>(genDType <em>x</em>, genIType <em>exp</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Builds a floating-point number from <em>x</em> and the corresponding integral
+      exponent of two in <em>exp</em>, returning:</p>
+<p class="tableblock">      <span class="eq">significand · 2<sup>exponent</sup></span></p>
+<p class="tableblock">      If this product is too large to be represented in the floating-point
+      type, the result is undefined.</p>
+<p class="tableblock">      If <em>exp</em> is greater than +128 (single-precision) or +1024
+      (double-precision), the value returned is undefined.
+      If <em>exp</em> is less than -126 (single-precision) or -1022
+      (double-precision), the value returned may be flushed to zero.
+      Additionally, splitting the value into a significand and exponent
+      using <strong>frexp</strong>() and then reconstructing a floating-point value using
+      <strong>ldexp</strong>() should yield the original input for zero and all finite
+      non-denormalized values.<br>
+      If the input <em>x</em> is a vector, this operation is performed in a
+      component-wise manner; the value passed in <em>exp</em> and returned by the
+      function are vectors with the same number of components as <em>x</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="floating-point-pack-and-unpack-functions">8.4. Floating-Point Pack and Unpack Functions</h3>
+<div class="paragraph">
+<p>These functions do not operate component-wise, rather, as described in each
+case.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>packUnorm2x16</strong>(vec2 <em>v</em>)<br>
+   uint <strong>packSnorm2x16</strong>(vec2 <em>v</em>)<br>
+   uint <strong>packUnorm4x8</strong>(vec4 <em>v</em>)<br>
+   uint <strong>packSnorm4x8</strong>(vec4 <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">First, converts each component of the normalized floating-point value
+      <em>v</em> into 16-bit (<strong>2x16</strong>) or 8-bit (<strong>4x8</strong>) integer values.
+      Then, the results are packed into the returned 32-bit unsigned
+      integer.</p>
+<p class="tableblock">      The conversion for component <em>c</em> of <em>v</em> to fixed point is done as
+      follows:</p>
+<p class="tableblock">      <strong>packUnorm2x16</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 65535.0)<br>
+      <strong>packSnorm2x16:</strong> <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 32767.0)<br>
+      <strong>packUnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, 0, +1) * 255.0)<br>
+      <strong>packSnorm4x8</strong>: <strong>round</strong>(<strong>clamp</strong>(<em>c</em>, -1, +1) * 127.0)</p>
+<p class="tableblock">      The first component of the vector will be written to the least
+      significant bits of the output; the last component will be written to
+      the most significant bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> vec2 <strong>unpackUnorm2x16</strong>( uint <em>p</em>)<br>
+   vec2 <strong>unpackSnorm2x16</strong>( uint <em>p</em>)<br>
+   vec4 <strong>unpackUnorm4x8</strong>( uint <em>p</em>)<br>
+   vec4 <strong>unpackSnorm4x8</strong>( uint <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">First, unpacks a single 32-bit unsigned integer <em>p</em> into a pair of
+      16-bit unsigned integers, a pair of 16-bit signed integers, four 8-bit
+      unsigned integers, or four 8-bit signed integers, respectively.
+      Then, each component is converted to a normalized floating-point value
+      to generate the returned two- or four-component vector.</p>
+<p class="tableblock">      The conversion for unpacked fixed-point value <em>f</em> to floating-point is
+      done as follows:</p>
+<p class="tableblock">      <strong>unpackUnorm2x16</strong>: <em>f</em> / 65535.0<br>
+      <strong>unpackSnorm2x16</strong>: <strong>clamp</strong>(<em>f</em> / 32767.0, -1, +1)<br>
+      <strong>unpackUnorm4x8</strong>: <em>f</em> / 255.0<br>
+      <strong>unpackSnorm4x8</strong>: <strong>clamp</strong>(<em>f</em> / 127.0, -1, +1)</p>
+<p class="tableblock">      The first component of the returned vector will be extracted from the
+      least significant bits of the input; the last component will be
+      extracted from the most significant bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>packHalf2x16</strong>(vec2 <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns an unsigned integer obtained by converting the components of a
+      two-component floating-point vector to the 16-bit floating-point
+      representation found in the <a href="#references">OpenGL Specification</a>, and
+      then packing these two 16-bit integers into a 32-bit unsigned integer.</p>
+<p class="tableblock">      The first vector component specifies the 16 least-significant bits of
+      the result; the second component specifies the 16 most-significant
+      bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> vec2 <strong>unpackHalf2x16</strong>( uint <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a two-component floating-point vector with components obtained
+      by unpacking a 32-bit unsigned integer into a pair of 16-bit values,
+      interpreting those values as 16-bit floating-point numbers according
+      to the <a href="#references">OpenGL Specification</a>, and converting them to
+      32-bit floating-point values.</p>
+<p class="tableblock">      The first component of the vector is obtained from the 16
+      least-significant bits of <em>v</em>; the second component is obtained from
+      the 16 most-significant bits of <em>v</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">double <strong>packDouble2x32</strong>(uvec2 <em>v</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a double-precision value obtained by packing the components of
+      <em>v</em> into a 64-bit value.
+      If an IEEE 754 Inf or NaN is created, it will not signal, and the
+      resulting floating-point value is unspecified.
+      Otherwise, the bit-level representation of <em>v</em> is preserved.
+      The first vector component specifies the 32 least significant bits;
+      the second component specifies the 32 most significant bits.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uvec2 <strong>unpackDouble2x32</strong>(double <em>v</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a two-component unsigned integer vector representation of <em>v</em>.
+      The bit-level representation of <em>v</em> is preserved.
+      The first component of the vector contains the 32 least significant
+      bits of the double; the second component consists of the 32 most
+      significant bits.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="geometric-functions">8.5. Geometric Functions</h3>
+<div class="paragraph">
+<p>These operate on vectors as vectors, not component-wise.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>length</strong>(genFType <em>x</em>)<br>
+  double <strong>length</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the length of vector <em>x</em>, i.e.,
+      <span class="eq">sqrt( x<sub>0</sub><sup>2</sup> + x<sub>1</sub><sup>2</sup> + &#8230;&#8203; )</span>.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>distance</strong>(genFType <em>p0</em>, genFType <em>p1</em>)<br>
+  double <strong>distance</strong>(genDType <em>p0</em>, genDType <em>p1</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the distance between <em>p0</em> and <em>p1</em>, i.e.,
+      <strong>length</strong>(<em>p0</em> - <em>p1</em>)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>dot</strong>(genFType <em>x</em>, genFType <em>y</em>)<br>
+  double <strong>dot</strong>(genDType <em>x</em>, genDType <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dot product of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">x<sub>0</sub> · y<sub>0</sub> + x<sub>1</sub> · y<sub>1</sub> + &#8230;&#8203;</span></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec3 <strong>cross</strong>(vec3 <em>x</em>, vec3 <em>y</em>)<br>
+  dvec3 <strong>cross</strong>(dvec3 <em>x</em>, dvec3 <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the cross product of <em>x</em> and <em>y</em>, i.e.,
+      <span class="eq">(x<sub>1</sub> · y<sub>2</sub> - y<sub>1</sub> · x<sub>2</sub>,
+            x<sub>2</sub> · y<sub>0</sub> - y<sub>2</sub> · x<sub>0</sub>,
+            x<sub>0</sub> · y<sub>1</sub> - y<sub>0</sub> · x<sub>1</sub>)</span>.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>normalize</strong>(genFType <em>x</em>)<br>
+  genDType <strong>normalize</strong>(genDType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a vector in the same direction as <em>x</em> but with a length of 1,
+      i.e. <em>x</em> / <strong>length</strong>(x).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">compatibility profile only<br>
+  vec4 <strong>ftransform</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Available only when using the compatibility profile.
+      For core OpenGL, use <strong>invariant</strong>.<br>
+      For vertex shaders only.
+      This function will ensure that the incoming vertex value will be
+      transformed in a way that produces exactly the same result as would be
+      produced by OpenGL&#8217;s fixed functionality transform.
+      It is intended to be used to compute <em>gl_Position</em>, e.g.</p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p><em>gl_Position</em> = <strong>ftransform</strong>()</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>This function should be used, for example, when an application is rendering
+the same geometry in separate passes, and one pass uses the fixed
+functionality path to render and another pass uses programmable shaders.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>faceforward</strong>(genFType <em>N</em>, genFType <em>I</em>, genFType <em>Nref</em>)<br>
+  genDType <strong>faceforward</strong>(genDType <em>N</em>, genDType <em>I</em>, genDType <em>Nref</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">If <strong>dot</strong>(<em>Nref</em>, <em>I</em>) &lt; 0 return <em>N</em>, otherwise return -<em>N</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>reflect</strong>(genFType <em>I</em>, genFType <em>N</em>)<br>
+  genDType <strong>reflect</strong>(genDType <em>I</em>, genDType <em>N</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">For the incident vector <em>I</em> and surface orientation <em>N</em>, returns the
+      reflection direction: <span class="eq">I - 2 · <strong>dot</strong>(N, I) · N</span>.
+      <em>N</em> must already be normalized in order to achieve the desired result.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>refract</strong>(genFType <em>I</em>, genFType <em>N</em>, float <em>eta</em>)<br>
+  genDType <strong>refract</strong>(genDType <em>I</em>, genDType <em>N</em>, double <em>eta</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>For the incident vector <em>I</em> and surface normal <em>N</em>, and the ratio of
+      indices of refraction <em>eta</em>, return the refraction vector.
+      The result is computed by the <a href="#refraction-equation">refraction
+      equation</a> shown below.</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>The input parameters for the incident vector _I_ and the surface
+normal _N_ must already be normalized to get the desired results.</pre>
+</div>
+</div></div></td>
+</tr>
+</tbody>
+</table>
+<div class="sect3">
+<h4 id="refraction-equation">8.5.1. Refraction Equation</h4>
+<div class="stemblock">
+<div class="content">
+\[k = 1.0 - eta * eta * (1.0 - \textbf{dot}(N,I) \cdot \textbf{dot}(N,I))\]
+</div>
+</div>
+<div class="stemblock">
+<div class="content">
+\[\begin{aligned}
+result &amp;=
+  \begin{cases}
+    genFType(0.0), &amp; k &lt; 0.0 \\
+    eta * I - (eta * \textbf{dot}(N,I) + \sqrt { k }) * N, &amp; \textbf{otherwise}
+  \end{cases}
+\end{aligned}\]
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="matrix-functions">8.6. Matrix Functions</h3>
+<div class="paragraph">
+<p>For each of the following built-in matrix functions, there is both a
+single-precision floating-point version, where all arguments and return
+values are single precision, and a double-precision floating-point version,
+where all arguments and return values are double precision.
+Only the single-precision floating-point version is shown.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat <strong>matrixCompMult</strong>(mat <em>x</em>, mat <em>y</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Multiply matrix <em>x</em> by matrix <em>y</em> component-wise, i.e., result[i][j]
+      is the scalar product of <em>x</em>[i][j] and <em>y</em>[i][j].<br></p>
+<p class="tableblock">      Note: to get linear algebraic matrix multiplication, use the multiply
+      operator (<strong>*</strong>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec2 <em>r</em>)<br>
+  mat3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec3 <em>r</em>)<br>
+  mat4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec4 <em>r</em>)<br>
+  mat2x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec2 <em>r</em>)<br>
+  mat3x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec3 <em>r</em>)<br>
+  mat2x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec2 <em>r</em>)<br>
+  mat4x2 <strong>outerProduct</strong>(vec2 <em>c</em>, vec4 <em>r</em>)<br>
+  mat3x4 <strong>outerProduct</strong>(vec4 <em>c</em>, vec3 <em>r</em>)<br>
+  mat4x3 <strong>outerProduct</strong>(vec3 <em>c</em>, vec4 <em>r</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Treats the first parameter <em>c</em> as a column vector (matrix with one
+      column) and the second parameter <em>r</em> as a row vector (matrix with one
+      row) and does a linear algebraic matrix multiply <em>c</em> * <em>r</em>, yielding a
+      matrix whose number of rows is the number of components in <em>c</em> and
+      whose number of columns is the number of components in <em>r</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>transpose</strong>(mat2 <em>m</em>)<br>
+  mat3 <strong>transpose</strong>(mat3 <em>m</em>)<br>
+  mat4 <strong>transpose</strong>(mat4 <em>m</em>)<br>
+  mat2x3 <strong>transpose</strong>(mat3x2 <em>m</em>)<br>
+  mat3x2 <strong>transpose</strong>(mat2x3 <em>m</em>)<br>
+  mat2x4 <strong>transpose</strong>(mat4x2 <em>m</em>)<br>
+  mat4x2 <strong>transpose</strong>(mat2x4 <em>m</em>)<br>
+  mat3x4 <strong>transpose</strong>(mat4x3 <em>m</em>)<br>
+  mat4x3 <strong>transpose</strong>(mat3x4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the transpose of <em>m</em>.
+      The input matrix <em>m</em> is not modified.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>determinant</strong>(mat2 <em>m</em>)<br>
+  float <strong>determinant</strong>(mat3 <em>m</em>)<br>
+  float <strong>determinant</strong>(mat4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the determinant of <em>m</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">mat2 <strong>inverse</strong>(mat2 <em>m</em>)<br>
+  mat3 <strong>inverse</strong>(mat3 <em>m</em>)<br>
+  mat4 <strong>inverse</strong>(mat4 <em>m</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a matrix that is the inverse of <em>m</em>.
+      The input matrix <em>m</em> is not modified.
+      The values in the returned matrix are undefined if <em>m</em> is singular or
+      poorly-conditioned (nearly singular).</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="vector-relational-functions">8.7. Vector Relational Functions</h3>
+<div class="paragraph">
+<p>Relational and equality operators (<strong>&lt;</strong>, <strong>&lt;=</strong>, <strong>&gt;</strong>, <strong>&gt;=</strong>, <strong>==</strong>, <strong>!=</strong>) are
+defined to operate on scalars and produce scalar Boolean results.
+For vector results, use the following built-in functions.
+Below, the following placeholders are used for the listed specific types:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Placeholder</th>
+<th class="tableblock halign-left valign-top">Specific Types Allowed</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec2, bvec3, bvec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">ivec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">ivec2, ivec3, ivec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uvec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uvec2, uvec3, uvec4</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec2, vec3, vec4, dvec2, dvec3, dvec4</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>In all cases, the sizes of all the input and return vectors for any
+particular call must match.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThan</strong>(vec x, vec y)<br>
+  bvec <strong>lessThan</strong>(ivec x, ivec y)<br>
+  bvec <strong>lessThan</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x &lt; y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>lessThanEqual</strong>(vec x, vec y)<br>
+  bvec <strong>lessThanEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>lessThanEqual</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≤ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThan</strong>(vec x, vec y)<br>
+  bvec <strong>greaterThan</strong>(ivec x, ivec y)<br>
+  bvec <strong>greaterThan</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x &gt; y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>greaterThanEqual</strong>(vec x, vec y)<br>
+  bvec <strong>greaterThanEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>greaterThanEqual</strong>(uvec x, uvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≥ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>equal</strong>(vec x, vec y)<br>
+  bvec <strong>equal</strong>(ivec x, ivec y)<br>
+  bvec <strong>equal</strong>(uvec x, uvec y)<br>
+  bvec <strong>equal</strong>(bvec x, bvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x == y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>notEqual</strong>(vec x, vec y)<br>
+  bvec <strong>notEqual</strong>(ivec x, ivec y)<br>
+  bvec <strong>notEqual</strong>(uvec x, uvec y)<br>
+  bvec <strong>notEqual</strong>(bvec x, bvec y)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise compare of <span class="eq">x ≠ y</span>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>any</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if any component of <em>x</em> is <strong>true</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>all</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> only if all components of <em>x</em> are <strong>true</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bvec <strong>not</strong>(bvec x)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the component-wise logical complement of <em>x</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="integer-functions">8.8. Integer Functions</h3>
+<div class="paragraph">
+<p>These all operate component-wise.
+The description is per component.
+The notation [<em>a</em>, <em>b</em>] means the set of bits from bit-number <em>a</em> through
+bit-number <em>b</em>, inclusive.
+The lowest-order bit is bit 0.
+&#8220;Bit number&#8221; will always refer to counting up from the lowest-order bit as
+bit 0.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>uaddCarry</strong>( genUType <em>x</em>,  genUType <em>y</em>, out  genUType <em>carry</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Adds 32-bit unsigned integers <em>x</em> and <em>y</em>, returning the sum modulo
+      2<sup>32</sup>.
+      The value <em>carry</em> is set to zero if the sum was less than 2<sup>32</sup>, or
+      one otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genUType <strong>usubBorrow</strong>( genUType <em>x</em>,  genUType <em>y</em>, out  genUType <em>borrow</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Subtracts the 32-bit unsigned integer <em>y</em> from <em>x</em>, returning the
+      difference if non-negative, or 2<sup>32</sup> plus the difference otherwise.
+      The value <em>borrow</em> is set to zero if <span class="eq">x ≥ y</span>, or one
+      otherwise.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>umulExtended</strong>( genUType <em>x</em>,  genUType <em>y</em>, out  genUType <em>msb</em>, out  genUType <em>lsb</em>)<br>
+  void <strong>imulExtended</strong>( genIType <em>x</em>,  genIType <em>y</em>, out  genIType <em>msb</em>, out  genIType <em>lsb</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Multiplies 32-bit unsigned or signed integers <em>x</em> and <em>y</em>, producing a
+      64-bit result.
+      The 32 least-significant bits are returned in <em>lsb</em>.
+      The 32 most-significant bits are returned in <em>msb</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldExtract</strong>(genIType <em>value</em>, int <em>offset</em>, int <em>bits</em>)<br>
+  genUType <strong>bitfieldExtract</strong>(genUType <em>value</em>, int <em>offset</em>, int <em>bits</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Extracts bits <span class="eq">[offset, offset + bits - 1]</span> from <em>value</em>,
+      returning them in the least significant bits of the result.<br></p>
+<p class="tableblock">      For unsigned data types, the most significant bits of the result will
+      be set to zero.
+      For signed data types, the most significant bits will be set to the
+      value of bit <span class="eq">offset + bits - 1</span>.<br></p>
+<p class="tableblock">      If <em>bits</em> is zero, the result will be zero.
+      The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if
+      the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used
+      to store the operand.
+      Note that for vector versions of <strong>bitfieldExtract</strong>(), a single pair of
+      <em>offset</em> and <em>bits</em> values is shared for all components.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldInsert</strong>(genIType <em>base</em>, genIType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)<br>
+  genUType <strong>bitfieldInsert</strong>(genUType <em>base</em>, genUType <em>insert</em>, int <em>offset</em>, int <em>bits</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Inserts the <em>bits</em> least significant bits of <em>insert</em> into <em>base</em>.</p>
+<p class="tableblock">      The result will have bits <span class="eq">[offset, offset + bits - 1]</span> taken from
+      bits <span class="eq">[0, bits - 1]</span> of <em>insert</em>, and all other bits taken
+      directly from the corresponding bits of <em>base</em>.
+      If <em>bits</em> is zero, the result will simply be <em>base</em>.
+      The result will be undefined if <em>offset</em> or <em>bits</em> is negative, or if
+      the sum of <em>offset</em> and <em>bits</em> is greater than the number of bits used
+      to store the operand.<br>
+      Note that for vector versions of <strong>bitfieldInsert</strong>(), a single pair of
+      <em>offset</em> and <em>bits</em> values is shared for all components.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genIType <strong>bitfieldReverse</strong>( genIType <em>value</em>)<br>
+  genUType <strong>bitfieldReverse</strong>( genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Reverses the bits of <em>value</em>.
+      The bit numbered <em>n</em> of the result will be taken from bit <span class="eq">(bits -
+      1) - n</span> of <em>value</em>, where <em>bits</em> is the total number of bits used to
+      represent <em>value</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> genIType <strong>bitCount</strong>(genIType <em>value</em>)<br>
+   genIType <strong>bitCount</strong>(genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of one bits in the binary representation of
+      <em>value</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> genIType <strong>findLSB</strong>(genIType <em>value</em>)<br>
+   genIType <strong>findLSB</strong>(genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the least significant one bit in the binary
+      representation of <em>value</em>.
+      If <em>value</em> is zero, -1 will be returned.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> genIType <strong>findMSB</strong>( genIType <em>value</em>)<br>
+   genIType <strong>findMSB</strong>( genUType <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the bit number of the most significant bit in the binary
+      representation of <em>value</em>.</p>
+<p class="tableblock">      For positive integers, the result will be the bit number of the most
+      significant one bit.
+      For negative integers, the result will be the bit number of the most
+      significant zero bit.
+      For a <em>value</em> of zero or negative one, -1 will be returned.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="texture-functions">8.9. Texture Functions</h3>
+<div class="paragraph">
+<p>Texture lookup functions are available in all shading stages.
+However, level-of-detail is implicitly computed only for fragment shaders.
+Other shaders operate as though the base level-of-detail were computed as
+zero.
+The functions in the table below provide access to textures through
+samplers, as set up through the OpenGL API.
+Texture properties such as size, pixel format, number of dimensions,
+filtering method, number of mipmap levels, depth comparison, and so on are
+also defined by OpenGL API calls.
+Such properties are taken into account as the texture is accessed via the
+built-in functions defined below.</p>
+</div>
+<div class="paragraph">
+<p>Texture data can be stored by the GL as single-precision floating-point,
+unsigned normalized integer, unsigned integer or signed integer data.
+This is determined by the type of the internal format of the texture.</p>
+</div>
+<div class="paragraph">
+<p>Texture lookup functions are provided that can return their result as
+floating-point, unsigned integer or signed integer, depending on the sampler
+type passed to the lookup function.
+Care must be taken to use the right sampler type for texture access.
+The following table lists the supported combinations of sampler types and
+texture internal formats.
+Blank entries are unsupported.
+Doing a texture lookup will return undefined values for unsupported
+combinations.</p>
+</div>
+<div class="paragraph">
+<p>For depth/stencil textures, the internal texture format is determined by the
+component being accessed as set through the OpenGL API.
+When the depth/stencil texture mode is set to DEPTH_COMPONENT, the internal
+format of the depth component should be used.
+When the depth/stencil texture mode is set to STENCIL_INDEX, the internal format
+of the stencil component should be used.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+<col style="width: 25%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Internal Texture Format</th>
+<th class="tableblock halign-left valign-top">Floating-Point Sampler Types</th>
+<th class="tableblock halign-left valign-top">Signed Integer Sampler Types</th>
+<th class="tableblock halign-left valign-top">Unsigned Integer Sampler Types</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Floating-point</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Normalized Integer</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Signed Integer</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+<td class="tableblock halign-left valign-top"></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Unsigned Integer</p></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Supported</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>If an integer sampler type is used, the result of a texture lookup is an
+<strong>ivec4</strong>.
+If an unsigned integer sampler type is used, the result of a texture lookup
+is a <strong>uvec4</strong>.
+If a floating-point sampler type is used, the result of a texture lookup is
+a <strong>vec4</strong>.</p>
+</div>
+<div class="paragraph">
+<p>In the prototypes below, the &#8220;_g_&#8221; in the return type &#8220;_gvec4_&#8221; is used
+as a placeholder for nothing, &#8220;_i_&#8221;, or &#8220;_u_&#8221; making a return type of
+<strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong>.
+In these cases, the sampler argument type also starts with &#8220;_g_&#8221;,
+indicating the same substitution done on the return type; it is either a
+single-precision
+floating-point, signed integer, or unsigned integer sampler, matching the
+basic type of the return type, as described above.</p>
+</div>
+<div class="paragraph">
+<p>For shadow forms (the sampler parameter is a shadow-type), a depth
+comparison lookup on the depth texture bound to <em>sampler</em> is done as
+described in section
+8.23
+&#8220;Texture Comparison Modes&#8221; of the
+<a href="#references">OpenGL Specification</a>.
+See the table below for which component specifies <em>D<sub>ref</sub></em>.
+The texture bound to <em>sampler</em> must be a depth texture, or results are
+undefined.
+If a non-shadow texture call is made to a sampler that represents a depth
+texture with depth comparisons turned on, then results are undefined.
+If a shadow texture call is made to a sampler that represents a depth
+texture with depth comparisons turned off, then results are undefined.
+If a shadow texture call is made to a sampler that does not represent a
+depth texture, then results are undefined.</p>
+</div>
+<div class="paragraph">
+<p>In all functions below, the <em>bias</em> parameter is optional for fragment
+shaders.
+The <em>bias</em> parameter is not accepted in any other shader stage.
+For a fragment shader, if <em>bias</em> is present, it is added to the implicit
+level-of-detail prior to performing the texture access operation.
+No <em>bias</em> or <em>lod</em> parameters for
+rectangle textures,
+multisample textures, or texture buffers
+are supported because mipmaps are not allowed for these types of textures.</p>
+</div>
+<div class="paragraph">
+<p>The implicit level-of-detail is selected as follows: For a texture that is
+not mipmapped, the texture is used directly.
+If it is mipmapped and running in a fragment shader, the level-of-detail
+computed by the implementation is used to do the texture lookup.
+If it is mipmapped and running in a non-fragment shader, then the base
+texture is used.</p>
+</div>
+<div class="paragraph">
+<p>Some texture functions (non-&#8220;<strong>Lod</strong>&#8221; and non-&#8220;<strong>Grad</strong>&#8221; versions) may
+require implicit derivatives.
+Implicit derivatives are undefined within non-uniform control flow and for
+non-fragment shader texture fetches.</p>
+</div>
+<div class="paragraph">
+<p>For <strong>Cube</strong> forms, the direction of <em>P</em> is used to select which face to do a
+2-dimensional texture lookup in, as described in section 8.13 &#8220;Cube Map
+Texture Selection&#8221; of the <a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>For <strong>Array</strong> forms, the array layer used will be</p>
+</div>
+<div class="paragraph">
+<p>\(\max(0,\min(d-1,\left\lfloor layer + 0.5\right\rfloor))\)</p>
+</div>
+<div class="paragraph">
+<p>where <em>d</em> is the depth of the texture array and <em>layer</em> comes from the
+component indicated in the tables below.</p>
+</div>
+<div class="sect3">
+<h4 id="texture-query-functions">8.9.1. Texture Query Functions</h4>
+<div class="paragraph">
+<p>The <strong>textureSize</strong> functions query the dimensions of a specific texture level
+for a sampler.</p>
+</div>
+<div class="paragraph">
+<p>The <strong>textureQueryLod</strong> functions are available only in a fragment shader.
+They take the components of <em>P</em> and compute the level-of-detail information
+that the texture pipe would use to access that texture through a normal
+texture lookup.
+The level-of-detail \(\lambda^{'}\) (equation 3.18 of the
+<a href="#references">OpenGL Specification</a>) is obtained after any level-of-detail bias, but
+prior to clamping to [TEXTURE_MIN_LOD, TEXTURE_MAX_LOD].
+The mipmap array(s) that would be accessed are also computed.
+If a single level-of-detail would be accessed, the level-of-detail number
+relative to the base level is returned.
+If multiple levels-of-detail would be accessed, a floating-point number
+between the two levels is returned, with the fractional part equal to the
+fractional part of the computed and clamped level-of-detail.</p>
+</div>
+<div class="paragraph">
+<p>The algorithm used is given by the following pseudo-code:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++"><span class="predefined-type">float</span> ComputeAccessedLod(<span class="predefined-type">float</span> computedLod)
+{
+    <span class="comment">// Clamp the computed LOD according to the texture LOD clamps.</span>
+    <span class="keyword">if</span> (computedLod &lt; TEXTURE_MIN_LOD) computedLod = TEXTURE_MIN_LOD;
+    <span class="keyword">if</span> (computedLod &gt; TEXTURE_MAX_LOD) computedLod = TEXTURE_MAX_LOD;
+
+    <span class="comment">// Clamp the computed LOD to the range of accessible levels.</span>
+    <span class="keyword">if</span> (computedLod &lt; <span class="float">0</span><span class="float">.0</span>)
+        computedLod = <span class="float">0</span><span class="float">.0</span>;
+    <span class="keyword">if</span> (computedLod &gt; (<span class="predefined-type">float</span>) maxAccessibleLevel)
+        computedLod = (<span class="predefined-type">float</span>) maxAccessibleLevel;
+
+    <span class="comment">// Return a value according to the min filter.</span>
+    <span class="keyword">if</span> (TEXTURE_MIN_FILTER is LINEAR <span class="keyword">or</span> NEAREST) {
+        <span class="keyword">return</span> <span class="float">0</span><span class="float">.0</span>;
+    } <span class="keyword">else</span> <span class="keyword">if</span> (TEXTURE_MIN_FILTER is NEAREST_MIPMAP_NEAREST
+               <span class="keyword">or</span> LINEAR_MIPMAP_NEAREST) {
+        <span class="keyword">return</span> ceil(computedLod + <span class="float">0</span><span class="float">.5</span>) - <span class="float">1</span><span class="float">.0</span>;
+    } <span class="keyword">else</span> {
+        <span class="keyword">return</span> computedLod;
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The value <em>maxAccessibleLevel</em> is the level number of the smallest
+accessible level of the mipmap array (the value <em>q</em> in section 8.14.3
+&#8220;Mipmapping&#8221; of the <a href="#references">OpenGL Specification</a>) minus the base level.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> int <strong>textureSize</strong>(gsampler1D <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(gsampler2D <em>sampler</em>, int <em>lod</em>)<br>
+   ivec3 <strong>textureSize</strong>(gsampler3D <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(gsamplerCube <em>sampler</em>, int <em>lod</em>)<br>
+   int <strong>textureSize</strong>(sampler1DShadow <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(sampler2DShadow <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(samplerCubeShadow <em>sampler</em>, int <em>lod</em>)
+   ivec3 <strong>textureSize</strong>(gsamplerCubeArray <em>sampler</em>, int <em>lod</em>)<br>
+   ivec3 <strong>textureSize</strong>(samplerCubeArrayShadow <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(gsampler2DRect <em>sampler</em>)<br>
+   ivec2 <strong>textureSize</strong>(sampler2DRectShadow <em>sampler</em>)<br>
+   ivec2 <strong>textureSize</strong>(gsampler1DArray <em>sampler</em>, int <em>lod</em>)<br>
+   ivec2 <strong>textureSize</strong>(sampler1DArrayShadow <em>sampler</em>, int <em>lod</em>)<br>
+   ivec3 <strong>textureSize</strong>(gsampler2DArray <em>sampler</em>, int <em>lod</em>)<br>
+   ivec3 <strong>textureSize</strong>(sampler2DArrayShadow <em>sampler</em>, int <em>lod</em>)<br>
+   int <strong>textureSize</strong>(gsamplerBuffer <em>sampler</em>)<br>
+   ivec2 <strong>textureSize</strong>(gsampler2DMS <em>sampler</em>)<br>
+   ivec3 <strong>textureSize</strong>(gsampler2DMSArray <em>sampler</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of level <em>lod</em> (if present) for the texture
+      bound to <em>sampler</em>, as described in section
+      8.11 &#8220;Texture Queries&#8221; of the <a href="#references">OpenGL Specification</a>.<br>
+      The components in the return value are filled in, in order, with the
+      width, height, and depth of the texture.</p>
+<p class="tableblock">      For the array forms, the last component of the return value is the
+      number of layers in the texture array, or the number of cubes in the
+      texture cube map array.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec2 <strong>textureQueryLod</strong>(gsampler1D <em>sampler</em>, float <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsampler1DArray <em>sampler</em>, float <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsampler2DArray <em>sampler</em>, vec2 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(gsamplerCubeArray <em>sampler</em>, vec3 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(sampler1DShadow <em>sampler</em>, float <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(samplerCubeShadow <em>sampler</em>, vec3 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(sampler1DArrayShadow <em>sampler</em>, float <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(sampler2DArrayShadow <em>sampler</em>, vec2 <em>P</em>)<br>
+  vec2 <strong>textureQueryLod</strong>(samplerCubeArrayShadow <em>sampler</em>, vec3 <em>P</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the mipmap array(s) that would be accessed in the <em>x</em>
+      component of the return value.</p>
+<p class="tableblock">      Returns the computed level-of-detail relative to the base level in the
+      <em>y</em> component of the return value.</p>
+<p class="tableblock">      If called on an incomplete texture, the results are undefined.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">int <strong>textureQueryLevels</strong>(gsampler1D <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsampler2D <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsampler3D <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsamplerCube <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsampler1DArray <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsampler2DArray <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(gsamplerCubeArray <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(sampler1DShadow <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(sampler2DShadow <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(samplerCubeShadow <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(sampler1DArrayShadow <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(sampler2DArrayShadow <em>sampler</em>)<br>
+  int <strong>textureQueryLevels</strong>(samplerCubeArrayShadow <em>sampler</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of mipmap levels accessible in the texture
+      associated with <em>sampler</em>, as defined in the <a href="#references">OpenGL Specification.</a></p>
+<p class="tableblock">      The value zero will be returned if no texture or an incomplete texture
+      is associated with <em>sampler</em>.</p>
+<p class="tableblock">      Available in all shader stages.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">int <strong>textureSamples</strong>(gsampler2DMS <em>sampler</em>)<br>
+  int <strong>textureSamples</strong>(gsampler2DMSArray <em>sampler</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of samples of the texture or textures bound to
+      <em>sampler</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="texel-lookup-functions">8.9.2. Texel Lookup Functions</h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texture</strong>(gsampler1D <em>sampler</em>, float <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>[, float <em>bias</em>] )<br>
+  float <strong>texture</strong>(sampler1DShadow <em>sampler</em>, <em>vec3 _P</em> [, float <em>bias</em>])<br>
+  float <strong>texture</strong>(sampler2DShadow <em>sampler</em>, <em>vec3 _P</em> [, float <em>bias</em>])<br>
+  float <strong>texture</strong>(samplerCubeShadow <em>sampler</em>, <em>vec4 _P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>texture</strong>(gsampler1DArray <em>sampler</em>, <em>vec2 _P</em> [, float <em>bias</em>] )<br>
+  float <strong>texture</strong>(sampler1DArrayShadow <em>sampler</em>,  <em>P</em> [, float <em>bias</em>] )<br>
+  float <strong>texture</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>)<br>
+  gvec4 <strong>texture</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>)<br>
+  float <strong>texture</strong>(sampler2DRectShadow <em>sampler</em>, vec3 <em>P</em>)<br>
+  float <strong>texture</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>compare</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Use the texture coordinate <em>P</em> to do a texture lookup in the texture
+      currently bound to <em>sampler</em>.</p>
+<p class="tableblock">      For shadow forms: When <em>compare</em> is present, it is used as <em>D<sub>ref</sub></em>
+      and the array layer comes from the last component of <em>P</em>.
+      When <em>compare</em> is not present, the last component of <em>P</em> is used as
+      <em>D<sub>ref</sub></em> and the array layer comes from the second to last component
+      of <em>P</em>.
+      (The second component of <em>P</em> is unused for <strong>1D</strong> shadow lookups.)</p>
+<p class="tableblock">      For non-shadow forms: the array layer comes from the last component of
+      <em>P</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProj</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  float <strong>textureProj</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  float <strong>textureProj</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProj</strong>(gsampler2DRect <em>sampler</em>, vec3 <em>P</em>)<br>
+  gvec4 <strong>textureProj</strong>(gsampler2DRect <em>sampler</em>, vec4 <em>P</em>)<br>
+  float <strong>textureProj</strong>(sampler2DRectShadow <em>sampler</em>, vec4 <em>P</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with projection.
+      The texture coordinates consumed from <em>P</em>, not including the last
+      component of <em>P</em>, are divided by the last component of <em>P</em> to
+      form projected coordinates <em>P'</em>.
+      The resulting third component of <em>P</em> in the shadow forms is used as
+      <em>D<sub>ref</sub></em>.
+      The third component of <em>P</em> is ignored when <em>sampler</em> has type
+      <strong>gsampler2D</strong> and <em>P</em> has type <strong>vec4</strong>.
+      After these values are computed, texture lookup proceeds as in
+      <strong>texture</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLod</strong>(gsampler1D <em>sampler</em>, float <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureLod</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureLod</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler1DArray <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureLod</strong>(sampler1DArrayShadow <em>sampler</em>,  <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureLod</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Do a texture lookup as in <strong>texture</strong> but with explicit level-of-detail;
+      <em>lod</em> specifies <span class="eq">λ<sub>base</sub>]</span> and sets the partial derivatives
+      as follows:<br>
+      (See section 8.14 &#8220;Texture Minification&#8221; and equations 8.4-8.6 of
+      the <a href="#references">OpenGL Specification</a>.)<br>
+     <br>
+      <span class="eq">∂u / ∂x =
+           ∂v / ∂x =
+           ∂w / ∂x = 0</span>
+     <br>
+      <span class="eq">∂u / ∂y =
+           ∂v / ∂y =
+           ∂w / ∂y = 0</span></p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureOffset</strong>(gsampler1D <em>sampler</em>, float <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureOffset</strong>(sampler2DRectShadow <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureOffset</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler1DArray <em>sampler</em>, vec2 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureOffset</strong>(sampler1DArrayShadow <em>sampler</em>, vec3 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 P, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup as in <strong>texture</strong> but with <em>offset</em> added to the
+      <span class="eq">(u,v,w)</span> texel coordinates before looking up each texel.
+      The offset value must be a constant expression.
+      A limited range of offset values are supported; the minimum and
+      maximum offset values are implementation-dependent and given by
+      <em>gl_MinProgramTexelOffset</em> and <em>gl_MaxProgramTexelOffset</em>,
+      respectively.</p>
+<p class="tableblock">      Note that <em>offset</em> does not apply to the layer coordinate for texture
+      arrays.
+      This is explained in detail in section 8.14.2 &#8220;Coordinate Wrapping
+      and Texel Selection&#8221; of the <a href="#references">OpenGL Specification</a>, where <em>offset</em>
+      is <span class="eq">(δ<sub>u</sub>, δ<sub>v</sub>, δ<sub>w</sub>)</span>.<br>
+      Note that texel offsets are also not supported for cube maps.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetch</strong>(gsampler1D <em>sampler</em>, int <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>)
+  gvec4 <strong>texelFetch</strong>(gsampler2DRect <em>sampler</em>, ivec2 <em>P</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler1DArray <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsamplerBuffer <em>sampler</em>, int <em>P</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2DMS <em>sampler</em>, ivec2 <em>P</em>, int <em>sample</em>)<br>
+  gvec4 <strong>texelFetch</strong>(gsampler2DMSArray <em>sampler</em>, ivec3 <em>P</em>, int <em>sample</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Use integer texture coordinate <em>P</em> to lookup a single texel from
+      <em>sampler</em>.
+      The array layer comes from the last component of <em>P</em> for the array
+      forms.
+      The level-of-detail <em>lod</em> (if present) is as described in sections
+      11.1.3.2 &#8220;Texel Fetches&#8221; and 8.14.1 &#8220;Scale Factor and Level of
+      Detail&#8221; of the <a href="#references">OpenGL Specification</a>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>texelFetchOffset</strong>(gsampler1D <em>sampler</em>, int <em>P</em>, int <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler2D <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler3D <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec3 <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler2DRect <em>sampler</em>, ivec2 <em>P</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler1DArray <em>sampler</em>, ivec2 <em>P</em>, int <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>texelFetchOffset</strong>(gsampler2DArray <em>sampler</em>, ivec3 <em>P</em>, int <em>lod</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Fetch a single texel as in <strong>texelFetch</strong>, offset by <em>offset</em> as
+      described in <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjOffset</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, ivec3 <em>offset</em> [, float <em>bias</em>] )<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler2DRect <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjOffset</strong>(gsampler2DRect <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureProjOffset</strong>(sampler2DRectShadow <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureProjOffset</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em>, int <em>offset</em> [, float <em>bias</em>] )<br>
+  float <strong>textureProjOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, ivec2 <em>offset</em> [, float <em>bias</em>] )</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup as described in <strong>textureProj</strong>, offset
+      by <em>offset</em> as described in <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureLodOffset</strong>(gsampler1D <em>sampler</em>, float <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureLodOffset</strong>(sampler1DShadow <em>sampler</em>,  <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  float <strong>textureLodOffset</strong>(sampler2DShadow <em>sampler</em>,  <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler1DArray <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureLodOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureLodOffset</strong>(sampler1DArrayShadow <em>sampler</em>,  <em>P</em>, float <em>lod</em>, int <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset texture lookup with explicit level-of-detail.
+      See <strong>textureLod</strong> and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLod</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  gvec4 <strong>textureProjLod</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureProjLod</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)<br>
+  float <strong>textureProjLod</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a projective texture lookup with explicit level-of-detail.
+      See <strong>textureProj</strong> and <strong>textureLod</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjLodOffset</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjLodOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec3 <em>offset</em>)<br>
+  float <strong>textureProjLodOffset</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, int <em>offset</em>)<br>
+  float <strong>textureProjLodOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>lod</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do an offset projective texture lookup with explicit level-of-detail.
+      See <strong>textureProj</strong>, <strong>textureLod</strong>, and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGrad</strong>(gsampler1D <em>sampler</em>, <em>float _P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler3D <em>sampler</em>,  <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler2DRectShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler1DArray <em>sampler</em>, vec2 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsampler2DArray <em>sampler</em>,  <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler1DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(samplerCubeShadow <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  float <strong>textureGrad</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureGrad</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Do a texture lookup as in <strong>texture</strong> but with <a href="#explicit-gradients">explicit gradients</a> as shown below.
+      The partial derivatives of <em>P</em> are with respect to window <em>x</em> and
+      window <em>y</em>.
+      For the cube version, the partial derivatives of <em>P</em> are assumed to be
+      in the coordinate system used before texture coordinates are projected
+      onto the appropriate cube face.</p>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGradOffset</strong>(gsampler1D <em>sampler</em>, float <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler3D <em>sampler</em>, vec3 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler2DRectShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGradOffset</strong>(gsampler1DArray <em>sampler</em>, vec2 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler1DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  float <strong>textureGradOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup with both explicit gradient and offset, as
+      described in <strong>textureGrad</strong> and <strong>textureOffset</strong>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGrad</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler2DRect <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  gvec4 <strong>textureProjGrad</strong>(gsampler2DRect <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureProjGrad</strong>(sampler2DRectShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)<br>
+  float <strong>textureProjGrad</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>)<br>
+  float <strong>textureProjGrad</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup both projectively, as described in <strong>textureProj</strong>,
+      and with explicit gradient as described in <strong>textureGrad</strong>.
+      The partial derivatives <em>dPdx</em> and <em>dPdy</em> are assumed to be already
+      projected.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureProjGradOffset</strong>(gsampler1D <em>sampler</em>, vec2 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler1D <em>sampler</em>, vec4 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler2D <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler3D <em>sampler</em>, vec4 <em>P</em>, vec3 <em>dPdx</em>, vec3 <em>dPdy</em>, ivec3 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler2DRect <em>sampler</em>, vec3 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureProjGradOffset</strong>(gsampler2DRect <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureProjGradOffset</strong>(sampler2DRectShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)<br>
+  float <strong>textureProjGradOffset</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>P</em>, float <em>dPdx</em>, float <em>dPdy</em>, int <em>offset</em>)<br>
+  float <strong>textureProjGradOffset</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>P</em>, vec2 <em>dPdx</em>, vec2 <em>dPdy</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Do a texture lookup projectively and with explicit gradient as
+      described in <strong>textureProjGrad</strong>, as well as with offset, as described in
+      <strong>textureOffset</strong>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="explicit-gradients">8.9.3. Explicit Gradients</h4>
+<div class="paragraph">
+<p>In the <strong>textureGrad</strong> functions described above, explicit gradients control
+texture lookups as follows:</p>
+</div>
+<div class="stemblock">
+<div class="content">
+\[\begin{aligned}
+  \frac{\partial{s}}{\partial{x}} &amp; =
+    \begin{cases}
+      \frac{\partial{P}}{\partial{x}}, &amp; \text{for a 1D texture} \\[0.8em]
+      \frac{\partial{P.s}}{\partial{x}}, &amp; \text{otherwise}
+    \end{cases} \\[2.5em]
+  \frac{\partial{s}}{\partial{y}} &amp; =
+    \begin{cases}
+      \frac{\partial{P}}{\partial{y}}, &amp; \text{for a 1D texture} \\[0.8em]
+      \frac{\partial{P.s}}{\partial{y}}, &amp; \text{otherwise}
+    \end{cases} \\[2.5em]
+  \frac{\partial{t}}{\partial{x}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for a 1D texture} \\[0.8em]
+      \frac{\partial{P.t}}{\partial{x}}, &amp; \text{otherwise}
+    \end{cases} \\[2.5em]
+  \frac{\partial{t}}{\partial{y}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for a 1D texture} \\[0.8em]
+      \frac{\partial{P.t}}{\partial{y}}, &amp; \text{otherwise}
+    \end{cases} \\[2.5em]
+  \frac{\partial{r}}{\partial{x}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for 1D or 2D} \\[0.8em]
+      \frac{\partial{P.p}}{\partial{x}}, &amp; \text{cube, other}
+    \end{cases} \\[2.5em]
+  \frac{\partial{r}}{\partial{y}} &amp; =
+    \begin{cases}
+      0.0,                               &amp; \text{for 1D or 2D} \\[0.8em]
+      \frac{\partial{P.p}}{\partial{y}}, &amp; \text{cube, other}
+    \end{cases}
+\end{aligned}\]
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="texture-gather-functions">8.9.4. Texture Gather Functions</h4>
+<div class="paragraph">
+<p>The texture gather functions take components of a single floating-point
+vector operand as a texture coordinate, determine a set of four texels to
+sample from the base level-of-detail of the specified texture image, and
+return one component from each texel in a four-component result vector.</p>
+</div>
+<div class="paragraph">
+<p>When performing a texture gather operation, the minification and
+magnification filters are ignored, and the rules for LINEAR filtering in the
+<a href="#references">OpenGL Specification</a> are applied to the base level of the texture image
+to identify the four texels <em>i<sub>0</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, and <em>i<sub>0</sub>
+j<sub>0</sub></em>.
+The texels are then converted to texture base colors (<em>R<sub>s</sub></em>, <em>G<sub>s</sub></em>,
+<em>B<sub>s</sub></em>, <em>A<sub>s</sub></em>) according to table 15.1, followed by application of the
+texture swizzle as described in section 15.2.1 &#8220;Texture Access&#8221; of the
+<a href="#references">OpenGL Specification</a>.
+A four-component vector is assembled by taking the selected component from
+each of the post-swizzled texture source colors in the order (<em>i<sub>0</sub> j<sub>1</sub></em>,
+<em>i<sub>1</sub> j<sub>1</sub></em>, <em>i<sub>1</sub> j<sub>0</sub></em>, <em>i<sub>0</sub> j<sub>0</sub></em>).</p>
+</div>
+<div class="paragraph">
+<p>For texture gather functions using a shadow sampler type, each of the four
+texel lookups perform a depth comparison against the depth reference value
+passed in (<em>refZ</em>), and returns the result of that comparison in the
+appropriate component of the result vector.</p>
+</div>
+<div class="paragraph">
+<p>As with other texture lookup functions, the results of a texture gather are
+undefined for shadow samplers if the texture referenced is not a depth
+texture or has depth comparisons disabled; or for non-shadow samplers if the
+texture referenced is a depth texture with depth comparisons enabled.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGather</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsamplerCube <em>sampler</em>, vec3 <em>P</em> [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsamplerCubeArray <em>sampler</em>, vec4 <em>P</em>[, int <em>comp</em>])<br>
+  gvec4 <strong>textureGather</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>[, int <em>comp</em>])<br>
+  vec4 <strong>textureGather</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(samplerCubeShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(samplerCubeArrayShadow <em>sampler</em>, vec4 <em>P</em>, float <em>refZ</em>)<br>
+  vec4 <strong>textureGather</strong>(sampler2DRectShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Returns the value<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">vec4(Sample_i0_j1(P, base).comp,
+     Sample_i1_j1(P, base).comp,
+     Sample_i1_j0(P, base).comp,
+     Sample_i0_j0(P, base).comp)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If specified, the value of <em>comp</em> must be a constant integer expression with
+a value of 0, 1, 2, or 3, identifying the <em>x</em>, <em>y</em>, <em>z</em>, or <em>w</em>
+post-swizzled component of the four-component vector lookup result for each
+texel, respectively.
+If <em>comp</em> is not specified, it is treated as 0, selecting the <em>x</em> component
+of each texel to generate the result.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffset</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em>, [ int <em>comp</em>])<br>
+  gvec4 <strong>textureGatherOffset</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offset</em> [ int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffset</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br>
+  vec4 <strong>textureGatherOffset</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)<br>
+  gvec4 <strong>textureGatherOffset</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offset</em> [ int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffset</strong>(sampler2DRectShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offset</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Perform a texture gather operation as in <strong>textureGather</strong> by <em>offset</em>
+      as described in <strong>textureOffset</strong> except that the <em>offset</em> can be
+      variable (non constant) and the implementation-dependent minimum and
+      maximum offset values are given by MIN_PROGRAM_TEXTURE_GATHER_OFFSET
+      and MAX_PROGRAM_TEXTURE_GATHER_OFFSET, respectively.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">gvec4 <strong>textureGatherOffsets</strong>(gsampler2D <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offsets</em>[4] [, int <em>comp</em>])<br>
+  gvec4 <strong>textureGatherOffsets</strong>(gsampler2DArray <em>sampler</em>, vec3 <em>P</em>, ivec2 <em>offsets</em>[4]   [, int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffsets</strong>(sampler2DShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br>
+  vec4 <strong>textureGatherOffsets</strong>(sampler2DArrayShadow <em>sampler</em>, vec3 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])<br>
+  gvec4 <strong>textureGatherOffsets</strong>(gsampler2DRect <em>sampler</em>, vec2 <em>P</em>, ivec2 <em>offsets</em>[4] [, int <em>comp</em>])<br>
+  vec4 <strong>textureGatherOffsets</strong>(sampler2DRectShadow <em>sampler</em>, vec2 <em>P</em>, float <em>refZ</em>, ivec2 <em>offsets</em>[4])</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Operate identically to <strong>textureGatherOffset</strong> except that <em>offsets</em> is
+      used to determine the location of the four texels to sample.
+      Each of the four texels is obtained by applying the corresponding
+      offset in <em>offsets</em> as a (<em>u</em>, <em>v</em>) coordinate offset to <em>P</em>,
+      identifying the four-texel LINEAR footprint, and then selecting the
+      texel <em>i<sub>0</sub> j<sub>0</sub></em> of that footprint.
+      The specified values in <em>offsets</em> must be constant integral
+      expressions.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="compatibility-profile-texture-functions">8.9.5. Compatibility Profile Texture Functions</h4>
+<div class="paragraph">
+<p>The following texture functions are only in the compatibility profile.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>texture1D</strong>(sampler1D <em>sampler</em>, float <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture1DProj</strong>(sampler1D <em>sampler</em>, vec2 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture1DProj</strong>(sampler1D <em>sampler</em>, vec4 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture1DLod</strong>(sampler1D <em>sampler</em>, float <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>texture1DProjLod</strong>(sampler1D <em>sampler</em>, vec2 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>texture1DProjLod</strong>(sampler1D <em>sampler</em>, vec4 <em>coord</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">See corresponding signature above without &#8220;1D&#8221; in the name.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>texture2D</strong>(sampler2D <em>sampler</em>, vec2 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture2DProj</strong>(sampler2D <em>sampler</em>, vec3 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture2DProj</strong>(sampler2D <em>sampler</em>, vec4 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture2DLod</strong>(sampler2D <em>sampler</em>, vec2 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>texture2DProjLod</strong>(sampler2D <em>sampler</em>, vec3 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>texture2DProjLod</strong>(sampler2D <em>sampler</em>, vec4 <em>coord</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">See corresponding signature above without &#8220;2D&#8221; in the name.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>texture3D</strong>(sampler3D <em>sampler</em>, vec3 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture3DProj</strong>(sampler3D <em>sampler</em>, vec4 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>texture3DLod</strong>(sampler3D <em>sampler</em>, vec3 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>texture3DProjLod</strong>(sampler3D <em>sampler</em>, vec4 <em>coord</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">See corresponding signature above without &#8220;3D&#8221; in the name.<br>
+      Use the texture coordinate <em>coord</em> to do a texture lookup in the 3D
+      texture currently bound to <em>sampler</em>.
+      For the projective (&#8220;<strong>Proj</strong>&#8221;) versions, the texture coordinate is
+      divided by <em>coord.q</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>textureCube</strong>(samplerCube <em>sampler</em>, vec3 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>textureCubeLod</strong>(samplerCube <em>sampler</em>, vec3 <em>coord</em>, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">See corresponding signature above without &#8220;Cube&#8221; in the name.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>shadow1D</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>shadow2D</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>shadow1DProj</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>shadow2DProj</strong>(sampler2DShadow <em>sampler</em>, vec4 <em>coord</em> [, float <em>bias</em>] )<br>
+  vec4 <strong>shadow1DLod</strong>(sampler1DShadow <em>sampler</em>, vec3 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>shadow2DLod</strong>(sampler2DShadow <em>sampler</em>, vec3 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>shadow1DProjLod</strong>(sampler1DShadow <em>sampler</em>, vec4 <em>coord</em>, float <em>lod</em>)<br>
+  vec4 <strong>shadow2DProjLod</strong>(sampler2DShadow <em>sampler</em>, vec4 coord, float <em>lod</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Same functionality as the &#8220;<strong>texture</strong>&#8221; based names above with the
+      same signature.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="atomic-counter-functions">8.10. Atomic Counter Functions</h3>
+<div class="paragraph">
+<p>The atomic-counter operations in this section operate atomically with
+respect to each other.
+They are atomic for any single counter, meaning any of these operations on a
+specific counter in one shader instantiation will be indivisible by any of
+these operations on the same counter from another shader instantiation.
+There is no guarantee that these operations are atomic with respect to other
+forms of access to the counter or that they are serialized when applied to
+separate counters.
+Such cases would require additional use of fences, barriers, or other forms
+of synchronization, if atomicity or serialization is desired.</p>
+</div>
+<div class="paragraph">
+<p>The underlying counter is a 32-bit unsigned integer.
+The result of operations will wrap to [0, 2<sup>32</sup>-1].</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterIncrement</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>increments the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the increment operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterDecrement</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>decrements the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns the value resulting from the decrement operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounter</strong>(atomic_uint <em>c</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the counter value for <em>c</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterAdd</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>adds the value of <em>data</em> to the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterSubtract</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>subtracts the value of <em>data</em> from the counter for <em>c</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterMin</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter for <em>c</em> to the minimum of the value of the counter and
+the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns the value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterMax</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter for <em>c</em> to the maximum of the value of the counter and
+the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns the value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterAnd</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter for <em>c</em> to the bitwise AND of the value of the counter
+and the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns the value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterOr</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter for <em>c</em> to the bitwise OR of the value of the counter
+and the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns the value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterXor</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter for <em>c</em> to the bitwise XOR of the value of the counter
+and the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns the value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterExchange</strong>(atomic_uint <em>c</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>sets the counter value for <em>c</em> to the value of <em>data</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These two steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCounterCompSwap</strong>(atomic_uint <em>c</em>, uint <em>compare</em>, uint <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
+<p>Atomically<br></p>
+</div>
+<div class="openblock">
+<div class="content">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>compares the value of <em>compare</em> and the counter value for <em>c</em></p>
+</li>
+<li>
+<p>if the values are equal, sets the counter value for <em>c</em> to the value of
+<em>data</em>, and</p>
+</li>
+<li>
+<p>returns its value prior to the operation.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>These three steps are done atomically with respect to the atomic counter
+functions in this table.</p>
+</div>
+</div>
+</div></div></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="atomic-memory-functions">8.11. Atomic Memory Functions</h3>
+<div class="paragraph">
+<p>Atomic memory functions perform atomic operations on an individual signed or
+unsigned integer stored in buffer object or shared variable storage.
+All of the atomic memory operations read a value from memory, compute a new
+value using one of the operations described below, write the new value to
+memory, and return the original value read.
+The contents of the memory being updated by the atomic operation are
+guaranteed not to be modified by any other assignment or atomic memory
+function in any shader invocation between the time the original value is
+read and the time the new value is written.</p>
+</div>
+<div class="paragraph">
+<p>Atomic memory functions are supported only for a limited set of variables.
+A shader will fail to compile if the value passed to the <em>mem</em> argument of
+an atomic memory function does not correspond to a buffer or shared
+variable.
+It is acceptable to pass an element of an array or a single component of a
+vector to the <em>mem</em> argument of an atomic memory function, as long as the
+underlying array or vector is a buffer or shared variable.</p>
+</div>
+<div class="paragraph">
+<p>All the built-in functions in this section accept arguments with
+combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification,
+despite not having them listed in the prototypes.
+The atomic operation will operate as required by the calling argument&#8217;s
+memory qualification, not by the built-in function&#8217;s formal parameter memory
+qualification.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAdd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicAdd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents
+      <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMin</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicMin</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and
+      the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicMax</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicMax</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value of <em>data</em> and
+      the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicAnd</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicAnd</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of
+      <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicOr</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicOr</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of
+      <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicXor</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicXor</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the
+      value of <em>data</em> and the contents of <em>mem</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicExchange</strong>(inout uint <em>mem</em>, uint <em>data</em>)<br>
+  int <strong>atomicExchange</strong>(inout int <em>mem</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">uint <strong>atomicCompSwap</strong>(inout uint <em>mem</em>, uint <em>compare</em>, uint <em>data</em>)<br>
+  int <strong>atomicCompSwap</strong>(inout int <em>mem</em>, int <em>compare</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of <em>mem</em>.
+      If the values are equal, the new value is given by <em>data</em>; otherwise,
+      it is taken from the original contents of <em>mem</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="image-functions">8.12. Image Functions</h3>
+<div class="paragraph">
+<p>Variables using one of the image basic types may be used by the built-in
+shader image memory functions defined in this section to read and write
+individual texels of a texture.
+Each image variable references an image unit, which has a texture image
+attached.</p>
+</div>
+<div class="paragraph">
+<p>When image memory functions below access memory, an individual texel in the
+image is identified using an (<em>i</em>), (<em>i, j</em>), or (<em>i, j, k</em>) coordinate
+corresponding to the values of <em>P</em>.
+For <strong>image2DMS</strong> and <strong>image2DMSArray</strong> variables (and the corresponding
+int/unsigned int types) corresponding to multisample textures, each texel
+may have multiple samples and an individual sample is identified using the
+integer <em>sample</em> parameter.
+The coordinates
+and sample number
+are used to select an individual texel in the manner described in section
+8.26
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>Loads and stores support float, integer, and unsigned integer types.
+The data types below starting &#8220;_gimage_&#8221; serve as placeholders meaning
+types starting either &#8220;<strong>image</strong>&#8221;, &#8220;<strong>iimage</strong>&#8221;, or &#8220;<strong>uimage</strong>&#8221; in the same
+way as <em>gvec</em> or <em>gsampler</em> in earlier sections.</p>
+</div>
+<div class="paragraph">
+<p>The <em>IMAGE_PARAMS</em> in the prototypes below is a placeholder representing
+33
+separate functions, each for a different type of image variable.
+The <em>IMAGE_PARAMS</em> placeholder is replaced by one of the following parameter
+lists:</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2D <em>image</em>, ivec2 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage3D <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageCube <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageBuffer <em>image</em>, int <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2DArray <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimageCubeArray <em>image</em>, ivec3 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage1D <em>image</em>, int <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage1DArray <em>image</em>, ivec2 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2DRect <em>image</em>, ivec2 <em>P</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2DMS <em>image</em>, ivec2 <em>P</em>, int <em>sample</em></p>
+</dd>
+<dt class="hdlist1"></dt>
+<dd>
+<p>gimage2DMSArray <em>image</em>, ivec3 <em>P</em>, int <em>sample</em></p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>where each of the lines represents one of three different image variable
+types, and <em>image</em>,
+<em>P</em>, and <em>sample</em>
+specify the individual texel to operate on.
+The method for identifying the individual texel operated on from <em>image</em>,
+<em>P</em>,
+and <em>sample</em>,
+and the method for reading and writing the texel are specified in section
+8.26
+&#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL Specification</a>.</p>
+</div>
+<div class="paragraph">
+<p>The atomic functions perform operations on individual texels or samples of
+an image variable.
+Atomic memory operations read a value from the selected texel, compute a new
+value using one of the operations described below, write the new value to
+the selected texel, and return the original value read.
+The contents of the texel being updated by the atomic operation are
+guaranteed not to be modified by any other image store or atomic function
+between the time the original value is read and the time the new value is
+written.</p>
+</div>
+<div class="paragraph">
+<p>Atomic memory operations are supported on only a subset of all image
+variable types; <em>image</em> must be either:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>a signed integer image variable (type starts &#8220;<strong>iimage</strong>&#8221;) and a format
+qualifier of <strong>r32i</strong>, used with a <em>data</em> argument of type <strong>int</strong>, or</p>
+</li>
+<li>
+<p>an unsigned integer image variable (type starts &#8220;<strong>uimage</strong>&#8221;) and a
+format qualifier of <strong>r32ui</strong>, used with a <em>data</em> argument of type <strong>uint</strong>,
+or</p>
+</li>
+<li>
+<p>a float image variable (type starts &#8220;<strong>image</strong>&#8221;) and a format qualifier
+of <strong>r32f</strong>, used with a <em>data</em> argument of type <strong>float</strong>
+(<strong>imageAtomicExchange</strong> only).</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>All the built-in functions in this section accept arguments with
+combinations of <strong>restrict</strong>, <strong>coherent</strong>, and <strong>volatile</strong> memory qualification,
+despite not having them listed in the prototypes.
+The image operation will operate as required by the calling argument&#8217;s
+memory qualification, not by the built-in function&#8217;s formal parameter memory
+qualification.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">   int <strong>imageSize</strong>(readonly writeonly gimage1D <em>image</em>)<br>
+   ivec2 <strong>imageSize</strong>(readonly writeonly gimage2D <em>image</em>)<br>
+   ivec3 <strong>imageSize</strong>(readonly writeonly gimage3D <em>image</em>)<br>
+   ivec2 <strong>imageSize</strong>(readonly writeonly gimageCube <em>image</em>)<br>
+   ivec3 <strong>imageSize</strong>(readonly writeonly gimageCubeArray <em>image</em>)<br>
+   ivec3 <strong>imageSize</strong>(readonly writeonly gimage2DArray <em>image</em>)<br>
+   ivec2 <strong>imageSize</strong>(readonly writeonly gimageRect <em>image</em>)<br>
+   ivec2 <strong>imageSize</strong>(readonly writeonly gimage1DArray <em>image</em>)<br>
+   ivec2 <strong>imageSize</strong>(readonly writeonly gimage2DMS <em>image</em>)<br>
+   ivec3 <strong>imageSize</strong>(readonly writeonly gimage2DMSArray <em>image</em>)<br>
+     int <strong>imageSize</strong>(readonly writeonly gimageBuffer <em>image</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the dimensions of the image or images bound to <em>image</em>.
+      For arrayed images, the last component of the return value will hold
+      the size of the array.
+      Cube images only return the dimensions of one face, and the number of
+      cubes in the cube map array, if arrayed.<br>
+      Note: The qualification <strong>readonly writeonly</strong> accepts a variable
+      qualified with <strong>readonly</strong>, <strong>writeonly</strong>, both, or neither.
+      It means the formal argument will be used for neither reading nor
+      writing to the underlying memory.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">int <strong>imageSamples</strong>(readonly writeonly gimage2DMS <em>image</em>)<br>
+  int <strong>imageSamples</strong>(readonly writeonly gimage2DMSArray <em>image</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the number of samples of the image or images bound to <em>image</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> gvec4 <strong>imageLoad</strong>(readonly <em>IMAGE_PARAMS</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Loads the texel at the coordinate <em>P</em> from the image unit <em>image</em> (in
+      <em>IMAGE_PARAMS</em>).
+      For multisample loads, the sample number is given by <em>sample</em>.
+      When <em>image</em>, <em>P</em>, and <em>sample</em>
+      identify a valid texel, the bits used to represent the selected texel in
+      memory are converted to a <strong>vec4</strong>, <strong>ivec4</strong>, or <strong>uvec4</strong> in the manner
+      described in section
+8.26
+      &#8220;Texture Image Loads and Stores&#8221; of the
+      <a href="#references">OpenGL Specification</a> and returned.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>imageStore</strong>(writeonly <em>IMAGE_PARAMS</em>, gvec4 <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Stores <em>data</em> into the texel at the coordinate <em>P</em> from the image
+      specified by <em>image</em>.
+      For multisample stores, the sample number is given by <em>sample</em>.
+      When <em>image</em>, <em>P</em>, and <em>sample</em>
+      identify a valid texel, the bits used to represent <em>data</em> are converted
+      to the format of the image unit in the manner described in section
+8.26
+      &#8220;Texture Image Loads and Stores&#8221; of the <a href="#references">OpenGL Specification</a>
+      and stored to the specified texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicAdd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by adding the value of <em>data</em> to the contents of
+      the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicMin</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the minimum of the value of <em>data</em> and
+      the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicMax</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by taking the maximum of the value <em>data</em> and the
+      contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicAnd</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise AND of the value of
+      <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicOr</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise OR of the value of
+      <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicXor</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by performing a bit-wise EXCLUSIVE OR of the
+      value of <em>data</em> and the contents of the selected texel.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, int <em>data</em>)<br>
+   float <strong>imageAtomicExchange</strong>(<em>IMAGE_PARAMS</em>, float <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Computes a new value by simply copying the value of <em>data</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock"> uint <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, uint <em>compare</em>, uint <em>data</em>)<br>
+   int <strong>imageAtomicCompSwap</strong>(<em>IMAGE_PARAMS</em>, int <em>compare</em>, int <em>data</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Compares the value of <em>compare</em> and the contents of the selected
+      texel.
+      If the values are equal, the new value is given by <em>data</em>; otherwise,
+      it is taken from the original value loaded from the texel.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="geometry-shader-functions">8.13. Geometry Shader Functions</h3>
+<div class="paragraph">
+<p>These functions are only available in geometry shaders.
+They are described in more depth following the table.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EmitStreamVertex</strong>(int <em>stream</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Emits the current values of output variables to the current output
+      primitive on stream <em>stream</em>.
+      The argument to <em>stream</em> must be a constant integral expression.
+      On return from this call, the values of all output variables are
+      undefined.<br>
+      Can only be used if multiple output streams are supported.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EndStreamPrimitive</strong>(int <em>stream</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Completes the current output primitive on stream <em>stream</em> and starts a
+      new one.
+      The argument to <em>stream</em> must be a constant integral expression.
+      No vertex is emitted.<br>
+      Can only be used if multiple output streams are supported.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EmitVertex</strong>()<br></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Emits the current values of output variables to the current output
+      primitive.
+      When multiple output streams are supported, this is equivalent to
+      calling <strong>EmitStreamVertex</strong>(0).<br>
+      On return from this call, the values of output variables are
+      undefined.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>EndPrimitive</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Completes the current output primitive and starts a new one.
+      When multiple output streams are supported, this is equivalent to
+      calling <strong>EndStreamPrimitive</strong>(0).<br>
+      No vertex is emitted.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The function <strong>EmitStreamVertex</strong>() specifies that a vertex is completed.
+A vertex is added to the current output primitive in vertex stream <em>stream</em>
+using the current values of all built-in and user-defined output variables
+associated with <em>stream</em>.
+The values of all output variables for all output streams are undefined
+after a call to <strong>EmitStreamVertex</strong>().
+If a geometry shader invocation has emitted more vertices than permitted by
+the output layout qualifier <strong>max_vertices</strong>, the results of calling
+<strong>EmitStreamVertex</strong>() are undefined.</p>
+</div>
+<div class="paragraph">
+<p>The function <strong>EndStreamPrimitive</strong>() specifies that the current output
+primitive for vertex stream <em>stream</em> is completed and a new output primitive
+(of the same type) will be started by any subsequent <strong>EmitStreamVertex</strong>().
+This function does not emit a vertex.
+If the output layout is declared to be <strong>points</strong>, calling
+<strong>EndStreamPrimitive</strong>() is optional.</p>
+</div>
+<div class="paragraph">
+<p>A geometry shader starts with an output primitive containing no vertices for
+each stream.
+When a geometry shader terminates, the current output primitive for each
+stream is automatically completed.
+It is not necessary to call <strong>EndStreamPrimitive</strong>() if the geometry shader
+writes only a single primitive.</p>
+</div>
+<div class="paragraph">
+<p>Multiple output streams are supported only if the output primitive type is
+declared to be <strong>points</strong>.
+It is a compile-time or link-time error if a program contains a geometry
+shader calling <strong>EmitStreamVertex</strong>() or <strong>EndStreamPrimitive</strong>() if its output
+primitive type is not <strong>points</strong>.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="fragment-processing-functions">8.14. Fragment Processing Functions</h3>
+<div class="paragraph">
+<p>Fragment processing functions are only available in fragment shaders.</p>
+</div>
+<div class="sect3">
+<h4 id="derivative-functions">8.14.1. Derivative Functions</h4>
+<div class="paragraph">
+<p>Derivatives may be computationally expensive and/or numerically unstable.
+Therefore, an OpenGL implementation may approximate the true derivatives
+by using a fast but not entirely accurate derivative computation.
+Derivatives are undefined within non-uniform control flow.</p>
+</div>
+<div class="paragraph">
+<p>The expected behavior of a derivative is specified using forward/backward
+differencing.</p>
+</div>
+<div class="paragraph">
+<p>Forward differencing:</p>
+</div>
+<div class="paragraph">
+<p>\(F(x+dx) - F(x) \sim dFdx(x) \cdot dx (1a)\)</p>
+</div>
+<div class="paragraph">
+<p>\(dFdx(x) \sim \frac{F(x+dx) - F(x)}{dx} (1b)\)</p>
+</div>
+<div class="paragraph">
+<p>Backward differencing:</p>
+</div>
+<div class="paragraph">
+<p>\(F(x-dx) - F(x) \sim -dFdx(x) \cdot dx (2a)\)</p>
+</div>
+<div class="paragraph">
+<p>\(dFdx(x) \sim \frac{F(x) - F(x-dx)}{dx} (2b)\)</p>
+</div>
+<div class="paragraph">
+<p>With single-sample rasterization, \(dx \leq 1.0\) in equations 1b
+and 2b.
+For multisample rasterization, \(dx &lt; 2.0\) in equations 1b and 2b.</p>
+</div>
+<div class="paragraph">
+<p>\(dFdy\) is approximated similarly, with <em>y</em> replacing <em>x</em>.</p>
+</div>
+<div class="paragraph">
+<p>With multisample rasterization, for any given fragment or sample, either
+neighboring fragments or samples may be considered.</p>
+</div>
+<div class="paragraph">
+<p>It is typical to consider a 2x2 square of fragments or samples, and compute
+independent <strong>dFdxFine</strong> per row and independent <strong>dFdyFine</strong> per column, while
+computing only a single <strong>dFdxCoarse</strong> and a single <strong>dFdyCoarse</strong> for the
+entire 2x2 square.
+Thus, all second-order coarse derivatives, e.g.
+<strong>dFdxCoarse</strong>(<strong>dFdxCoarse</strong>(<em>x</em>)), may be 0, even for non-linear arguments.
+However, second-order fine derivatives, e.g. <strong>dFdxFine</strong>(<strong>dFdyFine</strong>(<em>x</em>))
+will properly reflect the difference between the independent fine
+derivatives computed within the 2x2 square.</p>
+</div>
+<div class="paragraph">
+<p>The method may differ per fragment, subject to the constraint that the
+method may vary by window coordinates, not screen coordinates.
+The invariance requirement described in section 14.2 &#8220;Invariance&#8221; of the
+<a href="#references">OpenGL Specification</a>, is relaxed for derivative calculations, because
+the method may be a function of fragment location.</p>
+</div>
+<div class="paragraph">
+<p>In some implementations, varying degrees of derivative accuracy for <strong>dFdx</strong>
+and <strong>dFdy</strong> may be obtained by providing GL hints (see section 21.4 &#8220;Hints&#8221;
+of the <a href="#references">OpenGL Specification</a>), allowing a user to make an image quality
+versus speed trade off.
+These hints have no effect on <strong>dFdxCoarse</strong>, <strong>dFdyCoarse</strong>, <strong>dFdxFine</strong> and
+<strong>dFdyFine</strong>.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdx</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns either <strong>dFdxFine</strong>(<em>p</em>) or <strong>dFdxCoarse</strong>(<em>p</em>), based on
+      implementation choice, presumably whichever is the faster, or by whichever
+      is selected in the API through quality-versus-speed hints.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdy</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns either <strong>dFdyFine</strong>(<em>p</em>) or <strong>dFdyCoarse</strong>(<em>p</em>), based on
+      implementation choice, presumably whichever is the faster, or by
+      whichever is selected in the API through quality-versus-speed hints.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdxFine</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the partial derivative of <em>p</em> with respect to the window x
+      coordinate.
+      Will use local differencing based on the value of <em>p</em> for the current
+      fragment and its immediate neighbor(s).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdyFine</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the partial derivative of <em>p</em> with respect to the window y
+      coordinate.
+      Will use local differencing based on the value of <em>p</em> for the current
+      fragment and its immediate neighbor(s).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdxCoarse</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the partial derivative of <em>p</em> with respect to the window x
+      coordinate.
+      Will use local differencing based on the value of <em>p</em> for the current
+      fragment&#8217;s neighbors, and will possibly, but not necessarily, include
+      the value of <em>p</em> for the current fragment.
+      That is, over a given area, the implementation can x compute
+      derivatives in fewer unique locations than would be allowed for
+      <strong>dFdxFine</strong>(<em>p</em>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>dFdyCoarse</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the partial derivative of <em>p</em> with respect to the window y
+      coordinate.
+      Will use local differencing based on the value of <em>p</em> for the current
+      fragment&#8217;s neighbors, and will possibly, but not necessarily, include
+      the value of <em>p</em> for the current fragment.
+      That is, over a given area, the implementation can compute y
+      derivatives in fewer unique locations than would be allowed for
+      <strong>dFdyFine</strong>(<em>p</em>).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fwidth</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>abs</strong>(<strong>dFdx</strong>(<em>p</em>)) + <strong>abs</strong>(<strong>dFdy</strong>(<em>p</em>)).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fwidthFine</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>abs</strong>(<strong>dFdxFine</strong>(<em>p</em>)) + <strong>abs</strong>(<strong>dFdyFine</strong>(<em>p</em>)).</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">genFType <strong>fwidthCoarse</strong>(genFType <em>p</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>abs</strong>(<strong>dFdxCoarse</strong>(<em>p</em>)) + <strong>abs</strong>(<strong>dFdyCoarse</strong>(<em>p</em>)).</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="interpolation-functions">8.14.2. Interpolation Functions</h4>
+<div class="paragraph">
+<p>Built-in interpolation functions are available to compute an interpolated
+value of a fragment shader input variable at a shader-specified (<em>x</em>, <em>y</em>)
+location.
+A separate (<em>x</em>, <em>y</em>) location may be used for each invocation of the
+built-in function, and those locations may differ from the default (<em>x</em>,
+<em>y</em>) location used to produce the default value of the input.</p>
+</div>
+<div class="paragraph">
+<p>For all of the interpolation functions, <em>interpolant</em> must be an l-value
+from an <strong>in</strong> declaration;
+this can include a variable, a block or structure member, an array element, or
+some combination of these.
+Additionally, component selection operators (e.g. <strong>.xy</strong>, <strong>.xxz</strong>) may be applied
+to <em>interpolant</em>, in which case the interpolation function will return the
+result of applying the component selection operator to the interpolated value
+of <em>interpolant</em> (for example, interpolateAt(v.xxz) is defined to return
+interpolateAt(v).xxz).
+Arrayed inputs can be indexed with general (nonuniform) integer expressions.</p>
+</div>
+<div class="paragraph">
+<p>If <em>interpolant</em> is declared with the <strong>flat</strong> qualifier, the interpolated
+value will have the same value everywhere for a single primitive, so the
+location used for interpolation has no effect and the functions just return
+that same value.
+If <em>interpolant</em> is declared with the <strong>centroid</strong> qualifier, the value
+returned by <strong>interpolateAtSample</strong>() and <strong>interpolateAtOffset</strong>() will be
+evaluated at the specified location, ignoring the location normally used
+with the <strong>centroid</strong> qualifier.
+If <em>interpolant</em> is declared with the <strong>noperspective</strong> qualifier, the
+interpolated value will be computed without perspective correction.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtCentroid</strong>(float <em>interpolant</em>)<br>
+  vec2 <strong>interpolateAtCentroid</strong>(vec2 <em>interpolant</em>)<br>
+  vec3 <strong>interpolateAtCentroid</strong>(vec3 <em>interpolant</em>)<br>
+  vec4 <strong>interpolateAtCentroid</strong>(vec4 <em>interpolant</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> sampled at a location
+      inside both the pixel and the primitive being processed.
+      The value obtained would be the same value assigned to the input
+      variable if declared with the <strong>centroid</strong> qualifier.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtSample</strong>(float <em>interpolant</em>, int <em>sample</em>)<br>
+  vec2 <strong>interpolateAtSample</strong>(vec2 <em>interpolant</em>, int <em>sample</em>)<br>
+  vec3 <strong>interpolateAtSample</strong>(vec3 <em>interpolant</em>, int <em>sample</em>)<br>
+  vec4 <strong>interpolateAtSample</strong>(vec4 <em>interpolant</em>, int <em>sample</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable at the location
+      of sample number <em>sample</em>.
+      If multisample buffers are not available, the input variable will be
+      evaluated at the center of the pixel.
+      If sample <em>sample</em> does not exist, the position used to interpolate
+      the input variable is undefined.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>interpolateAtOffset</strong>(float <em>interpolant</em>, vec2 offset)<br>
+  vec2 <strong>interpolateAtOffset</strong>(vec2 <em>interpolant</em>, vec2 offset)<br>
+  vec3 <strong>interpolateAtOffset</strong>(vec3 <em>interpolant</em>, vec2 offset)<br>
+  vec4 <strong>interpolateAtOffset</strong>(vec4 <em>interpolant</em>, vec2 offset)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns the value of the input <em>interpolant</em> variable sampled at an
+      offset from the center of the pixel specified by <em>offset</em>.
+      The two floating-point components of <em>offset</em>, give the offset in
+      pixels in the <em>x</em> and <em>y</em> directions, respectively.<br>
+      An offset of (0, 0) identifies the center of the pixel.
+      The range and granularity of offsets supported by this function is
+      implementation-dependent.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="noise-functions">8.15. Noise Functions</h3>
+<div class="paragraph">
+<p>The noise functions <strong>noise1</strong>, <strong>noise2</strong>, <strong>noise3</strong>, and <strong>noise4</strong> have been
+deprecated starting with version 4.4 of GLSL.
+When not generating SPIR-V they are defined to return the value 0.0 or a vector
+whose components are all 0.0. When generating SPIR-V the noise functions are
+not declared and may not be used.</p>
+</div>
+<div class="paragraph">
+<p>As in previous releases, the noise functions are not semantically considered to
+be compile-time constant expressions.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax (deprecated)</th>
+<th class="tableblock halign-left valign-top">Description (deprecated)</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">float <strong>noise1</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a 1D noise value based on the input value <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec2 <strong>noise2</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a 2D noise value based on the input value <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec3 <strong>noise3</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a 3D noise value based on the input value <em>x</em>.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">vec4 <strong>noise4</strong>(genFType <em>x</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns a 4D noise value based on the input value <em>x</em>.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="shader-invocation-control-functions">8.16. Shader Invocation Control Functions</h3>
+<div class="paragraph">
+<p>The shader invocation control function is only available in tessellation
+control and compute shaders.
+It is used to control the relative execution order of multiple shader
+invocations used to process a patch (in the case of tessellation control
+shaders) or a workgroup (in the case of compute shaders), which are
+otherwise executed with an undefined relative order.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>barrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">For any given static instance of <strong>barrier</strong>(), all tessellation control
+      shader invocations for a single input patch must enter it before any
+      will be allowed to continue beyond it, or all compute shader
+      invocations for a single workgroup must enter it before any will
+      continue beyond it.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The function <strong>barrier</strong>() provides a partially defined order of execution
+between shader invocations.
+The ensures that, for some types of memory accesses, values written by one
+invocation prior to a given static instance of <strong>barrier</strong>() can be safely read
+by other invocations after their call to the same static instance <strong>barrier</strong>().
+Because invocations may execute in an undefined order between these barrier
+calls, the values of a per-vertex or per-patch output variable for tessellation
+control shaders, or the values of <strong>shared</strong> variables for compute shaders will be
+undefined in a number of cases enumerated in
+&#8220;<a href="#output-variables">Output Variables</a>&#8221; (for tessellation control shaders)
+and &#8220;<a href="#shared-variables">Shared Variables</a>&#8221; (for compute shaders).</p>
+</div>
+<div class="paragraph">
+<p>For tessellation control shaders, the <strong>barrier</strong>() function may only be
+placed inside the function <strong>main</strong>() of the shader and may not be called
+within any control flow.
+Barriers are also disallowed after a return statement in the function
+<strong>main</strong>().
+Any such misplaced barriers result in a compile-time error.</p>
+</div>
+<div class="paragraph">
+<p>A <strong>barrier</strong>() affects control flow but only synchronizes memory accesses
+to <strong>shared</strong> variables and tessellation control output variables.
+For other memory accesses, it does not ensure that values written by one invocation
+prior to a given static instance of <strong>barrier</strong>() can be safely read by other
+invocations after their call to the same static instance of <strong>barrier</strong>().
+To achieve this requires the use of both <strong>barrier</strong>() and a memory barrier.</p>
+</div>
+<div class="paragraph">
+<p>For compute shaders, the <strong>barrier</strong>() function may be placed within control
+flow, but that control flow must be uniform control flow.
+That is, all the controlling expressions that lead to execution of the
+barrier must be dynamically uniform expressions.
+This ensures that if any shader invocation enters a conditional statement,
+then all invocations will enter it.
+While compilers are encouraged to give warnings if they can detect this
+might not happen, compilers cannot completely determine this.
+Hence, it is the author&#8217;s responsibility to ensure <strong>barrier</strong>() only exists
+inside uniform control flow.
+Otherwise, some shader invocations will stall indefinitely, waiting for a
+barrier that is never reached by other invocations.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="shader-memory-control-functions">8.17. Shader Memory Control Functions</h3>
+<div class="paragraph">
+<p>Within a single shader invocation, the visibility and order of writes made
+by that invocation are well-defined.
+However, the relative order of reads and writes to a single shared memory
+address from multiple separate shader invocations is largely undefined.
+Additionally, the order of accesses to multiple memory addresses performed
+by a single shader invocation, as observed by other shader invocations, is
+also undefined.</p>
+</div>
+<div class="paragraph">
+<p>The following built-in functions can be used to control the ordering of
+reads and writes:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions issued by a single shader
+      invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierAtomicCounter</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of accesses to atomic-counter variables issued by
+      a single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierBuffer</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to buffer variables issued
+      within a single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierShared</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to shared variables issued
+      within a single shader invocation, as viewed by other invocations in
+      the same workgroup.<br>
+      Only available in compute shaders.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>memoryBarrierImage</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of memory transactions to images issued within a
+      single shader invocation.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">void <strong>groupMemoryBarrier</strong>()</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Control the ordering of all memory transactions issued within a single
+      shader invocation, as viewed by other invocations in the same workgroup.<br>
+      Only available in compute shaders.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>The memory barrier built-in functions can be used to order reads and writes
+to variables stored in memory accessible to other shader invocations.
+When called, these functions will wait for the completion of all reads and
+writes previously performed by the caller that access selected variable
+types, and then return with no other effect.
+The built-in functions <strong>memoryBarrierAtomicCounter</strong>(),
+<strong>memoryBarrierBuffer</strong>(), <strong>memoryBarrierImage</strong>(), and <strong>memoryBarrierShared</strong>()
+wait for the completion of accesses to atomic counter, buffer, image, and
+shared variables, respectively.
+The built-in functions <strong>memoryBarrier</strong>() and <strong>groupMemoryBarrier</strong>() wait for
+the completion of accesses to all of the above variable types.
+The functions <strong>memoryBarrierShared</strong>() and <strong>groupMemoryBarrier</strong>() are
+available only in compute shaders; the other functions are available in all
+shader types.</p>
+</div>
+<div class="paragraph">
+<p>When these functions return, the effects of any memory stores performed
+using coherent variables prior to the call will be visible to any
+future<sup>1</sup> coherent access to the same memory performed by any other shader
+invocation.
+In particular, the values written this way in one shader stage are
+guaranteed to be visible to coherent memory accesses performed by shader
+invocations in subsequent stages when those invocations were triggered by
+the execution of the original shader invocation (e.g. fragment shader
+invocations for a primitive resulting from a particular geometry
+shader invocation).</p>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1">1</dt>
+<dd>
+<p>An access is only a <em>future</em> access if a <em>happens-before</em> relation can
+be established between the store and the load.</p>
+</dd>
+</dl>
+</div>
+<div class="paragraph">
+<p>Additionally, memory barrier functions order stores performed by the calling
+invocation, as observed by other shader invocations.
+Without memory barriers, if one shader invocation performs two stores to
+coherent variables, a second shader invocation might see the values written
+by the second store prior to seeing those written by the first.
+However, if the first shader invocation calls a memory barrier function
+between the two stores, selected other shader invocations will never see the
+results of the second store before seeing those of the first.
+When using the functions <strong>groupMemoryBarrier</strong>() or <strong>memoryBarrierShared</strong>(),
+this ordering guarantee applies only to other shader invocations in the same
+compute shader workgroup; all other memory barrier functions provide the
+guarantee to all other shader invocations.
+No memory barrier is required to guarantee the order of memory stores as
+observed by the invocation performing the stores; an invocation reading from
+a variable that it previously wrote will always see the most recently
+written value unless another shader invocation also wrote to the same
+memory.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="shader-invocation-group-functions">8.18. Shader Invocation Group Functions</h3>
+<div class="paragraph">
+<p>Implementations of the OpenGL Shading Language may optionally group multiple shader
+invocations for a single shader stage into a single SIMD invocation group,
+where invocations are assigned to groups in an undefined,
+implementation-dependent manner.
+Shader algorithms on such implementations may benefit from being able to
+evaluate a composite of Boolean values over all active invocations in a
+group.</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Syntax</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>anyInvocation</strong>(bool <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if and only if <em>value</em> is <strong>true</strong> for at least one
+      active invocation in the group.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>allInvocations</strong>(bool <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if and only if <em>value</em> is <strong>true</strong> for all active
+      invocations in the group.</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p class="tableblock">bool <strong>allInvocationsEqual</strong>(bool <em>value</em>)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Returns <strong>true</strong> if <em>value</em> is the same for all active invocations in
+      the group.</p></td>
+</tr>
+</tbody>
+</table>
+<div class="paragraph">
+<p>For all of these functions, the same result is returned to all active
+invocations in the group.</p>
+</div>
+<div class="paragraph">
+<p>These functions may be called within conditionally executed code.
+In groups where some invocations do not execute the function call, the value
+returned by the function is not affected by any invocation not calling the
+function, even when value is well-defined for that invocation.</p>
+</div>
+<div class="paragraph">
+<p>Because these functions depend on the values of <em>value</em> in an undefined
+group of invocations, the value returned by these functions is largely
+undefined.
+However, <strong>anyInvocation</strong>() is guaranteed to return <strong>true</strong> if <em>value</em> is
+<strong>true</strong>, and <strong>allInvocations</strong>() is guaranteed to return <strong>false</strong> if <em>value</em> is
+<strong>false</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Because implementations are not required to combine invocations into groups,
+simply returning <em>value</em> for <strong>anyInvocation</strong>() and <strong>allInvocations</strong>() and
+returning true for <strong>allInvocationsEqual</strong>() is a legal implementation of
+these functions.</p>
+</div>
+<div class="paragraph">
+<p>For fragment shaders, invocations in a SIMD invocation group may include
+invocations corresponding to pixels that are covered by a primitive being
+rasterized, as well as invocations corresponding to neighboring pixels not
+covered by the primitive.
+<em>Helper invocations</em> (see &#8220;<a href="#built-in-language-variables">Built-In Language
+Variables</a>&#8221;) may be created and the value of <em>value</em> for such
+helper-invocation pixels may affect the value returned by <strong>anyInvocation</strong>(),
+<strong>allInvocations</strong>(), and <strong>allInvocationsEqual</strong>().</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="shading-language-grammar">9. Shading Language Grammar</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The grammar is fed from the output of lexical analysis.
+The tokens returned from lexical analysis are</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="c++">CONST BOOL FLOAT INT UINT
+DOUBLE
+
+BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4
+
+MAT2 MAT3 MAT4 CENTROID IN OUT INOUT
+
+UNIFORM PATCH SAMPLE BUFFER SHARED
+
+COHERENT VOLATILE RESTRICT READONLY WRITEONLY
+
+NOPERSPECTIVE
+FLAT SMOOTH LAYOUT
+
+MAT2X2 MAT2X3 MAT2X4
+
+MAT3X2 MAT3X3 MAT3X4
+
+MAT4X2 MAT4X3 MAT4X4
+
+DVEC2 DVEC3 DVEC4 DMAT2 DMAT3 DMAT4
+
+DMAT2X2 DMAT2X3 DMAT2X4
+
+DMAT3X2 DMAT3X3 DMAT3X4
+
+DMAT4X2 DMAT4X3 DMAT4X4
+
+ATOMIC_UINT
+
+SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER2DSHADOW
+
+SAMPLERCUBESHADOW SAMPLER2DARRAY SAMPLER2DARRAYSHADOW
+
+ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY
+
+USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY
+
+SAMPLER1D SAMPLER1DSHADOW
+
+SAMPLER1DARRAY SAMPLER1DARRAYSHADOW
+
+ISAMPLER1D ISAMPLER1DARRAY
+
+USAMPLER1D USAMPLER1DARRAY
+
+SAMPLER2DRECT SAMPLER2DRECTSHADOW ISAMPLER2DRECT USAMPLER2DRECT
+
+SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER
+
+SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW
+
+ISAMPLERCUBEARRAY USAMPLERCUBEARRAY
+
+SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
+
+SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
+
+IMAGE2D IIMAGE2D UIMAGE2D
+
+IMAGE3D IIMAGE3D UIMAGE3D
+
+IMAGECUBE IIMAGECUBE UIMAGECUBE
+
+IMAGEBUFFER IIMAGEBUFFER UIMAGEBUFFER
+
+IMAGE2DARRAY IIMAGE2DARRAY UIMAGE2DARRAY
+
+IMAGECUBEARRAY IIMAGECUBEARRAY UIMAGECUBEARRAY
+
+IMAGE1D IIMAGE1D UIMAGE1D
+
+IMAGE1DARRAY IIMAGE1DARRAY UIMAGE1DARRAY
+
+IMAGE2DRECT IIMAGE2DRECT UIMAGE2DRECT
+
+IMAGE2DMS IIMAGE2DMS UIMAGE2DMS
+
+IMAGE2DMSARRAY IIMAGE2DMSARRAY UIMAGE2DMSARRAY
+
+STRUCT VOID
+
+WHILE BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+SUBROUTINE
+
+IDENTIFIER TYPE_NAME
+
+FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT
+DOUBLECONSTANT
+
+FIELD_SELECTION
+
+LEFT_OP RIGHT_OP
+
+INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+
+AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+
+MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+
+SUB_ASSIGN
+
+LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+
+COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+
+LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+INVARIANT PRECISE
+
+HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The following describes the grammar for the OpenGL Shading Language in terms of the above
+tokens.
+The starting rule is <em>translation_unit</em>.
+An empty shader (one having no tokens to parse, after pre-processing) is
+valid, resulting in no compile-time errors, even though the grammar below
+does not have a rule to accept an empty token stream.</p>
+</div>
+<div class="openblock bnf">
+<div class="content">
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>variable_identifier</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em></p>
+</dd>
+<dt class="hdlist1"><em>primary_expression</em> : </dt>
+<dd>
+<p><em>variable_identifier</em><br>
+<em>INTCONSTANT</em><br>
+<em>UINTCONSTANT</em><br>
+<em>FLOATCONSTANT</em><br>
+<em>BOOLCONSTANT</em><br>
+<em>DOUBLECONSTANT</em><br>
+<em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>postfix_expression</em> : </dt>
+<dd>
+<p><em>primary_expression</em><br>
+<em>postfix_expression</em> <em>LEFT_BRACKET</em> <em>integer_expression</em> <em>RIGHT_BRACKET</em><br>
+<em>function_call</em><br>
+<em>postfix_expression</em> <em>DOT</em> <em>FIELD_SELECTION</em><br>
+<em>postfix_expression</em> <em>INC_OP</em><br>
+<em>postfix_expression</em> <em>DEC_OP</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>FIELD_SELECTION includes members in structures, component selection for
+vectors and the 'length' identifier for the length() method</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>integer_expression</em> : </dt>
+<dd>
+<p><em>expression</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call</em> : </dt>
+<dd>
+<p><em>function_call_or_method</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_or_method</em> : </dt>
+<dd>
+<p><em>function_call_generic</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_generic</em> : </dt>
+<dd>
+<p><em>function_call_header_with_parameters</em> <em>RIGHT_PAREN</em><br>
+<em>function_call_header_no_parameters</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header_no_parameters</em> : </dt>
+<dd>
+<p><em>function_call_header</em> <em>VOID</em><br>
+<em>function_call_header</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header_with_parameters</em> : </dt>
+<dd>
+<p><em>function_call_header</em> <em>assignment_expression</em><br>
+<em>function_call_header_with_parameters</em> <em>COMMA</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>function_call_header</em> : </dt>
+<dd>
+<p><em>function_identifier</em> <em>LEFT_PAREN</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: Constructors look like functions, but lexical analysis
+recognized most of them as keywords.
+They are now recognized through <em>type_specifier</em>.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Methods (<strong>.length</strong>), subroutine array calls, and identifiers are recognized
+through <em>postfix_expression</em>.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>function_identifier</em> : </dt>
+<dd>
+<p><em>type_specifier</em><br>
+<em>postfix_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>unary_expression</em> : </dt>
+<dd>
+<p><em>postfix_expression</em><br>
+<em>INC_OP</em> <em>unary_expression</em><br>
+<em>DEC_OP</em> <em>unary_expression</em><br>
+<em>unary_operator</em> <em>unary_expression</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No traditional style type casts.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>unary_operator</em> : </dt>
+<dd>
+<p><em>PLUS</em><br>
+<em>DASH</em><br>
+<em>BANG</em><br>
+<em>TILDE</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No '*' or '&amp;' unary ops.
+Pointers are not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>multiplicative_expression</em> : </dt>
+<dd>
+<p><em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>STAR</em> <em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>SLASH</em> <em>unary_expression</em><br>
+<em>multiplicative_expression</em> <em>PERCENT</em> <em>unary_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>additive_expression</em> : </dt>
+<dd>
+<p><em>multiplicative_expression</em><br>
+<em>additive_expression</em> <em>PLUS</em> <em>multiplicative_expression</em><br>
+<em>additive_expression</em> <em>DASH</em> <em>multiplicative_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>shift_expression</em> : </dt>
+<dd>
+<p><em>additive_expression</em><br>
+<em>shift_expression</em> <em>LEFT_OP</em> <em>additive_expression</em><br>
+<em>shift_expression</em> <em>RIGHT_OP</em> <em>additive_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>relational_expression</em> : </dt>
+<dd>
+<p><em>shift_expression</em><br>
+<em>relational_expression</em> <em>LEFT_ANGLE</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>RIGHT_ANGLE</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>LE_OP</em> <em>shift_expression</em><br>
+<em>relational_expression</em> <em>GE_OP</em> <em>shift_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>equality_expression</em> : </dt>
+<dd>
+<p><em>relational_expression</em><br>
+<em>equality_expression</em> <em>EQ_OP</em> <em>relational_expression</em><br>
+<em>equality_expression</em> <em>NE_OP</em> <em>relational_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>and_expression</em> : </dt>
+<dd>
+<p><em>equality_expression</em><br>
+<em>and_expression</em> <em>AMPERSAND</em> <em>equality_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>exclusive_or_expression</em> : </dt>
+<dd>
+<p><em>and_expression</em><br>
+<em>exclusive_or_expression</em> <em>CARET</em> <em>and_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>inclusive_or_expression</em> : </dt>
+<dd>
+<p><em>exclusive_or_expression</em><br>
+<em>inclusive_or_expression</em> <em>VERTICAL_BAR</em> <em>exclusive_or_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_and_expression</em> : </dt>
+<dd>
+<p><em>inclusive_or_expression</em><br>
+<em>logical_and_expression</em> <em>AND_OP</em> <em>inclusive_or_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_xor_expression</em> : </dt>
+<dd>
+<p><em>logical_and_expression</em><br>
+<em>logical_xor_expression</em> <em>XOR_OP</em> <em>logical_and_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>logical_or_expression</em> : </dt>
+<dd>
+<p><em>logical_xor_expression</em><br>
+<em>logical_or_expression</em> <em>OR_OP</em> <em>logical_xor_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>conditional_expression</em> : </dt>
+<dd>
+<p><em>logical_or_expression</em><br>
+<em>logical_or_expression</em> <em>QUESTION</em> <em>expression</em> <em>COLON</em>
+<em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>assignment_expression</em> : </dt>
+<dd>
+<p><em>conditional_expression</em><br>
+<em>unary_expression</em> <em>assignment_operator</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>assignment_operator</em> : </dt>
+<dd>
+<p><em>EQUAL</em><br>
+<em>MUL_ASSIGN</em><br>
+<em>DIV_ASSIGN</em><br>
+<em>MOD_ASSIGN</em><br>
+<em>ADD_ASSIGN</em><br>
+<em>SUB_ASSIGN</em><br>
+<em>LEFT_ASSIGN</em><br>
+<em>RIGHT_ASSIGN</em><br>
+<em>AND_ASSIGN</em><br>
+<em>XOR_ASSIGN</em><br>
+<em>OR_ASSIGN</em></p>
+</dd>
+<dt class="hdlist1"><em>expression</em> : </dt>
+<dd>
+<p><em>assignment_expression</em><br>
+<em>expression</em> <em>COMMA</em> <em>assignment_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>constant_expression</em> : </dt>
+<dd>
+<p><em>conditional_expression</em></p>
+</dd>
+<dt class="hdlist1"><em>declaration</em> : </dt>
+<dd>
+<p><em>function_prototype</em> <em>SEMICOLON</em><br>
+<em>init_declarator_list</em> <em>SEMICOLON</em><br>
+<em>PRECISION</em> <em>precision_qualifier</em> <em>type_specifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>IDENTIFIER</em> <em>identifier_list</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>identifier_list</em> : </dt>
+<dd>
+<p><em>COMMA</em> <em>IDENTIFIER</em><br>
+<em>identifier_list</em> <em>COMMA</em> <em>IDENTIFIER</em></p>
+</dd>
+<dt class="hdlist1"><em>function_prototype</em> : </dt>
+<dd>
+<p><em>function_declarator</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>function_declarator</em> : </dt>
+<dd>
+<p><em>function_header</em><br>
+<em>function_header_with_parameters</em></p>
+</dd>
+<dt class="hdlist1"><em>function_header_with_parameters</em> : </dt>
+<dd>
+<p><em>function_header</em> <em>parameter_declaration</em><br>
+<em>function_header_with_parameters</em> <em>COMMA</em> <em>parameter_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>function_header</em> : </dt>
+<dd>
+<p><em>fully_specified_type</em> <em>IDENTIFIER</em> <em>LEFT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_declarator</em> : </dt>
+<dd>
+<p><em>type_specifier</em> <em>IDENTIFIER</em><br>
+<em>type_specifier</em> <em>IDENTIFIER</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_declaration</em> : </dt>
+<dd>
+<p><em>type_qualifier</em> <em>parameter_declarator</em><br>
+<em>parameter_declarator</em><br>
+<em>type_qualifier</em> <em>parameter_type_specifier</em><br>
+<em>parameter_type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>parameter_type_specifier</em> : </dt>
+<dd>
+<p><em>type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>init_declarator_list</em> : </dt>
+<dd>
+<p><em>single_declaration</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em>
+<em>initializer</em><br>
+<em>init_declarator_list</em> <em>COMMA</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+<dt class="hdlist1"><em>single_declaration</em> : </dt>
+<dd>
+<p><em>fully_specified_type</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>array_specifier</em> <em>EQUAL</em>
+<em>initializer</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No 'enum', or 'typedef'.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>fully_specified_type</em> : </dt>
+<dd>
+<p><em>type_specifier</em><br>
+<em>type_qualifier</em> <em>type_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>invariant_qualifier</em> : </dt>
+<dd>
+<p><em>INVARIANT</em></p>
+</dd>
+<dt class="hdlist1"><em>interpolation_qualifier</em> : </dt>
+<dd>
+<p><em>SMOOTH</em><br>
+<em>FLAT</em><br>
+<em>NOPERSPECTIVE</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier</em> : </dt>
+<dd>
+<p><em>LAYOUT</em> <em>LEFT_PAREN</em> <em>layout_qualifier_id_list</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier_id_list</em> : </dt>
+<dd>
+<p><em>layout_qualifier_id</em><br>
+<em>layout_qualifier_id_list</em> <em>COMMA</em> <em>layout_qualifier_id</em></p>
+</dd>
+<dt class="hdlist1"><em>layout_qualifier_id</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em><br>
+<em>IDENTIFIER</em> <em>EQUAL</em> <em>constant_expression</em><br>
+<em>SHARED</em></p>
+</dd>
+<dt class="hdlist1"><em>precise_qualifier</em> : </dt>
+<dd>
+<p><em>PRECISE</em></p>
+</dd>
+<dt class="hdlist1"><em>type_qualifier</em> : </dt>
+<dd>
+<p><em>single_type_qualifier</em><br>
+<em>type_qualifier</em> <em>single_type_qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>single_type_qualifier</em> : </dt>
+<dd>
+<p><em>storage_qualifier</em><br>
+<em>layout_qualifier</em><br>
+<em>precision_qualifier</em><br>
+<em>interpolation_qualifier</em><br>
+<em>invariant_qualifier</em><br>
+<em>precise_qualifier</em></p>
+</dd>
+<dt class="hdlist1"><em>storage_qualifier</em> : </dt>
+<dd>
+<p><em>CONST</em><br>
+<em>IN</em><br>
+<em>OUT</em><br>
+<em>INOUT</em><br>
+<em>CENTROID</em><br>
+<em>PATCH</em><br>
+<em>SAMPLE</em><br>
+<em>UNIFORM</em><br>
+<em>BUFFER</em><br>
+<em>SHARED</em><br>
+<em>COHERENT</em><br>
+<em>VOLATILE</em><br>
+<em>RESTRICT</em><br>
+<em>READONLY</em><br>
+<em>WRITEONLY</em><br>
+<em>SUBROUTINE</em><br>
+<em>SUBROUTINE</em> <em>LEFT_PAREN</em> <em>type_name_list</em> <em>RIGHT_PAREN</em></p>
+</dd>
+<dt class="hdlist1"><em>type_name_list</em> : </dt>
+<dd>
+<p><em>TYPE_NAME</em><br>
+<em>type_name_list</em> <em>COMMA</em> <em>TYPE_NAME</em></p>
+</dd>
+<dt class="hdlist1"><em>type_specifier</em> : </dt>
+<dd>
+<p><em>type_specifier_nonarray</em><br>
+<em>type_specifier_nonarray</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>array_specifier</em> : </dt>
+<dd>
+<p><em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br>
+<em>LEFT_BRACKET</em> <em>constant_expression</em> <em>RIGHT_BRACKET</em><br>
+<em>array_specifier</em> <em>LEFT_BRACKET</em> <em>RIGHT_BRACKET</em><br>
+<em>array_specifier</em> <em>LEFT_BRACKET</em> <em>constant_expression</em> <em>RIGHT_BRACKET</em></p>
+</dd>
+<dt class="hdlist1"><em>type_specifier_nonarray</em> : </dt>
+<dd>
+<p><em>VOID</em><br>
+<em>FLOAT</em><br>
+<em>DOUBLE</em><br>
+<em>INT</em><br>
+<em>UINT</em><br>
+<em>BOOL</em><br>
+<em>VEC2</em><br>
+<em>VEC3</em><br>
+<em>VEC4</em><br>
+<em>DVEC2</em><br>
+<em>DVEC3</em><br>
+<em>DVEC4</em><br>
+<em>BVEC2</em><br>
+<em>BVEC3</em><br>
+<em>BVEC4</em><br>
+<em>IVEC2</em><br>
+<em>IVEC3</em><br>
+<em>IVEC4</em><br>
+<em>UVEC2</em><br>
+<em>UVEC3</em><br>
+<em>UVEC4</em><br>
+<em>MAT2</em><br>
+<em>MAT3</em><br>
+<em>MAT4</em><br>
+<em>MAT2X2</em><br>
+<em>MAT2X3</em><br>
+<em>MAT2X4</em><br>
+<em>MAT3X2</em><br>
+<em>MAT3X3</em><br>
+<em>MAT3X4</em><br>
+<em>MAT4X2</em><br>
+<em>MAT4X3</em><br>
+<em>MAT4X4</em><br>
+<em>DMAT2</em><br>
+<em>DMAT3</em><br>
+<em>DMAT4</em><br>
+<em>DMAT2X2</em><br>
+<em>DMAT2X3</em><br>
+<em>DMAT2X4</em><br>
+<em>DMAT3X2</em><br>
+<em>DMAT3X3</em><br>
+<em>DMAT3X4</em><br>
+<em>DMAT4X2</em><br>
+<em>DMAT4X3</em><br>
+<em>DMAT4X4</em><br>
+<em>ATOMIC_UINT</em><br>
+<em>SAMPLER2D</em><br>
+<em>SAMPLER3D</em><br>
+<em>SAMPLERCUBE</em><br>
+<em>SAMPLER2DSHADOW</em><br>
+<em>SAMPLERCUBESHADOW</em><br>
+<em>SAMPLER2DARRAY</em><br>
+<em>SAMPLER2DARRAYSHADOW</em><br>
+<em>SAMPLERCUBEARRAY</em><br>
+<em>SAMPLERCUBEARRAYSHADOW</em><br>
+<em>ISAMPLER2D</em><br>
+<em>ISAMPLER3D</em><br>
+<em>ISAMPLERCUBE</em><br>
+<em>ISAMPLER2DARRAY</em><br>
+<em>ISAMPLERCUBEARRAY</em><br>
+<em>USAMPLER2D</em><br>
+<em>USAMPLER3D</em><br>
+<em>USAMPLERCUBE</em><br>
+<em>USAMPLER2DARRAY</em><br>
+<em>USAMPLERCUBEARRAY</em><br>
+<em>SAMPLER1D</em><br>
+<em>SAMPLER1DSHADOW</em><br>
+<em>SAMPLER1DARRAY</em><br>
+<em>SAMPLER1DARRAYSHADOW</em><br>
+<em>ISAMPLER1D</em><br>
+<em>ISAMPLER1DARRAY</em><br>
+<em>USAMPLER1D</em><br>
+<em>USAMPLER1DARRAY</em><br>
+<em>SAMPLER2DRECT</em><br>
+<em>SAMPLER2DRECTSHADOW</em><br>
+<em>ISAMPLER2DRECT</em><br>
+<em>USAMPLER2DRECT</em><br>
+<em>SAMPLERBUFFER</em><br>
+<em>ISAMPLERBUFFER</em><br>
+<em>USAMPLERBUFFER</em><br>
+<em>SAMPLER2DMS</em><br>
+<em>ISAMPLER2DMS</em><br>
+<em>USAMPLER2DMS</em><br>
+<em>SAMPLER2DMSARRAY</em><br>
+<em>ISAMPLER2DMSARRAY</em><br>
+<em>USAMPLER2DMSARRAY</em><br>
+<em>IMAGE2D</em><br>
+<em>IIMAGE2D</em><br>
+<em>UIMAGE2D</em><br>
+<em>IMAGE3D</em><br>
+<em>IIMAGE3D</em><br>
+<em>UIMAGE3D</em><br>
+<em>IMAGECUBE</em><br>
+<em>IIMAGECUBE</em><br>
+<em>UIMAGECUBE</em><br>
+<em>IMAGEBUFFER</em><br>
+<em>IIMAGEBUFFER</em><br>
+<em>UIMAGEBUFFER</em><br>
+<em>IMAGE1D</em><br>
+<em>IIMAGE1D</em><br>
+<em>UIMAGE1D</em><br>
+<em>IMAGE1DARRAY</em><br>
+<em>IIMAGE1DARRAY</em><br>
+<em>UIMAGE1DARRAY</em><br>
+<em>IMAGE2DRECT</em><br>
+<em>IIMAGE2DRECT</em><br>
+<em>UIMAGE2DRECT</em><br>
+<em>IMAGE2DARRAY</em><br>
+<em>IIMAGE2DARRAY</em><br>
+<em>UIMAGE2DARRAY</em><br>
+<em>IMAGECUBEARRAY</em><br>
+<em>IIMAGECUBEARRAY</em><br>
+<em>UIMAGECUBEARRAY</em><br>
+<em>IMAGE2DMS</em><br>
+<em>IIMAGE2DMS</em><br>
+<em>UIMAGE2DMS</em><br>
+<em>IMAGE2DMSARRAY</em><br>
+<em>IIMAGE2DMSARRAY</em><br>
+<em>UIMAGE2DMSARRAY</em><br>
+<em>struct_specifier</em><br>
+<em>TYPE_NAME</em></p>
+</dd>
+<dt class="hdlist1"><em>precision_qualifier</em> : </dt>
+<dd>
+<p><em>HIGH_PRECISION</em><br>
+<em>MEDIUM_PRECISION</em><br>
+<em>LOW_PRECISION</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_specifier</em> : </dt>
+<dd>
+<p><em>STRUCT</em> <em>IDENTIFIER</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em>
+<em>RIGHT_BRACE</em><br>
+<em>STRUCT</em> <em>LEFT_BRACE</em> <em>struct_declaration_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declaration_list</em> : </dt>
+<dd>
+<p><em>struct_declaration</em><br>
+<em>struct_declaration_list</em> <em>struct_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declaration</em> : </dt>
+<dd>
+<p><em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em><br>
+<em>type_qualifier</em> <em>type_specifier</em> <em>struct_declarator_list</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declarator_list</em> : </dt>
+<dd>
+<p><em>struct_declarator</em><br>
+<em>struct_declarator_list</em> <em>COMMA</em> <em>struct_declarator</em></p>
+</dd>
+<dt class="hdlist1"><em>struct_declarator</em> : </dt>
+<dd>
+<p><em>IDENTIFIER</em><br>
+<em>IDENTIFIER</em> <em>array_specifier</em></p>
+</dd>
+<dt class="hdlist1"><em>initializer</em> : </dt>
+<dd>
+<p><em>assignment_expression</em><br>
+<em>LEFT_BRACE</em> <em>initializer_list</em> <em>RIGHT_BRACE</em><br>
+<em>LEFT_BRACE</em> <em>initializer_list</em> <em>COMMA</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>initializer_list</em> : </dt>
+<dd>
+<p><em>initializer</em><br>
+<em>initializer_list</em> <em>COMMA</em> <em>initializer</em></p>
+</dd>
+<dt class="hdlist1"><em>declaration_statement</em> : </dt>
+<dd>
+<p><em>declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>statement</em> : </dt>
+<dd>
+<p><em>compound_statement</em><br>
+<em>simple_statement</em></p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: labeled statements for SWITCH only; 'goto' is not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>simple_statement</em> : </dt>
+<dd>
+<p><em>declaration_statement</em><br>
+<em>expression_statement</em><br>
+<em>selection_statement</em><br>
+<em>switch_statement</em><br>
+<em>case_label</em><br>
+<em>iteration_statement</em><br>
+<em>jump_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>compound_statement</em> : </dt>
+<dd>
+<p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br>
+<em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>statement_no_new_scope</em> : </dt>
+<dd>
+<p><em>compound_statement_no_new_scope</em><br>
+<em>simple_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>compound_statement_no_new_scope</em> : </dt>
+<dd>
+<p><em>LEFT_BRACE</em> <em>RIGHT_BRACE</em><br>
+<em>LEFT_BRACE</em> <em>statement_list</em> <em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>statement_list</em> : </dt>
+<dd>
+<p><em>statement</em><br>
+<em>statement_list</em> <em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>expression_statement</em> : </dt>
+<dd>
+<p><em>SEMICOLON</em><br>
+<em>expression</em> <em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>selection_statement</em> : </dt>
+<dd>
+<p><em>IF</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>selection_rest_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>selection_rest_statement</em> : </dt>
+<dd>
+<p><em>statement</em> <em>ELSE</em> <em>statement</em><br>
+<em>statement</em></p>
+</dd>
+<dt class="hdlist1"><em>condition</em> : </dt>
+<dd>
+<p><em>expression</em><br>
+<em>fully_specified_type</em> <em>IDENTIFIER</em> <em>EQUAL</em> <em>initializer</em></p>
+</dd>
+<dt class="hdlist1"><em>switch_statement</em> : </dt>
+<dd>
+<p><em>SWITCH</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em> <em>LEFT_BRACE</em>
+<em>switch_statement_list</em><br>
+<em>RIGHT_BRACE</em></p>
+</dd>
+<dt class="hdlist1"><em>switch_statement_list</em> : </dt>
+<dd>
+<p>/* <em>nothing</em> */<br>
+<em>statement_list</em></p>
+</dd>
+<dt class="hdlist1"><em>case_label</em> : </dt>
+<dd>
+<p><em>CASE</em> <em>expression</em> <em>COLON</em><br>
+<em>DEFAULT</em> <em>COLON</em></p>
+</dd>
+<dt class="hdlist1"><em>iteration_statement</em> : </dt>
+<dd>
+<p><em>WHILE</em> <em>LEFT_PAREN</em> <em>condition</em> <em>RIGHT_PAREN</em> <em>statement_no_new_scope</em><br>
+<em>DO</em> <em>statement</em> <em>WHILE</em> <em>LEFT_PAREN</em> <em>expression</em> <em>RIGHT_PAREN</em>
+<em>SEMICOLON</em><br>
+<em>FOR</em> <em>LEFT_PAREN</em> <em>for_init_statement</em> <em>for_rest_statement</em>
+<em>RIGHT_PAREN</em> <em>statement_no_new_scope</em></p>
+</dd>
+<dt class="hdlist1"><em>for_init_statement</em> : </dt>
+<dd>
+<p><em>expression_statement</em><br>
+<em>declaration_statement</em></p>
+</dd>
+<dt class="hdlist1"><em>conditionopt</em> : </dt>
+<dd>
+<p><em>condition</em><br>
+/* <em>empty</em> */</p>
+</dd>
+<dt class="hdlist1"><em>for_rest_statement</em> : </dt>
+<dd>
+<p><em>conditionopt</em> <em>SEMICOLON</em><br>
+<em>conditionopt</em> <em>SEMICOLON</em> <em>expression</em></p>
+</dd>
+<dt class="hdlist1"><em>jump_statement</em> : </dt>
+<dd>
+<p><em>CONTINUE</em> <em>SEMICOLON</em><br>
+<em>BREAK</em> <em>SEMICOLON</em><br>
+<em>RETURN</em> <em>SEMICOLON</em><br>
+<em>RETURN</em> <em>expression</em> <em>SEMICOLON</em><br>
+<em>DISCARD</em> <em>SEMICOLON</em> // Fragment shader only.</p>
+</dd>
+</dl>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-note" title="Note"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>Grammar Note: No 'goto'.
+Gotos are not supported.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="dlist">
+<dl>
+<dt class="hdlist1"><em>translation_unit</em> : </dt>
+<dd>
+<p><em>external_declaration</em><br>
+<em>translation_unit</em> <em>external_declaration</em></p>
+</dd>
+<dt class="hdlist1"><em>external_declaration</em> : </dt>
+<dd>
+<p><em>function_definition</em><br>
+<em>declaration</em><br>
+<em>SEMICOLON</em></p>
+</dd>
+<dt class="hdlist1"><em>function_definition</em> : </dt>
+<dd>
+<p><em>function_prototype</em> <em>compound_statement_no_new_scope</em></p>
+</dd>
+</dl>
+</div>
+</div>
+</div>
+<div class="paragraph">
+<p>In general the above grammar describes a super set of the OpenGL Shading Language.
+Certain constructs that are valid purely in terms of the grammar are
+disallowed by statements elsewhere in this specification.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="acknowledgments">10. Acknowledgments</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This specification is based on the work of those who contributed to past
+versions of the Open GL and Open GL ES Language Specifications and the
+following contributors to this version:</p>
+</div>
+<div class="paragraph">
+<p>Pat Brown, NVIDIA<br>
+Jeff Bolz, NVIDIA<br>
+Frank Chen<br>
+Pierre Boudier, AMD<br>
+Piers Daniell, NVIDIA<br>
+Chris Dodd, NVIDIA<br>
+Nick Haemel, NVIDIA<br>
+Jason Green, Transgaming<br>
+Brent Insko, Intel<br>
+Jon Leech<br>
+Bill Licea-Kane, Qualcomm<br>
+Daniel Koch, NVIDIA<br>
+Graeme Leese, Broadcom<br>
+Barthold Lichtenbelt, NVIDIA<br>
+Bruce Merry, ARM<br>
+Robert Ohannessian<br>
+Tom Olson, ARM<br>
+Brian Paul, VMware<br>
+Acorn Pooley, NVIDIA<br>
+Daniel Rakos, AMD<br>
+Christophe Riccio, AMD<br>
+Kevin Rogovin<br>
+Ian Romanick, Intel<br>
+Greg Roth, NVIDIA<br>
+Graham Sellers, AMD<br>
+Dave Shreiner, ARM<br>
+Jeremy Sandmel, Apple<br>
+Robert Simpson, Qualcomm<br>
+Eric Werness, NVIDIA<br>
+Mark Young, AMD</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="references">11. Normative References</h2>
+<div class="sectionbody">
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>International Standard ISO/IEC 14882:1998(E).
+Programming Languages - C++. Referenced for preprocessor only</p>
+</li>
+<li>
+<p>IEEE 754-2008.
+<em>IEEE Standard for Floating-Point Arithmetic</em></p>
+</li>
+</ol>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Version 4.60.6<br>
+Last updated 2018-12-12 16:37:44 MST
+</div>
+</div>
+
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/specs/gl/GLSLangSpec.4.60.pdf b/specs/gl/GLSLangSpec.4.60.pdf
index bfdb80a..86aded6 100644
--- a/specs/gl/GLSLangSpec.4.60.pdf
+++ b/specs/gl/GLSLangSpec.4.60.pdf
Binary files differ
diff --git a/specs/gl/glspec46.compatibility.pdf b/specs/gl/glspec46.compatibility.pdf
index 9f09b25..467fd68 100644
--- a/specs/gl/glspec46.compatibility.pdf
+++ b/specs/gl/glspec46.compatibility.pdf
Binary files differ
diff --git a/specs/gl/glspec46.compatibility.withchanges.pdf b/specs/gl/glspec46.compatibility.withchanges.pdf
index 5344bbc..b682eab 100644
--- a/specs/gl/glspec46.compatibility.withchanges.pdf
+++ b/specs/gl/glspec46.compatibility.withchanges.pdf
Binary files differ
diff --git a/specs/gl/glspec46.core.pdf b/specs/gl/glspec46.core.pdf
index 65dba25..159d77e 100644
--- a/specs/gl/glspec46.core.pdf
+++ b/specs/gl/glspec46.core.pdf
Binary files differ
diff --git a/specs/gl/glspec46.core.withchanges.pdf b/specs/gl/glspec46.core.withchanges.pdf
index b92ea3a..a58e958 100644
--- a/specs/gl/glspec46.core.withchanges.pdf
+++ b/specs/gl/glspec46.core.withchanges.pdf
Binary files differ
diff --git a/specs/gl/katex/README.md b/specs/gl/katex/README.md
new file mode 100644
index 0000000..5f8caa8
--- /dev/null
+++ b/specs/gl/katex/README.md
@@ -0,0 +1,68 @@
+# [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX)
+
+[![Join the chat at https://gitter.im/Khan/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
+
+ * **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://jsperf.com/katex-vs-mathjax/).
+ * **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
+ * **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
+ * **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
+
+KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, and IE 8 - IE 11.  A list of supported  commands can be on the [wiki](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX).
+
+## Usage
+
+You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
+
+```html
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css">
+<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js"></script>
+```
+
+#### In-browser rendering
+
+Call `katex.render` with a TeX expression and a DOM element to render into:
+
+```js
+katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
+```
+
+If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
+
+#### Server side rendering or rendering to a string
+
+To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
+
+```js
+var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
+// '<span class="katex">...</span>'
+```
+
+Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
+
+#### Rendering options
+
+You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
+
+- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
+- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
+- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
+
+For example:
+
+```js
+katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true });
+```
+
+#### Automatic rendering of math on a page
+
+Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## License
+
+KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
diff --git a/specs/gl/katex/contrib/auto-render.min.js b/specs/gl/katex/contrib/auto-render.min.js
new file mode 100644
index 0000000..30cc312
--- /dev/null
+++ b/specs/gl/katex/contrib/auto-render.min.js
@@ -0,0 +1 @@
+(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.renderMathInElement=e()}})(function(){var e,t,r;return function n(e,t,r){function a(o,l){if(!t[o]){if(!e[o]){var f=typeof require=="function"&&require;if(!l&&f)return f(o,!0);if(i)return i(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var s=t[o]={exports:{}};e[o][0].call(s.exports,function(t){var r=e[o][1][t];return a(r?r:t)},s,s.exports,n,e,t,r)}return t[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)a(r[o]);return a}({1:[function(e,t,r){var n=e("./splitAtDelimiters");var a=function(e,t){var r=[{type:"text",data:e}];for(var a=0;a<t.length;a++){var i=t[a];r=n(r,i.left,i.right,i.display||false)}return r};var i=function(e,t){var r=a(e,t);var n=document.createDocumentFragment();for(var i=0;i<r.length;i++){if(r[i].type==="text"){n.appendChild(document.createTextNode(r[i].data))}else{var o=document.createElement("span");var l=r[i].data;try{katex.render(l,o,{displayMode:r[i].display})}catch(f){if(!(f instanceof katex.ParseError)){throw f}console.error("KaTeX auto-render: Failed to parse `"+r[i].data+"` with ",f);n.appendChild(document.createTextNode(r[i].rawData));continue}n.appendChild(o)}}return n};var o=function(e,t,r){for(var n=0;n<e.childNodes.length;n++){var a=e.childNodes[n];if(a.nodeType===3){var l=i(a.textContent,t);n+=l.childNodes.length-1;e.replaceChild(l,a)}else if(a.nodeType===1){var f=r.indexOf(a.nodeName.toLowerCase())===-1;if(f){o(a,t,r)}}}};var l={delimiters:[{left:"$$",right:"$$",display:true},{left:"\\[",right:"\\]",display:true},{left:"\\(",right:"\\)",display:false}],ignoredTags:["script","noscript","style","textarea","pre","code"]};var f=function(e){var t;var r;for(var n=1,a=arguments.length;n<a;n++){t=arguments[n];for(r in t){if(Object.prototype.hasOwnProperty.call(t,r)){e[r]=t[r]}}}return e};var d=function(e,t){if(!e){throw new Error("No element provided to render")}t=f({},l,t);o(e,t.delimiters,t.ignoredTags)};t.exports=d},{"./splitAtDelimiters":2}],2:[function(e,t,r){var n=function(e,t,r){var n=r;var a=0;var i=e.length;while(n<t.length){var o=t[n];if(a<=0&&t.slice(n,n+i)===e){return n}else if(o==="\\"){n++}else if(o==="{"){a++}else if(o==="}"){a--}n++}return-1};var a=function(e,t,r,a){var i=[];for(var o=0;o<e.length;o++){if(e[o].type==="text"){var l=e[o].data;var f=true;var d=0;var s;s=l.indexOf(t);if(s!==-1){d=s;i.push({type:"text",data:l.slice(0,d)});f=false}while(true){if(f){s=l.indexOf(t,d);if(s===-1){break}i.push({type:"text",data:l.slice(d,s)});d=s}else{s=n(r,l,d+t.length);if(s===-1){break}i.push({type:"math",data:l.slice(d+t.length,s),rawData:l.slice(d,s+r.length),display:a});d=s+r.length}f=!f}i.push({type:"text",data:l.slice(d)})}else{i.push(e[o])}}return i};t.exports=a},{}]},{},[1])(1)});
diff --git a/specs/gl/katex/fonts/KaTeX_AMS-Regular.eot b/specs/gl/katex/fonts/KaTeX_AMS-Regular.eot
new file mode 100644
index 0000000..784276a
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_AMS-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_AMS-Regular.ttf b/specs/gl/katex/fonts/KaTeX_AMS-Regular.ttf
new file mode 100644
index 0000000..6f1e0be
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_AMS-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff b/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff
new file mode 100644
index 0000000..4dded47
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff2
new file mode 100644
index 0000000..ea81079
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_AMS-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.eot b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.eot
new file mode 100644
index 0000000..1a0db0c
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.ttf b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.ttf
new file mode 100644
index 0000000..b94907d
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff
new file mode 100644
index 0000000..799fa81
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff2 b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff2
new file mode 100644
index 0000000..73bb542
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Bold.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.eot b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.eot
new file mode 100644
index 0000000..6cc83d0
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.ttf
new file mode 100644
index 0000000..cf51e20
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff
new file mode 100644
index 0000000..f5e5c62
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff2
new file mode 100644
index 0000000..dd76d34
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Caligraphic-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.eot b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.eot
new file mode 100644
index 0000000..1960b10
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.ttf b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.ttf
new file mode 100644
index 0000000..7b0790f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff
new file mode 100644
index 0000000..dc32571
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff2 b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff2
new file mode 100644
index 0000000..fdc4292
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Bold.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.eot b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.eot
new file mode 100644
index 0000000..e4e7379
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.ttf
new file mode 100644
index 0000000..063bc02
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff
new file mode 100644
index 0000000..c4b18d8
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff2
new file mode 100644
index 0000000..4318d93
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Fraktur-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Bold.eot b/specs/gl/katex/fonts/KaTeX_Main-Bold.eot
new file mode 100644
index 0000000..80fbd02
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Bold.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Bold.ttf b/specs/gl/katex/fonts/KaTeX_Main-Bold.ttf
new file mode 100644
index 0000000..8e10722
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Bold.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Bold.woff b/specs/gl/katex/fonts/KaTeX_Main-Bold.woff
new file mode 100644
index 0000000..43b361a
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Bold.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Bold.woff2 b/specs/gl/katex/fonts/KaTeX_Main-Bold.woff2
new file mode 100644
index 0000000..af57a96
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Bold.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Italic.eot b/specs/gl/katex/fonts/KaTeX_Main-Italic.eot
new file mode 100644
index 0000000..fc77016
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Italic.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Italic.ttf b/specs/gl/katex/fonts/KaTeX_Main-Italic.ttf
new file mode 100644
index 0000000..d124495
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Italic.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Italic.woff b/specs/gl/katex/fonts/KaTeX_Main-Italic.woff
new file mode 100644
index 0000000..e623236
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Italic.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Italic.woff2 b/specs/gl/katex/fonts/KaTeX_Main-Italic.woff2
new file mode 100644
index 0000000..944e974
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Italic.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Regular.eot b/specs/gl/katex/fonts/KaTeX_Main-Regular.eot
new file mode 100644
index 0000000..dc60c09
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Main-Regular.ttf
new file mode 100644
index 0000000..da5797f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Regular.woff b/specs/gl/katex/fonts/KaTeX_Main-Regular.woff
new file mode 100644
index 0000000..37db672
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Main-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Main-Regular.woff2
new file mode 100644
index 0000000..4882042
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Main-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.eot b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.eot
new file mode 100644
index 0000000..52c8b8c
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.ttf b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.ttf
new file mode 100644
index 0000000..a8b527c
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff
new file mode 100644
index 0000000..8940e0b
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff2 b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff2
new file mode 100644
index 0000000..15cf56d
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-BoldItalic.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Italic.eot b/specs/gl/katex/fonts/KaTeX_Math-Italic.eot
new file mode 100644
index 0000000..64c8992
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Italic.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Italic.ttf b/specs/gl/katex/fonts/KaTeX_Math-Italic.ttf
new file mode 100644
index 0000000..06f39d3
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Italic.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Italic.woff b/specs/gl/katex/fonts/KaTeX_Math-Italic.woff
new file mode 100644
index 0000000..cf3b4b7
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Italic.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Italic.woff2 b/specs/gl/katex/fonts/KaTeX_Math-Italic.woff2
new file mode 100644
index 0000000..5f8c4bf
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Italic.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Regular.eot b/specs/gl/katex/fonts/KaTeX_Math-Regular.eot
new file mode 100644
index 0000000..5521e6a
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Math-Regular.ttf
new file mode 100644
index 0000000..7312708
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Regular.woff b/specs/gl/katex/fonts/KaTeX_Math-Regular.woff
new file mode 100644
index 0000000..0e2ebdf
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Math-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Math-Regular.woff2
new file mode 100644
index 0000000..ebe3d02
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Math-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.eot b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.eot
new file mode 100644
index 0000000..1660e76
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.ttf b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.ttf
new file mode 100644
index 0000000..dbeb7b9
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff
new file mode 100644
index 0000000..8f144a8
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff2 b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff2
new file mode 100644
index 0000000..329e855
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Bold.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.eot b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.eot
new file mode 100644
index 0000000..289ae3f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.ttf b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.ttf
new file mode 100644
index 0000000..b3a2f38
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff
new file mode 100644
index 0000000..bddf7ea
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff2 b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff2
new file mode 100644
index 0000000..5fa767b
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Italic.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.eot b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.eot
new file mode 100644
index 0000000..1b38b98
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.ttf b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.ttf
new file mode 100644
index 0000000..e4712f8
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff
new file mode 100644
index 0000000..33be368
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff2
new file mode 100644
index 0000000..4fcb2e2
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_SansSerif-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Script-Regular.eot b/specs/gl/katex/fonts/KaTeX_Script-Regular.eot
new file mode 100644
index 0000000..7870d7f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Script-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Script-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Script-Regular.ttf
new file mode 100644
index 0000000..da4d113
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Script-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Script-Regular.woff b/specs/gl/katex/fonts/KaTeX_Script-Regular.woff
new file mode 100644
index 0000000..d6ae79f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Script-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Script-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Script-Regular.woff2
new file mode 100644
index 0000000..1b43deb
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Script-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size1-Regular.eot b/specs/gl/katex/fonts/KaTeX_Size1-Regular.eot
new file mode 100644
index 0000000..29950f9
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size1-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size1-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Size1-Regular.ttf
new file mode 100644
index 0000000..194466a
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size1-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff b/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff
new file mode 100644
index 0000000..237f271
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff2
new file mode 100644
index 0000000..39b6f8f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size1-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size2-Regular.eot b/specs/gl/katex/fonts/KaTeX_Size2-Regular.eot
new file mode 100644
index 0000000..b8b0536
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size2-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size2-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Size2-Regular.ttf
new file mode 100644
index 0000000..b41b66a
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size2-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff b/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff
new file mode 100644
index 0000000..4a30558
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff2
new file mode 100644
index 0000000..3facec1
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size2-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size3-Regular.eot b/specs/gl/katex/fonts/KaTeX_Size3-Regular.eot
new file mode 100644
index 0000000..576b864
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size3-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size3-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Size3-Regular.ttf
new file mode 100644
index 0000000..790ddbb
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size3-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff b/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff
new file mode 100644
index 0000000..3a6d062
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff2
new file mode 100644
index 0000000..2cffafe
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size3-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size4-Regular.eot b/specs/gl/katex/fonts/KaTeX_Size4-Regular.eot
new file mode 100644
index 0000000..c2b045f
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size4-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size4-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Size4-Regular.ttf
new file mode 100644
index 0000000..ce660aa
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size4-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff b/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff
new file mode 100644
index 0000000..7826c6c
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff2
new file mode 100644
index 0000000..c921898
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Size4-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.eot b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.eot
new file mode 100644
index 0000000..4c178f4
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.eot
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.ttf b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.ttf
new file mode 100644
index 0000000..b0427ad
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.ttf
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff
new file mode 100644
index 0000000..78e9904
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff
Binary files differ
diff --git a/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff2 b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff2
new file mode 100644
index 0000000..618de99
--- /dev/null
+++ b/specs/gl/katex/fonts/KaTeX_Typewriter-Regular.woff2
Binary files differ
diff --git a/specs/gl/katex/katex.css b/specs/gl/katex/katex.css
new file mode 100644
index 0000000..ef0aa62
--- /dev/null
+++ b/specs/gl/katex/katex.css
@@ -0,0 +1,976 @@
+@font-face {
+  font-family: 'KaTeX_AMS';
+  src: url('fonts/KaTeX_AMS-Regular.eot');
+  src: url('fonts/KaTeX_AMS-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_AMS-Regular.woff2') format('woff2'), url('fonts/KaTeX_AMS-Regular.woff') format('woff'), url('fonts/KaTeX_AMS-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Caligraphic';
+  src: url('fonts/KaTeX_Caligraphic-Bold.eot');
+  src: url('fonts/KaTeX_Caligraphic-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Caligraphic-Bold.woff2') format('woff2'), url('fonts/KaTeX_Caligraphic-Bold.woff') format('woff'), url('fonts/KaTeX_Caligraphic-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Caligraphic';
+  src: url('fonts/KaTeX_Caligraphic-Regular.eot');
+  src: url('fonts/KaTeX_Caligraphic-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Caligraphic-Regular.woff2') format('woff2'), url('fonts/KaTeX_Caligraphic-Regular.woff') format('woff'), url('fonts/KaTeX_Caligraphic-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Fraktur';
+  src: url('fonts/KaTeX_Fraktur-Bold.eot');
+  src: url('fonts/KaTeX_Fraktur-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Fraktur-Bold.woff2') format('woff2'), url('fonts/KaTeX_Fraktur-Bold.woff') format('woff'), url('fonts/KaTeX_Fraktur-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Fraktur';
+  src: url('fonts/KaTeX_Fraktur-Regular.eot');
+  src: url('fonts/KaTeX_Fraktur-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Fraktur-Regular.woff2') format('woff2'), url('fonts/KaTeX_Fraktur-Regular.woff') format('woff'), url('fonts/KaTeX_Fraktur-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Bold.eot');
+  src: url('fonts/KaTeX_Main-Bold.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Bold.woff2') format('woff2'), url('fonts/KaTeX_Main-Bold.woff') format('woff'), url('fonts/KaTeX_Main-Bold.ttf') format('truetype');
+  font-weight: bold;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Italic.eot');
+  src: url('fonts/KaTeX_Main-Italic.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Italic.woff2') format('woff2'), url('fonts/KaTeX_Main-Italic.woff') format('woff'), url('fonts/KaTeX_Main-Italic.ttf') format('truetype');
+  font-weight: normal;
+  font-style: italic;
+}
+@font-face {
+  font-family: 'KaTeX_Main';
+  src: url('fonts/KaTeX_Main-Regular.eot');
+  src: url('fonts/KaTeX_Main-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Main-Regular.woff2') format('woff2'), url('fonts/KaTeX_Main-Regular.woff') format('woff'), url('fonts/KaTeX_Main-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Math';
+  src: url('fonts/KaTeX_Math-Italic.eot');
+  src: url('fonts/KaTeX_Math-Italic.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Math-Italic.woff2') format('woff2'), url('fonts/KaTeX_Math-Italic.woff') format('woff'), url('fonts/KaTeX_Math-Italic.ttf') format('truetype');
+  font-weight: normal;
+  font-style: italic;
+}
+@font-face {
+  font-family: 'KaTeX_SansSerif';
+  src: url('fonts/KaTeX_SansSerif-Regular.eot');
+  src: url('fonts/KaTeX_SansSerif-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_SansSerif-Regular.woff2') format('woff2'), url('fonts/KaTeX_SansSerif-Regular.woff') format('woff'), url('fonts/KaTeX_SansSerif-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Script';
+  src: url('fonts/KaTeX_Script-Regular.eot');
+  src: url('fonts/KaTeX_Script-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Script-Regular.woff2') format('woff2'), url('fonts/KaTeX_Script-Regular.woff') format('woff'), url('fonts/KaTeX_Script-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size1';
+  src: url('fonts/KaTeX_Size1-Regular.eot');
+  src: url('fonts/KaTeX_Size1-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size1-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size1-Regular.woff') format('woff'), url('fonts/KaTeX_Size1-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size2';
+  src: url('fonts/KaTeX_Size2-Regular.eot');
+  src: url('fonts/KaTeX_Size2-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size2-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size2-Regular.woff') format('woff'), url('fonts/KaTeX_Size2-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size3';
+  src: url('fonts/KaTeX_Size3-Regular.eot');
+  src: url('fonts/KaTeX_Size3-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size3-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size3-Regular.woff') format('woff'), url('fonts/KaTeX_Size3-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Size4';
+  src: url('fonts/KaTeX_Size4-Regular.eot');
+  src: url('fonts/KaTeX_Size4-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Size4-Regular.woff2') format('woff2'), url('fonts/KaTeX_Size4-Regular.woff') format('woff'), url('fonts/KaTeX_Size4-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'KaTeX_Typewriter';
+  src: url('fonts/KaTeX_Typewriter-Regular.eot');
+  src: url('fonts/KaTeX_Typewriter-Regular.eot#iefix') format('embedded-opentype'), url('fonts/KaTeX_Typewriter-Regular.woff2') format('woff2'), url('fonts/KaTeX_Typewriter-Regular.woff') format('woff'), url('fonts/KaTeX_Typewriter-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+.katex-display {
+  display: block;
+  margin: 1em 0;
+  text-align: center;
+}
+.katex-display > .katex {
+  display: inline-block;
+  text-align: initial;
+}
+.katex {
+  font: normal 1.21em KaTeX_Main, Times New Roman, serif;
+  line-height: 1.2;
+  white-space: nowrap;
+  text-indent: 0;
+}
+.katex .katex-html {
+  display: inline-block;
+}
+.katex .katex-mathml {
+  position: absolute;
+  clip: rect(1px, 1px, 1px, 1px);
+  padding: 0;
+  border: 0;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+}
+.katex .base {
+  display: inline-block;
+}
+.katex .strut {
+  display: inline-block;
+}
+.katex .mathrm {
+  font-style: normal;
+}
+.katex .textit {
+  font-style: italic;
+}
+.katex .mathit {
+  font-family: KaTeX_Math;
+  font-style: italic;
+}
+.katex .mathbf {
+  font-family: KaTeX_Main;
+  font-weight: bold;
+}
+.katex .amsrm {
+  font-family: KaTeX_AMS;
+}
+.katex .mathbb {
+  font-family: KaTeX_AMS;
+}
+.katex .mathcal {
+  font-family: KaTeX_Caligraphic;
+}
+.katex .mathfrak {
+  font-family: KaTeX_Fraktur;
+}
+.katex .mathtt {
+  font-family: KaTeX_Typewriter;
+}
+.katex .mathscr {
+  font-family: KaTeX_Script;
+}
+.katex .mathsf {
+  font-family: KaTeX_SansSerif;
+}
+.katex .mainit {
+  font-family: KaTeX_Main;
+  font-style: italic;
+}
+.katex .mord + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mord + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .mord + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mord + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mord {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mop + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mbin + .mord {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .mop {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .mopen {
+  margin-left: 0.22222em;
+}
+.katex .mbin + .minner {
+  margin-left: 0.22222em;
+}
+.katex .mrel + .mord {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .mop {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .mopen {
+  margin-left: 0.27778em;
+}
+.katex .mrel + .minner {
+  margin-left: 0.27778em;
+}
+.katex .mclose + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mclose + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .mclose + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .mclose + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mord {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mop {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mrel {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mopen {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mclose {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .mpunct {
+  margin-left: 0.16667em;
+}
+.katex .mpunct + .minner {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mord {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mop {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mbin {
+  margin-left: 0.22222em;
+}
+.katex .minner + .mrel {
+  margin-left: 0.27778em;
+}
+.katex .minner + .mopen {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mpunct {
+  margin-left: 0.16667em;
+}
+.katex .minner + .minner {
+  margin-left: 0.16667em;
+}
+.katex .mord.mtight {
+  margin-left: 0;
+}
+.katex .mop.mtight {
+  margin-left: 0;
+}
+.katex .mbin.mtight {
+  margin-left: 0;
+}
+.katex .mrel.mtight {
+  margin-left: 0;
+}
+.katex .mopen.mtight {
+  margin-left: 0;
+}
+.katex .mclose.mtight {
+  margin-left: 0;
+}
+.katex .mpunct.mtight {
+  margin-left: 0;
+}
+.katex .minner.mtight {
+  margin-left: 0;
+}
+.katex .mord + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mord.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mop + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .mclose + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .minner + .mop.mtight {
+  margin-left: 0.16667em;
+}
+.katex .reset-textstyle.textstyle {
+  font-size: 1em;
+}
+.katex .reset-textstyle.scriptstyle {
+  font-size: 0.7em;
+}
+.katex .reset-textstyle.scriptscriptstyle {
+  font-size: 0.5em;
+}
+.katex .reset-scriptstyle.textstyle {
+  font-size: 1.42857em;
+}
+.katex .reset-scriptstyle.scriptstyle {
+  font-size: 1em;
+}
+.katex .reset-scriptstyle.scriptscriptstyle {
+  font-size: 0.71429em;
+}
+.katex .reset-scriptscriptstyle.textstyle {
+  font-size: 2em;
+}
+.katex .reset-scriptscriptstyle.scriptstyle {
+  font-size: 1.4em;
+}
+.katex .reset-scriptscriptstyle.scriptscriptstyle {
+  font-size: 1em;
+}
+.katex .style-wrap {
+  position: relative;
+}
+.katex .vlist {
+  display: inline-block;
+}
+.katex .vlist > span {
+  display: block;
+  height: 0;
+  position: relative;
+}
+.katex .vlist > span > span {
+  display: inline-block;
+}
+.katex .vlist .baseline-fix {
+  display: inline-table;
+  table-layout: fixed;
+}
+.katex .msupsub {
+  text-align: left;
+}
+.katex .mfrac > span > span {
+  text-align: center;
+}
+.katex .mfrac .frac-line {
+  width: 100%;
+}
+.katex .mfrac .frac-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .mfrac .frac-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .mspace {
+  display: inline-block;
+}
+.katex .mspace.negativethinspace {
+  margin-left: -0.16667em;
+}
+.katex .mspace.thinspace {
+  width: 0.16667em;
+}
+.katex .mspace.negativemediumspace {
+  margin-left: -0.22222em;
+}
+.katex .mspace.mediumspace {
+  width: 0.22222em;
+}
+.katex .mspace.thickspace {
+  width: 0.27778em;
+}
+.katex .mspace.sixmuspace {
+  width: 0.333333em;
+}
+.katex .mspace.eightmuspace {
+  width: 0.444444em;
+}
+.katex .mspace.enspace {
+  width: 0.5em;
+}
+.katex .mspace.twelvemuspace {
+  width: 0.666667em;
+}
+.katex .mspace.quad {
+  width: 1em;
+}
+.katex .mspace.qquad {
+  width: 2em;
+}
+.katex .llap,
+.katex .rlap {
+  width: 0;
+  position: relative;
+}
+.katex .llap > .inner,
+.katex .rlap > .inner {
+  position: absolute;
+}
+.katex .llap > .fix,
+.katex .rlap > .fix {
+  display: inline-block;
+}
+.katex .llap > .inner {
+  right: 0;
+}
+.katex .rlap > .inner {
+  left: 0;
+}
+.katex .katex-logo .a {
+  font-size: 0.75em;
+  margin-left: -0.32em;
+  position: relative;
+  top: -0.2em;
+}
+.katex .katex-logo .t {
+  margin-left: -0.23em;
+}
+.katex .katex-logo .e {
+  margin-left: -0.1667em;
+  position: relative;
+  top: 0.2155em;
+}
+.katex .katex-logo .x {
+  margin-left: -0.125em;
+}
+.katex .rule {
+  display: inline-block;
+  border: solid 0;
+  position: relative;
+}
+.katex .overline .overline-line,
+.katex .underline .underline-line {
+  width: 100%;
+}
+.katex .overline .overline-line:before,
+.katex .underline .underline-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .overline .overline-line:after,
+.katex .underline .underline-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .sqrt > .sqrt-sign {
+  position: relative;
+}
+.katex .sqrt .sqrt-line {
+  width: 100%;
+}
+.katex .sqrt .sqrt-line:before {
+  border-bottom-style: solid;
+  border-bottom-width: 1px;
+  content: "";
+  display: block;
+}
+.katex .sqrt .sqrt-line:after {
+  border-bottom-style: solid;
+  border-bottom-width: 0.04em;
+  content: "";
+  display: block;
+  margin-top: -1px;
+}
+.katex .sqrt > .root {
+  margin-left: 0.27777778em;
+  margin-right: -0.55555556em;
+}
+.katex .sizing,
+.katex .fontsize-ensurer {
+  display: inline-block;
+}
+.katex .sizing.reset-size1.size1,
+.katex .fontsize-ensurer.reset-size1.size1 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size1.size2,
+.katex .fontsize-ensurer.reset-size1.size2 {
+  font-size: 1.4em;
+}
+.katex .sizing.reset-size1.size3,
+.katex .fontsize-ensurer.reset-size1.size3 {
+  font-size: 1.6em;
+}
+.katex .sizing.reset-size1.size4,
+.katex .fontsize-ensurer.reset-size1.size4 {
+  font-size: 1.8em;
+}
+.katex .sizing.reset-size1.size5,
+.katex .fontsize-ensurer.reset-size1.size5 {
+  font-size: 2em;
+}
+.katex .sizing.reset-size1.size6,
+.katex .fontsize-ensurer.reset-size1.size6 {
+  font-size: 2.4em;
+}
+.katex .sizing.reset-size1.size7,
+.katex .fontsize-ensurer.reset-size1.size7 {
+  font-size: 2.88em;
+}
+.katex .sizing.reset-size1.size8,
+.katex .fontsize-ensurer.reset-size1.size8 {
+  font-size: 3.46em;
+}
+.katex .sizing.reset-size1.size9,
+.katex .fontsize-ensurer.reset-size1.size9 {
+  font-size: 4.14em;
+}
+.katex .sizing.reset-size1.size10,
+.katex .fontsize-ensurer.reset-size1.size10 {
+  font-size: 4.98em;
+}
+.katex .sizing.reset-size2.size1,
+.katex .fontsize-ensurer.reset-size2.size1 {
+  font-size: 0.71428571em;
+}
+.katex .sizing.reset-size2.size2,
+.katex .fontsize-ensurer.reset-size2.size2 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size2.size3,
+.katex .fontsize-ensurer.reset-size2.size3 {
+  font-size: 1.14285714em;
+}
+.katex .sizing.reset-size2.size4,
+.katex .fontsize-ensurer.reset-size2.size4 {
+  font-size: 1.28571429em;
+}
+.katex .sizing.reset-size2.size5,
+.katex .fontsize-ensurer.reset-size2.size5 {
+  font-size: 1.42857143em;
+}
+.katex .sizing.reset-size2.size6,
+.katex .fontsize-ensurer.reset-size2.size6 {
+  font-size: 1.71428571em;
+}
+.katex .sizing.reset-size2.size7,
+.katex .fontsize-ensurer.reset-size2.size7 {
+  font-size: 2.05714286em;
+}
+.katex .sizing.reset-size2.size8,
+.katex .fontsize-ensurer.reset-size2.size8 {
+  font-size: 2.47142857em;
+}
+.katex .sizing.reset-size2.size9,
+.katex .fontsize-ensurer.reset-size2.size9 {
+  font-size: 2.95714286em;
+}
+.katex .sizing.reset-size2.size10,
+.katex .fontsize-ensurer.reset-size2.size10 {
+  font-size: 3.55714286em;
+}
+.katex .sizing.reset-size3.size1,
+.katex .fontsize-ensurer.reset-size3.size1 {
+  font-size: 0.625em;
+}
+.katex .sizing.reset-size3.size2,
+.katex .fontsize-ensurer.reset-size3.size2 {
+  font-size: 0.875em;
+}
+.katex .sizing.reset-size3.size3,
+.katex .fontsize-ensurer.reset-size3.size3 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size3.size4,
+.katex .fontsize-ensurer.reset-size3.size4 {
+  font-size: 1.125em;
+}
+.katex .sizing.reset-size3.size5,
+.katex .fontsize-ensurer.reset-size3.size5 {
+  font-size: 1.25em;
+}
+.katex .sizing.reset-size3.size6,
+.katex .fontsize-ensurer.reset-size3.size6 {
+  font-size: 1.5em;
+}
+.katex .sizing.reset-size3.size7,
+.katex .fontsize-ensurer.reset-size3.size7 {
+  font-size: 1.8em;
+}
+.katex .sizing.reset-size3.size8,
+.katex .fontsize-ensurer.reset-size3.size8 {
+  font-size: 2.1625em;
+}
+.katex .sizing.reset-size3.size9,
+.katex .fontsize-ensurer.reset-size3.size9 {
+  font-size: 2.5875em;
+}
+.katex .sizing.reset-size3.size10,
+.katex .fontsize-ensurer.reset-size3.size10 {
+  font-size: 3.1125em;
+}
+.katex .sizing.reset-size4.size1,
+.katex .fontsize-ensurer.reset-size4.size1 {
+  font-size: 0.55555556em;
+}
+.katex .sizing.reset-size4.size2,
+.katex .fontsize-ensurer.reset-size4.size2 {
+  font-size: 0.77777778em;
+}
+.katex .sizing.reset-size4.size3,
+.katex .fontsize-ensurer.reset-size4.size3 {
+  font-size: 0.88888889em;
+}
+.katex .sizing.reset-size4.size4,
+.katex .fontsize-ensurer.reset-size4.size4 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size4.size5,
+.katex .fontsize-ensurer.reset-size4.size5 {
+  font-size: 1.11111111em;
+}
+.katex .sizing.reset-size4.size6,
+.katex .fontsize-ensurer.reset-size4.size6 {
+  font-size: 1.33333333em;
+}
+.katex .sizing.reset-size4.size7,
+.katex .fontsize-ensurer.reset-size4.size7 {
+  font-size: 1.6em;
+}
+.katex .sizing.reset-size4.size8,
+.katex .fontsize-ensurer.reset-size4.size8 {
+  font-size: 1.92222222em;
+}
+.katex .sizing.reset-size4.size9,
+.katex .fontsize-ensurer.reset-size4.size9 {
+  font-size: 2.3em;
+}
+.katex .sizing.reset-size4.size10,
+.katex .fontsize-ensurer.reset-size4.size10 {
+  font-size: 2.76666667em;
+}
+.katex .sizing.reset-size5.size1,
+.katex .fontsize-ensurer.reset-size5.size1 {
+  font-size: 0.5em;
+}
+.katex .sizing.reset-size5.size2,
+.katex .fontsize-ensurer.reset-size5.size2 {
+  font-size: 0.7em;
+}
+.katex .sizing.reset-size5.size3,
+.katex .fontsize-ensurer.reset-size5.size3 {
+  font-size: 0.8em;
+}
+.katex .sizing.reset-size5.size4,
+.katex .fontsize-ensurer.reset-size5.size4 {
+  font-size: 0.9em;
+}
+.katex .sizing.reset-size5.size5,
+.katex .fontsize-ensurer.reset-size5.size5 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size5.size6,
+.katex .fontsize-ensurer.reset-size5.size6 {
+  font-size: 1.2em;
+}
+.katex .sizing.reset-size5.size7,
+.katex .fontsize-ensurer.reset-size5.size7 {
+  font-size: 1.44em;
+}
+.katex .sizing.reset-size5.size8,
+.katex .fontsize-ensurer.reset-size5.size8 {
+  font-size: 1.73em;
+}
+.katex .sizing.reset-size5.size9,
+.katex .fontsize-ensurer.reset-size5.size9 {
+  font-size: 2.07em;
+}
+.katex .sizing.reset-size5.size10,
+.katex .fontsize-ensurer.reset-size5.size10 {
+  font-size: 2.49em;
+}
+.katex .sizing.reset-size6.size1,
+.katex .fontsize-ensurer.reset-size6.size1 {
+  font-size: 0.41666667em;
+}
+.katex .sizing.reset-size6.size2,
+.katex .fontsize-ensurer.reset-size6.size2 {
+  font-size: 0.58333333em;
+}
+.katex .sizing.reset-size6.size3,
+.katex .fontsize-ensurer.reset-size6.size3 {
+  font-size: 0.66666667em;
+}
+.katex .sizing.reset-size6.size4,
+.katex .fontsize-ensurer.reset-size6.size4 {
+  font-size: 0.75em;
+}
+.katex .sizing.reset-size6.size5,
+.katex .fontsize-ensurer.reset-size6.size5 {
+  font-size: 0.83333333em;
+}
+.katex .sizing.reset-size6.size6,
+.katex .fontsize-ensurer.reset-size6.size6 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size6.size7,
+.katex .fontsize-ensurer.reset-size6.size7 {
+  font-size: 1.2em;
+}
+.katex .sizing.reset-size6.size8,
+.katex .fontsize-ensurer.reset-size6.size8 {
+  font-size: 1.44166667em;
+}
+.katex .sizing.reset-size6.size9,
+.katex .fontsize-ensurer.reset-size6.size9 {
+  font-size: 1.725em;
+}
+.katex .sizing.reset-size6.size10,
+.katex .fontsize-ensurer.reset-size6.size10 {
+  font-size: 2.075em;
+}
+.katex .sizing.reset-size7.size1,
+.katex .fontsize-ensurer.reset-size7.size1 {
+  font-size: 0.34722222em;
+}
+.katex .sizing.reset-size7.size2,
+.katex .fontsize-ensurer.reset-size7.size2 {
+  font-size: 0.48611111em;
+}
+.katex .sizing.reset-size7.size3,
+.katex .fontsize-ensurer.reset-size7.size3 {
+  font-size: 0.55555556em;
+}
+.katex .sizing.reset-size7.size4,
+.katex .fontsize-ensurer.reset-size7.size4 {
+  font-size: 0.625em;
+}
+.katex .sizing.reset-size7.size5,
+.katex .fontsize-ensurer.reset-size7.size5 {
+  font-size: 0.69444444em;
+}
+.katex .sizing.reset-size7.size6,
+.katex .fontsize-ensurer.reset-size7.size6 {
+  font-size: 0.83333333em;
+}
+.katex .sizing.reset-size7.size7,
+.katex .fontsize-ensurer.reset-size7.size7 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size7.size8,
+.katex .fontsize-ensurer.reset-size7.size8 {
+  font-size: 1.20138889em;
+}
+.katex .sizing.reset-size7.size9,
+.katex .fontsize-ensurer.reset-size7.size9 {
+  font-size: 1.4375em;
+}
+.katex .sizing.reset-size7.size10,
+.katex .fontsize-ensurer.reset-size7.size10 {
+  font-size: 1.72916667em;
+}
+.katex .sizing.reset-size8.size1,
+.katex .fontsize-ensurer.reset-size8.size1 {
+  font-size: 0.28901734em;
+}
+.katex .sizing.reset-size8.size2,
+.katex .fontsize-ensurer.reset-size8.size2 {
+  font-size: 0.40462428em;
+}
+.katex .sizing.reset-size8.size3,
+.katex .fontsize-ensurer.reset-size8.size3 {
+  font-size: 0.46242775em;
+}
+.katex .sizing.reset-size8.size4,
+.katex .fontsize-ensurer.reset-size8.size4 {
+  font-size: 0.52023121em;
+}
+.katex .sizing.reset-size8.size5,
+.katex .fontsize-ensurer.reset-size8.size5 {
+  font-size: 0.57803468em;
+}
+.katex .sizing.reset-size8.size6,
+.katex .fontsize-ensurer.reset-size8.size6 {
+  font-size: 0.69364162em;
+}
+.katex .sizing.reset-size8.size7,
+.katex .fontsize-ensurer.reset-size8.size7 {
+  font-size: 0.83236994em;
+}
+.katex .sizing.reset-size8.size8,
+.katex .fontsize-ensurer.reset-size8.size8 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size8.size9,
+.katex .fontsize-ensurer.reset-size8.size9 {
+  font-size: 1.19653179em;
+}
+.katex .sizing.reset-size8.size10,
+.katex .fontsize-ensurer.reset-size8.size10 {
+  font-size: 1.43930636em;
+}
+.katex .sizing.reset-size9.size1,
+.katex .fontsize-ensurer.reset-size9.size1 {
+  font-size: 0.24154589em;
+}
+.katex .sizing.reset-size9.size2,
+.katex .fontsize-ensurer.reset-size9.size2 {
+  font-size: 0.33816425em;
+}
+.katex .sizing.reset-size9.size3,
+.katex .fontsize-ensurer.reset-size9.size3 {
+  font-size: 0.38647343em;
+}
+.katex .sizing.reset-size9.size4,
+.katex .fontsize-ensurer.reset-size9.size4 {
+  font-size: 0.43478261em;
+}
+.katex .sizing.reset-size9.size5,
+.katex .fontsize-ensurer.reset-size9.size5 {
+  font-size: 0.48309179em;
+}
+.katex .sizing.reset-size9.size6,
+.katex .fontsize-ensurer.reset-size9.size6 {
+  font-size: 0.57971014em;
+}
+.katex .sizing.reset-size9.size7,
+.katex .fontsize-ensurer.reset-size9.size7 {
+  font-size: 0.69565217em;
+}
+.katex .sizing.reset-size9.size8,
+.katex .fontsize-ensurer.reset-size9.size8 {
+  font-size: 0.83574879em;
+}
+.katex .sizing.reset-size9.size9,
+.katex .fontsize-ensurer.reset-size9.size9 {
+  font-size: 1em;
+}
+.katex .sizing.reset-size9.size10,
+.katex .fontsize-ensurer.reset-size9.size10 {
+  font-size: 1.20289855em;
+}
+.katex .sizing.reset-size10.size1,
+.katex .fontsize-ensurer.reset-size10.size1 {
+  font-size: 0.20080321em;
+}
+.katex .sizing.reset-size10.size2,
+.katex .fontsize-ensurer.reset-size10.size2 {
+  font-size: 0.2811245em;
+}
+.katex .sizing.reset-size10.size3,
+.katex .fontsize-ensurer.reset-size10.size3 {
+  font-size: 0.32128514em;
+}
+.katex .sizing.reset-size10.size4,
+.katex .fontsize-ensurer.reset-size10.size4 {
+  font-size: 0.36144578em;
+}
+.katex .sizing.reset-size10.size5,
+.katex .fontsize-ensurer.reset-size10.size5 {
+  font-size: 0.40160643em;
+}
+.katex .sizing.reset-size10.size6,
+.katex .fontsize-ensurer.reset-size10.size6 {
+  font-size: 0.48192771em;
+}
+.katex .sizing.reset-size10.size7,
+.katex .fontsize-ensurer.reset-size10.size7 {
+  font-size: 0.57831325em;
+}
+.katex .sizing.reset-size10.size8,
+.katex .fontsize-ensurer.reset-size10.size8 {
+  font-size: 0.69477912em;
+}
+.katex .sizing.reset-size10.size9,
+.katex .fontsize-ensurer.reset-size10.size9 {
+  font-size: 0.8313253em;
+}
+.katex .sizing.reset-size10.size10,
+.katex .fontsize-ensurer.reset-size10.size10 {
+  font-size: 1em;
+}
+.katex .delimsizing.size1 {
+  font-family: KaTeX_Size1;
+}
+.katex .delimsizing.size2 {
+  font-family: KaTeX_Size2;
+}
+.katex .delimsizing.size3 {
+  font-family: KaTeX_Size3;
+}
+.katex .delimsizing.size4 {
+  font-family: KaTeX_Size4;
+}
+.katex .delimsizing.mult .delim-size1 > span {
+  font-family: KaTeX_Size1;
+}
+.katex .delimsizing.mult .delim-size4 > span {
+  font-family: KaTeX_Size4;
+}
+.katex .nulldelimiter {
+  display: inline-block;
+  width: 0.12em;
+}
+.katex .op-symbol {
+  position: relative;
+}
+.katex .op-symbol.small-op {
+  font-family: KaTeX_Size1;
+}
+.katex .op-symbol.large-op {
+  font-family: KaTeX_Size2;
+}
+.katex .op-limits > .vlist > span {
+  text-align: center;
+}
+.katex .accent > .vlist > span {
+  text-align: center;
+}
+.katex .accent .accent-body > span {
+  width: 0;
+}
+.katex .accent .accent-body.accent-vec > span {
+  position: relative;
+  left: 0.326em;
+}
+.katex .mtable .vertical-separator {
+  display: inline-block;
+  margin: 0 -0.025em;
+  border-right: 0.05em solid black;
+}
+.katex .mtable .arraycolsep {
+  display: inline-block;
+}
+.katex .mtable .col-align-c > .vlist {
+  text-align: center;
+}
+.katex .mtable .col-align-l > .vlist {
+  text-align: left;
+}
+.katex .mtable .col-align-r > .vlist {
+  text-align: right;
+}
diff --git a/specs/gl/katex/katex.js b/specs/gl/katex/katex.js
new file mode 100644
index 0000000..e104be9
--- /dev/null
+++ b/specs/gl/katex/katex.js
@@ -0,0 +1,9075 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.katex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This is the main entry point for KaTeX. Here, we expose functions for
+ * rendering expressions either to DOM nodes or to markup strings.
+ *
+ * We also expose the ParseError class to check if errors thrown from KaTeX are
+ * errors in the expression, or errors in javascript handling.
+ */
+
+var ParseError = require("./src/ParseError");
+var Settings = require("./src/Settings");
+
+var buildTree = require("./src/buildTree");
+var parseTree = require("./src/parseTree");
+var utils = require("./src/utils");
+
+/**
+ * Parse and build an expression, and place that expression in the DOM node
+ * given.
+ */
+var render = function(expression, baseNode, options) {
+    utils.clearNode(baseNode);
+
+    var settings = new Settings(options);
+
+    var tree = parseTree(expression, settings);
+    var node = buildTree(tree, expression, settings).toNode();
+
+    baseNode.appendChild(node);
+};
+
+// KaTeX's styles don't work properly in quirks mode. Print out an error, and
+// disable rendering.
+if (typeof document !== "undefined") {
+    if (document.compatMode !== "CSS1Compat") {
+        typeof console !== "undefined" && console.warn(
+            "Warning: KaTeX doesn't work in quirks mode. Make sure your " +
+                "website has a suitable doctype.");
+
+        render = function() {
+            throw new ParseError("KaTeX doesn't work in quirks mode.");
+        };
+    }
+}
+
+/**
+ * Parse and build an expression, and return the markup for that.
+ */
+var renderToString = function(expression, options) {
+    var settings = new Settings(options);
+
+    var tree = parseTree(expression, settings);
+    return buildTree(tree, expression, settings).toMarkup();
+};
+
+/**
+ * Parse an expression and return the parse tree.
+ */
+var generateParseTree = function(expression, options) {
+    var settings = new Settings(options);
+    return parseTree(expression, settings);
+};
+
+module.exports = {
+    render: render,
+    renderToString: renderToString,
+    /**
+     * NOTE: This method is not currently recommended for public use.
+     * The internal tree representation is unstable and is very likely
+     * to change. Use at your own risk.
+     */
+    __parse: generateParseTree,
+    ParseError: ParseError
+};
+
+},{"./src/ParseError":6,"./src/Settings":8,"./src/buildTree":13,"./src/parseTree":22,"./src/utils":25}],2:[function(require,module,exports){
+/** @flow */
+
+"use strict";
+
+function getRelocatable(re) {
+  // In the future, this could use a WeakMap instead of an expando.
+  if (!re.__matchAtRelocatable) {
+    // Disjunctions are the lowest-precedence operator, so we can make any
+    // pattern match the empty string by appending `|()` to it:
+    // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-patterns
+    var source = re.source + "|()";
+
+    // We always make the new regex global.
+    var flags = "g" + (re.ignoreCase ? "i" : "") + (re.multiline ? "m" : "") + (re.unicode ? "u" : "")
+    // sticky (/.../y) doesn't make sense in conjunction with our relocation
+    // logic, so we ignore it here.
+    ;
+
+    re.__matchAtRelocatable = new RegExp(source, flags);
+  }
+  return re.__matchAtRelocatable;
+}
+
+function matchAt(re, str, pos) {
+  if (re.global || re.sticky) {
+    throw new Error("matchAt(...): Only non-global regexes are supported");
+  }
+  var reloc = getRelocatable(re);
+  reloc.lastIndex = pos;
+  var match = reloc.exec(str);
+  // Last capturing group is our sentinel that indicates whether the regex
+  // matched at the given location.
+  if (match[match.length - 1] == null) {
+    // Original regex matched.
+    match.length = match.length - 1;
+    return match;
+  } else {
+    return null;
+  }
+}
+
+module.exports = matchAt;
+},{}],3:[function(require,module,exports){
+/**
+ * The Lexer class handles tokenizing the input in various ways. Since our
+ * parser expects us to be able to backtrack, the lexer allows lexing from any
+ * given starting point.
+ *
+ * Its main exposed function is the `lex` function, which takes a position to
+ * lex from and a type of token to lex. It defers to the appropriate `_innerLex`
+ * function.
+ *
+ * The various `_innerLex` functions perform the actual lexing of different
+ * kinds.
+ */
+
+var matchAt = require("match-at");
+
+var ParseError = require("./ParseError");
+
+// The main lexer class
+function Lexer(input) {
+    this.input = input;
+    this.pos = 0;
+}
+
+/**
+ * The resulting token returned from `lex`.
+ *
+ * It consists of the token text plus some position information.
+ * The position information is essentially a range in an input string,
+ * but instead of referencing the bare input string, we refer to the lexer.
+ * That way it is possible to attach extra metadata to the input string,
+ * like for example a file name or similar.
+ *
+ * The position information (all three parameters) is optional,
+ * so it is OK to construct synthetic tokens if appropriate.
+ * Not providing available position information may lead to
+ * degraded error reporting, though.
+ *
+ * @param {string}  text   the text of this token
+ * @param {number=} start  the start offset, zero-based inclusive
+ * @param {number=} end    the end offset, zero-based exclusive
+ * @param {Lexer=}  lexer  the lexer which in turn holds the input string
+ */
+function Token(text, start, end, lexer) {
+    this.text = text;
+    this.start = start;
+    this.end = end;
+    this.lexer = lexer;
+}
+
+/**
+ * Given a pair of tokens (this and endToken), compute a “Token” encompassing
+ * the whole input range enclosed by these two.
+ *
+ * @param {Token}  endToken  last token of the range, inclusive
+ * @param {string} text      the text of the newly constructed token
+ */
+Token.prototype.range = function(endToken, text) {
+    if (endToken.lexer !== this.lexer) {
+        return new Token(text); // sorry, no position information available
+    }
+    return new Token(text, this.start, endToken.end, this.lexer);
+};
+
+/* The following tokenRegex
+ * - matches typical whitespace (but not NBSP etc.) using its first group
+ * - does not match any control character \x00-\x1f except whitespace
+ * - does not match a bare backslash
+ * - matches any ASCII character except those just mentioned
+ * - does not match the BMP private use area \uE000-\uF8FF
+ * - does not match bare surrogate code units
+ * - matches any BMP character except for those just described
+ * - matches any valid Unicode surrogate pair
+ * - matches a backslash followed by one or more letters
+ * - matches a backslash followed by any BMP character, including newline
+ * Just because the Lexer matches something doesn't mean it's valid input:
+ * If there is no matching function or symbol definition, the Parser will
+ * still reject the input.
+ */
+var tokenRegex = new RegExp(
+    "([ \r\n\t]+)|" +                                 // whitespace
+    "([!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" +  // single codepoint
+    "|[\uD800-\uDBFF][\uDC00-\uDFFF]" +               // surrogate pair
+    "|\\\\(?:[a-zA-Z]+|[^\uD800-\uDFFF])" +           // function name
+    ")"
+);
+
+/**
+ * This function lexes a single token.
+ */
+Lexer.prototype.lex = function() {
+    var input = this.input;
+    var pos = this.pos;
+    if (pos === input.length) {
+        return new Token("EOF", pos, pos, this);
+    }
+    var match = matchAt(tokenRegex, input, pos);
+    if (match === null) {
+        throw new ParseError(
+            "Unexpected character: '" + input[pos] + "'",
+            new Token(input[pos], pos, pos + 1, this));
+    }
+    var text = match[2] || " ";
+    var start = this.pos;
+    this.pos += match[0].length;
+    var end = this.pos;
+    return new Token(text, start, end, this);
+};
+
+module.exports = Lexer;
+
+},{"./ParseError":6,"match-at":2}],4:[function(require,module,exports){
+/**
+ * This file contains the “gullet” where macros are expanded
+ * until only non-macro tokens remain.
+ */
+
+var Lexer = require("./Lexer");
+
+function MacroExpander(input, macros) {
+    this.lexer = new Lexer(input);
+    this.macros = macros;
+    this.stack = []; // contains tokens in REVERSE order
+    this.discardedWhiteSpace = [];
+}
+
+/**
+ * Recursively expand first token, then return first non-expandable token.
+ */
+MacroExpander.prototype.nextToken = function() {
+    for (;;) {
+        if (this.stack.length === 0) {
+            this.stack.push(this.lexer.lex());
+        }
+        var topToken = this.stack.pop();
+        var name = topToken.text;
+        if (!(name.charAt(0) === "\\" && this.macros.hasOwnProperty(name))) {
+            return topToken;
+        }
+        var expansion = this.macros[name];
+        if (typeof expansion === "string") {
+            var bodyLexer = new Lexer(expansion);
+            expansion = [];
+            var tok = bodyLexer.lex();
+            while (tok.text !== "EOF") {
+                expansion.push(tok);
+                tok = bodyLexer.lex();
+            }
+            expansion.reverse(); // to fit in with stack using push and pop
+            this.macros[name] = expansion;
+        }
+        this.stack = this.stack.concat(expansion);
+    }
+};
+
+MacroExpander.prototype.get = function(ignoreSpace) {
+    this.discardedWhiteSpace = [];
+    var token = this.nextToken();
+    if (ignoreSpace) {
+        while (token.text === " ") {
+            this.discardedWhiteSpace.push(token);
+            token = this.nextToken();
+        }
+    }
+    return token;
+};
+
+/**
+ * Undo the effect of the preceding call to the get method.
+ * A call to this method MUST be immediately preceded and immediately followed
+ * by a call to get.  Only used during mode switching, i.e. after one token
+ * was got in the old mode but should get got again in a new mode
+ * with possibly different whitespace handling.
+ */
+MacroExpander.prototype.unget = function(token) {
+    this.stack.push(token);
+    while (this.discardedWhiteSpace.length !== 0) {
+        this.stack.push(this.discardedWhiteSpace.pop());
+    }
+};
+
+module.exports = MacroExpander;
+
+},{"./Lexer":3}],5:[function(require,module,exports){
+/**
+ * This file contains information about the options that the Parser carries
+ * around with it while parsing. Data is held in an `Options` object, and when
+ * recursing, a new `Options` object can be created with the `.with*` and
+ * `.reset` functions.
+ */
+
+/**
+ * This is the main options class. It contains the style, size, color, and font
+ * of the current parse level. It also contains the style and size of the parent
+ * parse level, so size changes can be handled efficiently.
+ *
+ * Each of the `.with*` and `.reset` functions passes its current style and size
+ * as the parentStyle and parentSize of the new options class, so parent
+ * handling is taken care of automatically.
+ */
+function Options(data) {
+    this.style = data.style;
+    this.color = data.color;
+    this.size = data.size;
+    this.phantom = data.phantom;
+    this.font = data.font;
+
+    if (data.parentStyle === undefined) {
+        this.parentStyle = data.style;
+    } else {
+        this.parentStyle = data.parentStyle;
+    }
+
+    if (data.parentSize === undefined) {
+        this.parentSize = data.size;
+    } else {
+        this.parentSize = data.parentSize;
+    }
+}
+
+/**
+ * Returns a new options object with the same properties as "this".  Properties
+ * from "extension" will be copied to the new options object.
+ */
+Options.prototype.extend = function(extension) {
+    var data = {
+        style: this.style,
+        size: this.size,
+        color: this.color,
+        parentStyle: this.style,
+        parentSize: this.size,
+        phantom: this.phantom,
+        font: this.font
+    };
+
+    for (var key in extension) {
+        if (extension.hasOwnProperty(key)) {
+            data[key] = extension[key];
+        }
+    }
+
+    return new Options(data);
+};
+
+/**
+ * Create a new options object with the given style.
+ */
+Options.prototype.withStyle = function(style) {
+    return this.extend({
+        style: style
+    });
+};
+
+/**
+ * Create a new options object with the given size.
+ */
+Options.prototype.withSize = function(size) {
+    return this.extend({
+        size: size
+    });
+};
+
+/**
+ * Create a new options object with the given color.
+ */
+Options.prototype.withColor = function(color) {
+    return this.extend({
+        color: color
+    });
+};
+
+/**
+ * Create a new options object with "phantom" set to true.
+ */
+Options.prototype.withPhantom = function() {
+    return this.extend({
+        phantom: true
+    });
+};
+
+/**
+ * Create a new options objects with the give font.
+ */
+Options.prototype.withFont = function(font) {
+    return this.extend({
+        font: font || this.font
+    });
+};
+
+/**
+ * Create a new options object with the same style, size, and color. This is
+ * used so that parent style and size changes are handled correctly.
+ */
+Options.prototype.reset = function() {
+    return this.extend({});
+};
+
+/**
+ * A map of color names to CSS colors.
+ * TODO(emily): Remove this when we have real macros
+ */
+var colorMap = {
+    "katex-blue": "#6495ed",
+    "katex-orange": "#ffa500",
+    "katex-pink": "#ff00af",
+    "katex-red": "#df0030",
+    "katex-green": "#28ae7b",
+    "katex-gray": "gray",
+    "katex-purple": "#9d38bd",
+    "katex-blueA": "#ccfaff",
+    "katex-blueB": "#80f6ff",
+    "katex-blueC": "#63d9ea",
+    "katex-blueD": "#11accd",
+    "katex-blueE": "#0c7f99",
+    "katex-tealA": "#94fff5",
+    "katex-tealB": "#26edd5",
+    "katex-tealC": "#01d1c1",
+    "katex-tealD": "#01a995",
+    "katex-tealE": "#208170",
+    "katex-greenA": "#b6ffb0",
+    "katex-greenB": "#8af281",
+    "katex-greenC": "#74cf70",
+    "katex-greenD": "#1fab54",
+    "katex-greenE": "#0d923f",
+    "katex-goldA": "#ffd0a9",
+    "katex-goldB": "#ffbb71",
+    "katex-goldC": "#ff9c39",
+    "katex-goldD": "#e07d10",
+    "katex-goldE": "#a75a05",
+    "katex-redA": "#fca9a9",
+    "katex-redB": "#ff8482",
+    "katex-redC": "#f9685d",
+    "katex-redD": "#e84d39",
+    "katex-redE": "#bc2612",
+    "katex-maroonA": "#ffbde0",
+    "katex-maroonB": "#ff92c6",
+    "katex-maroonC": "#ed5fa6",
+    "katex-maroonD": "#ca337c",
+    "katex-maroonE": "#9e034e",
+    "katex-purpleA": "#ddd7ff",
+    "katex-purpleB": "#c6b9fc",
+    "katex-purpleC": "#aa87ff",
+    "katex-purpleD": "#7854ab",
+    "katex-purpleE": "#543b78",
+    "katex-mintA": "#f5f9e8",
+    "katex-mintB": "#edf2df",
+    "katex-mintC": "#e0e5cc",
+    "katex-grayA": "#f6f7f7",
+    "katex-grayB": "#f0f1f2",
+    "katex-grayC": "#e3e5e6",
+    "katex-grayD": "#d6d8da",
+    "katex-grayE": "#babec2",
+    "katex-grayF": "#888d93",
+    "katex-grayG": "#626569",
+    "katex-grayH": "#3b3e40",
+    "katex-grayI": "#21242c",
+    "katex-kaBlue": "#314453",
+    "katex-kaGreen": "#71B307"
+};
+
+/**
+ * Gets the CSS color of the current options object, accounting for the
+ * `colorMap`.
+ */
+Options.prototype.getColor = function() {
+    if (this.phantom) {
+        return "transparent";
+    } else {
+        return colorMap[this.color] || this.color;
+    }
+};
+
+module.exports = Options;
+
+},{}],6:[function(require,module,exports){
+/**
+ * This is the ParseError class, which is the main error thrown by KaTeX
+ * functions when something has gone wrong. This is used to distinguish internal
+ * errors from errors in the expression that the user provided.
+ *
+ * If possible, a caller should provide a Token or ParseNode with information
+ * about where in the source string the problem occurred.
+ *
+ * @param {string} message  The error message
+ * @param {(Token|ParseNode)=} token  An object providing position information
+ */
+function ParseError(message, token) {
+    var error = "KaTeX parse error: " + message;
+    var start;
+    var end;
+
+    if (token && token.lexer && token.start <= token.end) {
+        // If we have the input and a position, make the error a bit fancier
+
+        // Get the input
+        var input = token.lexer.input;
+
+        // Prepend some information
+        start = token.start;
+        end = token.end;
+        if (start === input.length) {
+            error += " at end of input: ";
+        } else {
+            error += " at position " + (start + 1) + ": ";
+        }
+
+        // Underline token in question using combining underscores
+        var underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
+
+        // Extract some context from the input and add it to the error
+        var left;
+        if (start > 15) {
+            left = "…" + input.slice(start - 15, start);
+        } else {
+            left = input.slice(0, start);
+        }
+        var right;
+        if (end + 15 < input.length) {
+            right = input.slice(end, end + 15) + "…";
+        } else {
+            right = input.slice(end);
+        }
+        error += left + underlined + right;
+    }
+
+    // Some hackery to make ParseError a prototype of Error
+    // See http://stackoverflow.com/a/8460753
+    var self = new Error(error);
+    self.name = "ParseError";
+    self.__proto__ = ParseError.prototype;
+
+    self.position = start;
+    return self;
+}
+
+// More hackery
+ParseError.prototype.__proto__ = Error.prototype;
+
+module.exports = ParseError;
+
+},{}],7:[function(require,module,exports){
+/* eslint no-constant-condition:0 */
+var functions = require("./functions");
+var environments = require("./environments");
+var MacroExpander = require("./MacroExpander");
+var symbols = require("./symbols");
+var utils = require("./utils");
+var cjkRegex = require("./unicodeRegexes").cjkRegex;
+
+var parseData = require("./parseData");
+var ParseError = require("./ParseError");
+
+/**
+ * This file contains the parser used to parse out a TeX expression from the
+ * input. Since TeX isn't context-free, standard parsers don't work particularly
+ * well.
+ *
+ * The strategy of this parser is as such:
+ *
+ * The main functions (the `.parse...` ones) take a position in the current
+ * parse string to parse tokens from. The lexer (found in Lexer.js, stored at
+ * this.lexer) also supports pulling out tokens at arbitrary places. When
+ * individual tokens are needed at a position, the lexer is called to pull out a
+ * token, which is then used.
+ *
+ * The parser has a property called "mode" indicating the mode that
+ * the parser is currently in. Currently it has to be one of "math" or
+ * "text", which denotes whether the current environment is a math-y
+ * one or a text-y one (e.g. inside \text). Currently, this serves to
+ * limit the functions which can be used in text mode.
+ *
+ * The main functions then return an object which contains the useful data that
+ * was parsed at its given point, and a new position at the end of the parsed
+ * data. The main functions can call each other and continue the parsing by
+ * using the returned position as a new starting point.
+ *
+ * There are also extra `.handle...` functions, which pull out some reused
+ * functionality into self-contained functions.
+ *
+ * The earlier functions return ParseNodes.
+ * The later functions (which are called deeper in the parse) sometimes return
+ * ParseFuncOrArgument, which contain a ParseNode as well as some data about
+ * whether the parsed object is a function which is missing some arguments, or a
+ * standalone object which can be used as an argument to another function.
+ */
+
+/**
+ * Main Parser class
+ */
+function Parser(input, settings) {
+    // Create a new macro expander (gullet) and (indirectly via that) also a
+    // new lexer (mouth) for this parser (stomach, in the language of TeX)
+    this.gullet = new MacroExpander(input, settings.macros);
+    // Store the settings for use in parsing
+    this.settings = settings;
+    // Count leftright depth (for \middle errors)
+    this.leftrightDepth = 0;
+}
+
+var ParseNode = parseData.ParseNode;
+
+/**
+ * An initial function (without its arguments), or an argument to a function.
+ * The `result` argument should be a ParseNode.
+ */
+function ParseFuncOrArgument(result, isFunction, token) {
+    this.result = result;
+    // Is this a function (i.e. is it something defined in functions.js)?
+    this.isFunction = isFunction;
+    this.token = token;
+}
+
+/**
+ * Checks a result to make sure it has the right type, and throws an
+ * appropriate error otherwise.
+ *
+ * @param {boolean=} consume whether to consume the expected token,
+ *                           defaults to true
+ */
+Parser.prototype.expect = function(text, consume) {
+    if (this.nextToken.text !== text) {
+        throw new ParseError(
+            "Expected '" + text + "', got '" + this.nextToken.text + "'",
+            this.nextToken
+        );
+    }
+    if (consume !== false) {
+        this.consume();
+    }
+};
+
+/**
+ * Considers the current look ahead token as consumed,
+ * and fetches the one after that as the new look ahead.
+ */
+Parser.prototype.consume = function() {
+    this.nextToken = this.gullet.get(this.mode === "math");
+};
+
+Parser.prototype.switchMode = function(newMode) {
+    this.gullet.unget(this.nextToken);
+    this.mode = newMode;
+    this.consume();
+};
+
+/**
+ * Main parsing function, which parses an entire input.
+ *
+ * @return {?Array.<ParseNode>}
+ */
+Parser.prototype.parse = function() {
+    // Try to parse the input
+    this.mode = "math";
+    this.consume();
+    var parse = this.parseInput();
+    return parse;
+};
+
+/**
+ * Parses an entire input tree.
+ */
+Parser.prototype.parseInput = function() {
+    // Parse an expression
+    var expression = this.parseExpression(false);
+    // If we succeeded, make sure there's an EOF at the end
+    this.expect("EOF", false);
+    return expression;
+};
+
+var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
+
+/**
+ * Parses an "expression", which is a list of atoms.
+ *
+ * @param {boolean} breakOnInfix  Should the parsing stop when we hit infix
+ *                  nodes? This happens when functions have higher precendence
+ *                  than infix nodes in implicit parses.
+ *
+ * @param {?string} breakOnTokenText  The text of the token that the expression
+ *                  should end with, or `null` if something else should end the
+ *                  expression.
+ *
+ * @return {ParseNode}
+ */
+Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) {
+    var body = [];
+    // Keep adding atoms to the body until we can't parse any more atoms (either
+    // we reached the end, a }, or a \right)
+    while (true) {
+        var lex = this.nextToken;
+        if (endOfExpression.indexOf(lex.text) !== -1) {
+            break;
+        }
+        if (breakOnTokenText && lex.text === breakOnTokenText) {
+            break;
+        }
+        if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
+            break;
+        }
+        var atom = this.parseAtom();
+        if (!atom) {
+            if (!this.settings.throwOnError && lex.text[0] === "\\") {
+                var errorNode = this.handleUnsupportedCmd();
+                body.push(errorNode);
+                continue;
+            }
+
+            break;
+        }
+        body.push(atom);
+    }
+    return this.handleInfixNodes(body);
+};
+
+/**
+ * Rewrites infix operators such as \over with corresponding commands such
+ * as \frac.
+ *
+ * There can only be one infix operator per group.  If there's more than one
+ * then the expression is ambiguous.  This can be resolved by adding {}.
+ *
+ * @returns {Array}
+ */
+Parser.prototype.handleInfixNodes = function(body) {
+    var overIndex = -1;
+    var funcName;
+
+    for (var i = 0; i < body.length; i++) {
+        var node = body[i];
+        if (node.type === "infix") {
+            if (overIndex !== -1) {
+                throw new ParseError(
+                    "only one infix operator per group",
+                    node.value.token);
+            }
+            overIndex = i;
+            funcName = node.value.replaceWith;
+        }
+    }
+
+    if (overIndex !== -1) {
+        var numerNode;
+        var denomNode;
+
+        var numerBody = body.slice(0, overIndex);
+        var denomBody = body.slice(overIndex + 1);
+
+        if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
+            numerNode = numerBody[0];
+        } else {
+            numerNode = new ParseNode("ordgroup", numerBody, this.mode);
+        }
+
+        if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
+            denomNode = denomBody[0];
+        } else {
+            denomNode = new ParseNode("ordgroup", denomBody, this.mode);
+        }
+
+        var value = this.callFunction(
+            funcName, [numerNode, denomNode], null);
+        return [new ParseNode(value.type, value, this.mode)];
+    } else {
+        return body;
+    }
+};
+
+// The greediness of a superscript or subscript
+var SUPSUB_GREEDINESS = 1;
+
+/**
+ * Handle a subscript or superscript with nice errors.
+ */
+Parser.prototype.handleSupSubscript = function(name) {
+    var symbolToken = this.nextToken;
+    var symbol = symbolToken.text;
+    this.consume();
+    var group = this.parseGroup();
+
+    if (!group) {
+        if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") {
+            return this.handleUnsupportedCmd();
+        } else {
+            throw new ParseError(
+                "Expected group after '" + symbol + "'",
+                symbolToken
+            );
+        }
+    } else if (group.isFunction) {
+        // ^ and _ have a greediness, so handle interactions with functions'
+        // greediness
+        var funcGreediness = functions[group.result].greediness;
+        if (funcGreediness > SUPSUB_GREEDINESS) {
+            return this.parseFunction(group);
+        } else {
+            throw new ParseError(
+                "Got function '" + group.result + "' with no arguments " +
+                    "as " + name, symbolToken);
+        }
+    } else {
+        return group.result;
+    }
+};
+
+/**
+ * Converts the textual input of an unsupported command into a text node
+ * contained within a color node whose color is determined by errorColor
+ */
+Parser.prototype.handleUnsupportedCmd = function() {
+    var text = this.nextToken.text;
+    var textordArray = [];
+
+    for (var i = 0; i < text.length; i++) {
+        textordArray.push(new ParseNode("textord", text[i], "text"));
+    }
+
+    var textNode = new ParseNode(
+        "text",
+        {
+            body: textordArray,
+            type: "text"
+        },
+        this.mode);
+
+    var colorNode = new ParseNode(
+        "color",
+        {
+            color: this.settings.errorColor,
+            value: [textNode],
+            type: "color"
+        },
+        this.mode);
+
+    this.consume();
+    return colorNode;
+};
+
+/**
+ * Parses a group with optional super/subscripts.
+ *
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseAtom = function() {
+    // The body of an atom is an implicit group, so that things like
+    // \left(x\right)^2 work correctly.
+    var base = this.parseImplicitGroup();
+
+    // In text mode, we don't have superscripts or subscripts
+    if (this.mode === "text") {
+        return base;
+    }
+
+    // Note that base may be empty (i.e. null) at this point.
+
+    var superscript;
+    var subscript;
+    while (true) {
+        // Lex the first token
+        var lex = this.nextToken;
+
+        if (lex.text === "\\limits" || lex.text === "\\nolimits") {
+            // We got a limit control
+            if (!base || base.type !== "op") {
+                throw new ParseError(
+                    "Limit controls must follow a math operator",
+                    lex);
+            } else {
+                var limits = lex.text === "\\limits";
+                base.value.limits = limits;
+                base.value.alwaysHandleSupSub = true;
+            }
+            this.consume();
+        } else if (lex.text === "^") {
+            // We got a superscript start
+            if (superscript) {
+                throw new ParseError("Double superscript", lex);
+            }
+            superscript = this.handleSupSubscript("superscript");
+        } else if (lex.text === "_") {
+            // We got a subscript start
+            if (subscript) {
+                throw new ParseError("Double subscript", lex);
+            }
+            subscript = this.handleSupSubscript("subscript");
+        } else if (lex.text === "'") {
+            // We got a prime
+            var prime = new ParseNode("textord", "\\prime", this.mode);
+
+            // Many primes can be grouped together, so we handle this here
+            var primes = [prime];
+            this.consume();
+            // Keep lexing tokens until we get something that's not a prime
+            while (this.nextToken.text === "'") {
+                // For each one, add another prime to the list
+                primes.push(prime);
+                this.consume();
+            }
+            // Put them into an ordgroup as the superscript
+            superscript = new ParseNode("ordgroup", primes, this.mode);
+        } else {
+            // If it wasn't ^, _, or ', stop parsing super/subscripts
+            break;
+        }
+    }
+
+    if (superscript || subscript) {
+        // If we got either a superscript or subscript, create a supsub
+        return new ParseNode("supsub", {
+            base: base,
+            sup: superscript,
+            sub: subscript
+        }, this.mode);
+    } else {
+        // Otherwise return the original body
+        return base;
+    }
+};
+
+// A list of the size-changing functions, for use in parseImplicitGroup
+var sizeFuncs = [
+    "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
+    "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"
+];
+
+// A list of the style-changing functions, for use in parseImplicitGroup
+var styleFuncs = [
+    "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"
+];
+
+/**
+ * Parses an implicit group, which is a group that starts at the end of a
+ * specified, and ends right before a higher explicit group ends, or at EOL. It
+ * is used for functions that appear to affect the current style, like \Large or
+ * \textrm, where instead of keeping a style we just pretend that there is an
+ * implicit grouping after it until the end of the group. E.g.
+ *   small text {\Large large text} small text again
+ * It is also used for \left and \right to get the correct grouping.
+ *
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseImplicitGroup = function() {
+    var start = this.parseSymbol();
+
+    if (start == null) {
+        // If we didn't get anything we handle, fall back to parseFunction
+        return this.parseFunction();
+    }
+
+    var func = start.result;
+    var body;
+
+    if (func === "\\left") {
+        // If we see a left:
+        // Parse the entire left function (including the delimiter)
+        var left = this.parseFunction(start);
+        // Parse out the implicit body
+        ++this.leftrightDepth;
+        body = this.parseExpression(false);
+        --this.leftrightDepth;
+        // Check the next token
+        this.expect("\\right", false);
+        var right = this.parseFunction();
+        return new ParseNode("leftright", {
+            body: body,
+            left: left.value.value,
+            right: right.value.value
+        }, this.mode);
+    } else if (func === "\\begin") {
+        // begin...end is similar to left...right
+        var begin = this.parseFunction(start);
+        var envName = begin.value.name;
+        if (!environments.hasOwnProperty(envName)) {
+            throw new ParseError(
+                "No such environment: " + envName, begin.value.nameGroup);
+        }
+        // Build the environment object. Arguments and other information will
+        // be made available to the begin and end methods using properties.
+        var env = environments[envName];
+        var args = this.parseArguments("\\begin{" + envName + "}", env);
+        var context = {
+            mode: this.mode,
+            envName: envName,
+            parser: this,
+            positions: args.pop()
+        };
+        var result = env.handler(context, args);
+        this.expect("\\end", false);
+        var endNameToken = this.nextToken;
+        var end = this.parseFunction();
+        if (end.value.name !== envName) {
+            throw new ParseError(
+                "Mismatch: \\begin{" + envName + "} matched " +
+                "by \\end{" + end.value.name + "}",
+                endNameToken);
+        }
+        result.position = end.position;
+        return result;
+    } else if (utils.contains(sizeFuncs, func)) {
+        // If we see a sizing function, parse out the implict body
+        body = this.parseExpression(false);
+        return new ParseNode("sizing", {
+            // Figure out what size to use based on the list of functions above
+            size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
+            value: body
+        }, this.mode);
+    } else if (utils.contains(styleFuncs, func)) {
+        // If we see a styling function, parse out the implict body
+        body = this.parseExpression(true);
+        return new ParseNode("styling", {
+            // Figure out what style to use by pulling out the style from
+            // the function name
+            style: func.slice(1, func.length - 5),
+            value: body
+        }, this.mode);
+    } else {
+        // Defer to parseFunction if it's not a function we handle
+        return this.parseFunction(start);
+    }
+};
+
+/**
+ * Parses an entire function, including its base and all of its arguments.
+ * The base might either have been parsed already, in which case
+ * it is provided as an argument, or it's the next group in the input.
+ *
+ * @param {ParseFuncOrArgument=} baseGroup optional as described above
+ * @return {?ParseNode}
+ */
+Parser.prototype.parseFunction = function(baseGroup) {
+    if (!baseGroup) {
+        baseGroup = this.parseGroup();
+    }
+
+    if (baseGroup) {
+        if (baseGroup.isFunction) {
+            var func = baseGroup.result;
+            var funcData = functions[func];
+            if (this.mode === "text" && !funcData.allowedInText) {
+                throw new ParseError(
+                    "Can't use function '" + func + "' in text mode",
+                    baseGroup.token);
+            }
+
+            var args = this.parseArguments(func, funcData);
+            var token = baseGroup.token;
+            var result = this.callFunction(func, args, args.pop(), token);
+            return new ParseNode(result.type, result, this.mode);
+        } else {
+            return baseGroup.result;
+        }
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Call a function handler with a suitable context and arguments.
+ */
+Parser.prototype.callFunction = function(name, args, positions, token) {
+    var context = {
+        funcName: name,
+        parser: this,
+        positions: positions,
+        token: token
+    };
+    return functions[name].handler(context, args);
+};
+
+/**
+ * Parses the arguments of a function or environment
+ *
+ * @param {string} func  "\name" or "\begin{name}"
+ * @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData
+ * @return the array of arguments, with the list of positions as last element
+ */
+Parser.prototype.parseArguments = function(func, funcData) {
+    var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
+    if (totalArgs === 0) {
+        return [[this.pos]];
+    }
+
+    var baseGreediness = funcData.greediness;
+    var positions = [this.pos];
+    var args = [];
+
+    for (var i = 0; i < totalArgs; i++) {
+        var nextToken = this.nextToken;
+        var argType = funcData.argTypes && funcData.argTypes[i];
+        var arg;
+        if (i < funcData.numOptionalArgs) {
+            if (argType) {
+                arg = this.parseGroupOfType(argType, true);
+            } else {
+                arg = this.parseGroup(true);
+            }
+            if (!arg) {
+                args.push(null);
+                positions.push(this.pos);
+                continue;
+            }
+        } else {
+            if (argType) {
+                arg = this.parseGroupOfType(argType);
+            } else {
+                arg = this.parseGroup();
+            }
+            if (!arg) {
+                if (!this.settings.throwOnError &&
+                    this.nextToken.text[0] === "\\") {
+                    arg = new ParseFuncOrArgument(
+                        this.handleUnsupportedCmd(this.nextToken.text),
+                        false);
+                } else {
+                    throw new ParseError(
+                        "Expected group after '" + func + "'", nextToken);
+                }
+            }
+        }
+        var argNode;
+        if (arg.isFunction) {
+            var argGreediness =
+                functions[arg.result].greediness;
+            if (argGreediness > baseGreediness) {
+                argNode = this.parseFunction(arg);
+            } else {
+                throw new ParseError(
+                    "Got function '" + arg.result + "' as " +
+                    "argument to '" + func + "'", nextToken);
+            }
+        } else {
+            argNode = arg.result;
+        }
+        args.push(argNode);
+        positions.push(this.pos);
+    }
+
+    args.push(positions);
+
+    return args;
+};
+
+
+/**
+ * Parses a group when the mode is changing.
+ *
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseGroupOfType = function(innerMode, optional) {
+    var outerMode = this.mode;
+    // Handle `original` argTypes
+    if (innerMode === "original") {
+        innerMode = outerMode;
+    }
+
+    if (innerMode === "color") {
+        return this.parseColorGroup(optional);
+    }
+    if (innerMode === "size") {
+        return this.parseSizeGroup(optional);
+    }
+
+    this.switchMode(innerMode);
+    if (innerMode === "text") {
+        // text mode is special because it should ignore the whitespace before
+        // it
+        while (this.nextToken.text === " ") {
+            this.consume();
+        }
+    }
+    // By the time we get here, innerMode is one of "text" or "math".
+    // We switch the mode of the parser, recurse, then restore the old mode.
+    var res = this.parseGroup(optional);
+    this.switchMode(outerMode);
+    return res;
+};
+
+/**
+ * Parses a group, essentially returning the string formed by the
+ * brace-enclosed tokens plus some position information.
+ *
+ * @param {string} modeName  Used to describe the mode in error messages
+ * @param {boolean=} optional  Whether the group is optional or required
+ */
+Parser.prototype.parseStringGroup = function(modeName, optional) {
+    if (optional && this.nextToken.text !== "[") {
+        return null;
+    }
+    var outerMode = this.mode;
+    this.mode = "text";
+    this.expect(optional ? "[" : "{");
+    var str = "";
+    var firstToken = this.nextToken;
+    var lastToken = firstToken;
+    while (this.nextToken.text !== (optional ? "]" : "}")) {
+        if (this.nextToken.text === "EOF") {
+            throw new ParseError(
+                "Unexpected end of input in " + modeName,
+                firstToken.range(this.nextToken, str));
+        }
+        lastToken = this.nextToken;
+        str += lastToken.text;
+        this.consume();
+    }
+    this.mode = outerMode;
+    this.expect(optional ? "]" : "}");
+    return firstToken.range(lastToken, str);
+};
+
+/**
+ * Parses a regex-delimited group: the largest sequence of tokens
+ * whose concatenated strings match `regex`. Returns the string
+ * formed by the tokens plus some position information.
+ *
+ * @param {RegExp} regex
+ * @param {string} modeName  Used to describe the mode in error messages
+ */
+Parser.prototype.parseRegexGroup = function(regex, modeName) {
+    var outerMode = this.mode;
+    this.mode = "text";
+    var firstToken = this.nextToken;
+    var lastToken = firstToken;
+    var str = "";
+    while (this.nextToken.text !== "EOF"
+           && regex.test(str + this.nextToken.text)) {
+        lastToken = this.nextToken;
+        str += lastToken.text;
+        this.consume();
+    }
+    if (str === "") {
+        throw new ParseError(
+            "Invalid " + modeName + ": '" + firstToken.text + "'",
+            firstToken);
+    }
+    this.mode = outerMode;
+    return firstToken.range(lastToken, str);
+};
+
+/**
+ * Parses a color description.
+ */
+Parser.prototype.parseColorGroup = function(optional) {
+    var res = this.parseStringGroup("color", optional);
+    if (!res) {
+        return null;
+    }
+    var match = (/^(#[a-z0-9]+|[a-z]+)$/i).exec(res.text);
+    if (!match) {
+        throw new ParseError("Invalid color: '" + res.text + "'", res);
+    }
+    return new ParseFuncOrArgument(
+        new ParseNode("color", match[0], this.mode),
+        false);
+};
+
+/**
+ * Parses a size specification, consisting of magnitude and unit.
+ */
+Parser.prototype.parseSizeGroup = function(optional) {
+    var res;
+    if (!optional && this.nextToken.text !== "{") {
+        res = this.parseRegexGroup(
+            /^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/, "size");
+    } else {
+        res = this.parseStringGroup("size", optional);
+    }
+    if (!res) {
+        return null;
+    }
+    var match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(res.text);
+    if (!match) {
+        throw new ParseError("Invalid size: '" + res.text + "'", res);
+    }
+    var data = {
+        number: +(match[1] + match[2]), // sign + magnitude, cast to number
+        unit: match[3]
+    };
+    if (data.unit !== "em" && data.unit !== "ex" && data.unit !== "mu") {
+        throw new ParseError("Invalid unit: '" + data.unit + "'", res);
+    }
+    return new ParseFuncOrArgument(
+        new ParseNode("color", data, this.mode),
+        false);
+};
+
+/**
+ * If the argument is false or absent, this parses an ordinary group,
+ * which is either a single nucleus (like "x") or an expression
+ * in braces (like "{x+y}").
+ * If the argument is true, it parses either a bracket-delimited expression
+ * (like "[x+y]") or returns null to indicate the absence of a
+ * bracket-enclosed group.
+ *
+ * @param {boolean=} optional  Whether the group is optional or required
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseGroup = function(optional) {
+    var firstToken = this.nextToken;
+    // Try to parse an open brace
+    if (this.nextToken.text === (optional ? "[" : "{")) {
+        // If we get a brace, parse an expression
+        this.consume();
+        var expression = this.parseExpression(false, optional ? "]" : null);
+        var lastToken = this.nextToken;
+        // Make sure we get a close brace
+        this.expect(optional ? "]" : "}");
+        if (this.mode === "text") {
+            this.formLigatures(expression);
+        }
+        return new ParseFuncOrArgument(
+            new ParseNode("ordgroup", expression, this.mode,
+                          firstToken, lastToken),
+            false);
+    } else {
+        // Otherwise, just return a nucleus, or nothing for an optional group
+        return optional ? null : this.parseSymbol();
+    }
+};
+
+/**
+ * Form ligature-like combinations of characters for text mode.
+ * This includes inputs like "--", "---", "``" and "''".
+ * The result will simply replace multiple textord nodes with a single
+ * character in each value by a single textord node having multiple
+ * characters in its value.  The representation is still ASCII source.
+ *
+ * @param {Array.<ParseNode>} group  the nodes of this group,
+ *                                   list will be moified in place
+ */
+Parser.prototype.formLigatures = function(group) {
+    var i;
+    var n = group.length - 1;
+    for (i = 0; i < n; ++i) {
+        var a = group[i];
+        var v = a.value;
+        if (v === "-" && group[i + 1].value === "-") {
+            if (i + 1 < n && group[i + 2].value === "-") {
+                group.splice(i, 3, new ParseNode(
+                    "textord", "---", "text", a, group[i + 2]));
+                n -= 2;
+            } else {
+                group.splice(i, 2, new ParseNode(
+                    "textord", "--", "text", a, group[i + 1]));
+                n -= 1;
+            }
+        }
+        if ((v === "'" || v === "`") && group[i + 1].value === v) {
+            group.splice(i, 2, new ParseNode(
+                "textord", v + v, "text", a, group[i + 1]));
+            n -= 1;
+        }
+    }
+};
+
+/**
+ * Parse a single symbol out of the string. Here, we handle both the functions
+ * we have defined, as well as the single character symbols
+ *
+ * @return {?ParseFuncOrArgument}
+ */
+Parser.prototype.parseSymbol = function() {
+    var nucleus = this.nextToken;
+
+    if (functions[nucleus.text]) {
+        this.consume();
+        // If there exists a function with this name, we return the function and
+        // say that it is a function.
+        return new ParseFuncOrArgument(
+            nucleus.text,
+            true, nucleus);
+    } else if (symbols[this.mode][nucleus.text]) {
+        this.consume();
+        // Otherwise if this is a no-argument function, find the type it
+        // corresponds to in the symbols map
+        return new ParseFuncOrArgument(
+            new ParseNode(symbols[this.mode][nucleus.text].group,
+                          nucleus.text, this.mode, nucleus),
+            false, nucleus);
+    } else if (this.mode === "text" && cjkRegex.test(nucleus.text)) {
+        this.consume();
+        return new ParseFuncOrArgument(
+            new ParseNode("textord", nucleus.text, this.mode, nucleus),
+            false, nucleus);
+    } else {
+        return null;
+    }
+};
+
+Parser.prototype.ParseNode = ParseNode;
+
+module.exports = Parser;
+
+},{"./MacroExpander":4,"./ParseError":6,"./environments":16,"./functions":19,"./parseData":21,"./symbols":23,"./unicodeRegexes":24,"./utils":25}],8:[function(require,module,exports){
+/**
+ * This is a module for storing settings passed into KaTeX. It correctly handles
+ * default settings.
+ */
+
+/**
+ * Helper function for getting a default value if the value is undefined
+ */
+function get(option, defaultValue) {
+    return option === undefined ? defaultValue : option;
+}
+
+/**
+ * The main Settings object
+ *
+ * The current options stored are:
+ *  - displayMode: Whether the expression should be typeset by default in
+ *                 textstyle or displaystyle (default false)
+ */
+function Settings(options) {
+    // allow null options
+    options = options || {};
+    this.displayMode = get(options.displayMode, false);
+    this.throwOnError = get(options.throwOnError, true);
+    this.errorColor = get(options.errorColor, "#cc0000");
+    this.macros = options.macros || {};
+}
+
+module.exports = Settings;
+
+},{}],9:[function(require,module,exports){
+/**
+ * This file contains information and classes for the various kinds of styles
+ * used in TeX. It provides a generic `Style` class, which holds information
+ * about a specific style. It then provides instances of all the different kinds
+ * of styles possible, and provides functions to move between them and get
+ * information about them.
+ */
+
+var sigmas = require("./fontMetrics.js").sigmas;
+
+var metrics = [{}, {}, {}];
+var i;
+for (var key in sigmas) {
+    if (sigmas.hasOwnProperty(key)) {
+        for (i = 0; i < 3; i++) {
+            metrics[i][key] = sigmas[key][i];
+        }
+    }
+}
+for (i = 0; i < 3; i++) {
+    metrics[i].emPerEx = sigmas.xHeight[i] / sigmas.quad[i];
+}
+
+/**
+ * The main style class. Contains a unique id for the style, a size (which is
+ * the same for cramped and uncramped version of a style), a cramped flag, and a
+ * size multiplier, which gives the size difference between a style and
+ * textstyle.
+ */
+function Style(id, size, multiplier, cramped) {
+    this.id = id;
+    this.size = size;
+    this.cramped = cramped;
+    this.sizeMultiplier = multiplier;
+    this.metrics = metrics[size > 0 ? size - 1 : 0];
+}
+
+/**
+ * Get the style of a superscript given a base in the current style.
+ */
+Style.prototype.sup = function() {
+    return styles[sup[this.id]];
+};
+
+/**
+ * Get the style of a subscript given a base in the current style.
+ */
+Style.prototype.sub = function() {
+    return styles[sub[this.id]];
+};
+
+/**
+ * Get the style of a fraction numerator given the fraction in the current
+ * style.
+ */
+Style.prototype.fracNum = function() {
+    return styles[fracNum[this.id]];
+};
+
+/**
+ * Get the style of a fraction denominator given the fraction in the current
+ * style.
+ */
+Style.prototype.fracDen = function() {
+    return styles[fracDen[this.id]];
+};
+
+/**
+ * Get the cramped version of a style (in particular, cramping a cramped style
+ * doesn't change the style).
+ */
+Style.prototype.cramp = function() {
+    return styles[cramp[this.id]];
+};
+
+/**
+ * HTML class name, like "displaystyle cramped"
+ */
+Style.prototype.cls = function() {
+    return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped");
+};
+
+/**
+ * HTML Reset class name, like "reset-textstyle"
+ */
+Style.prototype.reset = function() {
+    return resetNames[this.size];
+};
+
+/**
+ * Return if this style is tightly spaced (scriptstyle/scriptscriptstyle)
+ */
+Style.prototype.isTight = function() {
+    return this.size >= 2;
+};
+
+// IDs of the different styles
+var D = 0;
+var Dc = 1;
+var T = 2;
+var Tc = 3;
+var S = 4;
+var Sc = 5;
+var SS = 6;
+var SSc = 7;
+
+// String names for the different sizes
+var sizeNames = [
+    "displaystyle textstyle",
+    "textstyle",
+    "scriptstyle",
+    "scriptscriptstyle"
+];
+
+// Reset names for the different sizes
+var resetNames = [
+    "reset-textstyle",
+    "reset-textstyle",
+    "reset-scriptstyle",
+    "reset-scriptscriptstyle"
+];
+
+// Instances of the different styles
+var styles = [
+    new Style(D, 0, 1.0, false),
+    new Style(Dc, 0, 1.0, true),
+    new Style(T, 1, 1.0, false),
+    new Style(Tc, 1, 1.0, true),
+    new Style(S, 2, 0.7, false),
+    new Style(Sc, 2, 0.7, true),
+    new Style(SS, 3, 0.5, false),
+    new Style(SSc, 3, 0.5, true)
+];
+
+// Lookup tables for switching from one style to another
+var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
+var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
+var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
+var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
+var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
+
+// We only export some of the styles. Also, we don't export the `Style` class so
+// no more styles can be generated.
+module.exports = {
+    DISPLAY: styles[D],
+    TEXT: styles[T],
+    SCRIPT: styles[S],
+    SCRIPTSCRIPT: styles[SS]
+};
+
+},{"./fontMetrics.js":17}],10:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This module contains general functions that can be used for building
+ * different kinds of domTree nodes in a consistent manner.
+ */
+
+var domTree = require("./domTree");
+var fontMetrics = require("./fontMetrics");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var greekCapitals = [
+    "\\Gamma",
+    "\\Delta",
+    "\\Theta",
+    "\\Lambda",
+    "\\Xi",
+    "\\Pi",
+    "\\Sigma",
+    "\\Upsilon",
+    "\\Phi",
+    "\\Psi",
+    "\\Omega"
+];
+
+// The following have to be loaded from Main-Italic font, using class mainit
+var mainitLetters = [
+    "\u0131",   // dotless i, \imath
+    "\u0237",   // dotless j, \jmath
+    "\u00a3"   // \pounds
+];
+
+/**
+ * Makes a symbolNode after translation via the list of symbols in symbols.js.
+ * Correctly pulls out metrics for the character, and optionally takes a list of
+ * classes to be attached to the node.
+ *
+ * TODO: make argument order closer to makeSpan
+ * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
+ * should if present come first in `classes`.
+ */
+var makeSymbol = function(value, fontFamily, mode, options, classes) {
+    // Replace the value with its replaced value from symbol.js
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var metrics = fontMetrics.getCharacterMetrics(value, fontFamily);
+
+    var symbolNode;
+    if (metrics) {
+        var italic = metrics.italic;
+        if (mode === "text") {
+            italic = 0;
+        }
+        symbolNode = new domTree.symbolNode(
+            value, metrics.height, metrics.depth, italic, metrics.skew,
+            classes);
+    } else {
+        // TODO(emily): Figure out a good way to only print this in development
+        typeof console !== "undefined" && console.warn(
+            "No character metrics for '" + value + "' in style '" +
+                fontFamily + "'");
+        symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
+    }
+
+    if (options) {
+        if (options.style.isTight()) {
+            symbolNode.classes.push("mtight");
+        }
+        if (options.getColor()) {
+            symbolNode.style.color = options.getColor();
+        }
+    }
+
+    return symbolNode;
+};
+
+/**
+ * Makes a symbol in Main-Regular or AMS-Regular.
+ * Used for rel, bin, open, close, inner, and punct.
+ */
+var mathsym = function(value, mode, options, classes) {
+    // Decide what font to render the symbol in by its entry in the symbols
+    // table.
+    // Have a special case for when the value = \ because the \ is used as a
+    // textord in unsupported command errors but cannot be parsed as a regular
+    // text ordinal and is therefore not present as a symbol in the symbols
+    // table for text
+    if (value === "\\" || symbols[mode][value].font === "main") {
+        return makeSymbol(value, "Main-Regular", mode, options, classes);
+    } else {
+        return makeSymbol(
+            value, "AMS-Regular", mode, options, classes.concat(["amsrm"]));
+    }
+};
+
+/**
+ * Makes a symbol in the default font for mathords and textords.
+ */
+var mathDefault = function(value, mode, options, classes, type) {
+    if (type === "mathord") {
+        return mathit(value, mode, options, classes);
+    } else if (type === "textord") {
+        return makeSymbol(
+            value, "Main-Regular", mode, options, classes.concat(["mathrm"]));
+    } else {
+        throw new Error("unexpected type: " + type + " in mathDefault");
+    }
+};
+
+/**
+ * Makes a symbol in the italic math font.
+ */
+var mathit = function(value, mode, options, classes) {
+    if (/[0-9]/.test(value.charAt(0)) ||
+            // glyphs for \imath and \jmath do not exist in Math-Italic so we
+            // need to use Main-Italic instead
+            utils.contains(mainitLetters, value) ||
+            utils.contains(greekCapitals, value)) {
+        return makeSymbol(
+            value, "Main-Italic", mode, options, classes.concat(["mainit"]));
+    } else {
+        return makeSymbol(
+            value, "Math-Italic", mode, options, classes.concat(["mathit"]));
+    }
+};
+
+/**
+ * Makes either a mathord or textord in the correct font and color.
+ */
+var makeOrd = function(group, options, type) {
+    var mode = group.mode;
+    var value = group.value;
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var classes = ["mord"];
+
+    var font = options.font;
+    if (font) {
+        if (font === "mathit" || utils.contains(mainitLetters, value)) {
+            return mathit(value, mode, options, classes);
+        } else {
+            var fontName = fontMap[font].fontName;
+            if (fontMetrics.getCharacterMetrics(value, fontName)) {
+                return makeSymbol(
+                    value, fontName, mode, options, classes.concat([font]));
+            } else {
+                return mathDefault(value, mode, options, classes, type);
+            }
+        }
+    } else {
+        return mathDefault(value, mode, options, classes, type);
+    }
+};
+
+/**
+ * Calculate the height, depth, and maxFontSize of an element based on its
+ * children.
+ */
+var sizeElementFromChildren = function(elem) {
+    var height = 0;
+    var depth = 0;
+    var maxFontSize = 0;
+
+    if (elem.children) {
+        for (var i = 0; i < elem.children.length; i++) {
+            if (elem.children[i].height > height) {
+                height = elem.children[i].height;
+            }
+            if (elem.children[i].depth > depth) {
+                depth = elem.children[i].depth;
+            }
+            if (elem.children[i].maxFontSize > maxFontSize) {
+                maxFontSize = elem.children[i].maxFontSize;
+            }
+        }
+    }
+
+    elem.height = height;
+    elem.depth = depth;
+    elem.maxFontSize = maxFontSize;
+};
+
+/**
+ * Makes a span with the given list of classes, list of children, and options.
+ *
+ * TODO: Ensure that `options` is always provided (currently some call sites
+ * don't pass it).
+ * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
+ * should if present come first in `classes`.
+ */
+var makeSpan = function(classes, children, options) {
+    var span = new domTree.span(classes, children, options);
+
+    sizeElementFromChildren(span);
+
+    return span;
+};
+
+/**
+ * Prepends the given children to the given span, updating height, depth, and
+ * maxFontSize.
+ */
+var prependChildren = function(span, children) {
+    span.children = children.concat(span.children);
+
+    sizeElementFromChildren(span);
+};
+
+/**
+ * Makes a document fragment with the given list of children.
+ */
+var makeFragment = function(children) {
+    var fragment = new domTree.documentFragment(children);
+
+    sizeElementFromChildren(fragment);
+
+    return fragment;
+};
+
+/**
+ * Makes an element placed in each of the vlist elements to ensure that each
+ * element has the same max font size. To do this, we create a zero-width space
+ * with the correct font size.
+ */
+var makeFontSizer = function(options, fontSize) {
+    var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
+    fontSizeInner.style.fontSize =
+        (fontSize / options.style.sizeMultiplier) + "em";
+
+    var fontSizer = makeSpan(
+        ["fontsize-ensurer", "reset-" + options.size, "size5"],
+        [fontSizeInner]);
+
+    return fontSizer;
+};
+
+/**
+ * Makes a vertical list by stacking elements and kerns on top of each other.
+ * Allows for many different ways of specifying the positioning method.
+ *
+ * Arguments:
+ *  - children: A list of child or kern nodes to be stacked on top of each other
+ *              (i.e. the first element will be at the bottom, and the last at
+ *              the top). Element nodes are specified as
+ *                {type: "elem", elem: node}
+ *              while kern nodes are specified as
+ *                {type: "kern", size: size}
+ *  - positionType: The method by which the vlist should be positioned. Valid
+ *                  values are:
+ *                   - "individualShift": The children list only contains elem
+ *                                        nodes, and each node contains an extra
+ *                                        "shift" value of how much it should be
+ *                                        shifted (note that shifting is always
+ *                                        moving downwards). positionData is
+ *                                        ignored.
+ *                   - "top": The positionData specifies the topmost point of
+ *                            the vlist (note this is expected to be a height,
+ *                            so positive values move up)
+ *                   - "bottom": The positionData specifies the bottommost point
+ *                               of the vlist (note this is expected to be a
+ *                               depth, so positive values move down
+ *                   - "shift": The vlist will be positioned such that its
+ *                              baseline is positionData away from the baseline
+ *                              of the first child. Positive values move
+ *                              downwards.
+ *                   - "firstBaseline": The vlist will be positioned such that
+ *                                      its baseline is aligned with the
+ *                                      baseline of the first child.
+ *                                      positionData is ignored. (this is
+ *                                      equivalent to "shift" with
+ *                                      positionData=0)
+ *  - positionData: Data used in different ways depending on positionType
+ *  - options: An Options object
+ *
+ */
+var makeVList = function(children, positionType, positionData, options) {
+    var depth;
+    var currPos;
+    var i;
+    if (positionType === "individualShift") {
+        var oldChildren = children;
+        children = [oldChildren[0]];
+
+        // Add in kerns to the list of children to get each element to be
+        // shifted to the correct specified shift
+        depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
+        currPos = depth;
+        for (i = 1; i < oldChildren.length; i++) {
+            var diff = -oldChildren[i].shift - currPos -
+                oldChildren[i].elem.depth;
+            var size = diff -
+                (oldChildren[i - 1].elem.height +
+                 oldChildren[i - 1].elem.depth);
+
+            currPos = currPos + diff;
+
+            children.push({type: "kern", size: size});
+            children.push(oldChildren[i]);
+        }
+    } else if (positionType === "top") {
+        // We always start at the bottom, so calculate the bottom by adding up
+        // all the sizes
+        var bottom = positionData;
+        for (i = 0; i < children.length; i++) {
+            if (children[i].type === "kern") {
+                bottom -= children[i].size;
+            } else {
+                bottom -= children[i].elem.height + children[i].elem.depth;
+            }
+        }
+        depth = bottom;
+    } else if (positionType === "bottom") {
+        depth = -positionData;
+    } else if (positionType === "shift") {
+        depth = -children[0].elem.depth - positionData;
+    } else if (positionType === "firstBaseline") {
+        depth = -children[0].elem.depth;
+    } else {
+        depth = 0;
+    }
+
+    // Make the fontSizer
+    var maxFontSize = 0;
+    for (i = 0; i < children.length; i++) {
+        if (children[i].type === "elem") {
+            maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
+        }
+    }
+    var fontSizer = makeFontSizer(options, maxFontSize);
+
+    // Create a new list of actual children at the correct offsets
+    var realChildren = [];
+    currPos = depth;
+    for (i = 0; i < children.length; i++) {
+        if (children[i].type === "kern") {
+            currPos += children[i].size;
+        } else {
+            var child = children[i].elem;
+
+            var shift = -child.depth - currPos;
+            currPos += child.height + child.depth;
+
+            var childWrap = makeSpan([], [fontSizer, child]);
+            childWrap.height -= shift;
+            childWrap.depth += shift;
+            childWrap.style.top = shift + "em";
+
+            realChildren.push(childWrap);
+        }
+    }
+
+    // Add in an element at the end with no offset to fix the calculation of
+    // baselines in some browsers (namely IE, sometimes safari)
+    var baselineFix = makeSpan(
+        ["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]);
+    realChildren.push(baselineFix);
+
+    var vlist = makeSpan(["vlist"], realChildren);
+    // Fix the final height and depth, in case there were kerns at the ends
+    // since the makeSpan calculation won't take that in to account.
+    vlist.height = Math.max(currPos, vlist.height);
+    vlist.depth = Math.max(-depth, vlist.depth);
+    return vlist;
+};
+
+// A table of size -> font size for the different sizing functions
+var sizingMultiplier = {
+    size1: 0.5,
+    size2: 0.7,
+    size3: 0.8,
+    size4: 0.9,
+    size5: 1.0,
+    size6: 1.2,
+    size7: 1.44,
+    size8: 1.73,
+    size9: 2.07,
+    size10: 2.49
+};
+
+// A map of spacing functions to their attributes, like size and corresponding
+// CSS class
+var spacingFunctions = {
+    "\\qquad": {
+        size: "2em",
+        className: "qquad"
+    },
+    "\\quad": {
+        size: "1em",
+        className: "quad"
+    },
+    "\\enspace": {
+        size: "0.5em",
+        className: "enspace"
+    },
+    "\\;": {
+        size: "0.277778em",
+        className: "thickspace"
+    },
+    "\\:": {
+        size: "0.22222em",
+        className: "mediumspace"
+    },
+    "\\,": {
+        size: "0.16667em",
+        className: "thinspace"
+    },
+    "\\!": {
+        size: "-0.16667em",
+        className: "negativethinspace"
+    }
+};
+
+/**
+ * Maps TeX font commands to objects containing:
+ * - variant: string used for "mathvariant" attribute in buildMathML.js
+ * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
+ */
+// A map between tex font commands an MathML mathvariant attribute values
+var fontMap = {
+    // styles
+    "mathbf": {
+        variant: "bold",
+        fontName: "Main-Bold"
+    },
+    "mathrm": {
+        variant: "normal",
+        fontName: "Main-Regular"
+    },
+    "textit": {
+        variant: "italic",
+        fontName: "Main-Italic"
+    },
+
+    // "mathit" is missing because it requires the use of two fonts: Main-Italic
+    // and Math-Italic.  This is handled by a special case in makeOrd which ends
+    // up calling mathit.
+
+    // families
+    "mathbb": {
+        variant: "double-struck",
+        fontName: "AMS-Regular"
+    },
+    "mathcal": {
+        variant: "script",
+        fontName: "Caligraphic-Regular"
+    },
+    "mathfrak": {
+        variant: "fraktur",
+        fontName: "Fraktur-Regular"
+    },
+    "mathscr": {
+        variant: "script",
+        fontName: "Script-Regular"
+    },
+    "mathsf": {
+        variant: "sans-serif",
+        fontName: "SansSerif-Regular"
+    },
+    "mathtt": {
+        variant: "monospace",
+        fontName: "Typewriter-Regular"
+    }
+};
+
+module.exports = {
+    fontMap: fontMap,
+    makeSymbol: makeSymbol,
+    mathsym: mathsym,
+    makeSpan: makeSpan,
+    makeFragment: makeFragment,
+    makeVList: makeVList,
+    makeOrd: makeOrd,
+    prependChildren: prependChildren,
+    sizingMultiplier: sizingMultiplier,
+    spacingFunctions: spacingFunctions
+};
+
+},{"./domTree":15,"./fontMetrics":17,"./symbols":23,"./utils":25}],11:[function(require,module,exports){
+/* eslint no-console:0 */
+/**
+ * This file does the main work of building a domTree structure from a parse
+ * tree. The entry point is the `buildHTML` function, which takes a parse tree.
+ * Then, the buildExpression, buildGroup, and various groupTypes functions are
+ * called, to produce a final HTML tree.
+ */
+
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var buildCommon = require("./buildCommon");
+var delimiter = require("./delimiter");
+var domTree = require("./domTree");
+var fontMetrics = require("./fontMetrics");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+
+var isSpace = function(node) {
+    return node instanceof domTree.span && node.classes[0] === "mspace";
+};
+
+// Binary atoms (first class `mbin`) change into ordinary atoms (`mord`)
+// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6,
+// and the text before Rule 19.
+
+var isBin = function(node) {
+    return node && node.classes[0] === "mbin";
+};
+
+var isBinLeftCanceller = function(node, isRealGroup) {
+    // TODO: This code assumes that a node's math class is the first element
+    // of its `classes` array. A later cleanup should ensure this, for
+    // instance by changing the signature of `makeSpan`.
+    if (node) {
+        return utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"],
+                              node.classes[0]);
+    } else {
+        return isRealGroup;
+    }
+};
+
+var isBinRightCanceller = function(node, isRealGroup) {
+    if (node) {
+        return utils.contains(["mrel", "mclose", "mpunct"], node.classes[0]);
+    } else {
+        return isRealGroup;
+    }
+};
+
+/**
+ * Take a list of nodes, build them in order, and return a list of the built
+ * nodes. documentFragments are flattened into their contents, so the
+ * returned list contains no fragments. `isRealGroup` is true if `expression`
+ * is a real group (no atoms will be added on either side), as opposed to
+ * a partial group (e.g. one created by \color).
+ */
+var buildExpression = function(expression, options, isRealGroup) {
+    // Parse expressions into `groups`.
+    var groups = [];
+    for (var i = 0; i < expression.length; i++) {
+        var group = expression[i];
+        var output = buildGroup(group, options);
+        if (output instanceof domTree.documentFragment) {
+            Array.prototype.push.apply(groups, output.children);
+        } else {
+            groups.push(output);
+        }
+    }
+    // At this point `groups` consists entirely of `symbolNode`s and `span`s.
+
+    // Explicit spaces (e.g., \;, \,) should be ignored with respect to atom
+    // spacing (e.g., "add thick space between mord and mrel"). Since CSS
+    // adjacency rules implement atom spacing, spaces should be invisible to
+    // CSS. So we splice them out of `groups` and into the atoms themselves.
+    var spaces = null;
+    for (i = 0; i < groups.length; i++) {
+        if (isSpace(groups[i])) {
+            spaces = spaces || [];
+            spaces.push(groups[i]);
+            groups.splice(i, 1);
+            i--;
+        } else if (spaces) {
+            if (groups[i] instanceof domTree.symbolNode) {
+                groups[i] = makeSpan([].concat(groups[i].classes), [groups[i]]);
+            }
+            buildCommon.prependChildren(groups[i], spaces);
+            spaces = null;
+        }
+    }
+    if (spaces) {
+        Array.prototype.push.apply(groups, spaces);
+    }
+
+    // Binary operators change to ordinary symbols in some contexts.
+    for (i = 0; i < groups.length; i++) {
+        if (isBin(groups[i])
+            && (isBinLeftCanceller(groups[i - 1], isRealGroup)
+                || isBinRightCanceller(groups[i + 1], isRealGroup))) {
+            groups[i].classes[0] = "mord";
+        }
+    }
+
+    return groups;
+};
+
+// Return math atom class (mclass) of a domTree.
+var getTypeOfDomTree = function(node) {
+    if (node instanceof domTree.documentFragment) {
+        if (node.children.length) {
+            return getTypeOfDomTree(
+                node.children[node.children.length - 1]);
+        }
+    } else {
+        if (utils.contains(["mord", "mop", "mbin", "mrel", "mopen", "mclose",
+            "mpunct", "minner"], node.classes[0])) {
+            return node.classes[0];
+        }
+    }
+    return null;
+};
+
+/**
+ * Sometimes, groups perform special rules when they have superscripts or
+ * subscripts attached to them. This function lets the `supsub` group know that
+ * its inner element should handle the superscripts and subscripts instead of
+ * handling them itself.
+ */
+var shouldHandleSupSub = function(group, options) {
+    if (!group) {
+        return false;
+    } else if (group.type === "op") {
+        // Operators handle supsubs differently when they have limits
+        // (e.g. `\displaystyle\sum_2^3`)
+        return group.value.limits &&
+            (options.style.size === Style.DISPLAY.size ||
+            group.value.alwaysHandleSupSub);
+    } else if (group.type === "accent") {
+        return isCharacterBox(group.value.base);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Sometimes we want to pull out the innermost element of a group. In most
+ * cases, this will just be the group itself, but when ordgroups and colors have
+ * a single element, we want to pull that out.
+ */
+var getBaseElem = function(group) {
+    if (!group) {
+        return false;
+    } else if (group.type === "ordgroup") {
+        if (group.value.length === 1) {
+            return getBaseElem(group.value[0]);
+        } else {
+            return group;
+        }
+    } else if (group.type === "color") {
+        if (group.value.value.length === 1) {
+            return getBaseElem(group.value.value[0]);
+        } else {
+            return group;
+        }
+    } else if (group.type === "font") {
+        return getBaseElem(group.value.body);
+    } else {
+        return group;
+    }
+};
+
+/**
+ * TeXbook algorithms often reference "character boxes", which are simply groups
+ * with a single character in them. To decide if something is a character box,
+ * we find its innermost group, and see if it is a single character.
+ */
+var isCharacterBox = function(group) {
+    var baseElem = getBaseElem(group);
+
+    // These are all they types of groups which hold single characters
+    return baseElem.type === "mathord" ||
+        baseElem.type === "textord" ||
+        baseElem.type === "bin" ||
+        baseElem.type === "rel" ||
+        baseElem.type === "inner" ||
+        baseElem.type === "open" ||
+        baseElem.type === "close" ||
+        baseElem.type === "punct";
+};
+
+var makeNullDelimiter = function(options, classes) {
+    return makeSpan(classes.concat([
+        "sizing", "reset-" + options.size, "size5",
+        options.style.reset(), Style.TEXT.cls(),
+        "nulldelimiter"]));
+};
+
+/**
+ * This is a map of group types to the function used to handle that type.
+ * Simpler types come at the beginning, while complicated types come afterwards.
+ */
+var groupTypes = {};
+
+groupTypes.mathord = function(group, options) {
+    return buildCommon.makeOrd(group, options, "mathord");
+};
+
+groupTypes.textord = function(group, options) {
+    return buildCommon.makeOrd(group, options, "textord");
+};
+
+groupTypes.bin = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mbin"]);
+};
+
+groupTypes.rel = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mrel"]);
+};
+
+groupTypes.open = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mopen"]);
+};
+
+groupTypes.close = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mclose"]);
+};
+
+groupTypes.inner = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["minner"]);
+};
+
+groupTypes.punct = function(group, options) {
+    return buildCommon.mathsym(
+        group.value, group.mode, options, ["mpunct"]);
+};
+
+groupTypes.ordgroup = function(group, options) {
+    return makeSpan(
+        ["mord", options.style.cls()],
+        buildExpression(group.value, options.reset(), true),
+        options
+    );
+};
+
+groupTypes.text = function(group, options) {
+    var newOptions = options.withFont(group.value.style);
+    var inner = buildExpression(group.value.body, newOptions, true);
+    for (var i = 0; i < inner.length - 1; i++) {
+        if (inner[i].tryCombine(inner[i + 1])) {
+            inner.splice(i + 1, 1);
+            i--;
+        }
+    }
+    return makeSpan(["mord", "text", newOptions.style.cls()],
+        inner, newOptions);
+};
+
+groupTypes.color = function(group, options) {
+    var elements = buildExpression(
+        group.value.value,
+        options.withColor(group.value.color),
+        false
+    );
+
+    // \color isn't supposed to affect the type of the elements it contains.
+    // To accomplish this, we wrap the results in a fragment, so the inner
+    // elements will be able to directly interact with their neighbors. For
+    // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
+    return new buildCommon.makeFragment(elements);
+};
+
+groupTypes.supsub = function(group, options) {
+    // Superscript and subscripts are handled in the TeXbook on page
+    // 445-446, rules 18(a-f).
+
+    // Here is where we defer to the inner group if it should handle
+    // superscripts and subscripts itself.
+    if (shouldHandleSupSub(group.value.base, options)) {
+        return groupTypes[group.value.base.type](group, options);
+    }
+
+    var base = buildGroup(group.value.base, options.reset());
+    var supmid;
+    var submid;
+    var sup;
+    var sub;
+
+    var style = options.style;
+    var newOptions;
+
+    if (group.value.sup) {
+        newOptions = options.withStyle(style.sup());
+        sup = buildGroup(group.value.sup, newOptions);
+        supmid = makeSpan([style.reset(), style.sup().cls()],
+            [sup], newOptions);
+    }
+
+    if (group.value.sub) {
+        newOptions = options.withStyle(style.sub());
+        sub = buildGroup(group.value.sub, newOptions);
+        submid = makeSpan([style.reset(), style.sub().cls()],
+            [sub], newOptions);
+    }
+
+    // Rule 18a
+    var supShift;
+    var subShift;
+    if (isCharacterBox(group.value.base)) {
+        supShift = 0;
+        subShift = 0;
+    } else {
+        supShift = base.height - style.metrics.supDrop;
+        subShift = base.depth + style.metrics.subDrop;
+    }
+
+    // Rule 18c
+    var minSupShift;
+    if (style === Style.DISPLAY) {
+        minSupShift = style.metrics.sup1;
+    } else if (style.cramped) {
+        minSupShift = style.metrics.sup3;
+    } else {
+        minSupShift = style.metrics.sup2;
+    }
+
+    // scriptspace is a font-size-independent size, so scale it
+    // appropriately
+    var multiplier = Style.TEXT.sizeMultiplier *
+            style.sizeMultiplier;
+    var scriptspace =
+        (0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
+
+    var supsub;
+    if (!group.value.sup) {
+        // Rule 18b
+        subShift = Math.max(
+            subShift, style.metrics.sub1,
+            sub.height - 0.8 * style.metrics.xHeight);
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: submid}
+        ], "shift", subShift, options);
+
+        supsub.children[0].style.marginRight = scriptspace;
+
+        // Subscripts shouldn't be shifted by the base's italic correction.
+        // Account for that by shifting the subscript back the appropriate
+        // amount. Note we only do this when the base is a single symbol.
+        if (base instanceof domTree.symbolNode) {
+            supsub.children[0].style.marginLeft = -base.italic + "em";
+        }
+    } else if (!group.value.sub) {
+        // Rule 18c, d
+        supShift = Math.max(supShift, minSupShift,
+            sup.depth + 0.25 * style.metrics.xHeight);
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: supmid}
+        ], "shift", -supShift, options);
+
+        supsub.children[0].style.marginRight = scriptspace;
+    } else {
+        supShift = Math.max(
+            supShift, minSupShift, sup.depth + 0.25 * style.metrics.xHeight);
+        subShift = Math.max(subShift, style.metrics.sub2);
+
+        var ruleWidth = fontMetrics.metrics.defaultRuleThickness;
+
+        // Rule 18e
+        if ((supShift - sup.depth) - (sub.height - subShift) <
+                4 * ruleWidth) {
+            subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height;
+            var psi = 0.8 * style.metrics.xHeight - (supShift - sup.depth);
+            if (psi > 0) {
+                supShift += psi;
+                subShift -= psi;
+            }
+        }
+
+        supsub = buildCommon.makeVList([
+            {type: "elem", elem: submid, shift: subShift},
+            {type: "elem", elem: supmid, shift: -supShift}
+        ], "individualShift", null, options);
+
+        // See comment above about subscripts not being shifted
+        if (base instanceof domTree.symbolNode) {
+            supsub.children[0].style.marginLeft = -base.italic + "em";
+        }
+
+        supsub.children[0].style.marginRight = scriptspace;
+        supsub.children[1].style.marginRight = scriptspace;
+    }
+
+    // We ensure to wrap the supsub vlist in a span.msupsub to reset text-align
+    var mclass = getTypeOfDomTree(base) || "mord";
+    return makeSpan([mclass],
+        [base, makeSpan(["msupsub"], [supsub])],
+        options);
+};
+
+groupTypes.genfrac = function(group, options) {
+    // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
+    // Figure out what style this fraction should be in based on the
+    // function used
+    var style = options.style;
+    if (group.value.size === "display") {
+        style = Style.DISPLAY;
+    } else if (group.value.size === "text") {
+        style = Style.TEXT;
+    }
+
+    var nstyle = style.fracNum();
+    var dstyle = style.fracDen();
+    var newOptions;
+
+    newOptions = options.withStyle(nstyle);
+    var numer = buildGroup(group.value.numer, newOptions);
+    var numerreset = makeSpan([style.reset(), nstyle.cls()],
+        [numer], newOptions);
+
+    newOptions = options.withStyle(dstyle);
+    var denom = buildGroup(group.value.denom, newOptions);
+    var denomreset = makeSpan([style.reset(), dstyle.cls()],
+        [denom], newOptions);
+
+    var ruleWidth;
+    if (group.value.hasBarLine) {
+        ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+            options.style.sizeMultiplier;
+    } else {
+        ruleWidth = 0;
+    }
+
+    // Rule 15b
+    var numShift;
+    var clearance;
+    var denomShift;
+    if (style.size === Style.DISPLAY.size) {
+        numShift = style.metrics.num1;
+        if (ruleWidth > 0) {
+            clearance = 3 * ruleWidth;
+        } else {
+            clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
+        }
+        denomShift = style.metrics.denom1;
+    } else {
+        if (ruleWidth > 0) {
+            numShift = style.metrics.num2;
+            clearance = ruleWidth;
+        } else {
+            numShift = style.metrics.num3;
+            clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
+        }
+        denomShift = style.metrics.denom2;
+    }
+
+    var frac;
+    if (ruleWidth === 0) {
+        // Rule 15c
+        var candidateClearance =
+            (numShift - numer.depth) - (denom.height - denomShift);
+        if (candidateClearance < clearance) {
+            numShift += 0.5 * (clearance - candidateClearance);
+            denomShift += 0.5 * (clearance - candidateClearance);
+        }
+
+        frac = buildCommon.makeVList([
+            {type: "elem", elem: denomreset, shift: denomShift},
+            {type: "elem", elem: numerreset, shift: -numShift}
+        ], "individualShift", null, options);
+    } else {
+        // Rule 15d
+        var axisHeight = style.metrics.axisHeight;
+
+        if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) <
+                clearance) {
+            numShift +=
+                clearance - ((numShift - numer.depth) -
+                             (axisHeight + 0.5 * ruleWidth));
+        }
+
+        if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) <
+                clearance) {
+            denomShift +=
+                clearance - ((axisHeight - 0.5 * ruleWidth) -
+                             (denom.height - denomShift));
+        }
+
+        var mid = makeSpan(
+            [options.style.reset(), Style.TEXT.cls(), "frac-line"]);
+        // Manually set the height of the line because its height is
+        // created in CSS
+        mid.height = ruleWidth;
+
+        var midShift = -(axisHeight - 0.5 * ruleWidth);
+
+        frac = buildCommon.makeVList([
+            {type: "elem", elem: denomreset, shift: denomShift},
+            {type: "elem", elem: mid,        shift: midShift},
+            {type: "elem", elem: numerreset, shift: -numShift}
+        ], "individualShift", null, options);
+    }
+
+    // Since we manually change the style sometimes (with \dfrac or \tfrac),
+    // account for the possible size change here.
+    frac.height *= style.sizeMultiplier / options.style.sizeMultiplier;
+    frac.depth *= style.sizeMultiplier / options.style.sizeMultiplier;
+
+    // Rule 15e
+    var delimSize;
+    if (style.size === Style.DISPLAY.size) {
+        delimSize = style.metrics.delim1;
+    } else {
+        delimSize = style.metrics.delim2;
+    }
+
+    var leftDelim;
+    var rightDelim;
+    if (group.value.leftDelim == null) {
+        leftDelim = makeNullDelimiter(options, ["mopen"]);
+    } else {
+        leftDelim = delimiter.customSizedDelim(
+            group.value.leftDelim, delimSize, true,
+            options.withStyle(style), group.mode, ["mopen"]);
+    }
+    if (group.value.rightDelim == null) {
+        rightDelim = makeNullDelimiter(options, ["mclose"]);
+    } else {
+        rightDelim = delimiter.customSizedDelim(
+            group.value.rightDelim, delimSize, true,
+            options.withStyle(style), group.mode, ["mclose"]);
+    }
+
+    return makeSpan(
+        ["mord", options.style.reset(), style.cls()],
+        [leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
+        options);
+};
+
+var calculateSize = function(sizeValue, style) {
+    var x = sizeValue.number;
+    if (sizeValue.unit === "ex") {
+        x *= style.metrics.emPerEx;
+    } else if (sizeValue.unit === "mu") {
+        x /= 18;
+    }
+    return x;
+};
+
+groupTypes.array = function(group, options) {
+    var r;
+    var c;
+    var nr = group.value.body.length;
+    var nc = 0;
+    var body = new Array(nr);
+
+    var style = options.style;
+
+    // Horizontal spacing
+    var pt = 1 / fontMetrics.metrics.ptPerEm;
+    var arraycolsep = 5 * pt; // \arraycolsep in article.cls
+
+    // Vertical spacing
+    var baselineskip = 12 * pt; // see size10.clo
+    // Default \arraystretch from lttab.dtx
+    // TODO(gagern): may get redefined once we have user-defined macros
+    var arraystretch = utils.deflt(group.value.arraystretch, 1);
+    var arrayskip = arraystretch * baselineskip;
+    var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
+    var arstrutDepth = 0.3 * arrayskip;  // \@arstrutbox in lttab.dtx
+
+    var totalHeight = 0;
+    for (r = 0; r < group.value.body.length; ++r) {
+        var inrow = group.value.body[r];
+        var height = arstrutHeight; // \@array adds an \@arstrut
+        var depth = arstrutDepth;   // to each tow (via the template)
+
+        if (nc < inrow.length) {
+            nc = inrow.length;
+        }
+
+        var outrow = new Array(inrow.length);
+        for (c = 0; c < inrow.length; ++c) {
+            var elt = buildGroup(inrow[c], options);
+            if (depth < elt.depth) {
+                depth = elt.depth;
+            }
+            if (height < elt.height) {
+                height = elt.height;
+            }
+            outrow[c] = elt;
+        }
+
+        var gap = 0;
+        if (group.value.rowGaps[r]) {
+            gap = calculateSize(group.value.rowGaps[r].value, style);
+            if (gap > 0) { // \@argarraycr
+                gap += arstrutDepth;
+                if (depth < gap) {
+                    depth = gap; // \@xargarraycr
+                }
+                gap = 0;
+            }
+        }
+
+        outrow.height = height;
+        outrow.depth = depth;
+        totalHeight += height;
+        outrow.pos = totalHeight;
+        totalHeight += depth + gap; // \@yargarraycr
+        body[r] = outrow;
+    }
+
+    var offset = totalHeight / 2 + style.metrics.axisHeight;
+    var colDescriptions = group.value.cols || [];
+    var cols = [];
+    var colSep;
+    var colDescrNum;
+    for (c = 0, colDescrNum = 0;
+         // Continue while either there are more columns or more column
+         // descriptions, so trailing separators don't get lost.
+         c < nc || colDescrNum < colDescriptions.length;
+         ++c, ++colDescrNum) {
+
+        var colDescr = colDescriptions[colDescrNum] || {};
+
+        var firstSeparator = true;
+        while (colDescr.type === "separator") {
+            // If there is more than one separator in a row, add a space
+            // between them.
+            if (!firstSeparator) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width =
+                    fontMetrics.metrics.doubleRuleSep + "em";
+                cols.push(colSep);
+            }
+
+            if (colDescr.separator === "|") {
+                var separator = makeSpan(
+                    ["vertical-separator"],
+                    []);
+                separator.style.height = totalHeight + "em";
+                separator.style.verticalAlign =
+                    -(totalHeight - offset) + "em";
+
+                cols.push(separator);
+            } else {
+                throw new ParseError(
+                    "Invalid separator type: " + colDescr.separator);
+            }
+
+            colDescrNum++;
+            colDescr = colDescriptions[colDescrNum] || {};
+            firstSeparator = false;
+        }
+
+        if (c >= nc) {
+            continue;
+        }
+
+        var sepwidth;
+        if (c > 0 || group.value.hskipBeforeAndAfter) {
+            sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
+            if (sepwidth !== 0) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width = sepwidth + "em";
+                cols.push(colSep);
+            }
+        }
+
+        var col = [];
+        for (r = 0; r < nr; ++r) {
+            var row = body[r];
+            var elem = row[c];
+            if (!elem) {
+                continue;
+            }
+            var shift = row.pos - offset;
+            elem.depth = row.depth;
+            elem.height = row.height;
+            col.push({type: "elem", elem: elem, shift: shift});
+        }
+
+        col = buildCommon.makeVList(col, "individualShift", null, options);
+        col = makeSpan(
+            ["col-align-" + (colDescr.align || "c")],
+            [col]);
+        cols.push(col);
+
+        if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
+            sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
+            if (sepwidth !== 0) {
+                colSep = makeSpan(["arraycolsep"], []);
+                colSep.style.width = sepwidth + "em";
+                cols.push(colSep);
+            }
+        }
+    }
+    body = makeSpan(["mtable"], cols);
+    return makeSpan(["mord"], [body], options);
+};
+
+groupTypes.spacing = function(group, options) {
+    if (group.value === "\\ " || group.value === "\\space" ||
+        group.value === " " || group.value === "~") {
+        // Spaces are generated by adding an actual space. Each of these
+        // things has an entry in the symbols table, so these will be turned
+        // into appropriate outputs.
+        if (group.mode === "text") {
+            return buildCommon.makeOrd(group, options, "textord");
+        } else {
+            return makeSpan(["mspace"],
+                [buildCommon.mathsym(group.value, group.mode, options)],
+                options);
+        }
+    } else {
+        // Other kinds of spaces are of arbitrary width. We use CSS to
+        // generate these.
+        return makeSpan(
+            ["mspace",
+                buildCommon.spacingFunctions[group.value].className],
+            [], options);
+    }
+};
+
+groupTypes.llap = function(group, options) {
+    var inner = makeSpan(
+        ["inner"], [buildGroup(group.value.body, options.reset())]);
+    var fix = makeSpan(["fix"], []);
+    return makeSpan(
+        ["mord", "llap", options.style.cls()], [inner, fix], options);
+};
+
+groupTypes.rlap = function(group, options) {
+    var inner = makeSpan(
+        ["inner"], [buildGroup(group.value.body, options.reset())]);
+    var fix = makeSpan(["fix"], []);
+    return makeSpan(
+        ["mord", "rlap", options.style.cls()], [inner, fix], options);
+};
+
+groupTypes.op = function(group, options) {
+    // Operators are handled in the TeXbook pg. 443-444, rule 13(a).
+    var supGroup;
+    var subGroup;
+    var hasLimits = false;
+    if (group.type === "supsub") {
+        // If we have limits, supsub will pass us its group to handle. Pull
+        // out the superscript and subscript and set the group to the op in
+        // its base.
+        supGroup = group.value.sup;
+        subGroup = group.value.sub;
+        group = group.value.base;
+        hasLimits = true;
+    }
+
+    var style = options.style;
+
+    // Most operators have a large successor symbol, but these don't.
+    var noSuccessor = [
+        "\\smallint"
+    ];
+
+    var large = false;
+    if (style.size === Style.DISPLAY.size &&
+        group.value.symbol &&
+        !utils.contains(noSuccessor, group.value.body)) {
+
+        // Most symbol operators get larger in displaystyle (rule 13)
+        large = true;
+    }
+
+    var base;
+    var baseShift = 0;
+    var slant = 0;
+    if (group.value.symbol) {
+        // If this is a symbol, create the symbol.
+        var fontName = large ? "Size2-Regular" : "Size1-Regular";
+        base = buildCommon.makeSymbol(
+            group.value.body, fontName, "math", options,
+            ["mop", "op-symbol", large ? "large-op" : "small-op"]);
+
+        // Shift the symbol so its center lies on the axis (rule 13). It
+        // appears that our fonts have the centers of the symbols already
+        // almost on the axis, so these numbers are very small. Note we
+        // don't actually apply this here, but instead it is used either in
+        // the vlist creation or separately when there are no limits.
+        baseShift = (base.height - base.depth) / 2 -
+            style.metrics.axisHeight * style.sizeMultiplier;
+
+        // The slant of the symbol is just its italic correction.
+        slant = base.italic;
+    } else if (group.value.value) {
+        // If this is a list, compose that list.
+        var inner = buildExpression(group.value.value, options, true);
+
+        base = makeSpan(["mop"], inner, options);
+    } else {
+        // Otherwise, this is a text operator. Build the text from the
+        // operator's name.
+        // TODO(emily): Add a space in the middle of some of these
+        // operators, like \limsup
+        var output = [];
+        for (var i = 1; i < group.value.body.length; i++) {
+            output.push(buildCommon.mathsym(group.value.body[i], group.mode));
+        }
+        base = makeSpan(["mop"], output, options);
+    }
+
+    if (hasLimits) {
+        // IE 8 clips \int if it is in a display: inline-block. We wrap it
+        // in a new span so it is an inline, and works.
+        base = makeSpan([], [base]);
+
+        var supmid;
+        var supKern;
+        var submid;
+        var subKern;
+        var newOptions;
+        // We manually have to handle the superscripts and subscripts. This,
+        // aside from the kern calculations, is copied from supsub.
+        if (supGroup) {
+            newOptions = options.withStyle(style.sup());
+            var sup = buildGroup(supGroup, newOptions);
+            supmid = makeSpan([style.reset(), style.sup().cls()],
+                [sup], newOptions);
+
+            supKern = Math.max(
+                fontMetrics.metrics.bigOpSpacing1,
+                fontMetrics.metrics.bigOpSpacing3 - sup.depth);
+        }
+
+        if (subGroup) {
+            newOptions = options.withStyle(style.sub());
+            var sub = buildGroup(subGroup, newOptions);
+            submid = makeSpan([style.reset(), style.sub().cls()],
+                [sub], newOptions);
+
+            subKern = Math.max(
+                fontMetrics.metrics.bigOpSpacing2,
+                fontMetrics.metrics.bigOpSpacing4 - sub.height);
+        }
+
+        // Build the final group as a vlist of the possible subscript, base,
+        // and possible superscript.
+        var finalGroup;
+        var top;
+        var bottom;
+        if (!supGroup) {
+            top = base.height - baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
+                {type: "elem", elem: submid},
+                {type: "kern", size: subKern},
+                {type: "elem", elem: base}
+            ], "top", top, options);
+
+            // Here, we shift the limits by the slant of the symbol. Note
+            // that we are supposed to shift the limits by 1/2 of the slant,
+            // but since we are centering the limits adding a full slant of
+            // margin will shift by 1/2 that.
+            finalGroup.children[0].style.marginLeft = -slant + "em";
+        } else if (!subGroup) {
+            bottom = base.depth + baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "elem", elem: base},
+                {type: "kern", size: supKern},
+                {type: "elem", elem: supmid},
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}
+            ], "bottom", bottom, options);
+
+            // See comment above about slants
+            finalGroup.children[1].style.marginLeft = slant + "em";
+        } else if (!supGroup && !subGroup) {
+            // This case probably shouldn't occur (this would mean the
+            // supsub was sending us a group with no superscript or
+            // subscript) but be safe.
+            return base;
+        } else {
+            bottom = fontMetrics.metrics.bigOpSpacing5 +
+                submid.height + submid.depth +
+                subKern +
+                base.depth + baseShift;
+
+            finalGroup = buildCommon.makeVList([
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
+                {type: "elem", elem: submid},
+                {type: "kern", size: subKern},
+                {type: "elem", elem: base},
+                {type: "kern", size: supKern},
+                {type: "elem", elem: supmid},
+                {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}
+            ], "bottom", bottom, options);
+
+            // See comment above about slants
+            finalGroup.children[0].style.marginLeft = -slant + "em";
+            finalGroup.children[2].style.marginLeft = slant + "em";
+        }
+
+        return makeSpan(["mop", "op-limits"], [finalGroup], options);
+    } else {
+        if (group.value.symbol) {
+            base.style.top = baseShift + "em";
+        }
+
+        return base;
+    }
+};
+
+groupTypes.mod = function(group, options) {
+    var inner = [];
+
+    if (group.value.modType === "bmod") {
+        // “\nonscript\mskip-\medmuskip\mkern5mu”
+        if (!options.style.isTight()) {
+            inner.push(makeSpan(
+                ["mspace", "negativemediumspace"], [], options));
+        }
+        inner.push(makeSpan(["mspace", "thickspace"], [], options));
+    } else if (options.style.size === Style.DISPLAY.size) {
+        inner.push(makeSpan(["mspace", "quad"], [], options));
+    } else if (group.value.modType === "mod") {
+        inner.push(makeSpan(["mspace", "twelvemuspace"], [], options));
+    } else {
+        inner.push(makeSpan(["mspace", "eightmuspace"], [], options));
+    }
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(buildCommon.mathsym("(", group.mode));
+    }
+
+    if (group.value.modType !== "pod") {
+        var modInner = [
+            buildCommon.mathsym("m", group.mode),
+            buildCommon.mathsym("o", group.mode),
+            buildCommon.mathsym("d", group.mode)];
+        if (group.value.modType === "bmod") {
+            inner.push(makeSpan(["mbin"], modInner, options));
+            // “\mkern5mu\nonscript\mskip-\medmuskip”
+            inner.push(makeSpan(["mspace", "thickspace"], [], options));
+            if (!options.style.isTight()) {
+                inner.push(makeSpan(
+                    ["mspace", "negativemediumspace"], [], options));
+            }
+        } else {
+            Array.prototype.push.apply(inner, modInner);
+            inner.push(makeSpan(["mspace", "sixmuspace"], [], options));
+        }
+    }
+
+    if (group.value.value) {
+        Array.prototype.push.apply(inner,
+            buildExpression(group.value.value, options, false));
+    }
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(buildCommon.mathsym(")", group.mode));
+    }
+
+    return buildCommon.makeFragment(inner);
+};
+
+groupTypes.katex = function(group, options) {
+    // The KaTeX logo. The offsets for the K and a were chosen to look
+    // good, but the offsets for the T, E, and X were taken from the
+    // definition of \TeX in TeX (see TeXbook pg. 356)
+    var k = makeSpan(
+        ["k"], [buildCommon.mathsym("K", group.mode)], options);
+    var a = makeSpan(
+        ["a"], [buildCommon.mathsym("A", group.mode)], options);
+
+    a.height = (a.height + 0.2) * 0.75;
+    a.depth = (a.height - 0.2) * 0.75;
+
+    var t = makeSpan(
+        ["t"], [buildCommon.mathsym("T", group.mode)], options);
+    var e = makeSpan(
+        ["e"], [buildCommon.mathsym("E", group.mode)], options);
+
+    e.height = (e.height - 0.2155);
+    e.depth = (e.depth + 0.2155);
+
+    var x = makeSpan(
+        ["x"], [buildCommon.mathsym("X", group.mode)], options);
+
+    return makeSpan(
+        ["mord", "katex-logo"], [k, a, t, e, x], options);
+};
+
+groupTypes.overline = function(group, options) {
+    // Overlines are handled in the TeXbook pg 443, Rule 9.
+    var style = options.style;
+
+    // Build the inner group in the cramped style.
+    var innerGroup = buildGroup(group.value.body,
+            options.withStyle(style.cramp()));
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    // Create the line above the body
+    var line = makeSpan(
+        [style.reset(), Style.TEXT.cls(), "overline-line"]);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    // Generate the vlist, with the appropriate kerns
+    var vlist = buildCommon.makeVList([
+        {type: "elem", elem: innerGroup},
+        {type: "kern", size: 3 * ruleWidth},
+        {type: "elem", elem: line},
+        {type: "kern", size: ruleWidth}
+    ], "firstBaseline", null, options);
+
+    return makeSpan(["mord", "overline"], [vlist], options);
+};
+
+groupTypes.underline = function(group, options) {
+    // Underlines are handled in the TeXbook pg 443, Rule 10.
+    var style = options.style;
+
+    // Build the inner group.
+    var innerGroup = buildGroup(group.value.body, options);
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    // Create the line above the body
+    var line = makeSpan([style.reset(), Style.TEXT.cls(), "underline-line"]);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    // Generate the vlist, with the appropriate kerns
+    var vlist = buildCommon.makeVList([
+        {type: "kern", size: ruleWidth},
+        {type: "elem", elem: line},
+        {type: "kern", size: 3 * ruleWidth},
+        {type: "elem", elem: innerGroup}
+    ], "top", innerGroup.height, options);
+
+    return makeSpan(["mord", "underline"], [vlist], options);
+};
+
+groupTypes.sqrt = function(group, options) {
+    // Square roots are handled in the TeXbook pg. 443, Rule 11.
+    var style = options.style;
+
+    // First, we do the same steps as in overline to build the inner group
+    // and line
+    var inner = buildGroup(group.value.body, options.withStyle(style.cramp()));
+
+    var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
+        style.sizeMultiplier;
+
+    var line = makeSpan(
+        [style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
+        options);
+    line.height = ruleWidth;
+    line.maxFontSize = 1.0;
+
+    var phi = ruleWidth;
+    if (style.id < Style.TEXT.id) {
+        phi = style.metrics.xHeight;
+    }
+
+    // Calculate the clearance between the body and line
+    var lineClearance = ruleWidth + phi / 4;
+
+    var innerHeight = (inner.height + inner.depth) * style.sizeMultiplier;
+    var minDelimiterHeight = innerHeight + lineClearance + ruleWidth;
+
+    // Create a \surd delimiter of the required minimum size
+    var delim = makeSpan(["sqrt-sign"], [
+        delimiter.customSizedDelim("\\surd", minDelimiterHeight,
+                                   false, options, group.mode)],
+                         options);
+
+    var delimDepth = (delim.height + delim.depth) - ruleWidth;
+
+    // Adjust the clearance based on the delimiter size
+    if (delimDepth > inner.height + inner.depth + lineClearance) {
+        lineClearance =
+            (lineClearance + delimDepth - inner.height - inner.depth) / 2;
+    }
+
+    // Shift the delimiter so that its top lines up with the top of the line
+    var delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height;
+    delim.style.top = delimShift + "em";
+    delim.height -= delimShift;
+    delim.depth += delimShift;
+
+    // We add a special case here, because even when `inner` is empty, we
+    // still get a line. So, we use a simple heuristic to decide if we
+    // should omit the body entirely. (note this doesn't work for something
+    // like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for
+    // it not to work.
+    var body;
+    if (inner.height === 0 && inner.depth === 0) {
+        body = makeSpan();
+    } else {
+        body = buildCommon.makeVList([
+            {type: "elem", elem: inner},
+            {type: "kern", size: lineClearance},
+            {type: "elem", elem: line},
+            {type: "kern", size: ruleWidth}
+        ], "firstBaseline", null, options);
+    }
+
+    if (!group.value.index) {
+        return makeSpan(["mord", "sqrt"], [delim, body], options);
+    } else {
+        // Handle the optional root index
+
+        // The index is always in scriptscript style
+        var newOptions = options.withStyle(Style.SCRIPTSCRIPT);
+        var root = buildGroup(group.value.index, newOptions);
+        var rootWrap = makeSpan(
+            [style.reset(), Style.SCRIPTSCRIPT.cls()],
+            [root],
+            newOptions);
+
+        // Figure out the height and depth of the inner part
+        var innerRootHeight = Math.max(delim.height, body.height);
+        var innerRootDepth = Math.max(delim.depth, body.depth);
+
+        // The amount the index is shifted by. This is taken from the TeX
+        // source, in the definition of `\r@@t`.
+        var toShift = 0.6 * (innerRootHeight - innerRootDepth);
+
+        // Build a VList with the superscript shifted up correctly
+        var rootVList = buildCommon.makeVList(
+            [{type: "elem", elem: rootWrap}],
+            "shift", -toShift, options);
+        // Add a class surrounding it so we can add on the appropriate
+        // kerning
+        var rootVListWrap = makeSpan(["root"], [rootVList]);
+
+        return makeSpan(["mord", "sqrt"],
+            [rootVListWrap, delim, body], options);
+    }
+};
+
+groupTypes.sizing = function(group, options) {
+    // Handle sizing operators like \Huge. Real TeX doesn't actually allow
+    // these functions inside of math expressions, so we do some special
+    // handling.
+    var inner = buildExpression(group.value.value,
+            options.withSize(group.value.size), false);
+
+    // Compute the correct maxFontSize.
+    var style = options.style;
+    var fontSize = buildCommon.sizingMultiplier[group.value.size];
+    fontSize = fontSize * style.sizeMultiplier;
+
+    // Add size-resetting classes to the inner list and set maxFontSize
+    // manually. Handle nested size changes.
+    for (var i = 0; i < inner.length; i++) {
+        var pos = utils.indexOf(inner[i].classes, "sizing");
+        if (pos < 0) {
+            inner[i].classes.push("sizing", "reset-" + options.size,
+                                  group.value.size, style.cls());
+            inner[i].maxFontSize = fontSize;
+        } else if (inner[i].classes[pos + 1] === "reset-" + group.value.size) {
+            // This is a nested size change: e.g., inner[i] is the "b" in
+            // `\Huge a \small b`. Override the old size (the `reset-` class)
+            // but not the new size.
+            inner[i].classes[pos + 1] = "reset-" + options.size;
+        }
+    }
+
+    return buildCommon.makeFragment(inner);
+};
+
+groupTypes.styling = function(group, options) {
+    // Style changes are handled in the TeXbook on pg. 442, Rule 3.
+
+    // Figure out what style we're changing to.
+    var styleMap = {
+        "display": Style.DISPLAY,
+        "text": Style.TEXT,
+        "script": Style.SCRIPT,
+        "scriptscript": Style.SCRIPTSCRIPT
+    };
+
+    var newStyle = styleMap[group.value.style];
+    var newOptions = options.withStyle(newStyle);
+
+    // Build the inner expression in the new style.
+    var inner = buildExpression(
+        group.value.value, newOptions, false);
+
+    // Add style-resetting classes to the inner list. Handle nested changes.
+    for (var i = 0; i < inner.length; i++) {
+        var pos = utils.indexOf(inner[i].classes, newStyle.reset());
+        if (pos < 0) {
+            inner[i].classes.push(options.style.reset(), newStyle.cls());
+        } else {
+            // This is a nested style change, as `\textstyle a\scriptstyle b`.
+            // Only override the old style (the reset class).
+            inner[i].classes[pos] = options.style.reset();
+        }
+    }
+
+    return new buildCommon.makeFragment(inner);
+};
+
+groupTypes.font = function(group, options) {
+    var font = group.value.font;
+    return buildGroup(group.value.body, options.withFont(font));
+};
+
+groupTypes.delimsizing = function(group, options) {
+    var delim = group.value.value;
+
+    if (delim === ".") {
+        // Empty delimiters still count as elements, even though they don't
+        // show anything.
+        return makeSpan([group.value.mclass]);
+    }
+
+    // Use delimiter.sizedDelim to generate the delimiter.
+    return delimiter.sizedDelim(
+            delim, group.value.size, options, group.mode,
+            [group.value.mclass]);
+};
+
+groupTypes.leftright = function(group, options) {
+    // Build the inner expression
+    var inner = buildExpression(group.value.body, options.reset(), true);
+
+    var innerHeight = 0;
+    var innerDepth = 0;
+    var hadMiddle = false;
+
+    // Calculate its height and depth
+    for (var i = 0; i < inner.length; i++) {
+        if (inner[i].isMiddle) {
+            hadMiddle = true;
+        } else {
+            innerHeight = Math.max(inner[i].height, innerHeight);
+            innerDepth = Math.max(inner[i].depth, innerDepth);
+        }
+    }
+
+    var style = options.style;
+
+    // The size of delimiters is the same, regardless of what style we are
+    // in. Thus, to correctly calculate the size of delimiter we need around
+    // a group, we scale down the inner size based on the size.
+    innerHeight *= style.sizeMultiplier;
+    innerDepth *= style.sizeMultiplier;
+
+    var leftDelim;
+    if (group.value.left === ".") {
+        // Empty delimiters in \left and \right make null delimiter spaces.
+        leftDelim = makeNullDelimiter(options, ["mopen"]);
+    } else {
+        // Otherwise, use leftRightDelim to generate the correct sized
+        // delimiter.
+        leftDelim = delimiter.leftRightDelim(
+            group.value.left, innerHeight, innerDepth, options,
+            group.mode, ["mopen"]);
+    }
+    // Add it to the beginning of the expression
+    inner.unshift(leftDelim);
+
+    // Handle middle delimiters
+    if (hadMiddle) {
+        for (i = 1; i < inner.length; i++) {
+            if (inner[i].isMiddle) {
+                // Apply the options that were active when \middle was called
+                inner[i] = delimiter.leftRightDelim(
+                    inner[i].isMiddle.value, innerHeight, innerDepth,
+                    inner[i].isMiddle.options, group.mode, []);
+            }
+        }
+    }
+
+    var rightDelim;
+    // Same for the right delimiter
+    if (group.value.right === ".") {
+        rightDelim = makeNullDelimiter(options, ["mclose"]);
+    } else {
+        rightDelim = delimiter.leftRightDelim(
+            group.value.right, innerHeight, innerDepth, options,
+            group.mode, ["mclose"]);
+    }
+    // Add it to the end of the expression.
+    inner.push(rightDelim);
+
+    return makeSpan(
+        ["minner", style.cls()], inner, options);
+};
+
+groupTypes.middle = function(group, options) {
+    var middleDelim;
+    if (group.value.value === ".") {
+        middleDelim = makeNullDelimiter(options, []);
+    } else {
+        middleDelim = delimiter.sizedDelim(
+            group.value.value, 1, options,
+            group.mode, []);
+        middleDelim.isMiddle = {value: group.value.value, options: options};
+    }
+    return middleDelim;
+};
+
+groupTypes.rule = function(group, options) {
+    // Make an empty span for the rule
+    var rule = makeSpan(["mord", "rule"], [], options);
+    var style = options.style;
+
+    // Calculate the shift, width, and height of the rule, and account for units
+    var shift = 0;
+    if (group.value.shift) {
+        shift = calculateSize(group.value.shift, style);
+    }
+
+    var width = calculateSize(group.value.width, style);
+    var height = calculateSize(group.value.height, style);
+
+    // The sizes of rules are absolute, so make it larger if we are in a
+    // smaller style.
+    shift /= style.sizeMultiplier;
+    width /= style.sizeMultiplier;
+    height /= style.sizeMultiplier;
+
+    // Style the rule to the right size
+    rule.style.borderRightWidth = width + "em";
+    rule.style.borderTopWidth = height + "em";
+    rule.style.bottom = shift + "em";
+
+    // Record the height and width
+    rule.width = width;
+    rule.height = height + shift;
+    rule.depth = -shift;
+
+    return rule;
+};
+
+groupTypes.kern = function(group, options) {
+    // Make an empty span for the rule
+    var rule = makeSpan(["mord", "rule"], [], options);
+    var style = options.style;
+
+    var dimension = 0;
+    if (group.value.dimension) {
+        dimension = calculateSize(group.value.dimension, style);
+    }
+
+    dimension /= style.sizeMultiplier;
+
+    rule.style.marginLeft = dimension + "em";
+
+    return rule;
+};
+
+groupTypes.accent = function(group, options) {
+    // Accents are handled in the TeXbook pg. 443, rule 12.
+    var base = group.value.base;
+    var style = options.style;
+
+    var supsubGroup;
+    if (group.type === "supsub") {
+        // If our base is a character box, and we have superscripts and
+        // subscripts, the supsub will defer to us. In particular, we want
+        // to attach the superscripts and subscripts to the inner body (so
+        // that the position of the superscripts and subscripts won't be
+        // affected by the height of the accent). We accomplish this by
+        // sticking the base of the accent into the base of the supsub, and
+        // rendering that, while keeping track of where the accent is.
+
+        // The supsub group is the group that was passed in
+        var supsub = group;
+        // The real accent group is the base of the supsub group
+        group = supsub.value.base;
+        // The character box is the base of the accent group
+        base = group.value.base;
+        // Stick the character box into the base of the supsub group
+        supsub.value.base = base;
+
+        // Rerender the supsub group with its new base, and store that
+        // result.
+        supsubGroup = buildGroup(
+            supsub, options.reset());
+    }
+
+    // Build the base group
+    var body = buildGroup(
+        base, options.withStyle(style.cramp()));
+
+    // Calculate the skew of the accent. This is based on the line "If the
+    // nucleus is not a single character, let s = 0; otherwise set s to the
+    // kern amount for the nucleus followed by the \skewchar of its font."
+    // Note that our skew metrics are just the kern between each character
+    // and the skewchar.
+    var skew;
+    if (isCharacterBox(base)) {
+        // If the base is a character box, then we want the skew of the
+        // innermost character. To do that, we find the innermost character:
+        var baseChar = getBaseElem(base);
+        // Then, we render its group to get the symbol inside it
+        var baseGroup = buildGroup(
+            baseChar, options.withStyle(style.cramp()));
+        // Finally, we pull the skew off of the symbol.
+        skew = baseGroup.skew;
+        // Note that we now throw away baseGroup, because the layers we
+        // removed with getBaseElem might contain things like \color which
+        // we can't get rid of.
+        // TODO(emily): Find a better way to get the skew
+    } else {
+        skew = 0;
+    }
+
+    // calculate the amount of space between the body and the accent
+    var clearance = Math.min(
+        body.height,
+        style.metrics.xHeight);
+
+    // Build the accent
+    var accent = buildCommon.makeSymbol(
+        group.value.accent, "Main-Regular", "math", options);
+    // Remove the italic correction of the accent, because it only serves to
+    // shift the accent over to a place we don't want.
+    accent.italic = 0;
+
+    // The \vec character that the fonts use is a combining character, and
+    // thus shows up much too far to the left. To account for this, we add a
+    // specific class which shifts the accent over to where we want it.
+    // TODO(emily): Fix this in a better way, like by changing the font
+    var vecClass = group.value.accent === "\\vec" ? "accent-vec" : null;
+
+    var accentBody = makeSpan(["accent-body", vecClass], [
+        makeSpan([], [accent])]);
+
+    accentBody = buildCommon.makeVList([
+        {type: "elem", elem: body},
+        {type: "kern", size: -clearance},
+        {type: "elem", elem: accentBody}
+    ], "firstBaseline", null, options);
+
+    // Shift the accent over by the skew. Note we shift by twice the skew
+    // because we are centering the accent, so by adding 2*skew to the left,
+    // we shift it to the right by 1*skew.
+    accentBody.children[1].style.marginLeft = 2 * skew + "em";
+
+    var accentWrap = makeSpan(["mord", "accent"], [accentBody], options);
+
+    if (supsubGroup) {
+        // Here, we replace the "base" child of the supsub with our newly
+        // generated accent.
+        supsubGroup.children[0] = accentWrap;
+
+        // Since we don't rerun the height calculation after replacing the
+        // accent, we manually recalculate height.
+        supsubGroup.height = Math.max(accentWrap.height, supsubGroup.height);
+
+        // Accents should always be ords, even when their innards are not.
+        supsubGroup.classes[0] = "mord";
+
+        return supsubGroup;
+    } else {
+        return accentWrap;
+    }
+};
+
+groupTypes.phantom = function(group, options) {
+    var elements = buildExpression(
+        group.value.value,
+        options.withPhantom(),
+        false
+    );
+
+    // \phantom isn't supposed to affect the elements it contains.
+    // See "color" for more details.
+    return new buildCommon.makeFragment(elements);
+};
+
+groupTypes.mclass = function(group, options) {
+    var elements = buildExpression(group.value.value, options, true);
+
+    return makeSpan([group.value.mclass], elements, options);
+};
+
+/**
+ * buildGroup is the function that takes a group and calls the correct groupType
+ * function for it. It also handles the interaction of size and style changes
+ * between parents and children.
+ */
+var buildGroup = function(group, options) {
+    if (!group) {
+        return makeSpan();
+    }
+
+    if (groupTypes[group.type]) {
+        // Call the groupTypes function
+        var groupNode = groupTypes[group.type](group, options);
+        var multiplier;
+
+        // If the style changed between the parent and the current group,
+        // account for the size difference
+        if (options.style !== options.parentStyle) {
+            multiplier = options.style.sizeMultiplier /
+                    options.parentStyle.sizeMultiplier;
+
+            groupNode.height *= multiplier;
+            groupNode.depth *= multiplier;
+        }
+
+        // If the size changed between the parent and the current group, account
+        // for that size difference.
+        if (options.size !== options.parentSize) {
+            multiplier = buildCommon.sizingMultiplier[options.size] /
+                    buildCommon.sizingMultiplier[options.parentSize];
+
+            groupNode.height *= multiplier;
+            groupNode.depth *= multiplier;
+        }
+
+        return groupNode;
+    } else {
+        throw new ParseError(
+            "Got group of unknown type: '" + group.type + "'");
+    }
+};
+
+/**
+ * Take an entire parse tree, and build it into an appropriate set of HTML
+ * nodes.
+ */
+var buildHTML = function(tree, options) {
+    // buildExpression is destructive, so we need to make a clone
+    // of the incoming tree so that it isn't accidentally changed
+    tree = JSON.parse(JSON.stringify(tree));
+
+    // Build the expression contained in the tree
+    var expression = buildExpression(tree, options, true);
+    var body = makeSpan(["base", options.style.cls()], expression, options);
+
+    // Add struts, which ensure that the top of the HTML element falls at the
+    // height of the expression, and the bottom of the HTML element falls at the
+    // depth of the expression.
+    var topStrut = makeSpan(["strut"]);
+    var bottomStrut = makeSpan(["strut", "bottom"]);
+
+    topStrut.style.height = body.height + "em";
+    bottomStrut.style.height = (body.height + body.depth) + "em";
+    // We'd like to use `vertical-align: top` but in IE 9 this lowers the
+    // baseline of the box to the bottom of this strut (instead staying in the
+    // normal place) so we use an absolute value for vertical-align instead
+    bottomStrut.style.verticalAlign = -body.depth + "em";
+
+    // Wrap the struts and body together
+    var htmlNode = makeSpan(["katex-html"], [topStrut, bottomStrut, body]);
+
+    htmlNode.setAttribute("aria-hidden", "true");
+
+    return htmlNode;
+};
+
+module.exports = buildHTML;
+
+},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./delimiter":14,"./domTree":15,"./fontMetrics":17,"./utils":25}],12:[function(require,module,exports){
+/**
+ * This file converts a parse tree into a cooresponding MathML tree. The main
+ * entry point is the `buildMathML` function, which takes a parse tree from the
+ * parser.
+ */
+
+var buildCommon = require("./buildCommon");
+var fontMetrics = require("./fontMetrics");
+var mathMLTree = require("./mathMLTree");
+var ParseError = require("./ParseError");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+var fontMap = buildCommon.fontMap;
+
+/**
+ * Takes a symbol and converts it into a MathML text node after performing
+ * optional replacement from symbols.js.
+ */
+var makeText = function(text, mode) {
+    if (symbols[mode][text] && symbols[mode][text].replace) {
+        text = symbols[mode][text].replace;
+    }
+
+    return new mathMLTree.TextNode(text);
+};
+
+/**
+ * Returns the math variant as a string or null if none is required.
+ */
+var getVariant = function(group, options) {
+    var font = options.font;
+    if (!font) {
+        return null;
+    }
+
+    var mode = group.mode;
+    if (font === "mathit") {
+        return "italic";
+    }
+
+    var value = group.value;
+    if (utils.contains(["\\imath", "\\jmath"], value)) {
+        return null;
+    }
+
+    if (symbols[mode][value] && symbols[mode][value].replace) {
+        value = symbols[mode][value].replace;
+    }
+
+    var fontName = fontMap[font].fontName;
+    if (fontMetrics.getCharacterMetrics(value, fontName)) {
+        return fontMap[options.font].variant;
+    }
+
+    return null;
+};
+
+/**
+ * Functions for handling the different types of groups found in the parse
+ * tree. Each function should take a parse group and return a MathML node.
+ */
+var groupTypes = {};
+
+groupTypes.mathord = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mi",
+        [makeText(group.value, group.mode)]);
+
+    var variant = getVariant(group, options);
+    if (variant) {
+        node.setAttribute("mathvariant", variant);
+    }
+    return node;
+};
+
+groupTypes.textord = function(group, options) {
+    var text = makeText(group.value, group.mode);
+
+    var variant = getVariant(group, options) || "normal";
+
+    var node;
+    if (/[0-9]/.test(group.value)) {
+        // TODO(kevinb) merge adjacent <mn> nodes
+        // do it as a post processing step
+        node = new mathMLTree.MathNode("mn", [text]);
+        if (options.font) {
+            node.setAttribute("mathvariant", variant);
+        }
+    } else {
+        node = new mathMLTree.MathNode("mi", [text]);
+        node.setAttribute("mathvariant", variant);
+    }
+
+    return node;
+};
+
+groupTypes.bin = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.rel = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.open = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.close = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.inner = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    return node;
+};
+
+groupTypes.punct = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mo", [makeText(group.value, group.mode)]);
+
+    node.setAttribute("separator", "true");
+
+    return node;
+};
+
+groupTypes.ordgroup = function(group, options) {
+    var inner = buildExpression(group.value, options);
+
+    var node = new mathMLTree.MathNode("mrow", inner);
+
+    return node;
+};
+
+groupTypes.text = function(group, options) {
+    var inner = buildExpression(group.value.body, options);
+
+    var node = new mathMLTree.MathNode("mtext", inner);
+
+    return node;
+};
+
+groupTypes.color = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    node.setAttribute("mathcolor", group.value.color);
+
+    return node;
+};
+
+groupTypes.supsub = function(group, options) {
+    var children = [buildGroup(group.value.base, options)];
+
+    if (group.value.sub) {
+        children.push(buildGroup(group.value.sub, options));
+    }
+
+    if (group.value.sup) {
+        children.push(buildGroup(group.value.sup, options));
+    }
+
+    var nodeType;
+    if (!group.value.sub) {
+        nodeType = "msup";
+    } else if (!group.value.sup) {
+        nodeType = "msub";
+    } else {
+        nodeType = "msubsup";
+    }
+
+    var node = new mathMLTree.MathNode(nodeType, children);
+
+    return node;
+};
+
+groupTypes.genfrac = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mfrac",
+        [buildGroup(group.value.numer, options),
+            buildGroup(group.value.denom, options)]);
+
+    if (!group.value.hasBarLine) {
+        node.setAttribute("linethickness", "0px");
+    }
+
+    if (group.value.leftDelim != null || group.value.rightDelim != null) {
+        var withDelims = [];
+
+        if (group.value.leftDelim != null) {
+            var leftOp = new mathMLTree.MathNode(
+                "mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
+
+            leftOp.setAttribute("fence", "true");
+
+            withDelims.push(leftOp);
+        }
+
+        withDelims.push(node);
+
+        if (group.value.rightDelim != null) {
+            var rightOp = new mathMLTree.MathNode(
+                "mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
+
+            rightOp.setAttribute("fence", "true");
+
+            withDelims.push(rightOp);
+        }
+
+        var outerNode = new mathMLTree.MathNode("mrow", withDelims);
+
+        return outerNode;
+    }
+
+    return node;
+};
+
+groupTypes.array = function(group, options) {
+    return new mathMLTree.MathNode(
+        "mtable", group.value.body.map(function(row) {
+            return new mathMLTree.MathNode(
+                "mtr", row.map(function(cell) {
+                    return new mathMLTree.MathNode(
+                        "mtd", [buildGroup(cell, options)]);
+                }));
+        }));
+};
+
+groupTypes.sqrt = function(group, options) {
+    var node;
+    if (group.value.index) {
+        node = new mathMLTree.MathNode(
+            "mroot", [
+                buildGroup(group.value.body, options),
+                buildGroup(group.value.index, options)
+            ]);
+    } else {
+        node = new mathMLTree.MathNode(
+            "msqrt", [buildGroup(group.value.body, options)]);
+    }
+
+    return node;
+};
+
+groupTypes.leftright = function(group, options) {
+    var inner = buildExpression(group.value.body, options);
+
+    if (group.value.left !== ".") {
+        var leftNode = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.left, group.mode)]);
+
+        leftNode.setAttribute("fence", "true");
+
+        inner.unshift(leftNode);
+    }
+
+    if (group.value.right !== ".") {
+        var rightNode = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.right, group.mode)]);
+
+        rightNode.setAttribute("fence", "true");
+
+        inner.push(rightNode);
+    }
+
+    var outerNode = new mathMLTree.MathNode("mrow", inner);
+
+    return outerNode;
+};
+
+groupTypes.middle = function(group, options) {
+    var middleNode = new mathMLTree.MathNode(
+        "mo", [makeText(group.value.middle, group.mode)]);
+    middleNode.setAttribute("fence", "true");
+    return middleNode;
+};
+
+groupTypes.accent = function(group, options) {
+    var accentNode = new mathMLTree.MathNode(
+        "mo", [makeText(group.value.accent, group.mode)]);
+
+    var node = new mathMLTree.MathNode(
+        "mover",
+        [buildGroup(group.value.base, options),
+            accentNode]);
+
+    node.setAttribute("accent", "true");
+
+    return node;
+};
+
+groupTypes.spacing = function(group) {
+    var node;
+
+    if (group.value === "\\ " || group.value === "\\space" ||
+        group.value === " " || group.value === "~") {
+        node = new mathMLTree.MathNode(
+            "mtext", [new mathMLTree.TextNode("\u00a0")]);
+    } else {
+        node = new mathMLTree.MathNode("mspace");
+
+        node.setAttribute(
+            "width", buildCommon.spacingFunctions[group.value].size);
+    }
+
+    return node;
+};
+
+groupTypes.op = function(group, options) {
+    var node;
+
+    // TODO(emily): handle big operators using the `largeop` attribute
+
+    if (group.value.symbol) {
+        // This is a symbol. Just add the symbol.
+        node = new mathMLTree.MathNode(
+            "mo", [makeText(group.value.body, group.mode)]);
+    } else if (group.value.value) {
+        // This is an operator with children. Add them.
+        node = new mathMLTree.MathNode(
+            "mo", buildExpression(group.value.value, options));
+    } else {
+        // This is a text operator. Add all of the characters from the
+        // operator's name.
+        // TODO(emily): Add a space in the middle of some of these
+        // operators, like \limsup.
+        node = new mathMLTree.MathNode(
+            "mi", [new mathMLTree.TextNode(group.value.body.slice(1))]);
+    }
+
+    return node;
+};
+
+groupTypes.mod = function(group, options) {
+    var inner = [];
+
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText("(", group.mode)]));
+    }
+    if (group.value.modType !== "pod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText("mod", group.mode)]));
+    }
+    if (group.value.value) {
+        var space = new mathMLTree.MathNode("mspace");
+        space.setAttribute("width", "0.333333em");
+        inner.push(space);
+        inner = inner.concat(buildExpression(group.value.value, options));
+    }
+    if (group.value.modType === "pod" || group.value.modType === "pmod") {
+        inner.push(new mathMLTree.MathNode(
+            "mo", [makeText(")", group.mode)]));
+    }
+
+    return new mathMLTree.MathNode("mo", inner);
+};
+
+groupTypes.katex = function(group) {
+    var node = new mathMLTree.MathNode(
+        "mtext", [new mathMLTree.TextNode("KaTeX")]);
+
+    return node;
+};
+
+groupTypes.font = function(group, options) {
+    var font = group.value.font;
+    return buildGroup(group.value.body, options.withFont(font));
+};
+
+groupTypes.delimsizing = function(group) {
+    var children = [];
+
+    if (group.value.value !== ".") {
+        children.push(makeText(group.value.value, group.mode));
+    }
+
+    var node = new mathMLTree.MathNode("mo", children);
+
+    if (group.value.mclass === "mopen" ||
+        group.value.mclass === "mclose") {
+        // Only some of the delimsizing functions act as fences, and they
+        // return "mopen" or "mclose" mclass.
+        node.setAttribute("fence", "true");
+    } else {
+        // Explicitly disable fencing if it's not a fence, to override the
+        // defaults.
+        node.setAttribute("fence", "false");
+    }
+
+    return node;
+};
+
+groupTypes.styling = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    var styleAttributes = {
+        "display": ["0", "true"],
+        "text": ["0", "false"],
+        "script": ["1", "false"],
+        "scriptscript": ["2", "false"]
+    };
+
+    var attr = styleAttributes[group.value.style];
+
+    node.setAttribute("scriptlevel", attr[0]);
+    node.setAttribute("displaystyle", attr[1]);
+
+    return node;
+};
+
+groupTypes.sizing = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+
+    var node = new mathMLTree.MathNode("mstyle", inner);
+
+    // TODO(emily): This doesn't produce the correct size for nested size
+    // changes, because we don't keep state of what style we're currently
+    // in, so we can't reset the size to normal before changing it.  Now
+    // that we're passing an options parameter we should be able to fix
+    // this.
+    node.setAttribute(
+        "mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
+
+    return node;
+};
+
+groupTypes.overline = function(group, options) {
+    var operator = new mathMLTree.MathNode(
+        "mo", [new mathMLTree.TextNode("\u203e")]);
+    operator.setAttribute("stretchy", "true");
+
+    var node = new mathMLTree.MathNode(
+        "mover",
+        [buildGroup(group.value.body, options),
+            operator]);
+    node.setAttribute("accent", "true");
+
+    return node;
+};
+
+groupTypes.underline = function(group, options) {
+    var operator = new mathMLTree.MathNode(
+        "mo", [new mathMLTree.TextNode("\u203e")]);
+    operator.setAttribute("stretchy", "true");
+
+    var node = new mathMLTree.MathNode(
+        "munder",
+        [buildGroup(group.value.body, options),
+            operator]);
+    node.setAttribute("accentunder", "true");
+
+    return node;
+};
+
+groupTypes.rule = function(group) {
+    // TODO(emily): Figure out if there's an actual way to draw black boxes
+    // in MathML.
+    var node = new mathMLTree.MathNode("mrow");
+
+    return node;
+};
+
+groupTypes.kern = function(group) {
+    // TODO(kevin): Figure out if there's a way to add space in MathML
+    var node = new mathMLTree.MathNode("mrow");
+
+    return node;
+};
+
+groupTypes.llap = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mpadded", [buildGroup(group.value.body, options)]);
+
+    node.setAttribute("lspace", "-1width");
+    node.setAttribute("width", "0px");
+
+    return node;
+};
+
+groupTypes.rlap = function(group, options) {
+    var node = new mathMLTree.MathNode(
+        "mpadded", [buildGroup(group.value.body, options)]);
+
+    node.setAttribute("width", "0px");
+
+    return node;
+};
+
+groupTypes.phantom = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+    return new mathMLTree.MathNode("mphantom", inner);
+};
+
+groupTypes.mclass = function(group, options) {
+    var inner = buildExpression(group.value.value, options);
+    return new mathMLTree.MathNode("mstyle", inner);
+};
+
+/**
+ * Takes a list of nodes, builds them, and returns a list of the generated
+ * MathML nodes. A little simpler than the HTML version because we don't do any
+ * previous-node handling.
+ */
+var buildExpression = function(expression, options) {
+    var groups = [];
+    for (var i = 0; i < expression.length; i++) {
+        var group = expression[i];
+        groups.push(buildGroup(group, options));
+    }
+    return groups;
+};
+
+/**
+ * Takes a group from the parser and calls the appropriate groupTypes function
+ * on it to produce a MathML node.
+ */
+var buildGroup = function(group, options) {
+    if (!group) {
+        return new mathMLTree.MathNode("mrow");
+    }
+
+    if (groupTypes[group.type]) {
+        // Call the groupTypes function
+        return groupTypes[group.type](group, options);
+    } else {
+        throw new ParseError(
+            "Got group of unknown type: '" + group.type + "'");
+    }
+};
+
+/**
+ * Takes a full parse tree and settings and builds a MathML representation of
+ * it. In particular, we put the elements from building the parse tree into a
+ * <semantics> tag so we can also include that TeX source as an annotation.
+ *
+ * Note that we actually return a domTree element with a `<math>` inside it so
+ * we can do appropriate styling.
+ */
+var buildMathML = function(tree, texExpression, options) {
+    var expression = buildExpression(tree, options);
+
+    // Wrap up the expression in an mrow so it is presented in the semantics
+    // tag correctly.
+    var wrapper = new mathMLTree.MathNode("mrow", expression);
+
+    // Build a TeX annotation of the source
+    var annotation = new mathMLTree.MathNode(
+        "annotation", [new mathMLTree.TextNode(texExpression)]);
+
+    annotation.setAttribute("encoding", "application/x-tex");
+
+    var semantics = new mathMLTree.MathNode(
+        "semantics", [wrapper, annotation]);
+
+    var math = new mathMLTree.MathNode("math", [semantics]);
+
+    // You can't style <math> nodes, so we wrap the node in a span.
+    return makeSpan(["katex-mathml"], [math]);
+};
+
+module.exports = buildMathML;
+
+},{"./ParseError":6,"./buildCommon":10,"./fontMetrics":17,"./mathMLTree":20,"./symbols":23,"./utils":25}],13:[function(require,module,exports){
+var buildHTML = require("./buildHTML");
+var buildMathML = require("./buildMathML");
+var buildCommon = require("./buildCommon");
+var Options = require("./Options");
+var Settings = require("./Settings");
+var Style = require("./Style");
+
+var makeSpan = buildCommon.makeSpan;
+
+var buildTree = function(tree, expression, settings) {
+    settings = settings || new Settings({});
+
+    var startStyle = Style.TEXT;
+    if (settings.displayMode) {
+        startStyle = Style.DISPLAY;
+    }
+
+    // Setup the default options
+    var options = new Options({
+        style: startStyle,
+        size: "size5"
+    });
+
+    // `buildHTML` sometimes messes with the parse tree (like turning bins ->
+    // ords), so we build the MathML version first.
+    var mathMLNode = buildMathML(tree, expression, options);
+    var htmlNode = buildHTML(tree, options);
+
+    var katexNode = makeSpan(["katex"], [
+        mathMLNode, htmlNode
+    ]);
+
+    if (settings.displayMode) {
+        return makeSpan(["katex-display"], [katexNode]);
+    } else {
+        return katexNode;
+    }
+};
+
+module.exports = buildTree;
+
+},{"./Options":5,"./Settings":8,"./Style":9,"./buildCommon":10,"./buildHTML":11,"./buildMathML":12}],14:[function(require,module,exports){
+/**
+ * This file deals with creating delimiters of various sizes. The TeXbook
+ * discusses these routines on page 441-442, in the "Another subroutine sets box
+ * x to a specified variable delimiter" paragraph.
+ *
+ * There are three main routines here. `makeSmallDelim` makes a delimiter in the
+ * normal font, but in either text, script, or scriptscript style.
+ * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1,
+ * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of
+ * smaller pieces that are stacked on top of one another.
+ *
+ * The functions take a parameter `center`, which determines if the delimiter
+ * should be centered around the axis.
+ *
+ * Then, there are three exposed functions. `sizedDelim` makes a delimiter in
+ * one of the given sizes. This is used for things like `\bigl`.
+ * `customSizedDelim` makes a delimiter with a given total height+depth. It is
+ * called in places like `\sqrt`. `leftRightDelim` makes an appropriate
+ * delimiter which surrounds an expression of a given height an depth. It is
+ * used in `\left` and `\right`.
+ */
+
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var buildCommon = require("./buildCommon");
+var fontMetrics = require("./fontMetrics");
+var symbols = require("./symbols");
+var utils = require("./utils");
+
+var makeSpan = buildCommon.makeSpan;
+
+/**
+ * Get the metrics for a given symbol and font, after transformation (i.e.
+ * after following replacement from symbols.js)
+ */
+var getMetrics = function(symbol, font) {
+    if (symbols.math[symbol] && symbols.math[symbol].replace) {
+        return fontMetrics.getCharacterMetrics(
+            symbols.math[symbol].replace, font);
+    } else {
+        return fontMetrics.getCharacterMetrics(
+            symbol, font);
+    }
+};
+
+/**
+ * Builds a symbol in the given font size (note size is an integer)
+ */
+var mathrmSize = function(value, size, mode, options) {
+    return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
+        mode, options);
+};
+
+/**
+ * Puts a delimiter span in a given style, and adds appropriate height, depth,
+ * and maxFontSizes.
+ */
+var styleWrap = function(delim, toStyle, options, classes) {
+    classes = classes || [];
+    var span = makeSpan(
+        classes.concat(["style-wrap", options.style.reset(), toStyle.cls()]),
+        [delim], options);
+
+    var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
+
+    span.height *= multiplier;
+    span.depth *= multiplier;
+    span.maxFontSize = toStyle.sizeMultiplier;
+
+    return span;
+};
+
+/**
+ * Makes a small delimiter. This is a delimiter that comes in the Main-Regular
+ * font, but is restyled to either be in textstyle, scriptstyle, or
+ * scriptscriptstyle.
+ */
+var makeSmallDelim = function(delim, style, center, options, mode, classes) {
+    var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
+
+    var span = styleWrap(text, style, options, classes);
+
+    if (center) {
+        var shift =
+            (1 - options.style.sizeMultiplier / style.sizeMultiplier) *
+            options.style.metrics.axisHeight;
+
+        span.style.top = shift + "em";
+        span.height -= shift;
+        span.depth += shift;
+    }
+
+    return span;
+};
+
+/**
+ * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
+ * Size3, or Size4 fonts. It is always rendered in textstyle.
+ */
+var makeLargeDelim = function(delim, size, center, options, mode, classes) {
+    var inner = mathrmSize(delim, size, mode, options);
+
+    var span = styleWrap(
+        makeSpan(["delimsizing", "size" + size], [inner], options),
+        Style.TEXT, options, classes);
+
+    if (center) {
+        var shift = (1 - options.style.sizeMultiplier) *
+            options.style.metrics.axisHeight;
+
+        span.style.top = shift + "em";
+        span.height -= shift;
+        span.depth += shift;
+    }
+
+    return span;
+};
+
+/**
+ * Make an inner span with the given offset and in the given font. This is used
+ * in `makeStackedDelim` to make the stacking pieces for the delimiter.
+ */
+var makeInner = function(symbol, font, mode) {
+    var sizeClass;
+    // Apply the correct CSS class to choose the right font.
+    if (font === "Size1-Regular") {
+        sizeClass = "delim-size1";
+    } else if (font === "Size4-Regular") {
+        sizeClass = "delim-size4";
+    }
+
+    var inner = makeSpan(
+        ["delimsizinginner", sizeClass],
+        [makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]);
+
+    // Since this will be passed into `makeVList` in the end, wrap the element
+    // in the appropriate tag that VList uses.
+    return {type: "elem", elem: inner};
+};
+
+/**
+ * Make a stacked delimiter out of a given delimiter, with the total height at
+ * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook.
+ */
+var makeStackedDelim = function(delim, heightTotal, center, options, mode,
+                                classes) {
+    // There are four parts, the top, an optional middle, a repeated part, and a
+    // bottom.
+    var top;
+    var middle;
+    var repeat;
+    var bottom;
+    top = repeat = bottom = delim;
+    middle = null;
+    // Also keep track of what font the delimiters are in
+    var font = "Size1-Regular";
+
+    // We set the parts and font based on the symbol. Note that we use
+    // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
+    // repeats of the arrows
+    if (delim === "\\uparrow") {
+        repeat = bottom = "\u23d0";
+    } else if (delim === "\\Uparrow") {
+        repeat = bottom = "\u2016";
+    } else if (delim === "\\downarrow") {
+        top = repeat = "\u23d0";
+    } else if (delim === "\\Downarrow") {
+        top = repeat = "\u2016";
+    } else if (delim === "\\updownarrow") {
+        top = "\\uparrow";
+        repeat = "\u23d0";
+        bottom = "\\downarrow";
+    } else if (delim === "\\Updownarrow") {
+        top = "\\Uparrow";
+        repeat = "\u2016";
+        bottom = "\\Downarrow";
+    } else if (delim === "[" || delim === "\\lbrack") {
+        top = "\u23a1";
+        repeat = "\u23a2";
+        bottom = "\u23a3";
+        font = "Size4-Regular";
+    } else if (delim === "]" || delim === "\\rbrack") {
+        top = "\u23a4";
+        repeat = "\u23a5";
+        bottom = "\u23a6";
+        font = "Size4-Regular";
+    } else if (delim === "\\lfloor") {
+        repeat = top = "\u23a2";
+        bottom = "\u23a3";
+        font = "Size4-Regular";
+    } else if (delim === "\\lceil") {
+        top = "\u23a1";
+        repeat = bottom = "\u23a2";
+        font = "Size4-Regular";
+    } else if (delim === "\\rfloor") {
+        repeat = top = "\u23a5";
+        bottom = "\u23a6";
+        font = "Size4-Regular";
+    } else if (delim === "\\rceil") {
+        top = "\u23a4";
+        repeat = bottom = "\u23a5";
+        font = "Size4-Regular";
+    } else if (delim === "(") {
+        top = "\u239b";
+        repeat = "\u239c";
+        bottom = "\u239d";
+        font = "Size4-Regular";
+    } else if (delim === ")") {
+        top = "\u239e";
+        repeat = "\u239f";
+        bottom = "\u23a0";
+        font = "Size4-Regular";
+    } else if (delim === "\\{" || delim === "\\lbrace") {
+        top = "\u23a7";
+        middle = "\u23a8";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\}" || delim === "\\rbrace") {
+        top = "\u23ab";
+        middle = "\u23ac";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\lgroup") {
+        top = "\u23a7";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\rgroup") {
+        top = "\u23ab";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\lmoustache") {
+        top = "\u23a7";
+        bottom = "\u23ad";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\rmoustache") {
+        top = "\u23ab";
+        bottom = "\u23a9";
+        repeat = "\u23aa";
+        font = "Size4-Regular";
+    } else if (delim === "\\surd") {
+        top = "\ue001";
+        bottom = "\u23b7";
+        repeat = "\ue000";
+        font = "Size4-Regular";
+    }
+
+    // Get the metrics of the four sections
+    var topMetrics = getMetrics(top, font);
+    var topHeightTotal = topMetrics.height + topMetrics.depth;
+    var repeatMetrics = getMetrics(repeat, font);
+    var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
+    var bottomMetrics = getMetrics(bottom, font);
+    var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
+    var middleHeightTotal = 0;
+    var middleFactor = 1;
+    if (middle !== null) {
+        var middleMetrics = getMetrics(middle, font);
+        middleHeightTotal = middleMetrics.height + middleMetrics.depth;
+        middleFactor = 2; // repeat symmetrically above and below middle
+    }
+
+    // Calcuate the minimal height that the delimiter can have.
+    // It is at least the size of the top, bottom, and optional middle combined.
+    var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
+
+    // Compute the number of copies of the repeat symbol we will need
+    var repeatCount = Math.ceil(
+        (heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
+
+    // Compute the total height of the delimiter including all the symbols
+    var realHeightTotal =
+        minHeight + repeatCount * middleFactor * repeatHeightTotal;
+
+    // The center of the delimiter is placed at the center of the axis. Note
+    // that in this context, "center" means that the delimiter should be
+    // centered around the axis in the current style, while normally it is
+    // centered around the axis in textstyle.
+    var axisHeight = options.style.metrics.axisHeight;
+    if (center) {
+        axisHeight *= options.style.sizeMultiplier;
+    }
+    // Calculate the depth
+    var depth = realHeightTotal / 2 - axisHeight;
+
+    // Now, we start building the pieces that will go into the vlist
+
+    // Keep a list of the inner pieces
+    var inners = [];
+
+    // Add the bottom symbol
+    inners.push(makeInner(bottom, font, mode));
+
+    var i;
+    if (middle === null) {
+        // Add that many symbols
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+    } else {
+        // When there is a middle bit, we need the middle part and two repeated
+        // sections
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+        inners.push(makeInner(middle, font, mode));
+        for (i = 0; i < repeatCount; i++) {
+            inners.push(makeInner(repeat, font, mode));
+        }
+    }
+
+    // Add the top symbol
+    inners.push(makeInner(top, font, mode));
+
+    // Finally, build the vlist
+    var inner = buildCommon.makeVList(inners, "bottom", depth, options);
+
+    return styleWrap(
+        makeSpan(["delimsizing", "mult"], [inner], options),
+        Style.TEXT, options, classes);
+};
+
+// There are three kinds of delimiters, delimiters that stack when they become
+// too large
+var stackLargeDelimiters = [
+    "(", ")", "[", "\\lbrack", "]", "\\rbrack",
+    "\\{", "\\lbrace", "\\}", "\\rbrace",
+    "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
+    "\\surd"
+];
+
+// delimiters that always stack
+var stackAlwaysDelimiters = [
+    "\\uparrow", "\\downarrow", "\\updownarrow",
+    "\\Uparrow", "\\Downarrow", "\\Updownarrow",
+    "|", "\\|", "\\vert", "\\Vert",
+    "\\lvert", "\\rvert", "\\lVert", "\\rVert",
+    "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache"
+];
+
+// and delimiters that never stack
+var stackNeverDelimiters = [
+    "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt"
+];
+
+// Metrics of the different sizes. Found by looking at TeX's output of
+// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
+// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
+var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
+
+/**
+ * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4.
+ */
+var makeSizedDelim = function(delim, size, options, mode, classes) {
+    // < and > turn into \langle and \rangle in delimiters
+    if (delim === "<" || delim === "\\lt") {
+        delim = "\\langle";
+    } else if (delim === ">" || delim === "\\gt") {
+        delim = "\\rangle";
+    }
+
+    // Sized delimiters are never centered.
+    if (utils.contains(stackLargeDelimiters, delim) ||
+        utils.contains(stackNeverDelimiters, delim)) {
+        return makeLargeDelim(delim, size, false, options, mode, classes);
+    } else if (utils.contains(stackAlwaysDelimiters, delim)) {
+        return makeStackedDelim(
+            delim, sizeToMaxHeight[size], false, options, mode, classes);
+    } else {
+        throw new ParseError("Illegal delimiter: '" + delim + "'");
+    }
+};
+
+/**
+ * There are three different sequences of delimiter sizes that the delimiters
+ * follow depending on the kind of delimiter. This is used when creating custom
+ * sized delimiters to decide whether to create a small, large, or stacked
+ * delimiter.
+ *
+ * In real TeX, these sequences aren't explicitly defined, but are instead
+ * defined inside the font metrics. Since there are only three sequences that
+ * are possible for the delimiters that TeX defines, it is easier to just encode
+ * them explicitly here.
+ */
+
+// Delimiters that never stack try small delimiters and large delimiters only
+var stackNeverDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "large", size: 1},
+    {type: "large", size: 2},
+    {type: "large", size: 3},
+    {type: "large", size: 4}
+];
+
+// Delimiters that always stack try the small delimiters first, then stack
+var stackAlwaysDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "stack"}
+];
+
+// Delimiters that stack when large try the small and then large delimiters, and
+// stack afterwards
+var stackLargeDelimiterSequence = [
+    {type: "small", style: Style.SCRIPTSCRIPT},
+    {type: "small", style: Style.SCRIPT},
+    {type: "small", style: Style.TEXT},
+    {type: "large", size: 1},
+    {type: "large", size: 2},
+    {type: "large", size: 3},
+    {type: "large", size: 4},
+    {type: "stack"}
+];
+
+/**
+ * Get the font used in a delimiter based on what kind of delimiter it is.
+ */
+var delimTypeToFont = function(type) {
+    if (type.type === "small") {
+        return "Main-Regular";
+    } else if (type.type === "large") {
+        return "Size" + type.size + "-Regular";
+    } else if (type.type === "stack") {
+        return "Size4-Regular";
+    }
+};
+
+/**
+ * Traverse a sequence of types of delimiters to decide what kind of delimiter
+ * should be used to create a delimiter of the given height+depth.
+ */
+var traverseSequence = function(delim, height, sequence, options) {
+    // Here, we choose the index we should start at in the sequences. In smaller
+    // sizes (which correspond to larger numbers in style.size) we start earlier
+    // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts
+    // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2
+    var start = Math.min(2, 3 - options.style.size);
+    for (var i = start; i < sequence.length; i++) {
+        if (sequence[i].type === "stack") {
+            // This is always the last delimiter, so we just break the loop now.
+            break;
+        }
+
+        var metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
+        var heightDepth = metrics.height + metrics.depth;
+
+        // Small delimiters are scaled down versions of the same font, so we
+        // account for the style change size.
+
+        if (sequence[i].type === "small") {
+            heightDepth *= sequence[i].style.sizeMultiplier;
+        }
+
+        // Check if the delimiter at this size works for the given height.
+        if (heightDepth > height) {
+            return sequence[i];
+        }
+    }
+
+    // If we reached the end of the sequence, return the last sequence element.
+    return sequence[sequence.length - 1];
+};
+
+/**
+ * Make a delimiter of a given height+depth, with optional centering. Here, we
+ * traverse the sequences, and create a delimiter that the sequence tells us to.
+ */
+var makeCustomSizedDelim = function(delim, height, center, options, mode,
+                                    classes) {
+    if (delim === "<" || delim === "\\lt") {
+        delim = "\\langle";
+    } else if (delim === ">" || delim === "\\gt") {
+        delim = "\\rangle";
+    }
+
+    // Decide what sequence to use
+    var sequence;
+    if (utils.contains(stackNeverDelimiters, delim)) {
+        sequence = stackNeverDelimiterSequence;
+    } else if (utils.contains(stackLargeDelimiters, delim)) {
+        sequence = stackLargeDelimiterSequence;
+    } else {
+        sequence = stackAlwaysDelimiterSequence;
+    }
+
+    // Look through the sequence
+    var delimType = traverseSequence(delim, height, sequence, options);
+
+    // Depending on the sequence element we decided on, call the appropriate
+    // function.
+    if (delimType.type === "small") {
+        return makeSmallDelim(delim, delimType.style, center, options, mode,
+                              classes);
+    } else if (delimType.type === "large") {
+        return makeLargeDelim(delim, delimType.size, center, options, mode,
+                              classes);
+    } else if (delimType.type === "stack") {
+        return makeStackedDelim(delim, height, center, options, mode, classes);
+    }
+};
+
+/**
+ * Make a delimiter for use with `\left` and `\right`, given a height and depth
+ * of an expression that the delimiters surround.
+ */
+var makeLeftRightDelim = function(delim, height, depth, options, mode,
+                                  classes) {
+    // We always center \left/\right delimiters, so the axis is always shifted
+    var axisHeight =
+        options.style.metrics.axisHeight * options.style.sizeMultiplier;
+
+    // Taken from TeX source, tex.web, function make_left_right
+    var delimiterFactor = 901;
+    var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
+
+    var maxDistFromAxis = Math.max(
+        height - axisHeight, depth + axisHeight);
+
+    var totalHeight = Math.max(
+        // In real TeX, calculations are done using integral values which are
+        // 65536 per pt, or 655360 per em. So, the division here truncates in
+        // TeX but doesn't here, producing different results. If we wanted to
+        // exactly match TeX's calculation, we could do
+        //   Math.floor(655360 * maxDistFromAxis / 500) *
+        //    delimiterFactor / 655360
+        // (To see the difference, compare
+        //    x^{x^{\left(\rule{0.1em}{0.68em}\right)}}
+        // in TeX and KaTeX)
+        maxDistFromAxis / 500 * delimiterFactor,
+        2 * maxDistFromAxis - delimiterExtend);
+
+    // Finally, we defer to `makeCustomSizedDelim` with our calculated total
+    // height
+    return makeCustomSizedDelim(delim, totalHeight, true, options, mode,
+                                classes);
+};
+
+module.exports = {
+    sizedDelim: makeSizedDelim,
+    customSizedDelim: makeCustomSizedDelim,
+    leftRightDelim: makeLeftRightDelim
+};
+
+},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(require,module,exports){
+/**
+ * These objects store the data about the DOM nodes we create, as well as some
+ * extra data. They can then be transformed into real DOM nodes with the
+ * `toNode` function or HTML markup using `toMarkup`. They are useful for both
+ * storing extra properties on the nodes, as well as providing a way to easily
+ * work with the DOM.
+ *
+ * Similar functions for working with MathML nodes exist in mathMLTree.js.
+ */
+var unicodeRegexes = require("./unicodeRegexes");
+var utils = require("./utils");
+
+/**
+ * Create an HTML className based on a list of classes. In addition to joining
+ * with spaces, we also remove null or empty classes.
+ */
+var createClass = function(classes) {
+    classes = classes.slice();
+    for (var i = classes.length - 1; i >= 0; i--) {
+        if (!classes[i]) {
+            classes.splice(i, 1);
+        }
+    }
+
+    return classes.join(" ");
+};
+
+/**
+ * This node represents a span node, with a className, a list of children, and
+ * an inline style. It also contains information about its height, depth, and
+ * maxFontSize.
+ */
+function span(classes, children, options) {
+    this.classes = classes || [];
+    this.children = children || [];
+    this.height = 0;
+    this.depth = 0;
+    this.maxFontSize = 0;
+    this.style = {};
+    this.attributes = {};
+    if (options) {
+        if (options.style.isTight()) {
+            this.classes.push("mtight");
+        }
+        if (options.getColor()) {
+            this.style.color = options.getColor();
+        }
+    }
+}
+
+/**
+ * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all
+ * browsers support attributes the same, and having too many custom attributes
+ * is probably bad.
+ */
+span.prototype.setAttribute = function(attribute, value) {
+    this.attributes[attribute] = value;
+};
+
+span.prototype.tryCombine = function(sibling) {
+    return false;
+};
+
+/**
+ * Convert the span into an HTML node
+ */
+span.prototype.toNode = function() {
+    var span = document.createElement("span");
+
+    // Apply the class
+    span.className = createClass(this.classes);
+
+    // Apply inline styles
+    for (var style in this.style) {
+        if (Object.prototype.hasOwnProperty.call(this.style, style)) {
+            span.style[style] = this.style[style];
+        }
+    }
+
+    // Apply attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            span.setAttribute(attr, this.attributes[attr]);
+        }
+    }
+
+    // Append the children, also as HTML nodes
+    for (var i = 0; i < this.children.length; i++) {
+        span.appendChild(this.children[i].toNode());
+    }
+
+    return span;
+};
+
+/**
+ * Convert the span into an HTML markup string
+ */
+span.prototype.toMarkup = function() {
+    var markup = "<span";
+
+    // Add the class
+    if (this.classes.length) {
+        markup += " class=\"";
+        markup += utils.escape(createClass(this.classes));
+        markup += "\"";
+    }
+
+    var styles = "";
+
+    // Add the styles, after hyphenation
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
+        }
+    }
+
+    if (styles) {
+        markup += " style=\"" + utils.escape(styles) + "\"";
+    }
+
+    // Add the attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            markup += " " + attr + "=\"";
+            markup += utils.escape(this.attributes[attr]);
+            markup += "\"";
+        }
+    }
+
+    markup += ">";
+
+    // Add the markup of the children, also as markup
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    markup += "</span>";
+
+    return markup;
+};
+
+/**
+ * This node represents a document fragment, which contains elements, but when
+ * placed into the DOM doesn't have any representation itself. Thus, it only
+ * contains children and doesn't have any HTML properties. It also keeps track
+ * of a height, depth, and maxFontSize.
+ */
+function documentFragment(children) {
+    this.children = children || [];
+    this.height = 0;
+    this.depth = 0;
+    this.maxFontSize = 0;
+}
+
+/**
+ * Convert the fragment into a node
+ */
+documentFragment.prototype.toNode = function() {
+    // Create a fragment
+    var frag = document.createDocumentFragment();
+
+    // Append the children
+    for (var i = 0; i < this.children.length; i++) {
+        frag.appendChild(this.children[i].toNode());
+    }
+
+    return frag;
+};
+
+/**
+ * Convert the fragment into HTML markup
+ */
+documentFragment.prototype.toMarkup = function() {
+    var markup = "";
+
+    // Simply concatenate the markup for the children together
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    return markup;
+};
+
+var iCombinations = {
+    'î': '\u0131\u0302',
+    'ï': '\u0131\u0308',
+    'í': '\u0131\u0301',
+    // 'ī': '\u0131\u0304', // enable when we add Extended Latin
+    'ì': '\u0131\u0300'
+};
+
+/**
+ * A symbol node contains information about a single symbol. It either renders
+ * to a single text node, or a span with a single text node in it, depending on
+ * whether it has CSS classes, styles, or needs italic correction.
+ */
+function symbolNode(value, height, depth, italic, skew, classes, style) {
+    this.value = value || "";
+    this.height = height || 0;
+    this.depth = depth || 0;
+    this.italic = italic || 0;
+    this.skew = skew || 0;
+    this.classes = classes || [];
+    this.style = style || {};
+    this.maxFontSize = 0;
+
+    // Mark CJK characters with specific classes so that we can specify which
+    // fonts to use.  This allows us to render these characters with a serif
+    // font in situations where the browser would either default to a sans serif
+    // or render a placeholder character.
+    if (unicodeRegexes.cjkRegex.test(value)) {
+        // I couldn't find any fonts that contained Hangul as well as all of
+        // the other characters we wanted to test there for it gets its own
+        // CSS class.
+        if (unicodeRegexes.hangulRegex.test(value)) {
+            this.classes.push('hangul_fallback');
+        } else {
+            this.classes.push('cjk_fallback');
+        }
+    }
+
+    if (/[îïíì]/.test(this.value)) {    // add ī when we add Extended Latin
+        this.value = iCombinations[this.value];
+    }
+}
+
+symbolNode.prototype.tryCombine = function(sibling) {
+    if (!sibling
+        || !(sibling instanceof symbolNode)
+        || this.italic > 0
+        || createClass(this.classes) !== createClass(sibling.classes)
+        || this.skew !== sibling.skew
+        || this.maxFontSize !== sibling.maxFontSize) {
+        return false;
+    }
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)
+            && this.style[style] !== sibling.style[style]) {
+            return false;
+        }
+    }
+    for (style in sibling.style) {
+        if (sibling.style.hasOwnProperty(style)
+            && this.style[style] !== sibling.style[style]) {
+            return false;
+        }
+    }
+    this.value += sibling.value;
+    this.height = Math.max(this.height, sibling.height);
+    this.depth = Math.max(this.depth, sibling.depth);
+    this.italic = sibling.italic;
+    return true;
+};
+
+/**
+ * Creates a text node or span from a symbol node. Note that a span is only
+ * created if it is needed.
+ */
+symbolNode.prototype.toNode = function() {
+    var node = document.createTextNode(this.value);
+    var span = null;
+
+    if (this.italic > 0) {
+        span = document.createElement("span");
+        span.style.marginRight = this.italic + "em";
+    }
+
+    if (this.classes.length > 0) {
+        span = span || document.createElement("span");
+        span.className = createClass(this.classes);
+    }
+
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            span = span || document.createElement("span");
+            span.style[style] = this.style[style];
+        }
+    }
+
+    if (span) {
+        span.appendChild(node);
+        return span;
+    } else {
+        return node;
+    }
+};
+
+/**
+ * Creates markup for a symbol node.
+ */
+symbolNode.prototype.toMarkup = function() {
+    // TODO(alpert): More duplication than I'd like from
+    // span.prototype.toMarkup and symbolNode.prototype.toNode...
+    var needsSpan = false;
+
+    var markup = "<span";
+
+    if (this.classes.length) {
+        needsSpan = true;
+        markup += " class=\"";
+        markup += utils.escape(createClass(this.classes));
+        markup += "\"";
+    }
+
+    var styles = "";
+
+    if (this.italic > 0) {
+        styles += "margin-right:" + this.italic + "em;";
+    }
+    for (var style in this.style) {
+        if (this.style.hasOwnProperty(style)) {
+            styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
+        }
+    }
+
+    if (styles) {
+        needsSpan = true;
+        markup += " style=\"" + utils.escape(styles) + "\"";
+    }
+
+    var escaped = utils.escape(this.value);
+    if (needsSpan) {
+        markup += ">";
+        markup += escaped;
+        markup += "</span>";
+        return markup;
+    } else {
+        return escaped;
+    }
+};
+
+module.exports = {
+    span: span,
+    documentFragment: documentFragment,
+    symbolNode: symbolNode
+};
+
+},{"./unicodeRegexes":24,"./utils":25}],16:[function(require,module,exports){
+/* eslint no-constant-condition:0 */
+var parseData = require("./parseData");
+var ParseError = require("./ParseError");
+var Style = require("./Style");
+
+var ParseNode = parseData.ParseNode;
+
+/**
+ * Parse the body of the environment, with rows delimited by \\ and
+ * columns delimited by &, and create a nested list in row-major order
+ * with one group per cell.
+ */
+function parseArray(parser, result) {
+    var row = [];
+    var body = [row];
+    var rowGaps = [];
+    while (true) {
+        var cell = parser.parseExpression(false, null);
+        row.push(new ParseNode("ordgroup", cell, parser.mode));
+        var next = parser.nextToken.text;
+        if (next === "&") {
+            parser.consume();
+        } else if (next === "\\end") {
+            break;
+        } else if (next === "\\\\" || next === "\\cr") {
+            var cr = parser.parseFunction();
+            rowGaps.push(cr.value.size);
+            row = [];
+            body.push(row);
+        } else {
+            throw new ParseError("Expected & or \\\\ or \\end",
+                                 parser.nextToken);
+        }
+    }
+    result.body = body;
+    result.rowGaps = rowGaps;
+    return new ParseNode(result.type, result, parser.mode);
+}
+
+/*
+ * An environment definition is very similar to a function definition:
+ * it is declared with a name or a list of names, a set of properties
+ * and a handler containing the actual implementation.
+ *
+ * The properties include:
+ *  - numArgs: The number of arguments after the \begin{name} function.
+ *  - argTypes: (optional) Just like for a function
+ *  - allowedInText: (optional) Whether or not the environment is allowed inside
+ *                   text mode (default false) (not enforced yet)
+ *  - numOptionalArgs: (optional) Just like for a function
+ * A bare number instead of that object indicates the numArgs value.
+ *
+ * The handler function will receive two arguments
+ *  - context: information and references provided by the parser
+ *  - args: an array of arguments passed to \begin{name}
+ * The context contains the following properties:
+ *  - envName: the name of the environment, one of the listed names.
+ *  - parser: the parser object
+ *  - lexer: the lexer object
+ *  - positions: the positions associated with these arguments from args.
+ * The handler must return a ParseResult.
+ */
+
+function defineEnvironment(names, props, handler) {
+    if (typeof names === "string") {
+        names = [names];
+    }
+    if (typeof props === "number") {
+        props = { numArgs: props };
+    }
+    // Set default values of environments
+    var data = {
+        numArgs: props.numArgs || 0,
+        argTypes: props.argTypes,
+        greediness: 1,
+        allowedInText: !!props.allowedInText,
+        numOptionalArgs: props.numOptionalArgs || 0,
+        handler: handler
+    };
+    for (var i = 0; i < names.length; ++i) {
+        module.exports[names[i]] = data;
+    }
+}
+
+// Arrays are part of LaTeX, defined in lttab.dtx so its documentation
+// is part of the source2e.pdf file of LaTeX2e source documentation.
+defineEnvironment("array", {
+    numArgs: 1
+}, function(context, args) {
+    var colalign = args[0];
+    colalign = colalign.value.map ? colalign.value : [colalign];
+    var cols = colalign.map(function(node) {
+        var ca = node.value;
+        if ("lcr".indexOf(ca) !== -1) {
+            return {
+                type: "align",
+                align: ca
+            };
+        } else if (ca === "|") {
+            return {
+                type: "separator",
+                separator: "|"
+            };
+        }
+        throw new ParseError(
+            "Unknown column alignment: " + node.value,
+            node);
+    });
+    var res = {
+        type: "array",
+        cols: cols,
+        hskipBeforeAndAfter: true // \@preamble in lttab.dtx
+    };
+    res = parseArray(context.parser, res);
+    return res;
+});
+
+// The matrix environments of amsmath builds on the array environment
+// of LaTeX, which is discussed above.
+defineEnvironment([
+    "matrix",
+    "pmatrix",
+    "bmatrix",
+    "Bmatrix",
+    "vmatrix",
+    "Vmatrix"
+], {
+}, function(context) {
+    var delimiters = {
+        "matrix": null,
+        "pmatrix": ["(", ")"],
+        "bmatrix": ["[", "]"],
+        "Bmatrix": ["\\{", "\\}"],
+        "vmatrix": ["|", "|"],
+        "Vmatrix": ["\\Vert", "\\Vert"]
+    }[context.envName];
+    var res = {
+        type: "array",
+        hskipBeforeAndAfter: false // \hskip -\arraycolsep in amsmath
+    };
+    res = parseArray(context.parser, res);
+    if (delimiters) {
+        res = new ParseNode("leftright", {
+            body: [res],
+            left: delimiters[0],
+            right: delimiters[1]
+        }, context.mode);
+    }
+    return res;
+});
+
+// A cases environment (in amsmath.sty) is almost equivalent to
+// \def\arraystretch{1.2}%
+// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
+defineEnvironment("cases", {
+}, function(context) {
+    var res = {
+        type: "array",
+        arraystretch: 1.2,
+        cols: [{
+            type: "align",
+            align: "l",
+            pregap: 0,
+            // TODO(kevinb) get the current style.
+            // For now we use the metrics for TEXT style which is what we were
+            // doing before.  Before attempting to get the current style we
+            // should look at TeX's behavior especially for \over and matrices.
+            postgap: Style.TEXT.metrics.quad
+        }, {
+            type: "align",
+            align: "l",
+            pregap: 0,
+            postgap: 0
+        }]
+    };
+    res = parseArray(context.parser, res);
+    res = new ParseNode("leftright", {
+        body: [res],
+        left: "\\{",
+        right: "."
+    }, context.mode);
+    return res;
+});
+
+// An aligned environment is like the align* environment
+// except it operates within math mode.
+// Note that we assume \nomallineskiplimit to be zero,
+// so that \strut@ is the same as \strut.
+defineEnvironment("aligned", {
+}, function(context) {
+    var res = {
+        type: "array",
+        cols: []
+    };
+    res = parseArray(context.parser, res);
+    var emptyGroup = new ParseNode("ordgroup", [], context.mode);
+    var numCols = 0;
+    res.value.body.forEach(function(row) {
+        var i;
+        for (i = 1; i < row.length; i += 2) {
+            row[i].value.unshift(emptyGroup);
+        }
+        if (numCols < row.length) {
+            numCols = row.length;
+        }
+    });
+    for (var i = 0; i < numCols; ++i) {
+        var align = "r";
+        var pregap = 0;
+        if (i % 2 === 1) {
+            align = "l";
+        } else if (i > 0) {
+            pregap = 2; // one \qquad between columns
+        }
+        res.value.cols[i] = {
+            type: "align",
+            align: align,
+            pregap: pregap,
+            postgap: 0
+        };
+    }
+    return res;
+});
+
+},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(require,module,exports){
+/* eslint no-unused-vars:0 */
+
+var Style = require("./Style");
+var cjkRegex = require("./unicodeRegexes").cjkRegex;
+
+/**
+ * This file contains metrics regarding fonts and individual symbols. The sigma
+ * and xi variables, as well as the metricMap map contain data extracted from
+ * TeX, TeX font metrics, and the TTF files. These data are then exposed via the
+ * `metrics` variable and the getCharacterMetrics function.
+ */
+
+// In TeX, there are actually three sets of dimensions, one for each of
+// textstyle, scriptstyle, and scriptscriptstyle.  These are provided in the
+// the arrays below, in that order.
+//
+// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively.
+// This was determined by running the folllowing script:
+//
+//     latex -interaction=nonstopmode \
+//     '\documentclass{article}\usepackage{amsmath}\begin{document}' \
+//     '$a$ \expandafter\show\the\textfont2' \
+//     '\expandafter\show\the\scriptfont2' \
+//     '\expandafter\show\the\scriptscriptfont2' \
+//     '\stop'
+//
+// The metrics themselves were retreived using the following commands:
+//
+//     tftopl cmsy10
+//     tftopl cmsy7
+//     tftopl cmsy5
+//
+// The output of each of these commands is quite lengthy.  The only part we
+// care about is the FONTDIMEN section. Each value is measured in EMs.
+var sigmas = {
+    slant: [0.250, 0.250, 0.250],       // sigma1
+    space: [0.000, 0.000, 0.000],       // sigma2
+    stretch: [0.000, 0.000, 0.000],     // sigma3
+    shrink: [0.000, 0.000, 0.000],      // sigma4
+    xHeight: [0.431, 0.431, 0.431],     // sigma5
+    quad: [1.000, 1.171, 1.472],        // sigma6
+    extraSpace: [0.000, 0.000, 0.000],  // sigma7
+    num1: [0.677, 0.732, 0.925],        // sigma8
+    num2: [0.394, 0.384, 0.387],        // sigma9
+    num3: [0.444, 0.471, 0.504],        // sigma10
+    denom1: [0.686, 0.752, 1.025],      // sigma11
+    denom2: [0.345, 0.344, 0.532],      // sigma12
+    sup1: [0.413, 0.503, 0.504],        // sigma13
+    sup2: [0.363, 0.431, 0.404],        // sigma14
+    sup3: [0.289, 0.286, 0.294],        // sigma15
+    sub1: [0.150, 0.143, 0.200],        // sigma16
+    sub2: [0.247, 0.286, 0.400],        // sigma17
+    supDrop: [0.386, 0.353, 0.494],     // sigma18
+    subDrop: [0.050, 0.071, 0.100],     // sigma19
+    delim1: [2.390, 1.700, 1.980],      // sigma20
+    delim2: [1.010, 1.157, 1.420],      // sigma21
+    axisHeight: [0.250, 0.250, 0.250]  // sigma22
+};
+
+// These font metrics are extracted from TeX by using
+// \font\a=cmex10
+// \showthe\fontdimenX\a
+// where X is the corresponding variable number. These correspond to the font
+// parameters of the extension fonts (family 3). See the TeXbook, page 441.
+var xi1 = 0;
+var xi2 = 0;
+var xi3 = 0;
+var xi4 = 0;
+var xi5 = 0.431;
+var xi6 = 1;
+var xi7 = 0;
+var xi8 = 0.04;
+var xi9 = 0.111;
+var xi10 = 0.166;
+var xi11 = 0.2;
+var xi12 = 0.6;
+var xi13 = 0.1;
+
+// This value determines how large a pt is, for metrics which are defined in
+// terms of pts.
+// This value is also used in katex.less; if you change it make sure the values
+// match.
+var ptPerEm = 10.0;
+
+// The space between adjacent `|` columns in an array definition. From
+// `\showthe\doublerulesep` in LaTeX.
+var doubleRuleSep = 2.0 / ptPerEm;
+
+/**
+ * This is just a mapping from common names to real metrics
+ */
+var metrics = {
+    defaultRuleThickness: xi8,
+    bigOpSpacing1: xi9,
+    bigOpSpacing2: xi10,
+    bigOpSpacing3: xi11,
+    bigOpSpacing4: xi12,
+    bigOpSpacing5: xi13,
+    ptPerEm: ptPerEm,
+    doubleRuleSep: doubleRuleSep
+};
+
+// This map contains a mapping from font name and character code to character
+// metrics, including height, depth, italic correction, and skew (kern from the
+// character to the corresponding \skewchar)
+// This map is generated via `make metrics`. It should not be changed manually.
+var metricMap = require("./fontMetricsData");
+
+// These are very rough approximations.  We default to Times New Roman which
+// should have Latin-1 and Cyrillic characters, but may not depending on the
+// operating system.  The metrics do not account for extra height from the
+// accents.  In the case of Cyrillic characters which have both ascenders and
+// descenders we prefer approximations with ascenders, primarily to prevent
+// the fraction bar or root line from intersecting the glyph.
+// TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
+var extraCharacterMap = {
+    // Latin-1
+    'À': 'A',
+    'Á': 'A',
+    'Â': 'A',
+    'Ã': 'A',
+    'Ä': 'A',
+    'Å': 'A',
+    'Æ': 'A',
+    'Ç': 'C',
+    'È': 'E',
+    'É': 'E',
+    'Ê': 'E',
+    'Ë': 'E',
+    'Ì': 'I',
+    'Í': 'I',
+    'Î': 'I',
+    'Ï': 'I',
+    'Ð': 'D',
+    'Ñ': 'N',
+    'Ò': 'O',
+    'Ó': 'O',
+    'Ô': 'O',
+    'Õ': 'O',
+    'Ö': 'O',
+    'Ø': 'O',
+    'Ù': 'U',
+    'Ú': 'U',
+    'Û': 'U',
+    'Ü': 'U',
+    'Ý': 'Y',
+    'Þ': 'o',
+    'ß': 'B',
+    'à': 'a',
+    'á': 'a',
+    'â': 'a',
+    'ã': 'a',
+    'ä': 'a',
+    'å': 'a',
+    'æ': 'a',
+    'ç': 'c',
+    'è': 'e',
+    'é': 'e',
+    'ê': 'e',
+    'ë': 'e',
+    'ì': 'i',
+    'í': 'i',
+    'î': 'i',
+    'ï': 'i',
+    'ð': 'd',
+    'ñ': 'n',
+    'ò': 'o',
+    'ó': 'o',
+    'ô': 'o',
+    'õ': 'o',
+    'ö': 'o',
+    'ø': 'o',
+    'ù': 'u',
+    'ú': 'u',
+    'û': 'u',
+    'ü': 'u',
+    'ý': 'y',
+    'þ': 'o',
+    'ÿ': 'y',
+
+    // Cyrillic
+    'А': 'A',
+    'Б': 'B',
+    'В': 'B',
+    'Г': 'F',
+    'Д': 'A',
+    'Е': 'E',
+    'Ж': 'K',
+    'З': '3',
+    'И': 'N',
+    'Й': 'N',
+    'К': 'K',
+    'Л': 'N',
+    'М': 'M',
+    'Н': 'H',
+    'О': 'O',
+    'П': 'N',
+    'Р': 'P',
+    'С': 'C',
+    'Т': 'T',
+    'У': 'y',
+    'Ф': 'O',
+    'Х': 'X',
+    'Ц': 'U',
+    'Ч': 'h',
+    'Ш': 'W',
+    'Щ': 'W',
+    'Ъ': 'B',
+    'Ы': 'X',
+    'Ь': 'B',
+    'Э': '3',
+    'Ю': 'X',
+    'Я': 'R',
+    'а': 'a',
+    'б': 'b',
+    'в': 'a',
+    'г': 'r',
+    'д': 'y',
+    'е': 'e',
+    'ж': 'm',
+    'з': 'e',
+    'и': 'n',
+    'й': 'n',
+    'к': 'n',
+    'л': 'n',
+    'м': 'm',
+    'н': 'n',
+    'о': 'o',
+    'п': 'n',
+    'р': 'p',
+    'с': 'c',
+    'т': 'o',
+    'у': 'y',
+    'ф': 'b',
+    'х': 'x',
+    'ц': 'n',
+    'ч': 'n',
+    'ш': 'w',
+    'щ': 'w',
+    'ъ': 'a',
+    'ы': 'm',
+    'ь': 'a',
+    'э': 'e',
+    'ю': 'm',
+    'я': 'r'
+};
+
+/**
+ * This function is a convenience function for looking up information in the
+ * metricMap table. It takes a character as a string, and a style.
+ *
+ * Note: the `width` property may be undefined if fontMetricsData.js wasn't
+ * built using `Make extended_metrics`.
+ */
+var getCharacterMetrics = function(character, style) {
+    var ch = character.charCodeAt(0);
+    if (character[0] in extraCharacterMap) {
+        ch = extraCharacterMap[character[0]].charCodeAt(0);
+    } else if (cjkRegex.test(character[0])) {
+        ch = 'M'.charCodeAt(0);
+    }
+    var metrics = metricMap[style][ch];
+    if (metrics) {
+        return {
+            depth: metrics[0],
+            height: metrics[1],
+            italic: metrics[2],
+            skew: metrics[3],
+            width: metrics[4]
+        };
+    }
+};
+
+module.exports = {
+    metrics: metrics,
+    sigmas: sigmas,
+    getCharacterMetrics: getCharacterMetrics
+};
+
+},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(require,module,exports){
+module.exports = {
+    "AMS-Regular": {
+        "65": [0, 0.68889, 0, 0],
+        "66": [0, 0.68889, 0, 0],
+        "67": [0, 0.68889, 0, 0],
+        "68": [0, 0.68889, 0, 0],
+        "69": [0, 0.68889, 0, 0],
+        "70": [0, 0.68889, 0, 0],
+        "71": [0, 0.68889, 0, 0],
+        "72": [0, 0.68889, 0, 0],
+        "73": [0, 0.68889, 0, 0],
+        "74": [0.16667, 0.68889, 0, 0],
+        "75": [0, 0.68889, 0, 0],
+        "76": [0, 0.68889, 0, 0],
+        "77": [0, 0.68889, 0, 0],
+        "78": [0, 0.68889, 0, 0],
+        "79": [0.16667, 0.68889, 0, 0],
+        "80": [0, 0.68889, 0, 0],
+        "81": [0.16667, 0.68889, 0, 0],
+        "82": [0, 0.68889, 0, 0],
+        "83": [0, 0.68889, 0, 0],
+        "84": [0, 0.68889, 0, 0],
+        "85": [0, 0.68889, 0, 0],
+        "86": [0, 0.68889, 0, 0],
+        "87": [0, 0.68889, 0, 0],
+        "88": [0, 0.68889, 0, 0],
+        "89": [0, 0.68889, 0, 0],
+        "90": [0, 0.68889, 0, 0],
+        "107": [0, 0.68889, 0, 0],
+        "165": [0, 0.675, 0.025, 0],
+        "174": [0.15559, 0.69224, 0, 0],
+        "240": [0, 0.68889, 0, 0],
+        "295": [0, 0.68889, 0, 0],
+        "710": [0, 0.825, 0, 0],
+        "732": [0, 0.9, 0, 0],
+        "770": [0, 0.825, 0, 0],
+        "771": [0, 0.9, 0, 0],
+        "989": [0.08167, 0.58167, 0, 0],
+        "1008": [0, 0.43056, 0.04028, 0],
+        "8245": [0, 0.54986, 0, 0],
+        "8463": [0, 0.68889, 0, 0],
+        "8487": [0, 0.68889, 0, 0],
+        "8498": [0, 0.68889, 0, 0],
+        "8502": [0, 0.68889, 0, 0],
+        "8503": [0, 0.68889, 0, 0],
+        "8504": [0, 0.68889, 0, 0],
+        "8513": [0, 0.68889, 0, 0],
+        "8592": [-0.03598, 0.46402, 0, 0],
+        "8594": [-0.03598, 0.46402, 0, 0],
+        "8602": [-0.13313, 0.36687, 0, 0],
+        "8603": [-0.13313, 0.36687, 0, 0],
+        "8606": [0.01354, 0.52239, 0, 0],
+        "8608": [0.01354, 0.52239, 0, 0],
+        "8610": [0.01354, 0.52239, 0, 0],
+        "8611": [0.01354, 0.52239, 0, 0],
+        "8619": [0, 0.54986, 0, 0],
+        "8620": [0, 0.54986, 0, 0],
+        "8621": [-0.13313, 0.37788, 0, 0],
+        "8622": [-0.13313, 0.36687, 0, 0],
+        "8624": [0, 0.69224, 0, 0],
+        "8625": [0, 0.69224, 0, 0],
+        "8630": [0, 0.43056, 0, 0],
+        "8631": [0, 0.43056, 0, 0],
+        "8634": [0.08198, 0.58198, 0, 0],
+        "8635": [0.08198, 0.58198, 0, 0],
+        "8638": [0.19444, 0.69224, 0, 0],
+        "8639": [0.19444, 0.69224, 0, 0],
+        "8642": [0.19444, 0.69224, 0, 0],
+        "8643": [0.19444, 0.69224, 0, 0],
+        "8644": [0.1808, 0.675, 0, 0],
+        "8646": [0.1808, 0.675, 0, 0],
+        "8647": [0.1808, 0.675, 0, 0],
+        "8648": [0.19444, 0.69224, 0, 0],
+        "8649": [0.1808, 0.675, 0, 0],
+        "8650": [0.19444, 0.69224, 0, 0],
+        "8651": [0.01354, 0.52239, 0, 0],
+        "8652": [0.01354, 0.52239, 0, 0],
+        "8653": [-0.13313, 0.36687, 0, 0],
+        "8654": [-0.13313, 0.36687, 0, 0],
+        "8655": [-0.13313, 0.36687, 0, 0],
+        "8666": [0.13667, 0.63667, 0, 0],
+        "8667": [0.13667, 0.63667, 0, 0],
+        "8669": [-0.13313, 0.37788, 0, 0],
+        "8672": [-0.064, 0.437, 0, 0],
+        "8674": [-0.064, 0.437, 0, 0],
+        "8705": [0, 0.825, 0, 0],
+        "8708": [0, 0.68889, 0, 0],
+        "8709": [0.08167, 0.58167, 0, 0],
+        "8717": [0, 0.43056, 0, 0],
+        "8722": [-0.03598, 0.46402, 0, 0],
+        "8724": [0.08198, 0.69224, 0, 0],
+        "8726": [0.08167, 0.58167, 0, 0],
+        "8733": [0, 0.69224, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8737": [0, 0.69224, 0, 0],
+        "8738": [0.03517, 0.52239, 0, 0],
+        "8739": [0.08167, 0.58167, 0, 0],
+        "8740": [0.25142, 0.74111, 0, 0],
+        "8741": [0.08167, 0.58167, 0, 0],
+        "8742": [0.25142, 0.74111, 0, 0],
+        "8756": [0, 0.69224, 0, 0],
+        "8757": [0, 0.69224, 0, 0],
+        "8764": [-0.13313, 0.36687, 0, 0],
+        "8765": [-0.13313, 0.37788, 0, 0],
+        "8769": [-0.13313, 0.36687, 0, 0],
+        "8770": [-0.03625, 0.46375, 0, 0],
+        "8774": [0.30274, 0.79383, 0, 0],
+        "8776": [-0.01688, 0.48312, 0, 0],
+        "8778": [0.08167, 0.58167, 0, 0],
+        "8782": [0.06062, 0.54986, 0, 0],
+        "8783": [0.06062, 0.54986, 0, 0],
+        "8785": [0.08198, 0.58198, 0, 0],
+        "8786": [0.08198, 0.58198, 0, 0],
+        "8787": [0.08198, 0.58198, 0, 0],
+        "8790": [0, 0.69224, 0, 0],
+        "8791": [0.22958, 0.72958, 0, 0],
+        "8796": [0.08198, 0.91667, 0, 0],
+        "8806": [0.25583, 0.75583, 0, 0],
+        "8807": [0.25583, 0.75583, 0, 0],
+        "8808": [0.25142, 0.75726, 0, 0],
+        "8809": [0.25142, 0.75726, 0, 0],
+        "8812": [0.25583, 0.75583, 0, 0],
+        "8814": [0.20576, 0.70576, 0, 0],
+        "8815": [0.20576, 0.70576, 0, 0],
+        "8816": [0.30274, 0.79383, 0, 0],
+        "8817": [0.30274, 0.79383, 0, 0],
+        "8818": [0.22958, 0.72958, 0, 0],
+        "8819": [0.22958, 0.72958, 0, 0],
+        "8822": [0.1808, 0.675, 0, 0],
+        "8823": [0.1808, 0.675, 0, 0],
+        "8828": [0.13667, 0.63667, 0, 0],
+        "8829": [0.13667, 0.63667, 0, 0],
+        "8830": [0.22958, 0.72958, 0, 0],
+        "8831": [0.22958, 0.72958, 0, 0],
+        "8832": [0.20576, 0.70576, 0, 0],
+        "8833": [0.20576, 0.70576, 0, 0],
+        "8840": [0.30274, 0.79383, 0, 0],
+        "8841": [0.30274, 0.79383, 0, 0],
+        "8842": [0.13597, 0.63597, 0, 0],
+        "8843": [0.13597, 0.63597, 0, 0],
+        "8847": [0.03517, 0.54986, 0, 0],
+        "8848": [0.03517, 0.54986, 0, 0],
+        "8858": [0.08198, 0.58198, 0, 0],
+        "8859": [0.08198, 0.58198, 0, 0],
+        "8861": [0.08198, 0.58198, 0, 0],
+        "8862": [0, 0.675, 0, 0],
+        "8863": [0, 0.675, 0, 0],
+        "8864": [0, 0.675, 0, 0],
+        "8865": [0, 0.675, 0, 0],
+        "8872": [0, 0.69224, 0, 0],
+        "8873": [0, 0.69224, 0, 0],
+        "8874": [0, 0.69224, 0, 0],
+        "8876": [0, 0.68889, 0, 0],
+        "8877": [0, 0.68889, 0, 0],
+        "8878": [0, 0.68889, 0, 0],
+        "8879": [0, 0.68889, 0, 0],
+        "8882": [0.03517, 0.54986, 0, 0],
+        "8883": [0.03517, 0.54986, 0, 0],
+        "8884": [0.13667, 0.63667, 0, 0],
+        "8885": [0.13667, 0.63667, 0, 0],
+        "8888": [0, 0.54986, 0, 0],
+        "8890": [0.19444, 0.43056, 0, 0],
+        "8891": [0.19444, 0.69224, 0, 0],
+        "8892": [0.19444, 0.69224, 0, 0],
+        "8901": [0, 0.54986, 0, 0],
+        "8903": [0.08167, 0.58167, 0, 0],
+        "8905": [0.08167, 0.58167, 0, 0],
+        "8906": [0.08167, 0.58167, 0, 0],
+        "8907": [0, 0.69224, 0, 0],
+        "8908": [0, 0.69224, 0, 0],
+        "8909": [-0.03598, 0.46402, 0, 0],
+        "8910": [0, 0.54986, 0, 0],
+        "8911": [0, 0.54986, 0, 0],
+        "8912": [0.03517, 0.54986, 0, 0],
+        "8913": [0.03517, 0.54986, 0, 0],
+        "8914": [0, 0.54986, 0, 0],
+        "8915": [0, 0.54986, 0, 0],
+        "8916": [0, 0.69224, 0, 0],
+        "8918": [0.0391, 0.5391, 0, 0],
+        "8919": [0.0391, 0.5391, 0, 0],
+        "8920": [0.03517, 0.54986, 0, 0],
+        "8921": [0.03517, 0.54986, 0, 0],
+        "8922": [0.38569, 0.88569, 0, 0],
+        "8923": [0.38569, 0.88569, 0, 0],
+        "8926": [0.13667, 0.63667, 0, 0],
+        "8927": [0.13667, 0.63667, 0, 0],
+        "8928": [0.30274, 0.79383, 0, 0],
+        "8929": [0.30274, 0.79383, 0, 0],
+        "8934": [0.23222, 0.74111, 0, 0],
+        "8935": [0.23222, 0.74111, 0, 0],
+        "8936": [0.23222, 0.74111, 0, 0],
+        "8937": [0.23222, 0.74111, 0, 0],
+        "8938": [0.20576, 0.70576, 0, 0],
+        "8939": [0.20576, 0.70576, 0, 0],
+        "8940": [0.30274, 0.79383, 0, 0],
+        "8941": [0.30274, 0.79383, 0, 0],
+        "8994": [0.19444, 0.69224, 0, 0],
+        "8995": [0.19444, 0.69224, 0, 0],
+        "9416": [0.15559, 0.69224, 0, 0],
+        "9484": [0, 0.69224, 0, 0],
+        "9488": [0, 0.69224, 0, 0],
+        "9492": [0, 0.37788, 0, 0],
+        "9496": [0, 0.37788, 0, 0],
+        "9585": [0.19444, 0.68889, 0, 0],
+        "9586": [0.19444, 0.74111, 0, 0],
+        "9632": [0, 0.675, 0, 0],
+        "9633": [0, 0.675, 0, 0],
+        "9650": [0, 0.54986, 0, 0],
+        "9651": [0, 0.54986, 0, 0],
+        "9654": [0.03517, 0.54986, 0, 0],
+        "9660": [0, 0.54986, 0, 0],
+        "9661": [0, 0.54986, 0, 0],
+        "9664": [0.03517, 0.54986, 0, 0],
+        "9674": [0.11111, 0.69224, 0, 0],
+        "9733": [0.19444, 0.69224, 0, 0],
+        "10003": [0, 0.69224, 0, 0],
+        "10016": [0, 0.69224, 0, 0],
+        "10731": [0.11111, 0.69224, 0, 0],
+        "10846": [0.19444, 0.75583, 0, 0],
+        "10877": [0.13667, 0.63667, 0, 0],
+        "10878": [0.13667, 0.63667, 0, 0],
+        "10885": [0.25583, 0.75583, 0, 0],
+        "10886": [0.25583, 0.75583, 0, 0],
+        "10887": [0.13597, 0.63597, 0, 0],
+        "10888": [0.13597, 0.63597, 0, 0],
+        "10889": [0.26167, 0.75726, 0, 0],
+        "10890": [0.26167, 0.75726, 0, 0],
+        "10891": [0.48256, 0.98256, 0, 0],
+        "10892": [0.48256, 0.98256, 0, 0],
+        "10901": [0.13667, 0.63667, 0, 0],
+        "10902": [0.13667, 0.63667, 0, 0],
+        "10933": [0.25142, 0.75726, 0, 0],
+        "10934": [0.25142, 0.75726, 0, 0],
+        "10935": [0.26167, 0.75726, 0, 0],
+        "10936": [0.26167, 0.75726, 0, 0],
+        "10937": [0.26167, 0.75726, 0, 0],
+        "10938": [0.26167, 0.75726, 0, 0],
+        "10949": [0.25583, 0.75583, 0, 0],
+        "10950": [0.25583, 0.75583, 0, 0],
+        "10955": [0.28481, 0.79383, 0, 0],
+        "10956": [0.28481, 0.79383, 0, 0],
+        "57350": [0.08167, 0.58167, 0, 0],
+        "57351": [0.08167, 0.58167, 0, 0],
+        "57352": [0.08167, 0.58167, 0, 0],
+        "57353": [0, 0.43056, 0.04028, 0],
+        "57356": [0.25142, 0.75726, 0, 0],
+        "57357": [0.25142, 0.75726, 0, 0],
+        "57358": [0.41951, 0.91951, 0, 0],
+        "57359": [0.30274, 0.79383, 0, 0],
+        "57360": [0.30274, 0.79383, 0, 0],
+        "57361": [0.41951, 0.91951, 0, 0],
+        "57366": [0.25142, 0.75726, 0, 0],
+        "57367": [0.25142, 0.75726, 0, 0],
+        "57368": [0.25142, 0.75726, 0, 0],
+        "57369": [0.25142, 0.75726, 0, 0],
+        "57370": [0.13597, 0.63597, 0, 0],
+        "57371": [0.13597, 0.63597, 0, 0]
+    },
+    "Caligraphic-Regular": {
+        "48": [0, 0.43056, 0, 0],
+        "49": [0, 0.43056, 0, 0],
+        "50": [0, 0.43056, 0, 0],
+        "51": [0.19444, 0.43056, 0, 0],
+        "52": [0.19444, 0.43056, 0, 0],
+        "53": [0.19444, 0.43056, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0.19444, 0.43056, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0.19444, 0.43056, 0, 0],
+        "65": [0, 0.68333, 0, 0.19445],
+        "66": [0, 0.68333, 0.03041, 0.13889],
+        "67": [0, 0.68333, 0.05834, 0.13889],
+        "68": [0, 0.68333, 0.02778, 0.08334],
+        "69": [0, 0.68333, 0.08944, 0.11111],
+        "70": [0, 0.68333, 0.09931, 0.11111],
+        "71": [0.09722, 0.68333, 0.0593, 0.11111],
+        "72": [0, 0.68333, 0.00965, 0.11111],
+        "73": [0, 0.68333, 0.07382, 0],
+        "74": [0.09722, 0.68333, 0.18472, 0.16667],
+        "75": [0, 0.68333, 0.01445, 0.05556],
+        "76": [0, 0.68333, 0, 0.13889],
+        "77": [0, 0.68333, 0, 0.13889],
+        "78": [0, 0.68333, 0.14736, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.11111],
+        "80": [0, 0.68333, 0.08222, 0.08334],
+        "81": [0.09722, 0.68333, 0, 0.11111],
+        "82": [0, 0.68333, 0, 0.08334],
+        "83": [0, 0.68333, 0.075, 0.13889],
+        "84": [0, 0.68333, 0.25417, 0],
+        "85": [0, 0.68333, 0.09931, 0.08334],
+        "86": [0, 0.68333, 0.08222, 0],
+        "87": [0, 0.68333, 0.08222, 0.08334],
+        "88": [0, 0.68333, 0.14643, 0.13889],
+        "89": [0.09722, 0.68333, 0.08222, 0.08334],
+        "90": [0, 0.68333, 0.07944, 0.13889]
+    },
+    "Fraktur-Regular": {
+        "33": [0, 0.69141, 0, 0],
+        "34": [0, 0.69141, 0, 0],
+        "38": [0, 0.69141, 0, 0],
+        "39": [0, 0.69141, 0, 0],
+        "40": [0.24982, 0.74947, 0, 0],
+        "41": [0.24982, 0.74947, 0, 0],
+        "42": [0, 0.62119, 0, 0],
+        "43": [0.08319, 0.58283, 0, 0],
+        "44": [0, 0.10803, 0, 0],
+        "45": [0.08319, 0.58283, 0, 0],
+        "46": [0, 0.10803, 0, 0],
+        "47": [0.24982, 0.74947, 0, 0],
+        "48": [0, 0.47534, 0, 0],
+        "49": [0, 0.47534, 0, 0],
+        "50": [0, 0.47534, 0, 0],
+        "51": [0.18906, 0.47534, 0, 0],
+        "52": [0.18906, 0.47534, 0, 0],
+        "53": [0.18906, 0.47534, 0, 0],
+        "54": [0, 0.69141, 0, 0],
+        "55": [0.18906, 0.47534, 0, 0],
+        "56": [0, 0.69141, 0, 0],
+        "57": [0.18906, 0.47534, 0, 0],
+        "58": [0, 0.47534, 0, 0],
+        "59": [0.12604, 0.47534, 0, 0],
+        "61": [-0.13099, 0.36866, 0, 0],
+        "63": [0, 0.69141, 0, 0],
+        "65": [0, 0.69141, 0, 0],
+        "66": [0, 0.69141, 0, 0],
+        "67": [0, 0.69141, 0, 0],
+        "68": [0, 0.69141, 0, 0],
+        "69": [0, 0.69141, 0, 0],
+        "70": [0.12604, 0.69141, 0, 0],
+        "71": [0, 0.69141, 0, 0],
+        "72": [0.06302, 0.69141, 0, 0],
+        "73": [0, 0.69141, 0, 0],
+        "74": [0.12604, 0.69141, 0, 0],
+        "75": [0, 0.69141, 0, 0],
+        "76": [0, 0.69141, 0, 0],
+        "77": [0, 0.69141, 0, 0],
+        "78": [0, 0.69141, 0, 0],
+        "79": [0, 0.69141, 0, 0],
+        "80": [0.18906, 0.69141, 0, 0],
+        "81": [0.03781, 0.69141, 0, 0],
+        "82": [0, 0.69141, 0, 0],
+        "83": [0, 0.69141, 0, 0],
+        "84": [0, 0.69141, 0, 0],
+        "85": [0, 0.69141, 0, 0],
+        "86": [0, 0.69141, 0, 0],
+        "87": [0, 0.69141, 0, 0],
+        "88": [0, 0.69141, 0, 0],
+        "89": [0.18906, 0.69141, 0, 0],
+        "90": [0.12604, 0.69141, 0, 0],
+        "91": [0.24982, 0.74947, 0, 0],
+        "93": [0.24982, 0.74947, 0, 0],
+        "94": [0, 0.69141, 0, 0],
+        "97": [0, 0.47534, 0, 0],
+        "98": [0, 0.69141, 0, 0],
+        "99": [0, 0.47534, 0, 0],
+        "100": [0, 0.62119, 0, 0],
+        "101": [0, 0.47534, 0, 0],
+        "102": [0.18906, 0.69141, 0, 0],
+        "103": [0.18906, 0.47534, 0, 0],
+        "104": [0.18906, 0.69141, 0, 0],
+        "105": [0, 0.69141, 0, 0],
+        "106": [0, 0.69141, 0, 0],
+        "107": [0, 0.69141, 0, 0],
+        "108": [0, 0.69141, 0, 0],
+        "109": [0, 0.47534, 0, 0],
+        "110": [0, 0.47534, 0, 0],
+        "111": [0, 0.47534, 0, 0],
+        "112": [0.18906, 0.52396, 0, 0],
+        "113": [0.18906, 0.47534, 0, 0],
+        "114": [0, 0.47534, 0, 0],
+        "115": [0, 0.47534, 0, 0],
+        "116": [0, 0.62119, 0, 0],
+        "117": [0, 0.47534, 0, 0],
+        "118": [0, 0.52396, 0, 0],
+        "119": [0, 0.52396, 0, 0],
+        "120": [0.18906, 0.47534, 0, 0],
+        "121": [0.18906, 0.47534, 0, 0],
+        "122": [0.18906, 0.47534, 0, 0],
+        "8216": [0, 0.69141, 0, 0],
+        "8217": [0, 0.69141, 0, 0],
+        "58112": [0, 0.62119, 0, 0],
+        "58113": [0, 0.62119, 0, 0],
+        "58114": [0.18906, 0.69141, 0, 0],
+        "58115": [0.18906, 0.69141, 0, 0],
+        "58116": [0.18906, 0.47534, 0, 0],
+        "58117": [0, 0.69141, 0, 0],
+        "58118": [0, 0.62119, 0, 0],
+        "58119": [0, 0.47534, 0, 0]
+    },
+    "Main-Bold": {
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.13333, 0.63333, 0, 0],
+        "44": [0.19444, 0.15556, 0, 0],
+        "45": [0, 0.44444, 0, 0],
+        "46": [0, 0.15556, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.64444, 0, 0],
+        "49": [0, 0.64444, 0, 0],
+        "50": [0, 0.64444, 0, 0],
+        "51": [0, 0.64444, 0, 0],
+        "52": [0, 0.64444, 0, 0],
+        "53": [0, 0.64444, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0, 0.64444, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0, 0.64444, 0, 0],
+        "58": [0, 0.44444, 0, 0],
+        "59": [0.19444, 0.44444, 0, 0],
+        "60": [0.08556, 0.58556, 0, 0],
+        "61": [-0.10889, 0.39111, 0, 0],
+        "62": [0.08556, 0.58556, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.68611, 0, 0],
+        "66": [0, 0.68611, 0, 0],
+        "67": [0, 0.68611, 0, 0],
+        "68": [0, 0.68611, 0, 0],
+        "69": [0, 0.68611, 0, 0],
+        "70": [0, 0.68611, 0, 0],
+        "71": [0, 0.68611, 0, 0],
+        "72": [0, 0.68611, 0, 0],
+        "73": [0, 0.68611, 0, 0],
+        "74": [0, 0.68611, 0, 0],
+        "75": [0, 0.68611, 0, 0],
+        "76": [0, 0.68611, 0, 0],
+        "77": [0, 0.68611, 0, 0],
+        "78": [0, 0.68611, 0, 0],
+        "79": [0, 0.68611, 0, 0],
+        "80": [0, 0.68611, 0, 0],
+        "81": [0.19444, 0.68611, 0, 0],
+        "82": [0, 0.68611, 0, 0],
+        "83": [0, 0.68611, 0, 0],
+        "84": [0, 0.68611, 0, 0],
+        "85": [0, 0.68611, 0, 0],
+        "86": [0, 0.68611, 0.01597, 0],
+        "87": [0, 0.68611, 0.01597, 0],
+        "88": [0, 0.68611, 0, 0],
+        "89": [0, 0.68611, 0.02875, 0],
+        "90": [0, 0.68611, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "92": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.31, 0.13444, 0.03194, 0],
+        "96": [0, 0.69444, 0, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0, 0.69444, 0.10903, 0],
+        "103": [0.19444, 0.44444, 0.01597, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.69444, 0, 0],
+        "106": [0.19444, 0.69444, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0, 0],
+        "114": [0, 0.44444, 0, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.63492, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.01597, 0],
+        "119": [0, 0.44444, 0.01597, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.01597, 0],
+        "122": [0, 0.44444, 0, 0],
+        "123": [0.25, 0.75, 0, 0],
+        "124": [0.25, 0.75, 0, 0],
+        "125": [0.25, 0.75, 0, 0],
+        "126": [0.35, 0.34444, 0, 0],
+        "168": [0, 0.69444, 0, 0],
+        "172": [0, 0.44444, 0, 0],
+        "175": [0, 0.59611, 0, 0],
+        "176": [0, 0.69444, 0, 0],
+        "177": [0.13333, 0.63333, 0, 0],
+        "180": [0, 0.69444, 0, 0],
+        "215": [0.13333, 0.63333, 0, 0],
+        "247": [0.13333, 0.63333, 0, 0],
+        "305": [0, 0.44444, 0, 0],
+        "567": [0.19444, 0.44444, 0, 0],
+        "710": [0, 0.69444, 0, 0],
+        "711": [0, 0.63194, 0, 0],
+        "713": [0, 0.59611, 0, 0],
+        "714": [0, 0.69444, 0, 0],
+        "715": [0, 0.69444, 0, 0],
+        "728": [0, 0.69444, 0, 0],
+        "729": [0, 0.69444, 0, 0],
+        "730": [0, 0.69444, 0, 0],
+        "732": [0, 0.69444, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.69444, 0, 0],
+        "772": [0, 0.59611, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.69444, 0, 0],
+        "776": [0, 0.69444, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.63194, 0, 0],
+        "824": [0.19444, 0.69444, 0, 0],
+        "915": [0, 0.68611, 0, 0],
+        "916": [0, 0.68611, 0, 0],
+        "920": [0, 0.68611, 0, 0],
+        "923": [0, 0.68611, 0, 0],
+        "926": [0, 0.68611, 0, 0],
+        "928": [0, 0.68611, 0, 0],
+        "931": [0, 0.68611, 0, 0],
+        "933": [0, 0.68611, 0, 0],
+        "934": [0, 0.68611, 0, 0],
+        "936": [0, 0.68611, 0, 0],
+        "937": [0, 0.68611, 0, 0],
+        "8211": [0, 0.44444, 0.03194, 0],
+        "8212": [0, 0.44444, 0.03194, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0],
+        "8224": [0.19444, 0.69444, 0, 0],
+        "8225": [0.19444, 0.69444, 0, 0],
+        "8242": [0, 0.55556, 0, 0],
+        "8407": [0, 0.72444, 0.15486, 0],
+        "8463": [0, 0.69444, 0, 0],
+        "8465": [0, 0.69444, 0, 0],
+        "8467": [0, 0.69444, 0, 0],
+        "8472": [0.19444, 0.44444, 0, 0],
+        "8476": [0, 0.69444, 0, 0],
+        "8501": [0, 0.69444, 0, 0],
+        "8592": [-0.10889, 0.39111, 0, 0],
+        "8593": [0.19444, 0.69444, 0, 0],
+        "8594": [-0.10889, 0.39111, 0, 0],
+        "8595": [0.19444, 0.69444, 0, 0],
+        "8596": [-0.10889, 0.39111, 0, 0],
+        "8597": [0.25, 0.75, 0, 0],
+        "8598": [0.19444, 0.69444, 0, 0],
+        "8599": [0.19444, 0.69444, 0, 0],
+        "8600": [0.19444, 0.69444, 0, 0],
+        "8601": [0.19444, 0.69444, 0, 0],
+        "8636": [-0.10889, 0.39111, 0, 0],
+        "8637": [-0.10889, 0.39111, 0, 0],
+        "8640": [-0.10889, 0.39111, 0, 0],
+        "8641": [-0.10889, 0.39111, 0, 0],
+        "8656": [-0.10889, 0.39111, 0, 0],
+        "8657": [0.19444, 0.69444, 0, 0],
+        "8658": [-0.10889, 0.39111, 0, 0],
+        "8659": [0.19444, 0.69444, 0, 0],
+        "8660": [-0.10889, 0.39111, 0, 0],
+        "8661": [0.25, 0.75, 0, 0],
+        "8704": [0, 0.69444, 0, 0],
+        "8706": [0, 0.69444, 0.06389, 0],
+        "8707": [0, 0.69444, 0, 0],
+        "8709": [0.05556, 0.75, 0, 0],
+        "8711": [0, 0.68611, 0, 0],
+        "8712": [0.08556, 0.58556, 0, 0],
+        "8715": [0.08556, 0.58556, 0, 0],
+        "8722": [0.13333, 0.63333, 0, 0],
+        "8723": [0.13333, 0.63333, 0, 0],
+        "8725": [0.25, 0.75, 0, 0],
+        "8726": [0.25, 0.75, 0, 0],
+        "8727": [-0.02778, 0.47222, 0, 0],
+        "8728": [-0.02639, 0.47361, 0, 0],
+        "8729": [-0.02639, 0.47361, 0, 0],
+        "8730": [0.18, 0.82, 0, 0],
+        "8733": [0, 0.44444, 0, 0],
+        "8734": [0, 0.44444, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8739": [0.25, 0.75, 0, 0],
+        "8741": [0.25, 0.75, 0, 0],
+        "8743": [0, 0.55556, 0, 0],
+        "8744": [0, 0.55556, 0, 0],
+        "8745": [0, 0.55556, 0, 0],
+        "8746": [0, 0.55556, 0, 0],
+        "8747": [0.19444, 0.69444, 0.12778, 0],
+        "8764": [-0.10889, 0.39111, 0, 0],
+        "8768": [0.19444, 0.69444, 0, 0],
+        "8771": [0.00222, 0.50222, 0, 0],
+        "8776": [0.02444, 0.52444, 0, 0],
+        "8781": [0.00222, 0.50222, 0, 0],
+        "8801": [0.00222, 0.50222, 0, 0],
+        "8804": [0.19667, 0.69667, 0, 0],
+        "8805": [0.19667, 0.69667, 0, 0],
+        "8810": [0.08556, 0.58556, 0, 0],
+        "8811": [0.08556, 0.58556, 0, 0],
+        "8826": [0.08556, 0.58556, 0, 0],
+        "8827": [0.08556, 0.58556, 0, 0],
+        "8834": [0.08556, 0.58556, 0, 0],
+        "8835": [0.08556, 0.58556, 0, 0],
+        "8838": [0.19667, 0.69667, 0, 0],
+        "8839": [0.19667, 0.69667, 0, 0],
+        "8846": [0, 0.55556, 0, 0],
+        "8849": [0.19667, 0.69667, 0, 0],
+        "8850": [0.19667, 0.69667, 0, 0],
+        "8851": [0, 0.55556, 0, 0],
+        "8852": [0, 0.55556, 0, 0],
+        "8853": [0.13333, 0.63333, 0, 0],
+        "8854": [0.13333, 0.63333, 0, 0],
+        "8855": [0.13333, 0.63333, 0, 0],
+        "8856": [0.13333, 0.63333, 0, 0],
+        "8857": [0.13333, 0.63333, 0, 0],
+        "8866": [0, 0.69444, 0, 0],
+        "8867": [0, 0.69444, 0, 0],
+        "8868": [0, 0.69444, 0, 0],
+        "8869": [0, 0.69444, 0, 0],
+        "8900": [-0.02639, 0.47361, 0, 0],
+        "8901": [-0.02639, 0.47361, 0, 0],
+        "8902": [-0.02778, 0.47222, 0, 0],
+        "8968": [0.25, 0.75, 0, 0],
+        "8969": [0.25, 0.75, 0, 0],
+        "8970": [0.25, 0.75, 0, 0],
+        "8971": [0.25, 0.75, 0, 0],
+        "8994": [-0.13889, 0.36111, 0, 0],
+        "8995": [-0.13889, 0.36111, 0, 0],
+        "9651": [0.19444, 0.69444, 0, 0],
+        "9657": [-0.02778, 0.47222, 0, 0],
+        "9661": [0.19444, 0.69444, 0, 0],
+        "9667": [-0.02778, 0.47222, 0, 0],
+        "9711": [0.19444, 0.69444, 0, 0],
+        "9824": [0.12963, 0.69444, 0, 0],
+        "9825": [0.12963, 0.69444, 0, 0],
+        "9826": [0.12963, 0.69444, 0, 0],
+        "9827": [0.12963, 0.69444, 0, 0],
+        "9837": [0, 0.75, 0, 0],
+        "9838": [0.19444, 0.69444, 0, 0],
+        "9839": [0.19444, 0.69444, 0, 0],
+        "10216": [0.25, 0.75, 0, 0],
+        "10217": [0.25, 0.75, 0, 0],
+        "10815": [0, 0.68611, 0, 0],
+        "10927": [0.19667, 0.69667, 0, 0],
+        "10928": [0.19667, 0.69667, 0, 0]
+    },
+    "Main-Italic": {
+        "33": [0, 0.69444, 0.12417, 0],
+        "34": [0, 0.69444, 0.06961, 0],
+        "35": [0.19444, 0.69444, 0.06616, 0],
+        "37": [0.05556, 0.75, 0.13639, 0],
+        "38": [0, 0.69444, 0.09694, 0],
+        "39": [0, 0.69444, 0.12417, 0],
+        "40": [0.25, 0.75, 0.16194, 0],
+        "41": [0.25, 0.75, 0.03694, 0],
+        "42": [0, 0.75, 0.14917, 0],
+        "43": [0.05667, 0.56167, 0.03694, 0],
+        "44": [0.19444, 0.10556, 0, 0],
+        "45": [0, 0.43056, 0.02826, 0],
+        "46": [0, 0.10556, 0, 0],
+        "47": [0.25, 0.75, 0.16194, 0],
+        "48": [0, 0.64444, 0.13556, 0],
+        "49": [0, 0.64444, 0.13556, 0],
+        "50": [0, 0.64444, 0.13556, 0],
+        "51": [0, 0.64444, 0.13556, 0],
+        "52": [0.19444, 0.64444, 0.13556, 0],
+        "53": [0, 0.64444, 0.13556, 0],
+        "54": [0, 0.64444, 0.13556, 0],
+        "55": [0.19444, 0.64444, 0.13556, 0],
+        "56": [0, 0.64444, 0.13556, 0],
+        "57": [0, 0.64444, 0.13556, 0],
+        "58": [0, 0.43056, 0.0582, 0],
+        "59": [0.19444, 0.43056, 0.0582, 0],
+        "61": [-0.13313, 0.36687, 0.06616, 0],
+        "63": [0, 0.69444, 0.1225, 0],
+        "64": [0, 0.69444, 0.09597, 0],
+        "65": [0, 0.68333, 0, 0],
+        "66": [0, 0.68333, 0.10257, 0],
+        "67": [0, 0.68333, 0.14528, 0],
+        "68": [0, 0.68333, 0.09403, 0],
+        "69": [0, 0.68333, 0.12028, 0],
+        "70": [0, 0.68333, 0.13305, 0],
+        "71": [0, 0.68333, 0.08722, 0],
+        "72": [0, 0.68333, 0.16389, 0],
+        "73": [0, 0.68333, 0.15806, 0],
+        "74": [0, 0.68333, 0.14028, 0],
+        "75": [0, 0.68333, 0.14528, 0],
+        "76": [0, 0.68333, 0, 0],
+        "77": [0, 0.68333, 0.16389, 0],
+        "78": [0, 0.68333, 0.16389, 0],
+        "79": [0, 0.68333, 0.09403, 0],
+        "80": [0, 0.68333, 0.10257, 0],
+        "81": [0.19444, 0.68333, 0.09403, 0],
+        "82": [0, 0.68333, 0.03868, 0],
+        "83": [0, 0.68333, 0.11972, 0],
+        "84": [0, 0.68333, 0.13305, 0],
+        "85": [0, 0.68333, 0.16389, 0],
+        "86": [0, 0.68333, 0.18361, 0],
+        "87": [0, 0.68333, 0.18361, 0],
+        "88": [0, 0.68333, 0.15806, 0],
+        "89": [0, 0.68333, 0.19383, 0],
+        "90": [0, 0.68333, 0.14528, 0],
+        "91": [0.25, 0.75, 0.1875, 0],
+        "93": [0.25, 0.75, 0.10528, 0],
+        "94": [0, 0.69444, 0.06646, 0],
+        "95": [0.31, 0.12056, 0.09208, 0],
+        "97": [0, 0.43056, 0.07671, 0],
+        "98": [0, 0.69444, 0.06312, 0],
+        "99": [0, 0.43056, 0.05653, 0],
+        "100": [0, 0.69444, 0.10333, 0],
+        "101": [0, 0.43056, 0.07514, 0],
+        "102": [0.19444, 0.69444, 0.21194, 0],
+        "103": [0.19444, 0.43056, 0.08847, 0],
+        "104": [0, 0.69444, 0.07671, 0],
+        "105": [0, 0.65536, 0.1019, 0],
+        "106": [0.19444, 0.65536, 0.14467, 0],
+        "107": [0, 0.69444, 0.10764, 0],
+        "108": [0, 0.69444, 0.10333, 0],
+        "109": [0, 0.43056, 0.07671, 0],
+        "110": [0, 0.43056, 0.07671, 0],
+        "111": [0, 0.43056, 0.06312, 0],
+        "112": [0.19444, 0.43056, 0.06312, 0],
+        "113": [0.19444, 0.43056, 0.08847, 0],
+        "114": [0, 0.43056, 0.10764, 0],
+        "115": [0, 0.43056, 0.08208, 0],
+        "116": [0, 0.61508, 0.09486, 0],
+        "117": [0, 0.43056, 0.07671, 0],
+        "118": [0, 0.43056, 0.10764, 0],
+        "119": [0, 0.43056, 0.10764, 0],
+        "120": [0, 0.43056, 0.12042, 0],
+        "121": [0.19444, 0.43056, 0.08847, 0],
+        "122": [0, 0.43056, 0.12292, 0],
+        "126": [0.35, 0.31786, 0.11585, 0],
+        "163": [0, 0.69444, 0, 0],
+        "305": [0, 0.43056, 0, 0.02778],
+        "567": [0.19444, 0.43056, 0, 0.08334],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0.09694, 0],
+        "770": [0, 0.69444, 0.06646, 0],
+        "771": [0, 0.66786, 0.11585, 0],
+        "772": [0, 0.56167, 0.10333, 0],
+        "774": [0, 0.69444, 0.10806, 0],
+        "775": [0, 0.66786, 0.11752, 0],
+        "776": [0, 0.66786, 0.10474, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0.1225, 0],
+        "780": [0, 0.62847, 0.08295, 0],
+        "915": [0, 0.68333, 0.13305, 0],
+        "916": [0, 0.68333, 0, 0],
+        "920": [0, 0.68333, 0.09403, 0],
+        "923": [0, 0.68333, 0, 0],
+        "926": [0, 0.68333, 0.15294, 0],
+        "928": [0, 0.68333, 0.16389, 0],
+        "931": [0, 0.68333, 0.12028, 0],
+        "933": [0, 0.68333, 0.11111, 0],
+        "934": [0, 0.68333, 0.05986, 0],
+        "936": [0, 0.68333, 0.11111, 0],
+        "937": [0, 0.68333, 0.10257, 0],
+        "8211": [0, 0.43056, 0.09208, 0],
+        "8212": [0, 0.43056, 0.09208, 0],
+        "8216": [0, 0.69444, 0.12417, 0],
+        "8217": [0, 0.69444, 0.12417, 0],
+        "8220": [0, 0.69444, 0.1685, 0],
+        "8221": [0, 0.69444, 0.06961, 0],
+        "8463": [0, 0.68889, 0, 0]
+    },
+    "Main-Regular": {
+        "32": [0, 0, 0, 0],
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.08333, 0.58333, 0, 0],
+        "44": [0.19444, 0.10556, 0, 0],
+        "45": [0, 0.43056, 0, 0],
+        "46": [0, 0.10556, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.64444, 0, 0],
+        "49": [0, 0.64444, 0, 0],
+        "50": [0, 0.64444, 0, 0],
+        "51": [0, 0.64444, 0, 0],
+        "52": [0, 0.64444, 0, 0],
+        "53": [0, 0.64444, 0, 0],
+        "54": [0, 0.64444, 0, 0],
+        "55": [0, 0.64444, 0, 0],
+        "56": [0, 0.64444, 0, 0],
+        "57": [0, 0.64444, 0, 0],
+        "58": [0, 0.43056, 0, 0],
+        "59": [0.19444, 0.43056, 0, 0],
+        "60": [0.0391, 0.5391, 0, 0],
+        "61": [-0.13313, 0.36687, 0, 0],
+        "62": [0.0391, 0.5391, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.68333, 0, 0],
+        "66": [0, 0.68333, 0, 0],
+        "67": [0, 0.68333, 0, 0],
+        "68": [0, 0.68333, 0, 0],
+        "69": [0, 0.68333, 0, 0],
+        "70": [0, 0.68333, 0, 0],
+        "71": [0, 0.68333, 0, 0],
+        "72": [0, 0.68333, 0, 0],
+        "73": [0, 0.68333, 0, 0],
+        "74": [0, 0.68333, 0, 0],
+        "75": [0, 0.68333, 0, 0],
+        "76": [0, 0.68333, 0, 0],
+        "77": [0, 0.68333, 0, 0],
+        "78": [0, 0.68333, 0, 0],
+        "79": [0, 0.68333, 0, 0],
+        "80": [0, 0.68333, 0, 0],
+        "81": [0.19444, 0.68333, 0, 0],
+        "82": [0, 0.68333, 0, 0],
+        "83": [0, 0.68333, 0, 0],
+        "84": [0, 0.68333, 0, 0],
+        "85": [0, 0.68333, 0, 0],
+        "86": [0, 0.68333, 0.01389, 0],
+        "87": [0, 0.68333, 0.01389, 0],
+        "88": [0, 0.68333, 0, 0],
+        "89": [0, 0.68333, 0.025, 0],
+        "90": [0, 0.68333, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "92": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.31, 0.12056, 0.02778, 0],
+        "96": [0, 0.69444, 0, 0],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.43056, 0, 0],
+        "102": [0, 0.69444, 0.07778, 0],
+        "103": [0.19444, 0.43056, 0.01389, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.66786, 0, 0],
+        "106": [0.19444, 0.66786, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0],
+        "112": [0.19444, 0.43056, 0, 0],
+        "113": [0.19444, 0.43056, 0, 0],
+        "114": [0, 0.43056, 0, 0],
+        "115": [0, 0.43056, 0, 0],
+        "116": [0, 0.61508, 0, 0],
+        "117": [0, 0.43056, 0, 0],
+        "118": [0, 0.43056, 0.01389, 0],
+        "119": [0, 0.43056, 0.01389, 0],
+        "120": [0, 0.43056, 0, 0],
+        "121": [0.19444, 0.43056, 0.01389, 0],
+        "122": [0, 0.43056, 0, 0],
+        "123": [0.25, 0.75, 0, 0],
+        "124": [0.25, 0.75, 0, 0],
+        "125": [0.25, 0.75, 0, 0],
+        "126": [0.35, 0.31786, 0, 0],
+        "160": [0, 0, 0, 0],
+        "168": [0, 0.66786, 0, 0],
+        "172": [0, 0.43056, 0, 0],
+        "175": [0, 0.56778, 0, 0],
+        "176": [0, 0.69444, 0, 0],
+        "177": [0.08333, 0.58333, 0, 0],
+        "180": [0, 0.69444, 0, 0],
+        "215": [0.08333, 0.58333, 0, 0],
+        "247": [0.08333, 0.58333, 0, 0],
+        "305": [0, 0.43056, 0, 0],
+        "567": [0.19444, 0.43056, 0, 0],
+        "710": [0, 0.69444, 0, 0],
+        "711": [0, 0.62847, 0, 0],
+        "713": [0, 0.56778, 0, 0],
+        "714": [0, 0.69444, 0, 0],
+        "715": [0, 0.69444, 0, 0],
+        "728": [0, 0.69444, 0, 0],
+        "729": [0, 0.66786, 0, 0],
+        "730": [0, 0.69444, 0, 0],
+        "732": [0, 0.66786, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.66786, 0, 0],
+        "772": [0, 0.56778, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.66786, 0, 0],
+        "776": [0, 0.66786, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.62847, 0, 0],
+        "824": [0.19444, 0.69444, 0, 0],
+        "915": [0, 0.68333, 0, 0],
+        "916": [0, 0.68333, 0, 0],
+        "920": [0, 0.68333, 0, 0],
+        "923": [0, 0.68333, 0, 0],
+        "926": [0, 0.68333, 0, 0],
+        "928": [0, 0.68333, 0, 0],
+        "931": [0, 0.68333, 0, 0],
+        "933": [0, 0.68333, 0, 0],
+        "934": [0, 0.68333, 0, 0],
+        "936": [0, 0.68333, 0, 0],
+        "937": [0, 0.68333, 0, 0],
+        "8211": [0, 0.43056, 0.02778, 0],
+        "8212": [0, 0.43056, 0.02778, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0],
+        "8224": [0.19444, 0.69444, 0, 0],
+        "8225": [0.19444, 0.69444, 0, 0],
+        "8230": [0, 0.12, 0, 0],
+        "8242": [0, 0.55556, 0, 0],
+        "8407": [0, 0.71444, 0.15382, 0],
+        "8463": [0, 0.68889, 0, 0],
+        "8465": [0, 0.69444, 0, 0],
+        "8467": [0, 0.69444, 0, 0.11111],
+        "8472": [0.19444, 0.43056, 0, 0.11111],
+        "8476": [0, 0.69444, 0, 0],
+        "8501": [0, 0.69444, 0, 0],
+        "8592": [-0.13313, 0.36687, 0, 0],
+        "8593": [0.19444, 0.69444, 0, 0],
+        "8594": [-0.13313, 0.36687, 0, 0],
+        "8595": [0.19444, 0.69444, 0, 0],
+        "8596": [-0.13313, 0.36687, 0, 0],
+        "8597": [0.25, 0.75, 0, 0],
+        "8598": [0.19444, 0.69444, 0, 0],
+        "8599": [0.19444, 0.69444, 0, 0],
+        "8600": [0.19444, 0.69444, 0, 0],
+        "8601": [0.19444, 0.69444, 0, 0],
+        "8614": [0.011, 0.511, 0, 0],
+        "8617": [0.011, 0.511, 0, 0],
+        "8618": [0.011, 0.511, 0, 0],
+        "8636": [-0.13313, 0.36687, 0, 0],
+        "8637": [-0.13313, 0.36687, 0, 0],
+        "8640": [-0.13313, 0.36687, 0, 0],
+        "8641": [-0.13313, 0.36687, 0, 0],
+        "8652": [0.011, 0.671, 0, 0],
+        "8656": [-0.13313, 0.36687, 0, 0],
+        "8657": [0.19444, 0.69444, 0, 0],
+        "8658": [-0.13313, 0.36687, 0, 0],
+        "8659": [0.19444, 0.69444, 0, 0],
+        "8660": [-0.13313, 0.36687, 0, 0],
+        "8661": [0.25, 0.75, 0, 0],
+        "8704": [0, 0.69444, 0, 0],
+        "8706": [0, 0.69444, 0.05556, 0.08334],
+        "8707": [0, 0.69444, 0, 0],
+        "8709": [0.05556, 0.75, 0, 0],
+        "8711": [0, 0.68333, 0, 0],
+        "8712": [0.0391, 0.5391, 0, 0],
+        "8715": [0.0391, 0.5391, 0, 0],
+        "8722": [0.08333, 0.58333, 0, 0],
+        "8723": [0.08333, 0.58333, 0, 0],
+        "8725": [0.25, 0.75, 0, 0],
+        "8726": [0.25, 0.75, 0, 0],
+        "8727": [-0.03472, 0.46528, 0, 0],
+        "8728": [-0.05555, 0.44445, 0, 0],
+        "8729": [-0.05555, 0.44445, 0, 0],
+        "8730": [0.2, 0.8, 0, 0],
+        "8733": [0, 0.43056, 0, 0],
+        "8734": [0, 0.43056, 0, 0],
+        "8736": [0, 0.69224, 0, 0],
+        "8739": [0.25, 0.75, 0, 0],
+        "8741": [0.25, 0.75, 0, 0],
+        "8743": [0, 0.55556, 0, 0],
+        "8744": [0, 0.55556, 0, 0],
+        "8745": [0, 0.55556, 0, 0],
+        "8746": [0, 0.55556, 0, 0],
+        "8747": [0.19444, 0.69444, 0.11111, 0],
+        "8764": [-0.13313, 0.36687, 0, 0],
+        "8768": [0.19444, 0.69444, 0, 0],
+        "8771": [-0.03625, 0.46375, 0, 0],
+        "8773": [-0.022, 0.589, 0, 0],
+        "8776": [-0.01688, 0.48312, 0, 0],
+        "8781": [-0.03625, 0.46375, 0, 0],
+        "8784": [-0.133, 0.67, 0, 0],
+        "8800": [0.215, 0.716, 0, 0],
+        "8801": [-0.03625, 0.46375, 0, 0],
+        "8804": [0.13597, 0.63597, 0, 0],
+        "8805": [0.13597, 0.63597, 0, 0],
+        "8810": [0.0391, 0.5391, 0, 0],
+        "8811": [0.0391, 0.5391, 0, 0],
+        "8826": [0.0391, 0.5391, 0, 0],
+        "8827": [0.0391, 0.5391, 0, 0],
+        "8834": [0.0391, 0.5391, 0, 0],
+        "8835": [0.0391, 0.5391, 0, 0],
+        "8838": [0.13597, 0.63597, 0, 0],
+        "8839": [0.13597, 0.63597, 0, 0],
+        "8846": [0, 0.55556, 0, 0],
+        "8849": [0.13597, 0.63597, 0, 0],
+        "8850": [0.13597, 0.63597, 0, 0],
+        "8851": [0, 0.55556, 0, 0],
+        "8852": [0, 0.55556, 0, 0],
+        "8853": [0.08333, 0.58333, 0, 0],
+        "8854": [0.08333, 0.58333, 0, 0],
+        "8855": [0.08333, 0.58333, 0, 0],
+        "8856": [0.08333, 0.58333, 0, 0],
+        "8857": [0.08333, 0.58333, 0, 0],
+        "8866": [0, 0.69444, 0, 0],
+        "8867": [0, 0.69444, 0, 0],
+        "8868": [0, 0.69444, 0, 0],
+        "8869": [0, 0.69444, 0, 0],
+        "8872": [0.249, 0.75, 0, 0],
+        "8900": [-0.05555, 0.44445, 0, 0],
+        "8901": [-0.05555, 0.44445, 0, 0],
+        "8902": [-0.03472, 0.46528, 0, 0],
+        "8904": [0.005, 0.505, 0, 0],
+        "8942": [0.03, 0.9, 0, 0],
+        "8943": [-0.19, 0.31, 0, 0],
+        "8945": [-0.1, 0.82, 0, 0],
+        "8968": [0.25, 0.75, 0, 0],
+        "8969": [0.25, 0.75, 0, 0],
+        "8970": [0.25, 0.75, 0, 0],
+        "8971": [0.25, 0.75, 0, 0],
+        "8994": [-0.14236, 0.35764, 0, 0],
+        "8995": [-0.14236, 0.35764, 0, 0],
+        "9136": [0.244, 0.744, 0, 0],
+        "9137": [0.244, 0.744, 0, 0],
+        "9651": [0.19444, 0.69444, 0, 0],
+        "9657": [-0.03472, 0.46528, 0, 0],
+        "9661": [0.19444, 0.69444, 0, 0],
+        "9667": [-0.03472, 0.46528, 0, 0],
+        "9711": [0.19444, 0.69444, 0, 0],
+        "9824": [0.12963, 0.69444, 0, 0],
+        "9825": [0.12963, 0.69444, 0, 0],
+        "9826": [0.12963, 0.69444, 0, 0],
+        "9827": [0.12963, 0.69444, 0, 0],
+        "9837": [0, 0.75, 0, 0],
+        "9838": [0.19444, 0.69444, 0, 0],
+        "9839": [0.19444, 0.69444, 0, 0],
+        "10216": [0.25, 0.75, 0, 0],
+        "10217": [0.25, 0.75, 0, 0],
+        "10222": [0.244, 0.744, 0, 0],
+        "10223": [0.244, 0.744, 0, 0],
+        "10229": [0.011, 0.511, 0, 0],
+        "10230": [0.011, 0.511, 0, 0],
+        "10231": [0.011, 0.511, 0, 0],
+        "10232": [0.024, 0.525, 0, 0],
+        "10233": [0.024, 0.525, 0, 0],
+        "10234": [0.024, 0.525, 0, 0],
+        "10236": [0.011, 0.511, 0, 0],
+        "10815": [0, 0.68333, 0, 0],
+        "10927": [0.13597, 0.63597, 0, 0],
+        "10928": [0.13597, 0.63597, 0, 0]
+    },
+    "Math-BoldItalic": {
+        "47": [0.19444, 0.69444, 0, 0],
+        "65": [0, 0.68611, 0, 0],
+        "66": [0, 0.68611, 0.04835, 0],
+        "67": [0, 0.68611, 0.06979, 0],
+        "68": [0, 0.68611, 0.03194, 0],
+        "69": [0, 0.68611, 0.05451, 0],
+        "70": [0, 0.68611, 0.15972, 0],
+        "71": [0, 0.68611, 0, 0],
+        "72": [0, 0.68611, 0.08229, 0],
+        "73": [0, 0.68611, 0.07778, 0],
+        "74": [0, 0.68611, 0.10069, 0],
+        "75": [0, 0.68611, 0.06979, 0],
+        "76": [0, 0.68611, 0, 0],
+        "77": [0, 0.68611, 0.11424, 0],
+        "78": [0, 0.68611, 0.11424, 0],
+        "79": [0, 0.68611, 0.03194, 0],
+        "80": [0, 0.68611, 0.15972, 0],
+        "81": [0.19444, 0.68611, 0, 0],
+        "82": [0, 0.68611, 0.00421, 0],
+        "83": [0, 0.68611, 0.05382, 0],
+        "84": [0, 0.68611, 0.15972, 0],
+        "85": [0, 0.68611, 0.11424, 0],
+        "86": [0, 0.68611, 0.25555, 0],
+        "87": [0, 0.68611, 0.15972, 0],
+        "88": [0, 0.68611, 0.07778, 0],
+        "89": [0, 0.68611, 0.25555, 0],
+        "90": [0, 0.68611, 0.06979, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0.19444, 0.69444, 0.11042, 0],
+        "103": [0.19444, 0.44444, 0.03704, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.69326, 0, 0],
+        "106": [0.19444, 0.69326, 0.0622, 0],
+        "107": [0, 0.69444, 0.01852, 0],
+        "108": [0, 0.69444, 0.0088, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0.03704, 0],
+        "114": [0, 0.44444, 0.03194, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.63492, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.03704, 0],
+        "119": [0, 0.44444, 0.02778, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.03704, 0],
+        "122": [0, 0.44444, 0.04213, 0],
+        "915": [0, 0.68611, 0.15972, 0],
+        "916": [0, 0.68611, 0, 0],
+        "920": [0, 0.68611, 0.03194, 0],
+        "923": [0, 0.68611, 0, 0],
+        "926": [0, 0.68611, 0.07458, 0],
+        "928": [0, 0.68611, 0.08229, 0],
+        "931": [0, 0.68611, 0.05451, 0],
+        "933": [0, 0.68611, 0.15972, 0],
+        "934": [0, 0.68611, 0, 0],
+        "936": [0, 0.68611, 0.11653, 0],
+        "937": [0, 0.68611, 0.04835, 0],
+        "945": [0, 0.44444, 0, 0],
+        "946": [0.19444, 0.69444, 0.03403, 0],
+        "947": [0.19444, 0.44444, 0.06389, 0],
+        "948": [0, 0.69444, 0.03819, 0],
+        "949": [0, 0.44444, 0, 0],
+        "950": [0.19444, 0.69444, 0.06215, 0],
+        "951": [0.19444, 0.44444, 0.03704, 0],
+        "952": [0, 0.69444, 0.03194, 0],
+        "953": [0, 0.44444, 0, 0],
+        "954": [0, 0.44444, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.44444, 0, 0],
+        "957": [0, 0.44444, 0.06898, 0],
+        "958": [0.19444, 0.69444, 0.03021, 0],
+        "959": [0, 0.44444, 0, 0],
+        "960": [0, 0.44444, 0.03704, 0],
+        "961": [0.19444, 0.44444, 0, 0],
+        "962": [0.09722, 0.44444, 0.07917, 0],
+        "963": [0, 0.44444, 0.03704, 0],
+        "964": [0, 0.44444, 0.13472, 0],
+        "965": [0, 0.44444, 0.03704, 0],
+        "966": [0.19444, 0.44444, 0, 0],
+        "967": [0.19444, 0.44444, 0, 0],
+        "968": [0.19444, 0.69444, 0.03704, 0],
+        "969": [0, 0.44444, 0.03704, 0],
+        "977": [0, 0.69444, 0, 0],
+        "981": [0.19444, 0.69444, 0, 0],
+        "982": [0, 0.44444, 0.03194, 0],
+        "1009": [0.19444, 0.44444, 0, 0],
+        "1013": [0, 0.44444, 0, 0]
+    },
+    "Math-Italic": {
+        "47": [0.19444, 0.69444, 0, 0],
+        "65": [0, 0.68333, 0, 0.13889],
+        "66": [0, 0.68333, 0.05017, 0.08334],
+        "67": [0, 0.68333, 0.07153, 0.08334],
+        "68": [0, 0.68333, 0.02778, 0.05556],
+        "69": [0, 0.68333, 0.05764, 0.08334],
+        "70": [0, 0.68333, 0.13889, 0.08334],
+        "71": [0, 0.68333, 0, 0.08334],
+        "72": [0, 0.68333, 0.08125, 0.05556],
+        "73": [0, 0.68333, 0.07847, 0.11111],
+        "74": [0, 0.68333, 0.09618, 0.16667],
+        "75": [0, 0.68333, 0.07153, 0.05556],
+        "76": [0, 0.68333, 0, 0.02778],
+        "77": [0, 0.68333, 0.10903, 0.08334],
+        "78": [0, 0.68333, 0.10903, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.08334],
+        "80": [0, 0.68333, 0.13889, 0.08334],
+        "81": [0.19444, 0.68333, 0, 0.08334],
+        "82": [0, 0.68333, 0.00773, 0.08334],
+        "83": [0, 0.68333, 0.05764, 0.08334],
+        "84": [0, 0.68333, 0.13889, 0.08334],
+        "85": [0, 0.68333, 0.10903, 0.02778],
+        "86": [0, 0.68333, 0.22222, 0],
+        "87": [0, 0.68333, 0.13889, 0],
+        "88": [0, 0.68333, 0.07847, 0.08334],
+        "89": [0, 0.68333, 0.22222, 0],
+        "90": [0, 0.68333, 0.07153, 0.08334],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0.05556],
+        "100": [0, 0.69444, 0, 0.16667],
+        "101": [0, 0.43056, 0, 0.05556],
+        "102": [0.19444, 0.69444, 0.10764, 0.16667],
+        "103": [0.19444, 0.43056, 0.03588, 0.02778],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.65952, 0, 0],
+        "106": [0.19444, 0.65952, 0.05724, 0],
+        "107": [0, 0.69444, 0.03148, 0],
+        "108": [0, 0.69444, 0.01968, 0.08334],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0.05556],
+        "112": [0.19444, 0.43056, 0, 0.08334],
+        "113": [0.19444, 0.43056, 0.03588, 0.08334],
+        "114": [0, 0.43056, 0.02778, 0.05556],
+        "115": [0, 0.43056, 0, 0.05556],
+        "116": [0, 0.61508, 0, 0.08334],
+        "117": [0, 0.43056, 0, 0.02778],
+        "118": [0, 0.43056, 0.03588, 0.02778],
+        "119": [0, 0.43056, 0.02691, 0.08334],
+        "120": [0, 0.43056, 0, 0.02778],
+        "121": [0.19444, 0.43056, 0.03588, 0.05556],
+        "122": [0, 0.43056, 0.04398, 0.05556],
+        "915": [0, 0.68333, 0.13889, 0.08334],
+        "916": [0, 0.68333, 0, 0.16667],
+        "920": [0, 0.68333, 0.02778, 0.08334],
+        "923": [0, 0.68333, 0, 0.16667],
+        "926": [0, 0.68333, 0.07569, 0.08334],
+        "928": [0, 0.68333, 0.08125, 0.05556],
+        "931": [0, 0.68333, 0.05764, 0.08334],
+        "933": [0, 0.68333, 0.13889, 0.05556],
+        "934": [0, 0.68333, 0, 0.08334],
+        "936": [0, 0.68333, 0.11, 0.05556],
+        "937": [0, 0.68333, 0.05017, 0.08334],
+        "945": [0, 0.43056, 0.0037, 0.02778],
+        "946": [0.19444, 0.69444, 0.05278, 0.08334],
+        "947": [0.19444, 0.43056, 0.05556, 0],
+        "948": [0, 0.69444, 0.03785, 0.05556],
+        "949": [0, 0.43056, 0, 0.08334],
+        "950": [0.19444, 0.69444, 0.07378, 0.08334],
+        "951": [0.19444, 0.43056, 0.03588, 0.05556],
+        "952": [0, 0.69444, 0.02778, 0.08334],
+        "953": [0, 0.43056, 0, 0.05556],
+        "954": [0, 0.43056, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.43056, 0, 0.02778],
+        "957": [0, 0.43056, 0.06366, 0.02778],
+        "958": [0.19444, 0.69444, 0.04601, 0.11111],
+        "959": [0, 0.43056, 0, 0.05556],
+        "960": [0, 0.43056, 0.03588, 0],
+        "961": [0.19444, 0.43056, 0, 0.08334],
+        "962": [0.09722, 0.43056, 0.07986, 0.08334],
+        "963": [0, 0.43056, 0.03588, 0],
+        "964": [0, 0.43056, 0.1132, 0.02778],
+        "965": [0, 0.43056, 0.03588, 0.02778],
+        "966": [0.19444, 0.43056, 0, 0.08334],
+        "967": [0.19444, 0.43056, 0, 0.05556],
+        "968": [0.19444, 0.69444, 0.03588, 0.11111],
+        "969": [0, 0.43056, 0.03588, 0],
+        "977": [0, 0.69444, 0, 0.08334],
+        "981": [0.19444, 0.69444, 0, 0.08334],
+        "982": [0, 0.43056, 0.02778, 0],
+        "1009": [0.19444, 0.43056, 0, 0.08334],
+        "1013": [0, 0.43056, 0, 0.05556]
+    },
+    "Math-Regular": {
+        "65": [0, 0.68333, 0, 0.13889],
+        "66": [0, 0.68333, 0.05017, 0.08334],
+        "67": [0, 0.68333, 0.07153, 0.08334],
+        "68": [0, 0.68333, 0.02778, 0.05556],
+        "69": [0, 0.68333, 0.05764, 0.08334],
+        "70": [0, 0.68333, 0.13889, 0.08334],
+        "71": [0, 0.68333, 0, 0.08334],
+        "72": [0, 0.68333, 0.08125, 0.05556],
+        "73": [0, 0.68333, 0.07847, 0.11111],
+        "74": [0, 0.68333, 0.09618, 0.16667],
+        "75": [0, 0.68333, 0.07153, 0.05556],
+        "76": [0, 0.68333, 0, 0.02778],
+        "77": [0, 0.68333, 0.10903, 0.08334],
+        "78": [0, 0.68333, 0.10903, 0.08334],
+        "79": [0, 0.68333, 0.02778, 0.08334],
+        "80": [0, 0.68333, 0.13889, 0.08334],
+        "81": [0.19444, 0.68333, 0, 0.08334],
+        "82": [0, 0.68333, 0.00773, 0.08334],
+        "83": [0, 0.68333, 0.05764, 0.08334],
+        "84": [0, 0.68333, 0.13889, 0.08334],
+        "85": [0, 0.68333, 0.10903, 0.02778],
+        "86": [0, 0.68333, 0.22222, 0],
+        "87": [0, 0.68333, 0.13889, 0],
+        "88": [0, 0.68333, 0.07847, 0.08334],
+        "89": [0, 0.68333, 0.22222, 0],
+        "90": [0, 0.68333, 0.07153, 0.08334],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.43056, 0, 0.05556],
+        "100": [0, 0.69444, 0, 0.16667],
+        "101": [0, 0.43056, 0, 0.05556],
+        "102": [0.19444, 0.69444, 0.10764, 0.16667],
+        "103": [0.19444, 0.43056, 0.03588, 0.02778],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.65952, 0, 0],
+        "106": [0.19444, 0.65952, 0.05724, 0],
+        "107": [0, 0.69444, 0.03148, 0],
+        "108": [0, 0.69444, 0.01968, 0.08334],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0.05556],
+        "112": [0.19444, 0.43056, 0, 0.08334],
+        "113": [0.19444, 0.43056, 0.03588, 0.08334],
+        "114": [0, 0.43056, 0.02778, 0.05556],
+        "115": [0, 0.43056, 0, 0.05556],
+        "116": [0, 0.61508, 0, 0.08334],
+        "117": [0, 0.43056, 0, 0.02778],
+        "118": [0, 0.43056, 0.03588, 0.02778],
+        "119": [0, 0.43056, 0.02691, 0.08334],
+        "120": [0, 0.43056, 0, 0.02778],
+        "121": [0.19444, 0.43056, 0.03588, 0.05556],
+        "122": [0, 0.43056, 0.04398, 0.05556],
+        "915": [0, 0.68333, 0.13889, 0.08334],
+        "916": [0, 0.68333, 0, 0.16667],
+        "920": [0, 0.68333, 0.02778, 0.08334],
+        "923": [0, 0.68333, 0, 0.16667],
+        "926": [0, 0.68333, 0.07569, 0.08334],
+        "928": [0, 0.68333, 0.08125, 0.05556],
+        "931": [0, 0.68333, 0.05764, 0.08334],
+        "933": [0, 0.68333, 0.13889, 0.05556],
+        "934": [0, 0.68333, 0, 0.08334],
+        "936": [0, 0.68333, 0.11, 0.05556],
+        "937": [0, 0.68333, 0.05017, 0.08334],
+        "945": [0, 0.43056, 0.0037, 0.02778],
+        "946": [0.19444, 0.69444, 0.05278, 0.08334],
+        "947": [0.19444, 0.43056, 0.05556, 0],
+        "948": [0, 0.69444, 0.03785, 0.05556],
+        "949": [0, 0.43056, 0, 0.08334],
+        "950": [0.19444, 0.69444, 0.07378, 0.08334],
+        "951": [0.19444, 0.43056, 0.03588, 0.05556],
+        "952": [0, 0.69444, 0.02778, 0.08334],
+        "953": [0, 0.43056, 0, 0.05556],
+        "954": [0, 0.43056, 0, 0],
+        "955": [0, 0.69444, 0, 0],
+        "956": [0.19444, 0.43056, 0, 0.02778],
+        "957": [0, 0.43056, 0.06366, 0.02778],
+        "958": [0.19444, 0.69444, 0.04601, 0.11111],
+        "959": [0, 0.43056, 0, 0.05556],
+        "960": [0, 0.43056, 0.03588, 0],
+        "961": [0.19444, 0.43056, 0, 0.08334],
+        "962": [0.09722, 0.43056, 0.07986, 0.08334],
+        "963": [0, 0.43056, 0.03588, 0],
+        "964": [0, 0.43056, 0.1132, 0.02778],
+        "965": [0, 0.43056, 0.03588, 0.02778],
+        "966": [0.19444, 0.43056, 0, 0.08334],
+        "967": [0.19444, 0.43056, 0, 0.05556],
+        "968": [0.19444, 0.69444, 0.03588, 0.11111],
+        "969": [0, 0.43056, 0.03588, 0],
+        "977": [0, 0.69444, 0, 0.08334],
+        "981": [0.19444, 0.69444, 0, 0.08334],
+        "982": [0, 0.43056, 0.02778, 0],
+        "1009": [0.19444, 0.43056, 0, 0.08334],
+        "1013": [0, 0.43056, 0, 0.05556]
+    },
+    "SansSerif-Regular": {
+        "33": [0, 0.69444, 0, 0],
+        "34": [0, 0.69444, 0, 0],
+        "35": [0.19444, 0.69444, 0, 0],
+        "36": [0.05556, 0.75, 0, 0],
+        "37": [0.05556, 0.75, 0, 0],
+        "38": [0, 0.69444, 0, 0],
+        "39": [0, 0.69444, 0, 0],
+        "40": [0.25, 0.75, 0, 0],
+        "41": [0.25, 0.75, 0, 0],
+        "42": [0, 0.75, 0, 0],
+        "43": [0.08333, 0.58333, 0, 0],
+        "44": [0.125, 0.08333, 0, 0],
+        "45": [0, 0.44444, 0, 0],
+        "46": [0, 0.08333, 0, 0],
+        "47": [0.25, 0.75, 0, 0],
+        "48": [0, 0.65556, 0, 0],
+        "49": [0, 0.65556, 0, 0],
+        "50": [0, 0.65556, 0, 0],
+        "51": [0, 0.65556, 0, 0],
+        "52": [0, 0.65556, 0, 0],
+        "53": [0, 0.65556, 0, 0],
+        "54": [0, 0.65556, 0, 0],
+        "55": [0, 0.65556, 0, 0],
+        "56": [0, 0.65556, 0, 0],
+        "57": [0, 0.65556, 0, 0],
+        "58": [0, 0.44444, 0, 0],
+        "59": [0.125, 0.44444, 0, 0],
+        "61": [-0.13, 0.37, 0, 0],
+        "63": [0, 0.69444, 0, 0],
+        "64": [0, 0.69444, 0, 0],
+        "65": [0, 0.69444, 0, 0],
+        "66": [0, 0.69444, 0, 0],
+        "67": [0, 0.69444, 0, 0],
+        "68": [0, 0.69444, 0, 0],
+        "69": [0, 0.69444, 0, 0],
+        "70": [0, 0.69444, 0, 0],
+        "71": [0, 0.69444, 0, 0],
+        "72": [0, 0.69444, 0, 0],
+        "73": [0, 0.69444, 0, 0],
+        "74": [0, 0.69444, 0, 0],
+        "75": [0, 0.69444, 0, 0],
+        "76": [0, 0.69444, 0, 0],
+        "77": [0, 0.69444, 0, 0],
+        "78": [0, 0.69444, 0, 0],
+        "79": [0, 0.69444, 0, 0],
+        "80": [0, 0.69444, 0, 0],
+        "81": [0.125, 0.69444, 0, 0],
+        "82": [0, 0.69444, 0, 0],
+        "83": [0, 0.69444, 0, 0],
+        "84": [0, 0.69444, 0, 0],
+        "85": [0, 0.69444, 0, 0],
+        "86": [0, 0.69444, 0.01389, 0],
+        "87": [0, 0.69444, 0.01389, 0],
+        "88": [0, 0.69444, 0, 0],
+        "89": [0, 0.69444, 0.025, 0],
+        "90": [0, 0.69444, 0, 0],
+        "91": [0.25, 0.75, 0, 0],
+        "93": [0.25, 0.75, 0, 0],
+        "94": [0, 0.69444, 0, 0],
+        "95": [0.35, 0.09444, 0.02778, 0],
+        "97": [0, 0.44444, 0, 0],
+        "98": [0, 0.69444, 0, 0],
+        "99": [0, 0.44444, 0, 0],
+        "100": [0, 0.69444, 0, 0],
+        "101": [0, 0.44444, 0, 0],
+        "102": [0, 0.69444, 0.06944, 0],
+        "103": [0.19444, 0.44444, 0.01389, 0],
+        "104": [0, 0.69444, 0, 0],
+        "105": [0, 0.67937, 0, 0],
+        "106": [0.19444, 0.67937, 0, 0],
+        "107": [0, 0.69444, 0, 0],
+        "108": [0, 0.69444, 0, 0],
+        "109": [0, 0.44444, 0, 0],
+        "110": [0, 0.44444, 0, 0],
+        "111": [0, 0.44444, 0, 0],
+        "112": [0.19444, 0.44444, 0, 0],
+        "113": [0.19444, 0.44444, 0, 0],
+        "114": [0, 0.44444, 0.01389, 0],
+        "115": [0, 0.44444, 0, 0],
+        "116": [0, 0.57143, 0, 0],
+        "117": [0, 0.44444, 0, 0],
+        "118": [0, 0.44444, 0.01389, 0],
+        "119": [0, 0.44444, 0.01389, 0],
+        "120": [0, 0.44444, 0, 0],
+        "121": [0.19444, 0.44444, 0.01389, 0],
+        "122": [0, 0.44444, 0, 0],
+        "126": [0.35, 0.32659, 0, 0],
+        "305": [0, 0.44444, 0, 0],
+        "567": [0.19444, 0.44444, 0, 0],
+        "768": [0, 0.69444, 0, 0],
+        "769": [0, 0.69444, 0, 0],
+        "770": [0, 0.69444, 0, 0],
+        "771": [0, 0.67659, 0, 0],
+        "772": [0, 0.60889, 0, 0],
+        "774": [0, 0.69444, 0, 0],
+        "775": [0, 0.67937, 0, 0],
+        "776": [0, 0.67937, 0, 0],
+        "778": [0, 0.69444, 0, 0],
+        "779": [0, 0.69444, 0, 0],
+        "780": [0, 0.63194, 0, 0],
+        "915": [0, 0.69444, 0, 0],
+        "916": [0, 0.69444, 0, 0],
+        "920": [0, 0.69444, 0, 0],
+        "923": [0, 0.69444, 0, 0],
+        "926": [0, 0.69444, 0, 0],
+        "928": [0, 0.69444, 0, 0],
+        "931": [0, 0.69444, 0, 0],
+        "933": [0, 0.69444, 0, 0],
+        "934": [0, 0.69444, 0, 0],
+        "936": [0, 0.69444, 0, 0],
+        "937": [0, 0.69444, 0, 0],
+        "8211": [0, 0.44444, 0.02778, 0],
+        "8212": [0, 0.44444, 0.02778, 0],
+        "8216": [0, 0.69444, 0, 0],
+        "8217": [0, 0.69444, 0, 0],
+        "8220": [0, 0.69444, 0, 0],
+        "8221": [0, 0.69444, 0, 0]
+    },
+    "Script-Regular": {
+        "65": [0, 0.7, 0.22925, 0],
+        "66": [0, 0.7, 0.04087, 0],
+        "67": [0, 0.7, 0.1689, 0],
+        "68": [0, 0.7, 0.09371, 0],
+        "69": [0, 0.7, 0.18583, 0],
+        "70": [0, 0.7, 0.13634, 0],
+        "71": [0, 0.7, 0.17322, 0],
+        "72": [0, 0.7, 0.29694, 0],
+        "73": [0, 0.7, 0.19189, 0],
+        "74": [0.27778, 0.7, 0.19189, 0],
+        "75": [0, 0.7, 0.31259, 0],
+        "76": [0, 0.7, 0.19189, 0],
+        "77": [0, 0.7, 0.15981, 0],
+        "78": [0, 0.7, 0.3525, 0],
+        "79": [0, 0.7, 0.08078, 0],
+        "80": [0, 0.7, 0.08078, 0],
+        "81": [0, 0.7, 0.03305, 0],
+        "82": [0, 0.7, 0.06259, 0],
+        "83": [0, 0.7, 0.19189, 0],
+        "84": [0, 0.7, 0.29087, 0],
+        "85": [0, 0.7, 0.25815, 0],
+        "86": [0, 0.7, 0.27523, 0],
+        "87": [0, 0.7, 0.27523, 0],
+        "88": [0, 0.7, 0.26006, 0],
+        "89": [0, 0.7, 0.2939, 0],
+        "90": [0, 0.7, 0.24037, 0]
+    },
+    "Size1-Regular": {
+        "40": [0.35001, 0.85, 0, 0],
+        "41": [0.35001, 0.85, 0, 0],
+        "47": [0.35001, 0.85, 0, 0],
+        "91": [0.35001, 0.85, 0, 0],
+        "92": [0.35001, 0.85, 0, 0],
+        "93": [0.35001, 0.85, 0, 0],
+        "123": [0.35001, 0.85, 0, 0],
+        "125": [0.35001, 0.85, 0, 0],
+        "710": [0, 0.72222, 0, 0],
+        "732": [0, 0.72222, 0, 0],
+        "770": [0, 0.72222, 0, 0],
+        "771": [0, 0.72222, 0, 0],
+        "8214": [-0.00099, 0.601, 0, 0],
+        "8593": [1e-05, 0.6, 0, 0],
+        "8595": [1e-05, 0.6, 0, 0],
+        "8657": [1e-05, 0.6, 0, 0],
+        "8659": [1e-05, 0.6, 0, 0],
+        "8719": [0.25001, 0.75, 0, 0],
+        "8720": [0.25001, 0.75, 0, 0],
+        "8721": [0.25001, 0.75, 0, 0],
+        "8730": [0.35001, 0.85, 0, 0],
+        "8739": [-0.00599, 0.606, 0, 0],
+        "8741": [-0.00599, 0.606, 0, 0],
+        "8747": [0.30612, 0.805, 0.19445, 0],
+        "8748": [0.306, 0.805, 0.19445, 0],
+        "8749": [0.306, 0.805, 0.19445, 0],
+        "8750": [0.30612, 0.805, 0.19445, 0],
+        "8896": [0.25001, 0.75, 0, 0],
+        "8897": [0.25001, 0.75, 0, 0],
+        "8898": [0.25001, 0.75, 0, 0],
+        "8899": [0.25001, 0.75, 0, 0],
+        "8968": [0.35001, 0.85, 0, 0],
+        "8969": [0.35001, 0.85, 0, 0],
+        "8970": [0.35001, 0.85, 0, 0],
+        "8971": [0.35001, 0.85, 0, 0],
+        "9168": [-0.00099, 0.601, 0, 0],
+        "10216": [0.35001, 0.85, 0, 0],
+        "10217": [0.35001, 0.85, 0, 0],
+        "10752": [0.25001, 0.75, 0, 0],
+        "10753": [0.25001, 0.75, 0, 0],
+        "10754": [0.25001, 0.75, 0, 0],
+        "10756": [0.25001, 0.75, 0, 0],
+        "10758": [0.25001, 0.75, 0, 0]
+    },
+    "Size2-Regular": {
+        "40": [0.65002, 1.15, 0, 0],
+        "41": [0.65002, 1.15, 0, 0],
+        "47": [0.65002, 1.15, 0, 0],
+        "91": [0.65002, 1.15, 0, 0],
+        "92": [0.65002, 1.15, 0, 0],
+        "93": [0.65002, 1.15, 0, 0],
+        "123": [0.65002, 1.15, 0, 0],
+        "125": [0.65002, 1.15, 0, 0],
+        "710": [0, 0.75, 0, 0],
+        "732": [0, 0.75, 0, 0],
+        "770": [0, 0.75, 0, 0],
+        "771": [0, 0.75, 0, 0],
+        "8719": [0.55001, 1.05, 0, 0],
+        "8720": [0.55001, 1.05, 0, 0],
+        "8721": [0.55001, 1.05, 0, 0],
+        "8730": [0.65002, 1.15, 0, 0],
+        "8747": [0.86225, 1.36, 0.44445, 0],
+        "8748": [0.862, 1.36, 0.44445, 0],
+        "8749": [0.862, 1.36, 0.44445, 0],
+        "8750": [0.86225, 1.36, 0.44445, 0],
+        "8896": [0.55001, 1.05, 0, 0],
+        "8897": [0.55001, 1.05, 0, 0],
+        "8898": [0.55001, 1.05, 0, 0],
+        "8899": [0.55001, 1.05, 0, 0],
+        "8968": [0.65002, 1.15, 0, 0],
+        "8969": [0.65002, 1.15, 0, 0],
+        "8970": [0.65002, 1.15, 0, 0],
+        "8971": [0.65002, 1.15, 0, 0],
+        "10216": [0.65002, 1.15, 0, 0],
+        "10217": [0.65002, 1.15, 0, 0],
+        "10752": [0.55001, 1.05, 0, 0],
+        "10753": [0.55001, 1.05, 0, 0],
+        "10754": [0.55001, 1.05, 0, 0],
+        "10756": [0.55001, 1.05, 0, 0],
+        "10758": [0.55001, 1.05, 0, 0]
+    },
+    "Size3-Regular": {
+        "40": [0.95003, 1.45, 0, 0],
+        "41": [0.95003, 1.45, 0, 0],
+        "47": [0.95003, 1.45, 0, 0],
+        "91": [0.95003, 1.45, 0, 0],
+        "92": [0.95003, 1.45, 0, 0],
+        "93": [0.95003, 1.45, 0, 0],
+        "123": [0.95003, 1.45, 0, 0],
+        "125": [0.95003, 1.45, 0, 0],
+        "710": [0, 0.75, 0, 0],
+        "732": [0, 0.75, 0, 0],
+        "770": [0, 0.75, 0, 0],
+        "771": [0, 0.75, 0, 0],
+        "8730": [0.95003, 1.45, 0, 0],
+        "8968": [0.95003, 1.45, 0, 0],
+        "8969": [0.95003, 1.45, 0, 0],
+        "8970": [0.95003, 1.45, 0, 0],
+        "8971": [0.95003, 1.45, 0, 0],
+        "10216": [0.95003, 1.45, 0, 0],
+        "10217": [0.95003, 1.45, 0, 0]
+    },
+    "Size4-Regular": {
+        "40": [1.25003, 1.75, 0, 0],
+        "41": [1.25003, 1.75, 0, 0],
+        "47": [1.25003, 1.75, 0, 0],
+        "91": [1.25003, 1.75, 0, 0],
+        "92": [1.25003, 1.75, 0, 0],
+        "93": [1.25003, 1.75, 0, 0],
+        "123": [1.25003, 1.75, 0, 0],
+        "125": [1.25003, 1.75, 0, 0],
+        "710": [0, 0.825, 0, 0],
+        "732": [0, 0.825, 0, 0],
+        "770": [0, 0.825, 0, 0],
+        "771": [0, 0.825, 0, 0],
+        "8730": [1.25003, 1.75, 0, 0],
+        "8968": [1.25003, 1.75, 0, 0],
+        "8969": [1.25003, 1.75, 0, 0],
+        "8970": [1.25003, 1.75, 0, 0],
+        "8971": [1.25003, 1.75, 0, 0],
+        "9115": [0.64502, 1.155, 0, 0],
+        "9116": [1e-05, 0.6, 0, 0],
+        "9117": [0.64502, 1.155, 0, 0],
+        "9118": [0.64502, 1.155, 0, 0],
+        "9119": [1e-05, 0.6, 0, 0],
+        "9120": [0.64502, 1.155, 0, 0],
+        "9121": [0.64502, 1.155, 0, 0],
+        "9122": [-0.00099, 0.601, 0, 0],
+        "9123": [0.64502, 1.155, 0, 0],
+        "9124": [0.64502, 1.155, 0, 0],
+        "9125": [-0.00099, 0.601, 0, 0],
+        "9126": [0.64502, 1.155, 0, 0],
+        "9127": [1e-05, 0.9, 0, 0],
+        "9128": [0.65002, 1.15, 0, 0],
+        "9129": [0.90001, 0, 0, 0],
+        "9130": [0, 0.3, 0, 0],
+        "9131": [1e-05, 0.9, 0, 0],
+        "9132": [0.65002, 1.15, 0, 0],
+        "9133": [0.90001, 0, 0, 0],
+        "9143": [0.88502, 0.915, 0, 0],
+        "10216": [1.25003, 1.75, 0, 0],
+        "10217": [1.25003, 1.75, 0, 0],
+        "57344": [-0.00499, 0.605, 0, 0],
+        "57345": [-0.00499, 0.605, 0, 0],
+        "57680": [0, 0.12, 0, 0],
+        "57681": [0, 0.12, 0, 0],
+        "57682": [0, 0.12, 0, 0],
+        "57683": [0, 0.12, 0, 0]
+    },
+    "Typewriter-Regular": {
+        "33": [0, 0.61111, 0, 0],
+        "34": [0, 0.61111, 0, 0],
+        "35": [0, 0.61111, 0, 0],
+        "36": [0.08333, 0.69444, 0, 0],
+        "37": [0.08333, 0.69444, 0, 0],
+        "38": [0, 0.61111, 0, 0],
+        "39": [0, 0.61111, 0, 0],
+        "40": [0.08333, 0.69444, 0, 0],
+        "41": [0.08333, 0.69444, 0, 0],
+        "42": [0, 0.52083, 0, 0],
+        "43": [-0.08056, 0.53055, 0, 0],
+        "44": [0.13889, 0.125, 0, 0],
+        "45": [-0.08056, 0.53055, 0, 0],
+        "46": [0, 0.125, 0, 0],
+        "47": [0.08333, 0.69444, 0, 0],
+        "48": [0, 0.61111, 0, 0],
+        "49": [0, 0.61111, 0, 0],
+        "50": [0, 0.61111, 0, 0],
+        "51": [0, 0.61111, 0, 0],
+        "52": [0, 0.61111, 0, 0],
+        "53": [0, 0.61111, 0, 0],
+        "54": [0, 0.61111, 0, 0],
+        "55": [0, 0.61111, 0, 0],
+        "56": [0, 0.61111, 0, 0],
+        "57": [0, 0.61111, 0, 0],
+        "58": [0, 0.43056, 0, 0],
+        "59": [0.13889, 0.43056, 0, 0],
+        "60": [-0.05556, 0.55556, 0, 0],
+        "61": [-0.19549, 0.41562, 0, 0],
+        "62": [-0.05556, 0.55556, 0, 0],
+        "63": [0, 0.61111, 0, 0],
+        "64": [0, 0.61111, 0, 0],
+        "65": [0, 0.61111, 0, 0],
+        "66": [0, 0.61111, 0, 0],
+        "67": [0, 0.61111, 0, 0],
+        "68": [0, 0.61111, 0, 0],
+        "69": [0, 0.61111, 0, 0],
+        "70": [0, 0.61111, 0, 0],
+        "71": [0, 0.61111, 0, 0],
+        "72": [0, 0.61111, 0, 0],
+        "73": [0, 0.61111, 0, 0],
+        "74": [0, 0.61111, 0, 0],
+        "75": [0, 0.61111, 0, 0],
+        "76": [0, 0.61111, 0, 0],
+        "77": [0, 0.61111, 0, 0],
+        "78": [0, 0.61111, 0, 0],
+        "79": [0, 0.61111, 0, 0],
+        "80": [0, 0.61111, 0, 0],
+        "81": [0.13889, 0.61111, 0, 0],
+        "82": [0, 0.61111, 0, 0],
+        "83": [0, 0.61111, 0, 0],
+        "84": [0, 0.61111, 0, 0],
+        "85": [0, 0.61111, 0, 0],
+        "86": [0, 0.61111, 0, 0],
+        "87": [0, 0.61111, 0, 0],
+        "88": [0, 0.61111, 0, 0],
+        "89": [0, 0.61111, 0, 0],
+        "90": [0, 0.61111, 0, 0],
+        "91": [0.08333, 0.69444, 0, 0],
+        "92": [0.08333, 0.69444, 0, 0],
+        "93": [0.08333, 0.69444, 0, 0],
+        "94": [0, 0.61111, 0, 0],
+        "95": [0.09514, 0, 0, 0],
+        "96": [0, 0.61111, 0, 0],
+        "97": [0, 0.43056, 0, 0],
+        "98": [0, 0.61111, 0, 0],
+        "99": [0, 0.43056, 0, 0],
+        "100": [0, 0.61111, 0, 0],
+        "101": [0, 0.43056, 0, 0],
+        "102": [0, 0.61111, 0, 0],
+        "103": [0.22222, 0.43056, 0, 0],
+        "104": [0, 0.61111, 0, 0],
+        "105": [0, 0.61111, 0, 0],
+        "106": [0.22222, 0.61111, 0, 0],
+        "107": [0, 0.61111, 0, 0],
+        "108": [0, 0.61111, 0, 0],
+        "109": [0, 0.43056, 0, 0],
+        "110": [0, 0.43056, 0, 0],
+        "111": [0, 0.43056, 0, 0],
+        "112": [0.22222, 0.43056, 0, 0],
+        "113": [0.22222, 0.43056, 0, 0],
+        "114": [0, 0.43056, 0, 0],
+        "115": [0, 0.43056, 0, 0],
+        "116": [0, 0.55358, 0, 0],
+        "117": [0, 0.43056, 0, 0],
+        "118": [0, 0.43056, 0, 0],
+        "119": [0, 0.43056, 0, 0],
+        "120": [0, 0.43056, 0, 0],
+        "121": [0.22222, 0.43056, 0, 0],
+        "122": [0, 0.43056, 0, 0],
+        "123": [0.08333, 0.69444, 0, 0],
+        "124": [0.08333, 0.69444, 0, 0],
+        "125": [0.08333, 0.69444, 0, 0],
+        "126": [0, 0.61111, 0, 0],
+        "127": [0, 0.61111, 0, 0],
+        "305": [0, 0.43056, 0, 0],
+        "567": [0.22222, 0.43056, 0, 0],
+        "768": [0, 0.61111, 0, 0],
+        "769": [0, 0.61111, 0, 0],
+        "770": [0, 0.61111, 0, 0],
+        "771": [0, 0.61111, 0, 0],
+        "772": [0, 0.56555, 0, 0],
+        "774": [0, 0.61111, 0, 0],
+        "776": [0, 0.61111, 0, 0],
+        "778": [0, 0.61111, 0, 0],
+        "780": [0, 0.56597, 0, 0],
+        "915": [0, 0.61111, 0, 0],
+        "916": [0, 0.61111, 0, 0],
+        "920": [0, 0.61111, 0, 0],
+        "923": [0, 0.61111, 0, 0],
+        "926": [0, 0.61111, 0, 0],
+        "928": [0, 0.61111, 0, 0],
+        "931": [0, 0.61111, 0, 0],
+        "933": [0, 0.61111, 0, 0],
+        "934": [0, 0.61111, 0, 0],
+        "936": [0, 0.61111, 0, 0],
+        "937": [0, 0.61111, 0, 0],
+        "2018": [0, 0.61111, 0, 0],
+        "2019": [0, 0.61111, 0, 0],
+        "8242": [0, 0.61111, 0, 0]
+    }
+};
+
+},{}],19:[function(require,module,exports){
+var utils = require("./utils");
+var ParseError = require("./ParseError");
+var parseData = require("./parseData");
+var ParseNode = parseData.ParseNode;
+
+/* This file contains a list of functions that we parse, identified by
+ * the calls to defineFunction.
+ *
+ * The first argument to defineFunction is a single name or a list of names.
+ * All functions named in such a list will share a single implementation.
+ *
+ * Each declared function can have associated properties, which
+ * include the following:
+ *
+ *  - numArgs: The number of arguments the function takes.
+ *             If this is the only property, it can be passed as a number
+ *             instead of an element of a properties object.
+ *  - argTypes: (optional) An array corresponding to each argument of the
+ *              function, giving the type of argument that should be parsed. Its
+ *              length should be equal to `numArgs + numOptionalArgs`. Valid
+ *              types:
+ *               - "size": A size-like thing, such as "1em" or "5ex"
+ *               - "color": An html color, like "#abc" or "blue"
+ *               - "original": The same type as the environment that the
+ *                             function being parsed is in (e.g. used for the
+ *                             bodies of functions like \color where the first
+ *                             argument is special and the second argument is
+ *                             parsed normally)
+ *              Other possible types (probably shouldn't be used)
+ *               - "text": Text-like (e.g. \text)
+ *               - "math": Normal math
+ *              If undefined, this will be treated as an appropriate length
+ *              array of "original" strings
+ *  - greediness: (optional) The greediness of the function to use ungrouped
+ *                arguments.
+ *
+ *                E.g. if you have an expression
+ *                  \sqrt \frac 1 2
+ *                since \frac has greediness=2 vs \sqrt's greediness=1, \frac
+ *                will use the two arguments '1' and '2' as its two arguments,
+ *                then that whole function will be used as the argument to
+ *                \sqrt. On the other hand, the expressions
+ *                  \frac \frac 1 2 3
+ *                and
+ *                  \frac \sqrt 1 2
+ *                will fail because \frac and \frac have equal greediness
+ *                and \sqrt has a lower greediness than \frac respectively. To
+ *                make these parse, we would have to change them to:
+ *                  \frac {\frac 1 2} 3
+ *                and
+ *                  \frac {\sqrt 1} 2
+ *
+ *                The default value is `1`
+ *  - allowedInText: (optional) Whether or not the function is allowed inside
+ *                   text mode (default false)
+ *  - numOptionalArgs: (optional) The number of optional arguments the function
+ *                     should parse. If the optional arguments aren't found,
+ *                     `null` will be passed to the handler in their place.
+ *                     (default 0)
+ *  - infix: (optional) Must be true if the function is an infix operator.
+ *
+ * The last argument is that implementation, the handler for the function(s).
+ * It is called to handle these functions and their arguments.
+ * It receives two arguments:
+ *  - context contains information and references provided by the parser
+ *  - args is an array of arguments obtained from TeX input
+ * The context contains the following properties:
+ *  - funcName: the text (i.e. name) of the function, including \
+ *  - parser: the parser object
+ *  - lexer: the lexer object
+ *  - positions: the positions in the overall string of the function
+ *               and the arguments.
+ * The latter three should only be used to produce error messages.
+ *
+ * The function should return an object with the following keys:
+ *  - type: The type of element that this is. This is then used in
+ *          buildHTML/buildMathML to determine which function
+ *          should be called to build this node into a DOM node
+ * Any other data can be added to the object, which will be passed
+ * in to the function in buildHTML/buildMathML as `group.value`.
+ */
+
+function defineFunction(names, props, handler) {
+    if (typeof names === "string") {
+        names = [names];
+    }
+    if (typeof props === "number") {
+        props = { numArgs: props };
+    }
+    // Set default values of functions
+    var data = {
+        numArgs: props.numArgs,
+        argTypes: props.argTypes,
+        greediness: (props.greediness === undefined) ? 1 : props.greediness,
+        allowedInText: !!props.allowedInText,
+        numOptionalArgs: props.numOptionalArgs || 0,
+        infix: !!props.infix,
+        handler: handler
+    };
+    for (var i = 0; i < names.length; ++i) {
+        module.exports[names[i]] = data;
+    }
+}
+
+// Since the corresponding buildHTML/buildMathML function expects a
+// list of elements, we normalize for different kinds of arguments
+var ordargument = function(arg) {
+    if (arg.type === "ordgroup") {
+        return arg.value;
+    } else {
+        return [arg];
+    }
+};
+
+// A normal square root
+defineFunction("\\sqrt", {
+    numArgs: 1,
+    numOptionalArgs: 1
+}, function(context, args) {
+    var index = args[0];
+    var body = args[1];
+    return {
+        type: "sqrt",
+        body: body,
+        index: index
+    };
+});
+
+// Non-mathy text, possibly in a font
+var textFunctionStyles = {
+    "\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
+    "\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
+    "\\textit": "textit"
+};
+
+defineFunction([
+    "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
+    "\\textbf", "\\textit"
+], {
+    numArgs: 1,
+    argTypes: ["text"],
+    greediness: 2,
+    allowedInText: true
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "text",
+        body: ordargument(body),
+        style: textFunctionStyles[context.funcName]
+    };
+});
+
+// A two-argument custom color
+defineFunction("\\color", {
+    numArgs: 2,
+    allowedInText: true,
+    greediness: 3,
+    argTypes: ["color", "original"]
+}, function(context, args) {
+    var color = args[0];
+    var body = args[1];
+    return {
+        type: "color",
+        color: color.value,
+        value: ordargument(body)
+    };
+});
+
+// An overline
+defineFunction("\\overline", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "overline",
+        body: body
+    };
+});
+
+// An underline
+defineFunction("\\underline", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "underline",
+        body: body
+    };
+});
+
+// A box of the width and height
+defineFunction("\\rule", {
+    numArgs: 2,
+    numOptionalArgs: 1,
+    argTypes: ["size", "size", "size"]
+}, function(context, args) {
+    var shift = args[0];
+    var width = args[1];
+    var height = args[2];
+    return {
+        type: "rule",
+        shift: shift && shift.value,
+        width: width.value,
+        height: height.value
+    };
+});
+
+// TODO: In TeX, \mkern only accepts mu-units, and \kern does not accept
+// mu-units. In current KaTeX we relax this; both commands accept any unit.
+defineFunction(["\\kern", "\\mkern"], {
+    numArgs: 1,
+    argTypes: ["size"]
+}, function(context, args) {
+    return {
+        type: "kern",
+        dimension: args[0].value
+    };
+});
+
+// A KaTeX logo
+defineFunction("\\KaTeX", {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "katex"
+    };
+});
+
+defineFunction("\\phantom", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "phantom",
+        value: ordargument(body)
+    };
+});
+
+// Math class commands except \mathop
+defineFunction([
+    "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
+    "\\mathclose", "\\mathpunct", "\\mathinner"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "mclass",
+        mclass: "m" + context.funcName.substr(5),
+        value: ordargument(body)
+    };
+});
+
+// Build a relation by placing one symbol on top of another
+defineFunction("\\stackrel", {
+    numArgs: 2
+}, function(context, args) {
+    var top = args[0];
+    var bottom = args[1];
+
+    var bottomop = new ParseNode("op", {
+        type: "op",
+        limits: true,
+        alwaysHandleSupSub: true,
+        symbol: false,
+        value: ordargument(bottom)
+    }, bottom.mode);
+
+    var supsub = new ParseNode("supsub", {
+        base: bottomop,
+        sup: top,
+        sub: null
+    }, top.mode);
+
+    return {
+        type: "mclass",
+        mclass: "mrel",
+        value: [supsub]
+    };
+});
+
+// \mod-type functions
+defineFunction("\\bmod", {
+    numArgs: 0
+}, function(context, args) {
+    return {
+        type: "mod",
+        modType: "bmod",
+        value: null
+    };
+});
+
+defineFunction(["\\pod", "\\pmod", "\\mod"], {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "mod",
+        modType: context.funcName.substr(1),
+        value: ordargument(body)
+    };
+});
+
+// Extra data needed for the delimiter handler down below
+var delimiterSizes = {
+    "\\bigl" : {mclass: "mopen",    size: 1},
+    "\\Bigl" : {mclass: "mopen",    size: 2},
+    "\\biggl": {mclass: "mopen",    size: 3},
+    "\\Biggl": {mclass: "mopen",    size: 4},
+    "\\bigr" : {mclass: "mclose",   size: 1},
+    "\\Bigr" : {mclass: "mclose",   size: 2},
+    "\\biggr": {mclass: "mclose",   size: 3},
+    "\\Biggr": {mclass: "mclose",   size: 4},
+    "\\bigm" : {mclass: "mrel",     size: 1},
+    "\\Bigm" : {mclass: "mrel",     size: 2},
+    "\\biggm": {mclass: "mrel",     size: 3},
+    "\\Biggm": {mclass: "mrel",     size: 4},
+    "\\big"  : {mclass: "mord",     size: 1},
+    "\\Big"  : {mclass: "mord",     size: 2},
+    "\\bigg" : {mclass: "mord",     size: 3},
+    "\\Bigg" : {mclass: "mord",     size: 4}
+};
+
+var delimiters = [
+    "(", ")", "[", "\\lbrack", "]", "\\rbrack",
+    "\\{", "\\lbrace", "\\}", "\\rbrace",
+    "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
+    "<", ">", "\\langle", "\\rangle", "\\lt", "\\gt",
+    "\\lvert", "\\rvert", "\\lVert", "\\rVert",
+    "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
+    "/", "\\backslash",
+    "|", "\\vert", "\\|", "\\Vert",
+    "\\uparrow", "\\Uparrow",
+    "\\downarrow", "\\Downarrow",
+    "\\updownarrow", "\\Updownarrow",
+    "."
+];
+
+var fontAliases = {
+    "\\Bbb": "\\mathbb",
+    "\\bold": "\\mathbf",
+    "\\frak": "\\mathfrak"
+};
+
+// Single-argument color functions
+defineFunction([
+    "\\blue", "\\orange", "\\pink", "\\red",
+    "\\green", "\\gray", "\\purple",
+    "\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
+    "\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
+    "\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
+    "\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
+    "\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
+    "\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
+    "\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
+    "\\mintA", "\\mintB", "\\mintC",
+    "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
+    "\\grayF", "\\grayG", "\\grayH", "\\grayI",
+    "\\kaBlue", "\\kaGreen"
+], {
+    numArgs: 1,
+    allowedInText: true,
+    greediness: 3
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "color",
+        color: "katex-" + context.funcName.slice(1),
+        value: ordargument(body)
+    };
+});
+
+// There are 2 flags for operators; whether they produce limits in
+// displaystyle, and whether they are symbols and should grow in
+// displaystyle. These four groups cover the four possible choices.
+
+// No limits, not symbols
+defineFunction([
+    "\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh",
+    "\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom",
+    "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh",
+    "\\tan", "\\tanh"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: false,
+        symbol: false,
+        body: context.funcName
+    };
+});
+
+// Limits, not symbols
+defineFunction([
+    "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
+    "\\min", "\\Pr", "\\sup"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: true,
+        symbol: false,
+        body: context.funcName
+    };
+});
+
+// No limits, symbols
+defineFunction([
+    "\\int", "\\iint", "\\iiint", "\\oint"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: false,
+        symbol: true,
+        body: context.funcName
+    };
+});
+
+// Limits, symbols
+defineFunction([
+    "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
+    "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
+    "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint"
+], {
+    numArgs: 0
+}, function(context) {
+    return {
+        type: "op",
+        limits: true,
+        symbol: true,
+        body: context.funcName
+    };
+});
+
+// \mathop class command
+defineFunction("\\mathop", {
+    numArgs: 1
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: "op",
+        limits: false,
+        symbol: false,
+        value: ordargument(body)
+    };
+});
+
+// Fractions
+defineFunction([
+    "\\dfrac", "\\frac", "\\tfrac",
+    "\\dbinom", "\\binom", "\\tbinom",
+    "\\\\atopfrac" // can’t be entered directly
+], {
+    numArgs: 2,
+    greediness: 2
+}, function(context, args) {
+    var numer = args[0];
+    var denom = args[1];
+    var hasBarLine;
+    var leftDelim = null;
+    var rightDelim = null;
+    var size = "auto";
+
+    switch (context.funcName) {
+        case "\\dfrac":
+        case "\\frac":
+        case "\\tfrac":
+            hasBarLine = true;
+            break;
+        case "\\\\atopfrac":
+            hasBarLine = false;
+            break;
+        case "\\dbinom":
+        case "\\binom":
+        case "\\tbinom":
+            hasBarLine = false;
+            leftDelim = "(";
+            rightDelim = ")";
+            break;
+        default:
+            throw new Error("Unrecognized genfrac command");
+    }
+
+    switch (context.funcName) {
+        case "\\dfrac":
+        case "\\dbinom":
+            size = "display";
+            break;
+        case "\\tfrac":
+        case "\\tbinom":
+            size = "text";
+            break;
+    }
+
+    return {
+        type: "genfrac",
+        numer: numer,
+        denom: denom,
+        hasBarLine: hasBarLine,
+        leftDelim: leftDelim,
+        rightDelim: rightDelim,
+        size: size
+    };
+});
+
+// Left and right overlap functions
+defineFunction(["\\llap", "\\rlap"], {
+    numArgs: 1,
+    allowedInText: true
+}, function(context, args) {
+    var body = args[0];
+    return {
+        type: context.funcName.slice(1),
+        body: body
+    };
+});
+
+// Delimiter functions
+var checkDelimiter = function(delim, context) {
+    if (utils.contains(delimiters, delim.value)) {
+        return delim;
+    } else {
+        throw new ParseError(
+            "Invalid delimiter: '" + delim.value + "' after '" +
+            context.funcName + "'", delim);
+    }
+};
+
+defineFunction([
+    "\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
+    "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
+    "\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
+    "\\big",  "\\Big",  "\\bigg",  "\\Bigg"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+
+    return {
+        type: "delimsizing",
+        size: delimiterSizes[context.funcName].size,
+        mclass: delimiterSizes[context.funcName].mclass,
+        value: delim.value
+    };
+});
+
+defineFunction([
+    "\\left", "\\right"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+
+    // \left and \right are caught somewhere in Parser.js, which is
+    // why this data doesn't match what is in buildHTML.
+    return {
+        type: "leftright",
+        value: delim.value
+    };
+});
+
+defineFunction("\\middle", {
+    numArgs: 1
+}, function(context, args) {
+    var delim = checkDelimiter(args[0], context);
+    if (!context.parser.leftrightDepth) {
+        throw new ParseError("\\middle without preceding \\left", delim);
+    }
+
+    return {
+        type: "middle",
+        value: delim.value
+    };
+});
+
+// Sizing functions (handled in Parser.js explicitly, hence no handler)
+defineFunction([
+    "\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
+    "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"
+], 0, null);
+
+// Style changing functions (handled in Parser.js explicitly, hence no
+// handler)
+defineFunction([
+    "\\displaystyle", "\\textstyle", "\\scriptstyle",
+    "\\scriptscriptstyle"
+], 0, null);
+
+defineFunction([
+    // styles
+    "\\mathrm", "\\mathit", "\\mathbf",
+
+    // families
+    "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
+    "\\mathtt",
+
+    // aliases
+    "\\Bbb", "\\bold", "\\frak"
+], {
+    numArgs: 1,
+    greediness: 2
+}, function(context, args) {
+    var body = args[0];
+    var func = context.funcName;
+    if (func in fontAliases) {
+        func = fontAliases[func];
+    }
+    return {
+        type: "font",
+        font: func.slice(1),
+        body: body
+    };
+});
+
+// Accents
+defineFunction([
+    "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
+    "\\check", "\\hat", "\\vec", "\\dot"
+    // We don't support expanding accents yet
+    // "\\widetilde", "\\widehat"
+], {
+    numArgs: 1
+}, function(context, args) {
+    var base = args[0];
+    return {
+        type: "accent",
+        accent: context.funcName,
+        base: base
+    };
+});
+
+// Infix generalized fractions
+defineFunction(["\\over", "\\choose", "\\atop"], {
+    numArgs: 0,
+    infix: true
+}, function(context) {
+    var replaceWith;
+    switch (context.funcName) {
+        case "\\over":
+            replaceWith = "\\frac";
+            break;
+        case "\\choose":
+            replaceWith = "\\binom";
+            break;
+        case "\\atop":
+            replaceWith = "\\\\atopfrac";
+            break;
+        default:
+            throw new Error("Unrecognized infix genfrac command");
+    }
+    return {
+        type: "infix",
+        replaceWith: replaceWith,
+        token: context.token
+    };
+});
+
+// Row breaks for aligned data
+defineFunction(["\\\\", "\\cr"], {
+    numArgs: 0,
+    numOptionalArgs: 1,
+    argTypes: ["size"]
+}, function(context, args) {
+    var size = args[0];
+    return {
+        type: "cr",
+        size: size
+    };
+});
+
+// Environment delimiters
+defineFunction(["\\begin", "\\end"], {
+    numArgs: 1,
+    argTypes: ["text"]
+}, function(context, args) {
+    var nameGroup = args[0];
+    if (nameGroup.type !== "ordgroup") {
+        throw new ParseError("Invalid environment name", nameGroup);
+    }
+    var name = "";
+    for (var i = 0; i < nameGroup.value.length; ++i) {
+        name += nameGroup.value[i].value;
+    }
+    return {
+        type: "environment",
+        name: name,
+        nameGroup: nameGroup
+    };
+});
+
+},{"./ParseError":6,"./parseData":21,"./utils":25}],20:[function(require,module,exports){
+/**
+ * These objects store data about MathML nodes. This is the MathML equivalent
+ * of the types in domTree.js. Since MathML handles its own rendering, and
+ * since we're mainly using MathML to improve accessibility, we don't manage
+ * any of the styling state that the plain DOM nodes do.
+ *
+ * The `toNode` and `toMarkup` functions work simlarly to how they do in
+ * domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
+ */
+
+var utils = require("./utils");
+
+/**
+ * This node represents a general purpose MathML node of any type. The
+ * constructor requires the type of node to create (for example, `"mo"` or
+ * `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
+ */
+function MathNode(type, children) {
+    this.type = type;
+    this.attributes = {};
+    this.children = children || [];
+}
+
+/**
+ * Sets an attribute on a MathML node. MathML depends on attributes to convey a
+ * semantic content, so this is used heavily.
+ */
+MathNode.prototype.setAttribute = function(name, value) {
+    this.attributes[name] = value;
+};
+
+/**
+ * Converts the math node into a MathML-namespaced DOM element.
+ */
+MathNode.prototype.toNode = function() {
+    var node = document.createElementNS(
+        "http://www.w3.org/1998/Math/MathML", this.type);
+
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            node.setAttribute(attr, this.attributes[attr]);
+        }
+    }
+
+    for (var i = 0; i < this.children.length; i++) {
+        node.appendChild(this.children[i].toNode());
+    }
+
+    return node;
+};
+
+/**
+ * Converts the math node into an HTML markup string.
+ */
+MathNode.prototype.toMarkup = function() {
+    var markup = "<" + this.type;
+
+    // Add the attributes
+    for (var attr in this.attributes) {
+        if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
+            markup += " " + attr + "=\"";
+            markup += utils.escape(this.attributes[attr]);
+            markup += "\"";
+        }
+    }
+
+    markup += ">";
+
+    for (var i = 0; i < this.children.length; i++) {
+        markup += this.children[i].toMarkup();
+    }
+
+    markup += "</" + this.type + ">";
+
+    return markup;
+};
+
+/**
+ * This node represents a piece of text.
+ */
+function TextNode(text) {
+    this.text = text;
+}
+
+/**
+ * Converts the text node into a DOM text node.
+ */
+TextNode.prototype.toNode = function() {
+    return document.createTextNode(this.text);
+};
+
+/**
+ * Converts the text node into HTML markup (which is just the text itself).
+ */
+TextNode.prototype.toMarkup = function() {
+    return utils.escape(this.text);
+};
+
+module.exports = {
+    MathNode: MathNode,
+    TextNode: TextNode
+};
+
+},{"./utils":25}],21:[function(require,module,exports){
+/**
+ * The resulting parse tree nodes of the parse tree.
+ *
+ * It is possible to provide position information, so that a ParseNode can
+ * fulfil a role similar to a Token in error reporting.
+ * For details on the corresponding properties see Token constructor.
+ * Providing such information can lead to better error reporting.
+ *
+ * @param {string}  type       type of node, like e.g. "ordgroup"
+ * @param {?object} value      type-specific representation of the node
+ * @param {string}  mode       parse mode in action for this node,
+ *                             "math" or "text"
+ * @param {Token=} firstToken  first token of the input for this node,
+ *                             will omit position information if unset
+ * @param {Token=} lastToken   last token of the input for this node,
+ *                             will default to firstToken if unset
+ */
+function ParseNode(type, value, mode, firstToken, lastToken) {
+    this.type = type;
+    this.value = value;
+    this.mode = mode;
+    if (firstToken && (!lastToken || lastToken.lexer === firstToken.lexer)) {
+        this.lexer = firstToken.lexer;
+        this.start = firstToken.start;
+        this.end = (lastToken || firstToken).end;
+    }
+}
+
+module.exports = {
+    ParseNode: ParseNode
+};
+
+
+},{}],22:[function(require,module,exports){
+/**
+ * Provides a single function for parsing an expression using a Parser
+ * TODO(emily): Remove this
+ */
+
+var Parser = require("./Parser");
+
+/**
+ * Parses an expression using a Parser, then returns the parsed result.
+ */
+var parseTree = function(toParse, settings) {
+    if (!(typeof toParse === 'string' || toParse instanceof String)) {
+        throw new TypeError('KaTeX can only parse string typed expression');
+    }
+    var parser = new Parser(toParse, settings);
+
+    return parser.parse();
+};
+
+module.exports = parseTree;
+
+},{"./Parser":7}],23:[function(require,module,exports){
+/**
+ * This file holds a list of all no-argument functions and single-character
+ * symbols (like 'a' or ';').
+ *
+ * For each of the symbols, there are three properties they can have:
+ * - font (required): the font to be used for this symbol. Either "main" (the
+     normal font), or "ams" (the ams fonts).
+ * - group (required): the ParseNode group type the symbol should have (i.e.
+     "textord", "mathord", etc).
+     See https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
+ * - replace: the character that this symbol or function should be
+ *   replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi
+ *   character in the main font).
+ *
+ * The outermost map in the table indicates what mode the symbols should be
+ * accepted in (e.g. "math" or "text").
+ */
+
+module.exports = {
+    math: {},
+    text: {}
+};
+
+function defineSymbol(mode, font, group, replace, name) {
+    module.exports[mode][name] = {
+        font: font,
+        group: group,
+        replace: replace
+    };
+}
+
+// Some abbreviations for commonly used strings.
+// This helps minify the code, and also spotting typos using jshint.
+
+// modes:
+var math = "math";
+var text = "text";
+
+// fonts:
+var main = "main";
+var ams = "ams";
+
+// groups:
+var accent = "accent";
+var bin = "bin";
+var close = "close";
+var inner = "inner";
+var mathord = "mathord";
+var op = "op";
+var open = "open";
+var punct = "punct";
+var rel = "rel";
+var spacing = "spacing";
+var textord = "textord";
+
+// Now comes the symbol table
+
+// Relation Symbols
+defineSymbol(math, main, rel, "\u2261", "\\equiv");
+defineSymbol(math, main, rel, "\u227a", "\\prec");
+defineSymbol(math, main, rel, "\u227b", "\\succ");
+defineSymbol(math, main, rel, "\u223c", "\\sim");
+defineSymbol(math, main, rel, "\u22a5", "\\perp");
+defineSymbol(math, main, rel, "\u2aaf", "\\preceq");
+defineSymbol(math, main, rel, "\u2ab0", "\\succeq");
+defineSymbol(math, main, rel, "\u2243", "\\simeq");
+defineSymbol(math, main, rel, "\u2223", "\\mid");
+defineSymbol(math, main, rel, "\u226a", "\\ll");
+defineSymbol(math, main, rel, "\u226b", "\\gg");
+defineSymbol(math, main, rel, "\u224d", "\\asymp");
+defineSymbol(math, main, rel, "\u2225", "\\parallel");
+defineSymbol(math, main, rel, "\u22c8", "\\bowtie");
+defineSymbol(math, main, rel, "\u2323", "\\smile");
+defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq");
+defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq");
+defineSymbol(math, main, rel, "\u2250", "\\doteq");
+defineSymbol(math, main, rel, "\u2322", "\\frown");
+defineSymbol(math, main, rel, "\u220b", "\\ni");
+defineSymbol(math, main, rel, "\u221d", "\\propto");
+defineSymbol(math, main, rel, "\u22a2", "\\vdash");
+defineSymbol(math, main, rel, "\u22a3", "\\dashv");
+defineSymbol(math, main, rel, "\u220b", "\\owns");
+
+// Punctuation
+defineSymbol(math, main, punct, "\u002e", "\\ldotp");
+defineSymbol(math, main, punct, "\u22c5", "\\cdotp");
+
+// Misc Symbols
+defineSymbol(math, main, textord, "\u0023", "\\#");
+defineSymbol(text, main, textord, "\u0023", "\\#");
+defineSymbol(math, main, textord, "\u0026", "\\&");
+defineSymbol(text, main, textord, "\u0026", "\\&");
+defineSymbol(math, main, textord, "\u2135", "\\aleph");
+defineSymbol(math, main, textord, "\u2200", "\\forall");
+defineSymbol(math, main, textord, "\u210f", "\\hbar");
+defineSymbol(math, main, textord, "\u2203", "\\exists");
+defineSymbol(math, main, textord, "\u2207", "\\nabla");
+defineSymbol(math, main, textord, "\u266d", "\\flat");
+defineSymbol(math, main, textord, "\u2113", "\\ell");
+defineSymbol(math, main, textord, "\u266e", "\\natural");
+defineSymbol(math, main, textord, "\u2663", "\\clubsuit");
+defineSymbol(math, main, textord, "\u2118", "\\wp");
+defineSymbol(math, main, textord, "\u266f", "\\sharp");
+defineSymbol(math, main, textord, "\u2662", "\\diamondsuit");
+defineSymbol(math, main, textord, "\u211c", "\\Re");
+defineSymbol(math, main, textord, "\u2661", "\\heartsuit");
+defineSymbol(math, main, textord, "\u2111", "\\Im");
+defineSymbol(math, main, textord, "\u2660", "\\spadesuit");
+
+// Math and Text
+defineSymbol(math, main, textord, "\u2020", "\\dag");
+defineSymbol(math, main, textord, "\u2021", "\\ddag");
+
+// Large Delimiters
+defineSymbol(math, main, close, "\u23b1", "\\rmoustache");
+defineSymbol(math, main, open, "\u23b0", "\\lmoustache");
+defineSymbol(math, main, close, "\u27ef", "\\rgroup");
+defineSymbol(math, main, open, "\u27ee", "\\lgroup");
+
+// Binary Operators
+defineSymbol(math, main, bin, "\u2213", "\\mp");
+defineSymbol(math, main, bin, "\u2296", "\\ominus");
+defineSymbol(math, main, bin, "\u228e", "\\uplus");
+defineSymbol(math, main, bin, "\u2293", "\\sqcap");
+defineSymbol(math, main, bin, "\u2217", "\\ast");
+defineSymbol(math, main, bin, "\u2294", "\\sqcup");
+defineSymbol(math, main, bin, "\u25ef", "\\bigcirc");
+defineSymbol(math, main, bin, "\u2219", "\\bullet");
+defineSymbol(math, main, bin, "\u2021", "\\ddagger");
+defineSymbol(math, main, bin, "\u2240", "\\wr");
+defineSymbol(math, main, bin, "\u2a3f", "\\amalg");
+
+// Arrow Symbols
+defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow");
+defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow");
+defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow");
+defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow");
+defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow");
+defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow");
+defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow");
+defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow");
+defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow");
+defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow");
+defineSymbol(math, main, rel, "\u21a6", "\\mapsto");
+defineSymbol(math, main, rel, "\u27fc", "\\longmapsto");
+defineSymbol(math, main, rel, "\u2197", "\\nearrow");
+defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow");
+defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow");
+defineSymbol(math, main, rel, "\u2198", "\\searrow");
+defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup");
+defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup");
+defineSymbol(math, main, rel, "\u2199", "\\swarrow");
+defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown");
+defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown");
+defineSymbol(math, main, rel, "\u2196", "\\nwarrow");
+defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons");
+
+// AMS Negated Binary Relations
+defineSymbol(math, ams, rel, "\u226e", "\\nless");
+defineSymbol(math, ams, rel, "\ue010", "\\nleqslant");
+defineSymbol(math, ams, rel, "\ue011", "\\nleqq");
+defineSymbol(math, ams, rel, "\u2a87", "\\lneq");
+defineSymbol(math, ams, rel, "\u2268", "\\lneqq");
+defineSymbol(math, ams, rel, "\ue00c", "\\lvertneqq");
+defineSymbol(math, ams, rel, "\u22e6", "\\lnsim");
+defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox");
+defineSymbol(math, ams, rel, "\u2280", "\\nprec");
+defineSymbol(math, ams, rel, "\u22e0", "\\npreceq");
+defineSymbol(math, ams, rel, "\u22e8", "\\precnsim");
+defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox");
+defineSymbol(math, ams, rel, "\u2241", "\\nsim");
+defineSymbol(math, ams, rel, "\ue006", "\\nshortmid");
+defineSymbol(math, ams, rel, "\u2224", "\\nmid");
+defineSymbol(math, ams, rel, "\u22ac", "\\nvdash");
+defineSymbol(math, ams, rel, "\u22ad", "\\nvDash");
+defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft");
+defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq");
+defineSymbol(math, ams, rel, "\u228a", "\\subsetneq");
+defineSymbol(math, ams, rel, "\ue01a", "\\varsubsetneq");
+defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq");
+defineSymbol(math, ams, rel, "\ue017", "\\varsubsetneqq");
+defineSymbol(math, ams, rel, "\u226f", "\\ngtr");
+defineSymbol(math, ams, rel, "\ue00f", "\\ngeqslant");
+defineSymbol(math, ams, rel, "\ue00e", "\\ngeqq");
+defineSymbol(math, ams, rel, "\u2a88", "\\gneq");
+defineSymbol(math, ams, rel, "\u2269", "\\gneqq");
+defineSymbol(math, ams, rel, "\ue00d", "\\gvertneqq");
+defineSymbol(math, ams, rel, "\u22e7", "\\gnsim");
+defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox");
+defineSymbol(math, ams, rel, "\u2281", "\\nsucc");
+defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq");
+defineSymbol(math, ams, rel, "\u22e9", "\\succnsim");
+defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox");
+defineSymbol(math, ams, rel, "\u2246", "\\ncong");
+defineSymbol(math, ams, rel, "\ue007", "\\nshortparallel");
+defineSymbol(math, ams, rel, "\u2226", "\\nparallel");
+defineSymbol(math, ams, rel, "\u22af", "\\nVDash");
+defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright");
+defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq");
+defineSymbol(math, ams, rel, "\ue018", "\\nsupseteqq");
+defineSymbol(math, ams, rel, "\u228b", "\\supsetneq");
+defineSymbol(math, ams, rel, "\ue01b", "\\varsupsetneq");
+defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq");
+defineSymbol(math, ams, rel, "\ue019", "\\varsupsetneqq");
+defineSymbol(math, ams, rel, "\u22ae", "\\nVdash");
+defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq");
+defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq");
+defineSymbol(math, ams, rel, "\ue016", "\\nsubseteqq");
+defineSymbol(math, ams, bin, "\u22b4", "\\unlhd");
+defineSymbol(math, ams, bin, "\u22b5", "\\unrhd");
+
+// AMS Negated Arrows
+defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow");
+defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow");
+defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow");
+defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow");
+defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow");
+defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow");
+
+// AMS Misc
+defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle");
+defineSymbol(math, ams, textord, "\u210f", "\\hslash");
+defineSymbol(math, ams, textord, "\u25bd", "\\triangledown");
+defineSymbol(math, ams, textord, "\u25ca", "\\lozenge");
+defineSymbol(math, ams, textord, "\u24c8", "\\circledS");
+defineSymbol(math, ams, textord, "\u00ae", "\\circledR");
+defineSymbol(math, ams, textord, "\u2221", "\\measuredangle");
+defineSymbol(math, ams, textord, "\u2204", "\\nexists");
+defineSymbol(math, ams, textord, "\u2127", "\\mho");
+defineSymbol(math, ams, textord, "\u2132", "\\Finv");
+defineSymbol(math, ams, textord, "\u2141", "\\Game");
+defineSymbol(math, ams, textord, "\u006b", "\\Bbbk");
+defineSymbol(math, ams, textord, "\u2035", "\\backprime");
+defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle");
+defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown");
+defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare");
+defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge");
+defineSymbol(math, ams, textord, "\u2605", "\\bigstar");
+defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle");
+defineSymbol(math, ams, textord, "\u2201", "\\complement");
+defineSymbol(math, ams, textord, "\u00f0", "\\eth");
+defineSymbol(math, ams, textord, "\u2571", "\\diagup");
+defineSymbol(math, ams, textord, "\u2572", "\\diagdown");
+defineSymbol(math, ams, textord, "\u25a1", "\\square");
+defineSymbol(math, ams, textord, "\u25a1", "\\Box");
+defineSymbol(math, ams, textord, "\u25ca", "\\Diamond");
+defineSymbol(math, ams, textord, "\u00a5", "\\yen");
+defineSymbol(math, ams, textord, "\u2713", "\\checkmark");
+
+// AMS Hebrew
+defineSymbol(math, ams, textord, "\u2136", "\\beth");
+defineSymbol(math, ams, textord, "\u2138", "\\daleth");
+defineSymbol(math, ams, textord, "\u2137", "\\gimel");
+
+// AMS Greek
+defineSymbol(math, ams, textord, "\u03dd", "\\digamma");
+defineSymbol(math, ams, textord, "\u03f0", "\\varkappa");
+
+// AMS Delimiters
+defineSymbol(math, ams, open, "\u250c", "\\ulcorner");
+defineSymbol(math, ams, close, "\u2510", "\\urcorner");
+defineSymbol(math, ams, open, "\u2514", "\\llcorner");
+defineSymbol(math, ams, close, "\u2518", "\\lrcorner");
+
+// AMS Binary Relations
+defineSymbol(math, ams, rel, "\u2266", "\\leqq");
+defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant");
+defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless");
+defineSymbol(math, ams, rel, "\u2272", "\\lesssim");
+defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox");
+defineSymbol(math, ams, rel, "\u224a", "\\approxeq");
+defineSymbol(math, ams, bin, "\u22d6", "\\lessdot");
+defineSymbol(math, ams, rel, "\u22d8", "\\lll");
+defineSymbol(math, ams, rel, "\u2276", "\\lessgtr");
+defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr");
+defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr");
+defineSymbol(math, ams, rel, "\u2251", "\\doteqdot");
+defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq");
+defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq");
+defineSymbol(math, ams, rel, "\u223d", "\\backsim");
+defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq");
+defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq");
+defineSymbol(math, ams, rel, "\u22d0", "\\Subset");
+defineSymbol(math, ams, rel, "\u228f", "\\sqsubset");
+defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq");
+defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec");
+defineSymbol(math, ams, rel, "\u227e", "\\precsim");
+defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox");
+defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft");
+defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq");
+defineSymbol(math, ams, rel, "\u22a8", "\\vDash");
+defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash");
+defineSymbol(math, ams, rel, "\u2323", "\\smallsmile");
+defineSymbol(math, ams, rel, "\u2322", "\\smallfrown");
+defineSymbol(math, ams, rel, "\u224f", "\\bumpeq");
+defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq");
+defineSymbol(math, ams, rel, "\u2267", "\\geqq");
+defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant");
+defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr");
+defineSymbol(math, ams, rel, "\u2273", "\\gtrsim");
+defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox");
+defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot");
+defineSymbol(math, ams, rel, "\u22d9", "\\ggg");
+defineSymbol(math, ams, rel, "\u2277", "\\gtrless");
+defineSymbol(math, ams, rel, "\u22db", "\\gtreqless");
+defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless");
+defineSymbol(math, ams, rel, "\u2256", "\\eqcirc");
+defineSymbol(math, ams, rel, "\u2257", "\\circeq");
+defineSymbol(math, ams, rel, "\u225c", "\\triangleq");
+defineSymbol(math, ams, rel, "\u223c", "\\thicksim");
+defineSymbol(math, ams, rel, "\u2248", "\\thickapprox");
+defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq");
+defineSymbol(math, ams, rel, "\u22d1", "\\Supset");
+defineSymbol(math, ams, rel, "\u2290", "\\sqsupset");
+defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq");
+defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc");
+defineSymbol(math, ams, rel, "\u227f", "\\succsim");
+defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox");
+defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright");
+defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq");
+defineSymbol(math, ams, rel, "\u22a9", "\\Vdash");
+defineSymbol(math, ams, rel, "\u2223", "\\shortmid");
+defineSymbol(math, ams, rel, "\u2225", "\\shortparallel");
+defineSymbol(math, ams, rel, "\u226c", "\\between");
+defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork");
+defineSymbol(math, ams, rel, "\u221d", "\\varpropto");
+defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft");
+defineSymbol(math, ams, rel, "\u2234", "\\therefore");
+defineSymbol(math, ams, rel, "\u220d", "\\backepsilon");
+defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright");
+defineSymbol(math, ams, rel, "\u2235", "\\because");
+defineSymbol(math, ams, rel, "\u22d8", "\\llless");
+defineSymbol(math, ams, rel, "\u22d9", "\\gggtr");
+defineSymbol(math, ams, bin, "\u22b2", "\\lhd");
+defineSymbol(math, ams, bin, "\u22b3", "\\rhd");
+defineSymbol(math, ams, rel, "\u2242", "\\eqsim");
+defineSymbol(math, main, rel, "\u22c8", "\\Join");
+defineSymbol(math, ams, rel, "\u2251", "\\Doteq");
+
+// AMS Binary Operators
+defineSymbol(math, ams, bin, "\u2214", "\\dotplus");
+defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus");
+defineSymbol(math, ams, bin, "\u22d2", "\\Cap");
+defineSymbol(math, ams, bin, "\u22d3", "\\Cup");
+defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge");
+defineSymbol(math, ams, bin, "\u229f", "\\boxminus");
+defineSymbol(math, ams, bin, "\u229e", "\\boxplus");
+defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes");
+defineSymbol(math, ams, bin, "\u22c9", "\\ltimes");
+defineSymbol(math, ams, bin, "\u22ca", "\\rtimes");
+defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes");
+defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes");
+defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge");
+defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee");
+defineSymbol(math, ams, bin, "\u229d", "\\circleddash");
+defineSymbol(math, ams, bin, "\u229b", "\\circledast");
+defineSymbol(math, ams, bin, "\u22c5", "\\centerdot");
+defineSymbol(math, ams, bin, "\u22ba", "\\intercal");
+defineSymbol(math, ams, bin, "\u22d2", "\\doublecap");
+defineSymbol(math, ams, bin, "\u22d3", "\\doublecup");
+defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes");
+
+// AMS Arrows
+defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow");
+defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow");
+defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows");
+defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows");
+defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow");
+defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow");
+defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail");
+defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft");
+defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons");
+defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft");
+defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft");
+defineSymbol(math, ams, rel, "\u21b0", "\\Lsh");
+defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows");
+defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft");
+defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft");
+defineSymbol(math, ams, rel, "\u22b8", "\\multimap");
+defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow");
+defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows");
+defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows");
+defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow");
+defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail");
+defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright");
+defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright");
+defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright");
+defineSymbol(math, ams, rel, "\u21b1", "\\Rsh");
+defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows");
+defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright");
+defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright");
+defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow");
+defineSymbol(math, ams, rel, "\u21dd", "\\leadsto");
+defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow");
+defineSymbol(math, ams, rel, "\u21be", "\\restriction");
+
+defineSymbol(math, main, textord, "\u2018", "`");
+defineSymbol(math, main, textord, "$", "\\$");
+defineSymbol(text, main, textord, "$", "\\$");
+defineSymbol(math, main, textord, "%", "\\%");
+defineSymbol(text, main, textord, "%", "\\%");
+defineSymbol(math, main, textord, "_", "\\_");
+defineSymbol(text, main, textord, "_", "\\_");
+defineSymbol(math, main, textord, "\u2220", "\\angle");
+defineSymbol(math, main, textord, "\u221e", "\\infty");
+defineSymbol(math, main, textord, "\u2032", "\\prime");
+defineSymbol(math, main, textord, "\u25b3", "\\triangle");
+defineSymbol(math, main, textord, "\u0393", "\\Gamma");
+defineSymbol(math, main, textord, "\u0394", "\\Delta");
+defineSymbol(math, main, textord, "\u0398", "\\Theta");
+defineSymbol(math, main, textord, "\u039b", "\\Lambda");
+defineSymbol(math, main, textord, "\u039e", "\\Xi");
+defineSymbol(math, main, textord, "\u03a0", "\\Pi");
+defineSymbol(math, main, textord, "\u03a3", "\\Sigma");
+defineSymbol(math, main, textord, "\u03a5", "\\Upsilon");
+defineSymbol(math, main, textord, "\u03a6", "\\Phi");
+defineSymbol(math, main, textord, "\u03a8", "\\Psi");
+defineSymbol(math, main, textord, "\u03a9", "\\Omega");
+defineSymbol(math, main, textord, "\u00ac", "\\neg");
+defineSymbol(math, main, textord, "\u00ac", "\\lnot");
+defineSymbol(math, main, textord, "\u22a4", "\\top");
+defineSymbol(math, main, textord, "\u22a5", "\\bot");
+defineSymbol(math, main, textord, "\u2205", "\\emptyset");
+defineSymbol(math, ams, textord, "\u2205", "\\varnothing");
+defineSymbol(math, main, mathord, "\u03b1", "\\alpha");
+defineSymbol(math, main, mathord, "\u03b2", "\\beta");
+defineSymbol(math, main, mathord, "\u03b3", "\\gamma");
+defineSymbol(math, main, mathord, "\u03b4", "\\delta");
+defineSymbol(math, main, mathord, "\u03f5", "\\epsilon");
+defineSymbol(math, main, mathord, "\u03b6", "\\zeta");
+defineSymbol(math, main, mathord, "\u03b7", "\\eta");
+defineSymbol(math, main, mathord, "\u03b8", "\\theta");
+defineSymbol(math, main, mathord, "\u03b9", "\\iota");
+defineSymbol(math, main, mathord, "\u03ba", "\\kappa");
+defineSymbol(math, main, mathord, "\u03bb", "\\lambda");
+defineSymbol(math, main, mathord, "\u03bc", "\\mu");
+defineSymbol(math, main, mathord, "\u03bd", "\\nu");
+defineSymbol(math, main, mathord, "\u03be", "\\xi");
+defineSymbol(math, main, mathord, "o", "\\omicron");
+defineSymbol(math, main, mathord, "\u03c0", "\\pi");
+defineSymbol(math, main, mathord, "\u03c1", "\\rho");
+defineSymbol(math, main, mathord, "\u03c3", "\\sigma");
+defineSymbol(math, main, mathord, "\u03c4", "\\tau");
+defineSymbol(math, main, mathord, "\u03c5", "\\upsilon");
+defineSymbol(math, main, mathord, "\u03d5", "\\phi");
+defineSymbol(math, main, mathord, "\u03c7", "\\chi");
+defineSymbol(math, main, mathord, "\u03c8", "\\psi");
+defineSymbol(math, main, mathord, "\u03c9", "\\omega");
+defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon");
+defineSymbol(math, main, mathord, "\u03d1", "\\vartheta");
+defineSymbol(math, main, mathord, "\u03d6", "\\varpi");
+defineSymbol(math, main, mathord, "\u03f1", "\\varrho");
+defineSymbol(math, main, mathord, "\u03c2", "\\varsigma");
+defineSymbol(math, main, mathord, "\u03c6", "\\varphi");
+defineSymbol(math, main, bin, "\u2217", "*");
+defineSymbol(math, main, bin, "+", "+");
+defineSymbol(math, main, bin, "\u2212", "-");
+defineSymbol(math, main, bin, "\u22c5", "\\cdot");
+defineSymbol(math, main, bin, "\u2218", "\\circ");
+defineSymbol(math, main, bin, "\u00f7", "\\div");
+defineSymbol(math, main, bin, "\u00b1", "\\pm");
+defineSymbol(math, main, bin, "\u00d7", "\\times");
+defineSymbol(math, main, bin, "\u2229", "\\cap");
+defineSymbol(math, main, bin, "\u222a", "\\cup");
+defineSymbol(math, main, bin, "\u2216", "\\setminus");
+defineSymbol(math, main, bin, "\u2227", "\\land");
+defineSymbol(math, main, bin, "\u2228", "\\lor");
+defineSymbol(math, main, bin, "\u2227", "\\wedge");
+defineSymbol(math, main, bin, "\u2228", "\\vee");
+defineSymbol(math, main, textord, "\u221a", "\\surd");
+defineSymbol(math, main, open, "(", "(");
+defineSymbol(math, main, open, "[", "[");
+defineSymbol(math, main, open, "\u27e8", "\\langle");
+defineSymbol(math, main, open, "\u2223", "\\lvert");
+defineSymbol(math, main, open, "\u2225", "\\lVert");
+defineSymbol(math, main, close, ")", ")");
+defineSymbol(math, main, close, "]", "]");
+defineSymbol(math, main, close, "?", "?");
+defineSymbol(math, main, close, "!", "!");
+defineSymbol(math, main, close, "\u27e9", "\\rangle");
+defineSymbol(math, main, close, "\u2223", "\\rvert");
+defineSymbol(math, main, close, "\u2225", "\\rVert");
+defineSymbol(math, main, rel, "=", "=");
+defineSymbol(math, main, rel, "<", "<");
+defineSymbol(math, main, rel, ">", ">");
+defineSymbol(math, main, rel, ":", ":");
+defineSymbol(math, main, rel, "\u2248", "\\approx");
+defineSymbol(math, main, rel, "\u2245", "\\cong");
+defineSymbol(math, main, rel, "\u2265", "\\ge");
+defineSymbol(math, main, rel, "\u2265", "\\geq");
+defineSymbol(math, main, rel, "\u2190", "\\gets");
+defineSymbol(math, main, rel, ">", "\\gt");
+defineSymbol(math, main, rel, "\u2208", "\\in");
+defineSymbol(math, main, rel, "\u2209", "\\notin");
+defineSymbol(math, main, rel, "\u2282", "\\subset");
+defineSymbol(math, main, rel, "\u2283", "\\supset");
+defineSymbol(math, main, rel, "\u2286", "\\subseteq");
+defineSymbol(math, main, rel, "\u2287", "\\supseteq");
+defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq");
+defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq");
+defineSymbol(math, main, rel, "\u22a8", "\\models");
+defineSymbol(math, main, rel, "\u2190", "\\leftarrow");
+defineSymbol(math, main, rel, "\u2264", "\\le");
+defineSymbol(math, main, rel, "\u2264", "\\leq");
+defineSymbol(math, main, rel, "<", "\\lt");
+defineSymbol(math, main, rel, "\u2260", "\\ne");
+defineSymbol(math, main, rel, "\u2260", "\\neq");
+defineSymbol(math, main, rel, "\u2192", "\\rightarrow");
+defineSymbol(math, main, rel, "\u2192", "\\to");
+defineSymbol(math, ams, rel, "\u2271", "\\ngeq");
+defineSymbol(math, ams, rel, "\u2270", "\\nleq");
+defineSymbol(math, main, spacing, null, "\\!");
+defineSymbol(math, main, spacing, "\u00a0", "\\ ");
+defineSymbol(math, main, spacing, "\u00a0", "~");
+defineSymbol(math, main, spacing, null, "\\,");
+defineSymbol(math, main, spacing, null, "\\:");
+defineSymbol(math, main, spacing, null, "\\;");
+defineSymbol(math, main, spacing, null, "\\enspace");
+defineSymbol(math, main, spacing, null, "\\qquad");
+defineSymbol(math, main, spacing, null, "\\quad");
+defineSymbol(math, main, spacing, "\u00a0", "\\space");
+defineSymbol(math, main, punct, ",", ",");
+defineSymbol(math, main, punct, ";", ";");
+defineSymbol(math, main, punct, ":", "\\colon");
+defineSymbol(math, ams, bin, "\u22bc", "\\barwedge");
+defineSymbol(math, ams, bin, "\u22bb", "\\veebar");
+defineSymbol(math, main, bin, "\u2299", "\\odot");
+defineSymbol(math, main, bin, "\u2295", "\\oplus");
+defineSymbol(math, main, bin, "\u2297", "\\otimes");
+defineSymbol(math, main, textord, "\u2202", "\\partial");
+defineSymbol(math, main, bin, "\u2298", "\\oslash");
+defineSymbol(math, ams, bin, "\u229a", "\\circledcirc");
+defineSymbol(math, ams, bin, "\u22a1", "\\boxdot");
+defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup");
+defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown");
+defineSymbol(math, main, bin, "\u2020", "\\dagger");
+defineSymbol(math, main, bin, "\u22c4", "\\diamond");
+defineSymbol(math, main, bin, "\u22c6", "\\star");
+defineSymbol(math, main, bin, "\u25c3", "\\triangleleft");
+defineSymbol(math, main, bin, "\u25b9", "\\triangleright");
+defineSymbol(math, main, open, "{", "\\{");
+defineSymbol(text, main, textord, "{", "\\{");
+defineSymbol(math, main, close, "}", "\\}");
+defineSymbol(text, main, textord, "}", "\\}");
+defineSymbol(math, main, open, "{", "\\lbrace");
+defineSymbol(math, main, close, "}", "\\rbrace");
+defineSymbol(math, main, open, "[", "\\lbrack");
+defineSymbol(math, main, close, "]", "\\rbrack");
+defineSymbol(math, main, open, "\u230a", "\\lfloor");
+defineSymbol(math, main, close, "\u230b", "\\rfloor");
+defineSymbol(math, main, open, "\u2308", "\\lceil");
+defineSymbol(math, main, close, "\u2309", "\\rceil");
+defineSymbol(math, main, textord, "\\", "\\backslash");
+defineSymbol(math, main, textord, "\u2223", "|");
+defineSymbol(math, main, textord, "\u2223", "\\vert");
+defineSymbol(math, main, textord, "\u2225", "\\|");
+defineSymbol(math, main, textord, "\u2225", "\\Vert");
+defineSymbol(math, main, rel, "\u2191", "\\uparrow");
+defineSymbol(math, main, rel, "\u21d1", "\\Uparrow");
+defineSymbol(math, main, rel, "\u2193", "\\downarrow");
+defineSymbol(math, main, rel, "\u21d3", "\\Downarrow");
+defineSymbol(math, main, rel, "\u2195", "\\updownarrow");
+defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow");
+defineSymbol(math, math, op, "\u2210", "\\coprod");
+defineSymbol(math, math, op, "\u22c1", "\\bigvee");
+defineSymbol(math, math, op, "\u22c0", "\\bigwedge");
+defineSymbol(math, math, op, "\u2a04", "\\biguplus");
+defineSymbol(math, math, op, "\u22c2", "\\bigcap");
+defineSymbol(math, math, op, "\u22c3", "\\bigcup");
+defineSymbol(math, math, op, "\u222b", "\\int");
+defineSymbol(math, math, op, "\u222b", "\\intop");
+defineSymbol(math, math, op, "\u222c", "\\iint");
+defineSymbol(math, math, op, "\u222d", "\\iiint");
+defineSymbol(math, math, op, "\u220f", "\\prod");
+defineSymbol(math, math, op, "\u2211", "\\sum");
+defineSymbol(math, math, op, "\u2a02", "\\bigotimes");
+defineSymbol(math, math, op, "\u2a01", "\\bigoplus");
+defineSymbol(math, math, op, "\u2a00", "\\bigodot");
+defineSymbol(math, math, op, "\u222e", "\\oint");
+defineSymbol(math, math, op, "\u2a06", "\\bigsqcup");
+defineSymbol(math, math, op, "\u222b", "\\smallint");
+defineSymbol(text, main, inner, "\u2026", "\\textellipsis");
+defineSymbol(math, main, inner, "\u2026", "\\mathellipsis");
+defineSymbol(text, main, inner, "\u2026", "\\ldots");
+defineSymbol(math, main, inner, "\u2026", "\\ldots");
+defineSymbol(math, main, inner, "\u22ef", "\\cdots");
+defineSymbol(math, main, inner, "\u22f1", "\\ddots");
+defineSymbol(math, main, textord, "\u22ee", "\\vdots");
+defineSymbol(math, main, accent, "\u00b4", "\\acute");
+defineSymbol(math, main, accent, "\u0060", "\\grave");
+defineSymbol(math, main, accent, "\u00a8", "\\ddot");
+defineSymbol(math, main, accent, "\u007e", "\\tilde");
+defineSymbol(math, main, accent, "\u00af", "\\bar");
+defineSymbol(math, main, accent, "\u02d8", "\\breve");
+defineSymbol(math, main, accent, "\u02c7", "\\check");
+defineSymbol(math, main, accent, "\u005e", "\\hat");
+defineSymbol(math, main, accent, "\u20d7", "\\vec");
+defineSymbol(math, main, accent, "\u02d9", "\\dot");
+defineSymbol(math, main, mathord, "\u0131", "\\imath");
+defineSymbol(math, main, mathord, "\u0237", "\\jmath");
+
+defineSymbol(text, main, textord, "\u2013", "--");
+defineSymbol(text, main, textord, "\u2014", "---");
+defineSymbol(text, main, textord, "\u2018", "`");
+defineSymbol(text, main, textord, "\u2019", "'");
+defineSymbol(text, main, textord, "\u201c", "``");
+defineSymbol(text, main, textord, "\u201d", "''");
+defineSymbol(math, main, textord, "\u00b0", "\\degree");
+defineSymbol(text, main, textord, "\u00b0", "\\degree");
+defineSymbol(math, main, mathord, "\u00a3", "\\pounds");
+defineSymbol(math, ams, textord, "\u2720", "\\maltese");
+defineSymbol(text, ams, textord, "\u2720", "\\maltese");
+
+defineSymbol(text, main, spacing, "\u00a0", "\\ ");
+defineSymbol(text, main, spacing, "\u00a0", " ");
+defineSymbol(text, main, spacing, "\u00a0", "~");
+
+// There are lots of symbols which are the same, so we add them in afterwards.
+var i;
+var ch;
+
+// All of these are textords in math mode
+var mathTextSymbols = "0123456789/@.\"";
+for (i = 0; i < mathTextSymbols.length; i++) {
+    ch = mathTextSymbols.charAt(i);
+    defineSymbol(math, main, textord, ch, ch);
+}
+
+// All of these are textords in text mode
+var textSymbols = "0123456789!@*()-=+[]\";:?/.,";
+for (i = 0; i < textSymbols.length; i++) {
+    ch = textSymbols.charAt(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// All of these are textords in text mode, and mathords in math mode
+var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+for (i = 0; i < letters.length; i++) {
+    ch = letters.charAt(i);
+    defineSymbol(math, main, mathord, ch, ch);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Latin-1 letters
+for (i = 0x00C0; i <= 0x00D6; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+for (i = 0x00D8; i <= 0x00F6; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+for (i = 0x00F8; i <= 0x00FF; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Cyrillic
+for (i = 0x0410; i <= 0x044F; i++) {
+    ch = String.fromCharCode(i);
+    defineSymbol(text, main, textord, ch, ch);
+}
+
+// Unicode versions of existing characters
+defineSymbol(text, main, textord, "\u2013", "–");
+defineSymbol(text, main, textord, "\u2014", "—");
+defineSymbol(text, main, textord, "\u2018", "‘");
+defineSymbol(text, main, textord, "\u2019", "’");
+defineSymbol(text, main, textord, "\u201c", "“");
+defineSymbol(text, main, textord, "\u201d", "”");
+
+},{}],24:[function(require,module,exports){
+var hangulRegex = /[\uAC00-\uD7AF]/;
+
+// This regex combines
+// - Hiragana: [\u3040-\u309F]
+// - Katakana: [\u30A0-\u30FF]
+// - CJK ideograms: [\u4E00-\u9FAF]
+// - Hangul syllables: [\uAC00-\uD7AF]
+// Notably missing are halfwidth Katakana and Romanji glyphs.
+var cjkRegex =
+    /[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/;
+
+module.exports = {
+    cjkRegex: cjkRegex,
+    hangulRegex: hangulRegex
+};
+
+},{}],25:[function(require,module,exports){
+/**
+ * This file contains a list of utility functions which are useful in other
+ * files.
+ */
+
+/**
+ * Provide an `indexOf` function which works in IE8, but defers to native if
+ * possible.
+ */
+var nativeIndexOf = Array.prototype.indexOf;
+var indexOf = function(list, elem) {
+    if (list == null) {
+        return -1;
+    }
+    if (nativeIndexOf && list.indexOf === nativeIndexOf) {
+        return list.indexOf(elem);
+    }
+    var i = 0;
+    var l = list.length;
+    for (; i < l; i++) {
+        if (list[i] === elem) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Return whether an element is contained in a list
+ */
+var contains = function(list, elem) {
+    return indexOf(list, elem) !== -1;
+};
+
+/**
+ * Provide a default value if a setting is undefined
+ */
+var deflt = function(setting, defaultIfUndefined) {
+    return setting === undefined ? defaultIfUndefined : setting;
+};
+
+// hyphenate and escape adapted from Facebook's React under Apache 2 license
+
+var uppercase = /([A-Z])/g;
+var hyphenate = function(str) {
+    return str.replace(uppercase, "-$1").toLowerCase();
+};
+
+var ESCAPE_LOOKUP = {
+    "&": "&amp;",
+    ">": "&gt;",
+    "<": "&lt;",
+    "\"": "&quot;",
+    "'": "&#x27;"
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+    return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escape(text) {
+    return ("" + text).replace(ESCAPE_REGEX, escaper);
+}
+
+/**
+ * A function to set the text content of a DOM element in all supported
+ * browsers. Note that we don't define this if there is no document.
+ */
+var setTextContent;
+if (typeof document !== "undefined") {
+    var testNode = document.createElement("span");
+    if ("textContent" in testNode) {
+        setTextContent = function(node, text) {
+            node.textContent = text;
+        };
+    } else {
+        setTextContent = function(node, text) {
+            node.innerText = text;
+        };
+    }
+}
+
+/**
+ * A function to clear a node.
+ */
+function clearNode(node) {
+    setTextContent(node, "");
+}
+
+module.exports = {
+    contains: contains,
+    deflt: deflt,
+    escape: escape,
+    hyphenate: hyphenate,
+    indexOf: indexOf,
+    setTextContent: setTextContent,
+    clearNode: clearNode
+};
+
+},{}]},{},[1])(1)
+});
\ No newline at end of file
diff --git a/specs/gl/katex/katex.min.css b/specs/gl/katex/katex.min.css
new file mode 100644
index 0000000..d6fb837
--- /dev/null
+++ b/specs/gl/katex/katex.min.css
@@ -0,0 +1 @@
+@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.eot);src:url(fonts/KaTeX_AMS-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_AMS-Regular.woff2) format('woff2'),url(fonts/KaTeX_AMS-Regular.woff) format('woff'),url(fonts/KaTeX_AMS-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.eot);src:url(fonts/KaTeX_Caligraphic-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Bold.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Bold.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.eot);src:url(fonts/KaTeX_Caligraphic-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Regular.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Regular.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.eot);src:url(fonts/KaTeX_Fraktur-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Bold.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Bold.woff) format('woff'),url(fonts/KaTeX_Fraktur-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.eot);src:url(fonts/KaTeX_Fraktur-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Regular.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Regular.woff) format('woff'),url(fonts/KaTeX_Fraktur-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.eot);src:url(fonts/KaTeX_Main-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Bold.woff2) format('woff2'),url(fonts/KaTeX_Main-Bold.woff) format('woff'),url(fonts/KaTeX_Main-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.eot);src:url(fonts/KaTeX_Main-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Italic.woff2) format('woff2'),url(fonts/KaTeX_Main-Italic.woff) format('woff'),url(fonts/KaTeX_Main-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.eot);src:url(fonts/KaTeX_Main-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Regular.woff2) format('woff2'),url(fonts/KaTeX_Main-Regular.woff) format('woff'),url(fonts/KaTeX_Main-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.eot);src:url(fonts/KaTeX_Math-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Math-Italic.woff2) format('woff2'),url(fonts/KaTeX_Math-Italic.woff) format('woff'),url(fonts/KaTeX_Math-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_SansSerif;src:url(fonts/KaTeX_SansSerif-Regular.eot);src:url(fonts/KaTeX_SansSerif-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_SansSerif-Regular.woff2) format('woff2'),url(fonts/KaTeX_SansSerif-Regular.woff) format('woff'),url(fonts/KaTeX_SansSerif-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.eot);src:url(fonts/KaTeX_Script-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Script-Regular.woff2) format('woff2'),url(fonts/KaTeX_Script-Regular.woff) format('woff'),url(fonts/KaTeX_Script-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.eot);src:url(fonts/KaTeX_Size1-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size1-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size1-Regular.woff) format('woff'),url(fonts/KaTeX_Size1-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.eot);src:url(fonts/KaTeX_Size2-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size2-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size2-Regular.woff) format('woff'),url(fonts/KaTeX_Size2-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.eot);src:url(fonts/KaTeX_Size3-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size3-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size3-Regular.woff) format('woff'),url(fonts/KaTeX_Size3-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.eot);src:url(fonts/KaTeX_Size4-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size4-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size4-Regular.woff) format('woff'),url(fonts/KaTeX_Size4-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.eot);src:url(fonts/KaTeX_Typewriter-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Typewriter-Regular.woff2) format('woff2'),url(fonts/KaTeX_Typewriter-Regular.woff) format('woff'),url(fonts/KaTeX_Typewriter-Regular.ttf) format('truetype');font-weight:400;font-style:normal}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:inline-block;text-align:initial}.katex{font:400 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;white-space:nowrap;text-indent:0}.katex .katex-html{display:inline-block}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .base,.katex .strut{display:inline-block}.katex .mathrm{font-style:normal}.katex .textit{font-style:italic}.katex .mathit{font-family:KaTeX_Math;font-style:italic}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .amsrm,.katex .mathbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr{font-family:KaTeX_Script}.katex .mathsf{font-family:KaTeX_SansSerif}.katex .mainit{font-family:KaTeX_Main;font-style:italic}.katex .mord+.mop{margin-left:.16667em}.katex .mord+.mbin{margin-left:.22222em}.katex .mord+.mrel{margin-left:.27778em}.katex .mop+.mop,.katex .mop+.mord,.katex .mord+.minner{margin-left:.16667em}.katex .mop+.mrel{margin-left:.27778em}.katex .mop+.minner{margin-left:.16667em}.katex .mbin+.minner,.katex .mbin+.mop,.katex .mbin+.mopen,.katex .mbin+.mord{margin-left:.22222em}.katex .mrel+.minner,.katex .mrel+.mop,.katex .mrel+.mopen,.katex .mrel+.mord{margin-left:.27778em}.katex .mclose+.mop{margin-left:.16667em}.katex .mclose+.mbin{margin-left:.22222em}.katex .mclose+.mrel{margin-left:.27778em}.katex .mclose+.minner,.katex .minner+.mop,.katex .minner+.mord,.katex .mpunct+.mclose,.katex .mpunct+.minner,.katex .mpunct+.mop,.katex .mpunct+.mopen,.katex .mpunct+.mord,.katex .mpunct+.mpunct,.katex .mpunct+.mrel{margin-left:.16667em}.katex .minner+.mbin{margin-left:.22222em}.katex .minner+.mrel{margin-left:.27778em}.katex .minner+.minner,.katex .minner+.mopen,.katex .minner+.mpunct{margin-left:.16667em}.katex .mbin.mtight,.katex .mclose.mtight,.katex .minner.mtight,.katex .mop.mtight,.katex .mopen.mtight,.katex .mord.mtight,.katex .mpunct.mtight,.katex .mrel.mtight{margin-left:0}.katex .mclose+.mop.mtight,.katex .minner+.mop.mtight,.katex .mop+.mop.mtight,.katex .mop+.mord.mtight,.katex .mord+.mop.mtight{margin-left:.16667em}.katex .reset-textstyle.textstyle{font-size:1em}.katex .reset-textstyle.scriptstyle{font-size:.7em}.katex .reset-textstyle.scriptscriptstyle{font-size:.5em}.katex .reset-scriptstyle.textstyle{font-size:1.42857em}.katex .reset-scriptstyle.scriptstyle{font-size:1em}.katex .reset-scriptstyle.scriptscriptstyle{font-size:.71429em}.katex .reset-scriptscriptstyle.textstyle{font-size:2em}.katex .reset-scriptscriptstyle.scriptstyle{font-size:1.4em}.katex .reset-scriptscriptstyle.scriptscriptstyle{font-size:1em}.katex .style-wrap{position:relative}.katex .vlist{display:inline-block}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist .baseline-fix{display:inline-table;table-layout:fixed}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{width:100%}.katex .mfrac .frac-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .mfrac .frac-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .mspace{display:inline-block}.katex .mspace.negativethinspace{margin-left:-.16667em}.katex .mspace.thinspace{width:.16667em}.katex .mspace.negativemediumspace{margin-left:-.22222em}.katex .mspace.mediumspace{width:.22222em}.katex .mspace.thickspace{width:.27778em}.katex .mspace.sixmuspace{width:.333333em}.katex .mspace.eightmuspace{width:.444444em}.katex .mspace.enspace{width:.5em}.katex .mspace.twelvemuspace{width:.666667em}.katex .mspace.quad{width:1em}.katex .mspace.qquad{width:2em}.katex .llap,.katex .rlap{width:0;position:relative}.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .rlap>.inner{left:0}.katex .katex-logo .a{font-size:.75em;margin-left:-.32em;position:relative;top:-.2em}.katex .katex-logo .t{margin-left:-.23em}.katex .katex-logo .e{margin-left:-.1667em;position:relative;top:.2155em}.katex .katex-logo .x{margin-left:-.125em}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .overline .overline-line,.katex .underline .underline-line{width:100%}.katex .overline .overline-line:before,.katex .underline .underline-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .overline .overline-line:after,.katex .underline .underline-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.sqrt-sign{position:relative}.katex .sqrt .sqrt-line{width:100%}.katex .sqrt .sqrt-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .sqrt .sqrt-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer,.katex .sizing{display:inline-block}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:2em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:3.46em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:4.14em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.98em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.47142857em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.95714286em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.55714286em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.875em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.125em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.25em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.5em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.8em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.1625em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.5875em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:3.1125em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.77777778em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.88888889em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.6em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.92222222em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.3em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.76666667em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.7em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.8em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.9em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.2em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.44em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.73em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:2.07em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.49em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.58333333em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.66666667em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.75em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.83333333em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44166667em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.725em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.075em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.48611111em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.55555556em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.625em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.69444444em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.20138889em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.4375em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72916667em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.28901734em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.40462428em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.46242775em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.52023121em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.57803468em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69364162em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83236994em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.19653179em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.43930636em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.24154589em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.33816425em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.38647343em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.43478261em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.48309179em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.57971014em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69565217em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83574879em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20289855em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.20080321em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2811245em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.32128514em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.36144578em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.40160643em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48192771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57831325em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69477912em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8313253em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist>span,.katex .op-limits>.vlist>span{text-align:center}.katex .accent .accent-body>span{width:0}.katex .accent .accent-body.accent-vec>span{position:relative;left:.326em}.katex .mtable .vertical-separator{display:inline-block;margin:0 -.025em;border-right:.05em solid #000}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist{text-align:center}.katex .mtable .col-align-l>.vlist{text-align:left}.katex .mtable .col-align-r>.vlist{text-align:right}
\ No newline at end of file
diff --git a/specs/gl/katex/katex.min.js b/specs/gl/katex/katex.min.js
new file mode 100644
index 0000000..66c0821
--- /dev/null
+++ b/specs/gl/katex/katex.min.js
@@ -0,0 +1,4 @@
+(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.katex=e()}})(function(){var e,t,r;return function a(e,t,r){function i(s,l){if(!t[s]){if(!e[s]){var o=typeof require=="function"&&require;if(!l&&o)return o(s,!0);if(n)return n(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var p=t[s]={exports:{}};e[s][0].call(p.exports,function(t){var r=e[s][1][t];return i(r?r:t)},p,p.exports,a,e,t,r)}return t[s].exports}var n=typeof require=="function"&&require;for(var s=0;s<r.length;s++)i(r[s]);return i}({1:[function(e,t,r){var a=e("./src/ParseError");var i=e("./src/Settings");var n=e("./src/buildTree");var s=e("./src/parseTree");var l=e("./src/utils");var o=function(e,t,r){l.clearNode(t);var a=new i(r);var o=s(e,a);var u=n(o,e,a).toNode();t.appendChild(u)};if(typeof document!=="undefined"){if(document.compatMode!=="CSS1Compat"){typeof console!=="undefined"&&console.warn("Warning: KaTeX doesn't work in quirks mode. Make sure your "+"website has a suitable doctype.");o=function(){throw new a("KaTeX doesn't work in quirks mode.")}}}var u=function(e,t){var r=new i(t);var a=s(e,r);return n(a,e,r).toMarkup()};var p=function(e,t){var r=new i(t);return s(e,r)};t.exports={render:o,renderToString:u,__parse:p,ParseError:a}},{"./src/ParseError":6,"./src/Settings":8,"./src/buildTree":13,"./src/parseTree":22,"./src/utils":25}],2:[function(e,t,r){"use strict";function a(e){if(!e.__matchAtRelocatable){var t=e.source+"|()";var r="g"+(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"");e.__matchAtRelocatable=new RegExp(t,r)}return e.__matchAtRelocatable}function i(e,t,r){if(e.global||e.sticky){throw new Error("matchAt(...): Only non-global regexes are supported")}var i=a(e);i.lastIndex=r;var n=i.exec(t);if(n[n.length-1]==null){n.length=n.length-1;return n}else{return null}}t.exports=i},{}],3:[function(e,t,r){var a=e("match-at");var i=e("./ParseError");function n(e){this.input=e;this.pos=0}function s(e,t,r,a){this.text=e;this.start=t;this.end=r;this.lexer=a}s.prototype.range=function(e,t){if(e.lexer!==this.lexer){return new s(t)}return new s(t,this.start,e.end,this.lexer)};var l=new RegExp("([ \r\n	]+)|"+"([!-\\[\\]-\u2027\u202a-\ud7ff\uf900-\uffff]"+"|[\ud800-\udbff][\udc00-\udfff]"+"|\\\\(?:[a-zA-Z]+|[^\ud800-\udfff])"+")");n.prototype.lex=function(){var e=this.input;var t=this.pos;if(t===e.length){return new s("EOF",t,t,this)}var r=a(l,e,t);if(r===null){throw new i("Unexpected character: '"+e[t]+"'",new s(e[t],t,t+1,this))}var n=r[2]||" ";var o=this.pos;this.pos+=r[0].length;var u=this.pos;return new s(n,o,u,this)};t.exports=n},{"./ParseError":6,"match-at":2}],4:[function(e,t,r){var a=e("./Lexer");function i(e,t){this.lexer=new a(e);this.macros=t;this.stack=[];this.discardedWhiteSpace=[]}i.prototype.nextToken=function(){for(;;){if(this.stack.length===0){this.stack.push(this.lexer.lex())}var e=this.stack.pop();var t=e.text;if(!(t.charAt(0)==="\\"&&this.macros.hasOwnProperty(t))){return e}var r=this.macros[t];if(typeof r==="string"){var i=new a(r);r=[];var n=i.lex();while(n.text!=="EOF"){r.push(n);n=i.lex()}r.reverse();this.macros[t]=r}this.stack=this.stack.concat(r)}};i.prototype.get=function(e){this.discardedWhiteSpace=[];var t=this.nextToken();if(e){while(t.text===" "){this.discardedWhiteSpace.push(t);t=this.nextToken()}}return t};i.prototype.unget=function(e){this.stack.push(e);while(this.discardedWhiteSpace.length!==0){this.stack.push(this.discardedWhiteSpace.pop())}};t.exports=i},{"./Lexer":3}],5:[function(e,t,r){function a(e){this.style=e.style;this.color=e.color;this.size=e.size;this.phantom=e.phantom;this.font=e.font;if(e.parentStyle===undefined){this.parentStyle=e.style}else{this.parentStyle=e.parentStyle}if(e.parentSize===undefined){this.parentSize=e.size}else{this.parentSize=e.parentSize}}a.prototype.extend=function(e){var t={style:this.style,size:this.size,color:this.color,parentStyle:this.style,parentSize:this.size,phantom:this.phantom,font:this.font};for(var r in e){if(e.hasOwnProperty(r)){t[r]=e[r]}}return new a(t)};a.prototype.withStyle=function(e){return this.extend({style:e})};a.prototype.withSize=function(e){return this.extend({size:e})};a.prototype.withColor=function(e){return this.extend({color:e})};a.prototype.withPhantom=function(){return this.extend({phantom:true})};a.prototype.withFont=function(e){return this.extend({font:e||this.font})};a.prototype.reset=function(){return this.extend({})};var i={"katex-blue":"#6495ed","katex-orange":"#ffa500","katex-pink":"#ff00af","katex-red":"#df0030","katex-green":"#28ae7b","katex-gray":"gray","katex-purple":"#9d38bd","katex-blueA":"#ccfaff","katex-blueB":"#80f6ff","katex-blueC":"#63d9ea","katex-blueD":"#11accd","katex-blueE":"#0c7f99","katex-tealA":"#94fff5","katex-tealB":"#26edd5","katex-tealC":"#01d1c1","katex-tealD":"#01a995","katex-tealE":"#208170","katex-greenA":"#b6ffb0","katex-greenB":"#8af281","katex-greenC":"#74cf70","katex-greenD":"#1fab54","katex-greenE":"#0d923f","katex-goldA":"#ffd0a9","katex-goldB":"#ffbb71","katex-goldC":"#ff9c39","katex-goldD":"#e07d10","katex-goldE":"#a75a05","katex-redA":"#fca9a9","katex-redB":"#ff8482","katex-redC":"#f9685d","katex-redD":"#e84d39","katex-redE":"#bc2612","katex-maroonA":"#ffbde0","katex-maroonB":"#ff92c6","katex-maroonC":"#ed5fa6","katex-maroonD":"#ca337c","katex-maroonE":"#9e034e","katex-purpleA":"#ddd7ff","katex-purpleB":"#c6b9fc","katex-purpleC":"#aa87ff","katex-purpleD":"#7854ab","katex-purpleE":"#543b78","katex-mintA":"#f5f9e8","katex-mintB":"#edf2df","katex-mintC":"#e0e5cc","katex-grayA":"#f6f7f7","katex-grayB":"#f0f1f2","katex-grayC":"#e3e5e6","katex-grayD":"#d6d8da","katex-grayE":"#babec2","katex-grayF":"#888d93","katex-grayG":"#626569","katex-grayH":"#3b3e40","katex-grayI":"#21242c","katex-kaBlue":"#314453","katex-kaGreen":"#71B307"};a.prototype.getColor=function(){if(this.phantom){return"transparent"}else{return i[this.color]||this.color}};t.exports=a},{}],6:[function(e,t,r){function a(e,t){var r="KaTeX parse error: "+e;var i;var n;if(t&&t.lexer&&t.start<=t.end){var s=t.lexer.input;i=t.start;n=t.end;if(i===s.length){r+=" at end of input: "}else{r+=" at position "+(i+1)+": "}var l=s.slice(i,n).replace(/[^]/g,"$&\u0332");var o;if(i>15){o="\u2026"+s.slice(i-15,i)}else{o=s.slice(0,i)}var u;if(n+15<s.length){u=s.slice(n,n+15)+"\u2026"}else{u=s.slice(n)}r+=o+l+u}var p=new Error(r);p.name="ParseError";p.__proto__=a.prototype;p.position=i;return p}a.prototype.__proto__=Error.prototype;t.exports=a},{}],7:[function(e,t,r){var a=e("./functions");var i=e("./environments");var n=e("./MacroExpander");var s=e("./symbols");var l=e("./utils");var o=e("./unicodeRegexes").cjkRegex;var u=e("./parseData");var p=e("./ParseError");function h(e,t){this.gullet=new n(e,t.macros);this.settings=t;this.leftrightDepth=0}var c=u.ParseNode;function m(e,t,r){this.result=e;this.isFunction=t;this.token=r}h.prototype.expect=function(e,t){if(this.nextToken.text!==e){throw new p("Expected '"+e+"', got '"+this.nextToken.text+"'",this.nextToken)}if(t!==false){this.consume()}};h.prototype.consume=function(){this.nextToken=this.gullet.get(this.mode==="math")};h.prototype.switchMode=function(e){this.gullet.unget(this.nextToken);this.mode=e;this.consume()};h.prototype.parse=function(){this.mode="math";this.consume();var e=this.parseInput();return e};h.prototype.parseInput=function(){var e=this.parseExpression(false);this.expect("EOF",false);return e};var f=["}","\\end","\\right","&","\\\\","\\cr"];h.prototype.parseExpression=function(e,t){var r=[];while(true){var i=this.nextToken;if(f.indexOf(i.text)!==-1){break}if(t&&i.text===t){break}if(e&&a[i.text]&&a[i.text].infix){break}var n=this.parseAtom();if(!n){if(!this.settings.throwOnError&&i.text[0]==="\\"){var s=this.handleUnsupportedCmd();r.push(s);continue}break}r.push(n)}return this.handleInfixNodes(r)};h.prototype.handleInfixNodes=function(e){var t=-1;var r;for(var a=0;a<e.length;a++){var i=e[a];if(i.type==="infix"){if(t!==-1){throw new p("only one infix operator per group",i.value.token)}t=a;r=i.value.replaceWith}}if(t!==-1){var n;var s;var l=e.slice(0,t);var o=e.slice(t+1);if(l.length===1&&l[0].type==="ordgroup"){n=l[0]}else{n=new c("ordgroup",l,this.mode)}if(o.length===1&&o[0].type==="ordgroup"){s=o[0]}else{s=new c("ordgroup",o,this.mode)}var u=this.callFunction(r,[n,s],null);return[new c(u.type,u,this.mode)]}else{return e}};var v=1;h.prototype.handleSupSubscript=function(e){var t=this.nextToken;var r=t.text;this.consume();var i=this.parseGroup();if(!i){if(!this.settings.throwOnError&&this.nextToken.text[0]==="\\"){return this.handleUnsupportedCmd()}else{throw new p("Expected group after '"+r+"'",t)}}else if(i.isFunction){var n=a[i.result].greediness;if(n>v){return this.parseFunction(i)}else{throw new p("Got function '"+i.result+"' with no arguments "+"as "+e,t)}}else{return i.result}};h.prototype.handleUnsupportedCmd=function(){var e=this.nextToken.text;var t=[];for(var r=0;r<e.length;r++){t.push(new c("textord",e[r],"text"))}var a=new c("text",{body:t,type:"text"},this.mode);var i=new c("color",{color:this.settings.errorColor,value:[a],type:"color"},this.mode);this.consume();return i};h.prototype.parseAtom=function(){var e=this.parseImplicitGroup();if(this.mode==="text"){return e}var t;var r;while(true){var a=this.nextToken;if(a.text==="\\limits"||a.text==="\\nolimits"){if(!e||e.type!=="op"){throw new p("Limit controls must follow a math operator",a)}else{var i=a.text==="\\limits";e.value.limits=i;e.value.alwaysHandleSupSub=true}this.consume()}else if(a.text==="^"){if(t){throw new p("Double superscript",a)}t=this.handleSupSubscript("superscript")}else if(a.text==="_"){if(r){throw new p("Double subscript",a)}r=this.handleSupSubscript("subscript")}else if(a.text==="'"){var n=new c("textord","\\prime",this.mode);var s=[n];this.consume();while(this.nextToken.text==="'"){s.push(n);this.consume()}t=new c("ordgroup",s,this.mode)}else{break}}if(t||r){return new c("supsub",{base:e,sup:t,sub:r},this.mode)}else{return e}};var d=["\\tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];var g=["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"];h.prototype.parseImplicitGroup=function(){var e=this.parseSymbol();if(e==null){return this.parseFunction()}var t=e.result;var r;if(t==="\\left"){var a=this.parseFunction(e);++this.leftrightDepth;r=this.parseExpression(false);--this.leftrightDepth;this.expect("\\right",false);var n=this.parseFunction();return new c("leftright",{body:r,left:a.value.value,right:n.value.value},this.mode)}else if(t==="\\begin"){var s=this.parseFunction(e);var o=s.value.name;if(!i.hasOwnProperty(o)){throw new p("No such environment: "+o,s.value.nameGroup)}var u=i[o];var h=this.parseArguments("\\begin{"+o+"}",u);var m={mode:this.mode,envName:o,parser:this,positions:h.pop()};var f=u.handler(m,h);this.expect("\\end",false);var v=this.nextToken;var y=this.parseFunction();if(y.value.name!==o){throw new p("Mismatch: \\begin{"+o+"} matched "+"by \\end{"+y.value.name+"}",v)}f.position=y.position;return f}else if(l.contains(d,t)){r=this.parseExpression(false);return new c("sizing",{size:"size"+(l.indexOf(d,t)+1),value:r},this.mode)}else if(l.contains(g,t)){r=this.parseExpression(true);return new c("styling",{style:t.slice(1,t.length-5),value:r},this.mode)}else{return this.parseFunction(e)}};h.prototype.parseFunction=function(e){if(!e){e=this.parseGroup()}if(e){if(e.isFunction){var t=e.result;var r=a[t];if(this.mode==="text"&&!r.allowedInText){throw new p("Can't use function '"+t+"' in text mode",e.token)}var i=this.parseArguments(t,r);var n=e.token;var s=this.callFunction(t,i,i.pop(),n);return new c(s.type,s,this.mode)}else{return e.result}}else{return null}};h.prototype.callFunction=function(e,t,r,i){var n={funcName:e,parser:this,positions:r,token:i};return a[e].handler(n,t)};h.prototype.parseArguments=function(e,t){var r=t.numArgs+t.numOptionalArgs;if(r===0){return[[this.pos]]}var i=t.greediness;var n=[this.pos];var s=[];for(var l=0;l<r;l++){var o=this.nextToken;var u=t.argTypes&&t.argTypes[l];var h;if(l<t.numOptionalArgs){if(u){h=this.parseGroupOfType(u,true)}else{h=this.parseGroup(true)}if(!h){s.push(null);n.push(this.pos);continue}}else{if(u){h=this.parseGroupOfType(u)}else{h=this.parseGroup()}if(!h){if(!this.settings.throwOnError&&this.nextToken.text[0]==="\\"){h=new m(this.handleUnsupportedCmd(this.nextToken.text),false)}else{throw new p("Expected group after '"+e+"'",o)}}}var c;if(h.isFunction){var f=a[h.result].greediness;if(f>i){c=this.parseFunction(h)}else{throw new p("Got function '"+h.result+"' as "+"argument to '"+e+"'",o)}}else{c=h.result}s.push(c);n.push(this.pos)}s.push(n);return s};h.prototype.parseGroupOfType=function(e,t){var r=this.mode;if(e==="original"){e=r}if(e==="color"){return this.parseColorGroup(t)}if(e==="size"){return this.parseSizeGroup(t)}this.switchMode(e);if(e==="text"){while(this.nextToken.text===" "){this.consume()}}var a=this.parseGroup(t);this.switchMode(r);return a};h.prototype.parseStringGroup=function(e,t){if(t&&this.nextToken.text!=="["){return null}var r=this.mode;this.mode="text";this.expect(t?"[":"{");var a="";var i=this.nextToken;var n=i;while(this.nextToken.text!==(t?"]":"}")){if(this.nextToken.text==="EOF"){throw new p("Unexpected end of input in "+e,i.range(this.nextToken,a))}n=this.nextToken;a+=n.text;this.consume()}this.mode=r;this.expect(t?"]":"}");return i.range(n,a)};h.prototype.parseRegexGroup=function(e,t){var r=this.mode;this.mode="text";var a=this.nextToken;var i=a;var n="";while(this.nextToken.text!=="EOF"&&e.test(n+this.nextToken.text)){i=this.nextToken;n+=i.text;this.consume()}if(n===""){throw new p("Invalid "+t+": '"+a.text+"'",a)}this.mode=r;return a.range(i,n)};h.prototype.parseColorGroup=function(e){var t=this.parseStringGroup("color",e);if(!t){return null}var r=/^(#[a-z0-9]+|[a-z]+)$/i.exec(t.text);if(!r){throw new p("Invalid color: '"+t.text+"'",t)}return new m(new c("color",r[0],this.mode),false)};h.prototype.parseSizeGroup=function(e){var t;if(!e&&this.nextToken.text!=="{"){t=this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/,"size")}else{t=this.parseStringGroup("size",e)}if(!t){return null}var r=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(t.text);if(!r){throw new p("Invalid size: '"+t.text+"'",t)}var a={number:+(r[1]+r[2]),unit:r[3]};if(a.unit!=="em"&&a.unit!=="ex"&&a.unit!=="mu"){throw new p("Invalid unit: '"+a.unit+"'",t)}return new m(new c("color",a,this.mode),false)};h.prototype.parseGroup=function(e){var t=this.nextToken;if(this.nextToken.text===(e?"[":"{")){this.consume();var r=this.parseExpression(false,e?"]":null);var a=this.nextToken;this.expect(e?"]":"}");if(this.mode==="text"){this.formLigatures(r)}return new m(new c("ordgroup",r,this.mode,t,a),false)}else{return e?null:this.parseSymbol()}};h.prototype.formLigatures=function(e){var t;var r=e.length-1;for(t=0;t<r;++t){var a=e[t];var i=a.value;if(i==="-"&&e[t+1].value==="-"){if(t+1<r&&e[t+2].value==="-"){e.splice(t,3,new c("textord","---","text",a,e[t+2]));r-=2}else{e.splice(t,2,new c("textord","--","text",a,e[t+1]));r-=1}}if((i==="'"||i==="`")&&e[t+1].value===i){e.splice(t,2,new c("textord",i+i,"text",a,e[t+1]));r-=1}}};h.prototype.parseSymbol=function(){var e=this.nextToken;if(a[e.text]){this.consume();return new m(e.text,true,e)}else if(s[this.mode][e.text]){this.consume();return new m(new c(s[this.mode][e.text].group,e.text,this.mode,e),false,e)}else if(this.mode==="text"&&o.test(e.text)){this.consume();return new m(new c("textord",e.text,this.mode,e),false,e)}else{return null}};h.prototype.ParseNode=c;t.exports=h},{"./MacroExpander":4,"./ParseError":6,"./environments":16,"./functions":19,"./parseData":21,"./symbols":23,"./unicodeRegexes":24,"./utils":25}],8:[function(e,t,r){function a(e,t){return e===undefined?t:e}function i(e){e=e||{};this.displayMode=a(e.displayMode,false);this.throwOnError=a(e.throwOnError,true);this.errorColor=a(e.errorColor,"#cc0000");this.macros=e.macros||{}}t.exports=i},{}],9:[function(e,t,r){var a=e("./fontMetrics.js").sigmas;var i=[{},{},{}];var n;for(var s in a){if(a.hasOwnProperty(s)){for(n=0;n<3;n++){i[n][s]=a[s][n]}}}for(n=0;n<3;n++){i[n].emPerEx=a.xHeight[n]/a.quad[n]}function l(e,t,r,a){this.id=e;this.size=t;this.cramped=a;this.sizeMultiplier=r;this.metrics=i[t>0?t-1:0]}l.prototype.sup=function(){return y[x[this.id]]};l.prototype.sub=function(){return y[b[this.id]]};l.prototype.fracNum=function(){return y[w[this.id]]};l.prototype.fracDen=function(){return y[k[this.id]]};l.prototype.cramp=function(){return y[z[this.id]]};l.prototype.cls=function(){return d[this.size]+(this.cramped?" cramped":" uncramped")};l.prototype.reset=function(){return g[this.size]};l.prototype.isTight=function(){return this.size>=2};var o=0;var u=1;var p=2;var h=3;var c=4;var m=5;var f=6;var v=7;var d=["displaystyle textstyle","textstyle","scriptstyle","scriptscriptstyle"];var g=["reset-textstyle","reset-textstyle","reset-scriptstyle","reset-scriptscriptstyle"];var y=[new l(o,0,1,false),new l(u,0,1,true),new l(p,1,1,false),new l(h,1,1,true),new l(c,2,.7,false),new l(m,2,.7,true),new l(f,3,.5,false),new l(v,3,.5,true)];var x=[c,m,c,m,f,v,f,v];var b=[m,m,m,m,v,v,v,v];var w=[p,h,c,m,f,v,f,v];var k=[h,h,m,m,v,v,v,v];var z=[u,u,h,h,m,m,v,v];t.exports={DISPLAY:y[o],TEXT:y[p],SCRIPT:y[c],SCRIPTSCRIPT:y[f]}},{"./fontMetrics.js":17}],10:[function(e,t,r){var a=e("./domTree");var i=e("./fontMetrics");var n=e("./symbols");var s=e("./utils");var l=["\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma","\\Upsilon","\\Phi","\\Psi","\\Omega"];var o=["\u0131","\u0237","\xa3"];var u=function(e,t,r,s,l){if(n[r][e]&&n[r][e].replace){e=n[r][e].replace}var o=i.getCharacterMetrics(e,t);var u;if(o){var p=o.italic;if(r==="text"){p=0}u=new a.symbolNode(e,o.height,o.depth,p,o.skew,l)}else{typeof console!=="undefined"&&console.warn("No character metrics for '"+e+"' in style '"+t+"'");u=new a.symbolNode(e,0,0,0,0,l)}if(s){if(s.style.isTight()){u.classes.push("mtight")}if(s.getColor()){u.style.color=s.getColor()}}return u};var p=function(e,t,r,a){if(e==="\\"||n[t][e].font==="main"){return u(e,"Main-Regular",t,r,a)}else{return u(e,"AMS-Regular",t,r,a.concat(["amsrm"]))}};var h=function(e,t,r,a,i){if(i==="mathord"){return c(e,t,r,a)}else if(i==="textord"){return u(e,"Main-Regular",t,r,a.concat(["mathrm"]))}else{throw new Error("unexpected type: "+i+" in mathDefault")}};var c=function(e,t,r,a){if(/[0-9]/.test(e.charAt(0))||s.contains(o,e)||s.contains(l,e)){return u(e,"Main-Italic",t,r,a.concat(["mainit"]))}else{return u(e,"Math-Italic",t,r,a.concat(["mathit"]))}};var m=function(e,t,r){var a=e.mode;var l=e.value;if(n[a][l]&&n[a][l].replace){l=n[a][l].replace}var p=["mord"];var m=t.font;if(m){if(m==="mathit"||s.contains(o,l)){return c(l,a,t,p)}else{var f=k[m].fontName;if(i.getCharacterMetrics(l,f)){return u(l,f,a,t,p.concat([m]))}else{return h(l,a,t,p,r)}}}else{return h(l,a,t,p,r)}};var f=function(e){var t=0;var r=0;var a=0;if(e.children){for(var i=0;i<e.children.length;i++){if(e.children[i].height>t){t=e.children[i].height}if(e.children[i].depth>r){r=e.children[i].depth}if(e.children[i].maxFontSize>a){a=e.children[i].maxFontSize}}}e.height=t;e.depth=r;e.maxFontSize=a};var v=function(e,t,r){var i=new a.span(e,t,r);f(i);return i};var d=function(e,t){e.children=t.concat(e.children);f(e)};var g=function(e){var t=new a.documentFragment(e);f(t);return t};var y=function(e,t){var r=v([],[new a.symbolNode("\u200b")]);r.style.fontSize=t/e.style.sizeMultiplier+"em";var i=v(["fontsize-ensurer","reset-"+e.size,"size5"],[r]);return i};var x=function(e,t,r,i){var n;var s;var l;if(t==="individualShift"){var o=e;e=[o[0]];n=-o[0].shift-o[0].elem.depth;s=n;for(l=1;l<o.length;l++){var u=-o[l].shift-s-o[l].elem.depth;var p=u-(o[l-1].elem.height+o[l-1].elem.depth);s=s+u;e.push({type:"kern",size:p});e.push(o[l])}}else if(t==="top"){var h=r;for(l=0;l<e.length;l++){if(e[l].type==="kern"){h-=e[l].size}else{h-=e[l].elem.height+e[l].elem.depth}}n=h}else if(t==="bottom"){n=-r}else if(t==="shift"){n=-e[0].elem.depth-r}else if(t==="firstBaseline"){n=-e[0].elem.depth}else{n=0}var c=0;for(l=0;l<e.length;l++){if(e[l].type==="elem"){c=Math.max(c,e[l].elem.maxFontSize)}}var m=y(i,c);var f=[];s=n;for(l=0;l<e.length;l++){if(e[l].type==="kern"){s+=e[l].size}else{var d=e[l].elem;var g=-d.depth-s;s+=d.height+d.depth;var x=v([],[m,d]);x.height-=g;x.depth+=g;x.style.top=g+"em";f.push(x)}}var b=v(["baseline-fix"],[m,new a.symbolNode("\u200b")]);f.push(b);var w=v(["vlist"],f);w.height=Math.max(s,w.height);w.depth=Math.max(-n,w.depth);return w};var b={size1:.5,size2:.7,size3:.8,size4:.9,size5:1,size6:1.2,size7:1.44,size8:1.73,size9:2.07,size10:2.49};var w={"\\qquad":{size:"2em",className:"qquad"},"\\quad":{size:"1em",className:"quad"},"\\enspace":{size:"0.5em",className:"enspace"},"\\;":{size:"0.277778em",className:"thickspace"},"\\:":{size:"0.22222em",className:"mediumspace"},"\\,":{size:"0.16667em",className:"thinspace"},"\\!":{size:"-0.16667em",className:"negativethinspace"}};var k={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}};t.exports={fontMap:k,makeSymbol:u,mathsym:p,makeSpan:v,makeFragment:g,makeVList:x,makeOrd:m,prependChildren:d,sizingMultiplier:b,spacingFunctions:w}},{"./domTree":15,"./fontMetrics":17,"./symbols":23,"./utils":25}],11:[function(e,t,r){var a=e("./ParseError");var i=e("./Style");var n=e("./buildCommon");var s=e("./delimiter");var l=e("./domTree");var o=e("./fontMetrics");var u=e("./utils");var p=n.makeSpan;var h=function(e){return e instanceof l.span&&e.classes[0]==="mspace"};var c=function(e){return e&&e.classes[0]==="mbin"};var m=function(e,t){if(e){return u.contains(["mbin","mopen","mrel","mop","mpunct"],e.classes[0])}else{return t}};var f=function(e,t){if(e){return u.contains(["mrel","mclose","mpunct"],e.classes[0])}else{return t}};var v=function(e,t,r){var a=[];for(var i=0;i<e.length;i++){var s=e[i];var o=z(s,t);if(o instanceof l.documentFragment){Array.prototype.push.apply(a,o.children)}else{a.push(o)}}var u=null;for(i=0;i<a.length;i++){if(h(a[i])){u=u||[];u.push(a[i]);a.splice(i,1);i--}else if(u){if(a[i]instanceof l.symbolNode){a[i]=p([].concat(a[i].classes),[a[i]])}n.prependChildren(a[i],u);u=null}}if(u){Array.prototype.push.apply(a,u)}for(i=0;i<a.length;i++){if(c(a[i])&&(m(a[i-1],r)||f(a[i+1],r))){a[i].classes[0]="mord"}}return a};var d=function(e){if(e instanceof l.documentFragment){if(e.children.length){return d(e.children[e.children.length-1])}}else{if(u.contains(["mord","mop","mbin","mrel","mopen","mclose","mpunct","minner"],e.classes[0])){return e.classes[0]}}return null};var g=function(e,t){if(!e){return false}else if(e.type==="op"){return e.value.limits&&(t.style.size===i.DISPLAY.size||e.value.alwaysHandleSupSub)}else if(e.type==="accent"){return x(e.value.base)}else{return null}};var y=function(e){if(!e){return false}else if(e.type==="ordgroup"){if(e.value.length===1){return y(e.value[0])}else{return e}}else if(e.type==="color"){if(e.value.value.length===1){return y(e.value.value[0])}else{return e}}else if(e.type==="font"){return y(e.value.body)}else{return e}};var x=function(e){var t=y(e);return t.type==="mathord"||t.type==="textord"||t.type==="bin"||t.type==="rel"||t.type==="inner"||t.type==="open"||t.type==="close"||t.type==="punct"};var b=function(e,t){return p(t.concat(["sizing","reset-"+e.size,"size5",e.style.reset(),i.TEXT.cls(),"nulldelimiter"]))};var w={};w.mathord=function(e,t){return n.makeOrd(e,t,"mathord")};w.textord=function(e,t){return n.makeOrd(e,t,"textord")};w.bin=function(e,t){return n.mathsym(e.value,e.mode,t,["mbin"])};w.rel=function(e,t){return n.mathsym(e.value,e.mode,t,["mrel"])};w.open=function(e,t){return n.mathsym(e.value,e.mode,t,["mopen"])};w.close=function(e,t){return n.mathsym(e.value,e.mode,t,["mclose"])};w.inner=function(e,t){return n.mathsym(e.value,e.mode,t,["minner"])};w.punct=function(e,t){return n.mathsym(e.value,e.mode,t,["mpunct"])};w.ordgroup=function(e,t){return p(["mord",t.style.cls()],v(e.value,t.reset(),true),t)};w.text=function(e,t){var r=t.withFont(e.value.style);var a=v(e.value.body,r,true);for(var i=0;i<a.length-1;i++){if(a[i].tryCombine(a[i+1])){a.splice(i+1,1);i--}}return p(["mord","text",r.style.cls()],a,r)};w.color=function(e,t){var r=v(e.value.value,t.withColor(e.value.color),false);return new n.makeFragment(r)};w.supsub=function(e,t){if(g(e.value.base,t)){return w[e.value.base.type](e,t)}var r=z(e.value.base,t.reset());var a;var s;var u;var h;var c=t.style;var m;if(e.value.sup){m=t.withStyle(c.sup());u=z(e.value.sup,m);a=p([c.reset(),c.sup().cls()],[u],m)}if(e.value.sub){m=t.withStyle(c.sub());h=z(e.value.sub,m);s=p([c.reset(),c.sub().cls()],[h],m)}var f;var v;if(x(e.value.base)){f=0;v=0}else{f=r.height-c.metrics.supDrop;v=r.depth+c.metrics.subDrop}var y;if(c===i.DISPLAY){y=c.metrics.sup1}else if(c.cramped){y=c.metrics.sup3}else{y=c.metrics.sup2}var b=i.TEXT.sizeMultiplier*c.sizeMultiplier;var k=.5/o.metrics.ptPerEm/b+"em";var S;if(!e.value.sup){v=Math.max(v,c.metrics.sub1,h.height-.8*c.metrics.xHeight);S=n.makeVList([{type:"elem",elem:s}],"shift",v,t);S.children[0].style.marginRight=k;if(r instanceof l.symbolNode){S.children[0].style.marginLeft=-r.italic+"em"}}else if(!e.value.sub){f=Math.max(f,y,u.depth+.25*c.metrics.xHeight);S=n.makeVList([{type:"elem",elem:a}],"shift",-f,t);S.children[0].style.marginRight=k}else{f=Math.max(f,y,u.depth+.25*c.metrics.xHeight);v=Math.max(v,c.metrics.sub2);var M=o.metrics.defaultRuleThickness;if(f-u.depth-(h.height-v)<4*M){v=4*M-(f-u.depth)+h.height;var T=.8*c.metrics.xHeight-(f-u.depth);if(T>0){f+=T;v-=T}}S=n.makeVList([{type:"elem",elem:s,shift:v},{type:"elem",elem:a,shift:-f}],"individualShift",null,t);if(r instanceof l.symbolNode){S.children[0].style.marginLeft=-r.italic+"em"}S.children[0].style.marginRight=k;S.children[1].style.marginRight=k}var A=d(r)||"mord";return p([A],[r,p(["msupsub"],[S])],t)};w.genfrac=function(e,t){var r=t.style;if(e.value.size==="display"){r=i.DISPLAY}else if(e.value.size==="text"){r=i.TEXT}var a=r.fracNum();var l=r.fracDen();var u;u=t.withStyle(a);var h=z(e.value.numer,u);var c=p([r.reset(),a.cls()],[h],u);u=t.withStyle(l);var m=z(e.value.denom,u);var f=p([r.reset(),l.cls()],[m],u);var v;if(e.value.hasBarLine){v=o.metrics.defaultRuleThickness/t.style.sizeMultiplier}else{v=0}var d;var g;var y;if(r.size===i.DISPLAY.size){d=r.metrics.num1;if(v>0){g=3*v}else{g=7*o.metrics.defaultRuleThickness}y=r.metrics.denom1}else{if(v>0){d=r.metrics.num2;g=v}else{d=r.metrics.num3;g=3*o.metrics.defaultRuleThickness}y=r.metrics.denom2}var x;if(v===0){var w=d-h.depth-(m.height-y);if(w<g){d+=.5*(g-w);y+=.5*(g-w)}x=n.makeVList([{type:"elem",elem:f,shift:y},{type:"elem",elem:c,shift:-d}],"individualShift",null,t)}else{var k=r.metrics.axisHeight;if(d-h.depth-(k+.5*v)<g){d+=g-(d-h.depth-(k+.5*v))}if(k-.5*v-(m.height-y)<g){y+=g-(k-.5*v-(m.height-y))}var S=p([t.style.reset(),i.TEXT.cls(),"frac-line"]);S.height=v;var M=-(k-.5*v);x=n.makeVList([{type:"elem",elem:f,shift:y},{type:"elem",elem:S,shift:M},{type:"elem",elem:c,shift:-d}],"individualShift",null,t)}x.height*=r.sizeMultiplier/t.style.sizeMultiplier;x.depth*=r.sizeMultiplier/t.style.sizeMultiplier;var T;if(r.size===i.DISPLAY.size){T=r.metrics.delim1}else{T=r.metrics.delim2}var A;var N;if(e.value.leftDelim==null){A=b(t,["mopen"])}else{A=s.customSizedDelim(e.value.leftDelim,T,true,t.withStyle(r),e.mode,["mopen"])}if(e.value.rightDelim==null){N=b(t,["mclose"])}else{N=s.customSizedDelim(e.value.rightDelim,T,true,t.withStyle(r),e.mode,["mclose"])}return p(["mord",t.style.reset(),r.cls()],[A,p(["mfrac"],[x]),N],t)};var k=function(e,t){var r=e.number;if(e.unit==="ex"){r*=t.metrics.emPerEx}else if(e.unit==="mu"){r/=18}return r};w.array=function(e,t){var r;var i;var s=e.value.body.length;var l=0;var h=new Array(s);var c=t.style;var m=1/o.metrics.ptPerEm;var f=5*m;var v=12*m;var d=u.deflt(e.value.arraystretch,1);var g=d*v;var y=.7*g;var x=.3*g;var b=0;for(r=0;r<e.value.body.length;++r){var w=e.value.body[r];var S=y;var M=x;if(l<w.length){l=w.length}var T=new Array(w.length);for(i=0;i<w.length;++i){var A=z(w[i],t);if(M<A.depth){M=A.depth}if(S<A.height){S=A.height}T[i]=A}var N=0;if(e.value.rowGaps[r]){N=k(e.value.rowGaps[r].value,c);if(N>0){N+=x;if(M<N){M=N}N=0}}T.height=S;T.depth=M;b+=S;T.pos=b;b+=M+N;h[r]=T}var q=b/2+c.metrics.axisHeight;var R=e.value.cols||[];var E=[];var C;var D;for(i=0,D=0;i<l||D<R.length;++i,++D){var O=R[D]||{};var P=true;while(O.type==="separator"){if(!P){C=p(["arraycolsep"],[]);C.style.width=o.metrics.doubleRuleSep+"em";E.push(C)}if(O.separator==="|"){var F=p(["vertical-separator"],[]);F.style.height=b+"em";F.style.verticalAlign=-(b-q)+"em";E.push(F)}else{throw new a("Invalid separator type: "+O.separator)}D++;O=R[D]||{};P=false}if(i>=l){continue}var I;if(i>0||e.value.hskipBeforeAndAfter){I=u.deflt(O.pregap,f);if(I!==0){C=p(["arraycolsep"],[]);C.style.width=I+"em";E.push(C)}}var L=[];for(r=0;r<s;++r){var B=h[r];var G=B[i];if(!G){continue}var V=B.pos-q;G.depth=B.depth;G.height=B.height;L.push({type:"elem",elem:G,shift:V})}L=n.makeVList(L,"individualShift",null,t);L=p(["col-align-"+(O.align||"c")],[L]);E.push(L);if(i<l-1||e.value.hskipBeforeAndAfter){I=u.deflt(O.postgap,f);if(I!==0){C=p(["arraycolsep"],[]);C.style.width=I+"em";E.push(C)}}}h=p(["mtable"],E);return p(["mord"],[h],t)};w.spacing=function(e,t){if(e.value==="\\ "||e.value==="\\space"||e.value===" "||e.value==="~"){if(e.mode==="text"){return n.makeOrd(e,t,"textord")}else{return p(["mspace"],[n.mathsym(e.value,e.mode,t)],t)}}else{return p(["mspace",n.spacingFunctions[e.value].className],[],t)}};w.llap=function(e,t){var r=p(["inner"],[z(e.value.body,t.reset())]);var a=p(["fix"],[]);return p(["mord","llap",t.style.cls()],[r,a],t)};w.rlap=function(e,t){var r=p(["inner"],[z(e.value.body,t.reset())]);var a=p(["fix"],[]);return p(["mord","rlap",t.style.cls()],[r,a],t)};w.op=function(e,t){var r;var a;var s=false;if(e.type==="supsub"){r=e.value.sup;a=e.value.sub;e=e.value.base;s=true}var l=t.style;var h=["\\smallint"];var c=false;if(l.size===i.DISPLAY.size&&e.value.symbol&&!u.contains(h,e.value.body)){c=true}var m;var f=0;var d=0;if(e.value.symbol){var g=c?"Size2-Regular":"Size1-Regular";m=n.makeSymbol(e.value.body,g,"math",t,["mop","op-symbol",c?"large-op":"small-op"]);f=(m.height-m.depth)/2-l.metrics.axisHeight*l.sizeMultiplier;d=m.italic}else if(e.value.value){var y=v(e.value.value,t,true);m=p(["mop"],y,t)}else{var x=[];for(var b=1;b<e.value.body.length;b++){x.push(n.mathsym(e.value.body[b],e.mode))}m=p(["mop"],x,t)}if(s){m=p([],[m]);var w;var k;var S;var M;var T;if(r){T=t.withStyle(l.sup());var A=z(r,T);w=p([l.reset(),l.sup().cls()],[A],T);k=Math.max(o.metrics.bigOpSpacing1,o.metrics.bigOpSpacing3-A.depth)}if(a){T=t.withStyle(l.sub());var N=z(a,T);S=p([l.reset(),l.sub().cls()],[N],T);M=Math.max(o.metrics.bigOpSpacing2,o.metrics.bigOpSpacing4-N.height)}var q;var R;var E;if(!r){R=m.height-f;q=n.makeVList([{type:"kern",size:o.metrics.bigOpSpacing5},{type:"elem",elem:S},{type:"kern",size:M},{type:"elem",elem:m}],"top",R,t);q.children[0].style.marginLeft=-d+"em"}else if(!a){E=m.depth+f;q=n.makeVList([{type:"elem",elem:m},{type:"kern",size:k},{type:"elem",elem:w},{type:"kern",size:o.metrics.bigOpSpacing5}],"bottom",E,t);q.children[1].style.marginLeft=d+"em"}else if(!r&&!a){return m}else{E=o.metrics.bigOpSpacing5+S.height+S.depth+M+m.depth+f;
+q=n.makeVList([{type:"kern",size:o.metrics.bigOpSpacing5},{type:"elem",elem:S},{type:"kern",size:M},{type:"elem",elem:m},{type:"kern",size:k},{type:"elem",elem:w},{type:"kern",size:o.metrics.bigOpSpacing5}],"bottom",E,t);q.children[0].style.marginLeft=-d+"em";q.children[2].style.marginLeft=d+"em"}return p(["mop","op-limits"],[q],t)}else{if(e.value.symbol){m.style.top=f+"em"}return m}};w.mod=function(e,t){var r=[];if(e.value.modType==="bmod"){if(!t.style.isTight()){r.push(p(["mspace","negativemediumspace"],[],t))}r.push(p(["mspace","thickspace"],[],t))}else if(t.style.size===i.DISPLAY.size){r.push(p(["mspace","quad"],[],t))}else if(e.value.modType==="mod"){r.push(p(["mspace","twelvemuspace"],[],t))}else{r.push(p(["mspace","eightmuspace"],[],t))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(n.mathsym("(",e.mode))}if(e.value.modType!=="pod"){var a=[n.mathsym("m",e.mode),n.mathsym("o",e.mode),n.mathsym("d",e.mode)];if(e.value.modType==="bmod"){r.push(p(["mbin"],a,t));r.push(p(["mspace","thickspace"],[],t));if(!t.style.isTight()){r.push(p(["mspace","negativemediumspace"],[],t))}}else{Array.prototype.push.apply(r,a);r.push(p(["mspace","sixmuspace"],[],t))}}if(e.value.value){Array.prototype.push.apply(r,v(e.value.value,t,false))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(n.mathsym(")",e.mode))}return n.makeFragment(r)};w.katex=function(e,t){var r=p(["k"],[n.mathsym("K",e.mode)],t);var a=p(["a"],[n.mathsym("A",e.mode)],t);a.height=(a.height+.2)*.75;a.depth=(a.height-.2)*.75;var i=p(["t"],[n.mathsym("T",e.mode)],t);var s=p(["e"],[n.mathsym("E",e.mode)],t);s.height=s.height-.2155;s.depth=s.depth+.2155;var l=p(["x"],[n.mathsym("X",e.mode)],t);return p(["mord","katex-logo"],[r,a,i,s,l],t)};w.overline=function(e,t){var r=t.style;var a=z(e.value.body,t.withStyle(r.cramp()));var s=o.metrics.defaultRuleThickness/r.sizeMultiplier;var l=p([r.reset(),i.TEXT.cls(),"overline-line"]);l.height=s;l.maxFontSize=1;var u=n.makeVList([{type:"elem",elem:a},{type:"kern",size:3*s},{type:"elem",elem:l},{type:"kern",size:s}],"firstBaseline",null,t);return p(["mord","overline"],[u],t)};w.underline=function(e,t){var r=t.style;var a=z(e.value.body,t);var s=o.metrics.defaultRuleThickness/r.sizeMultiplier;var l=p([r.reset(),i.TEXT.cls(),"underline-line"]);l.height=s;l.maxFontSize=1;var u=n.makeVList([{type:"kern",size:s},{type:"elem",elem:l},{type:"kern",size:3*s},{type:"elem",elem:a}],"top",a.height,t);return p(["mord","underline"],[u],t)};w.sqrt=function(e,t){var r=t.style;var a=z(e.value.body,t.withStyle(r.cramp()));var l=o.metrics.defaultRuleThickness/r.sizeMultiplier;var u=p([r.reset(),i.TEXT.cls(),"sqrt-line"],[],t);u.height=l;u.maxFontSize=1;var h=l;if(r.id<i.TEXT.id){h=r.metrics.xHeight}var c=l+h/4;var m=(a.height+a.depth)*r.sizeMultiplier;var f=m+c+l;var v=p(["sqrt-sign"],[s.customSizedDelim("\\surd",f,false,t,e.mode)],t);var d=v.height+v.depth-l;if(d>a.height+a.depth+c){c=(c+d-a.height-a.depth)/2}var g=-(a.height+c+l)+v.height;v.style.top=g+"em";v.height-=g;v.depth+=g;var y;if(a.height===0&&a.depth===0){y=p()}else{y=n.makeVList([{type:"elem",elem:a},{type:"kern",size:c},{type:"elem",elem:u},{type:"kern",size:l}],"firstBaseline",null,t)}if(!e.value.index){return p(["mord","sqrt"],[v,y],t)}else{var x=t.withStyle(i.SCRIPTSCRIPT);var b=z(e.value.index,x);var w=p([r.reset(),i.SCRIPTSCRIPT.cls()],[b],x);var k=Math.max(v.height,y.height);var S=Math.max(v.depth,y.depth);var M=.6*(k-S);var T=n.makeVList([{type:"elem",elem:w}],"shift",-M,t);var A=p(["root"],[T]);return p(["mord","sqrt"],[A,v,y],t)}};w.sizing=function(e,t){var r=v(e.value.value,t.withSize(e.value.size),false);var a=t.style;var i=n.sizingMultiplier[e.value.size];i=i*a.sizeMultiplier;for(var s=0;s<r.length;s++){var l=u.indexOf(r[s].classes,"sizing");if(l<0){r[s].classes.push("sizing","reset-"+t.size,e.value.size,a.cls());r[s].maxFontSize=i}else if(r[s].classes[l+1]==="reset-"+e.value.size){r[s].classes[l+1]="reset-"+t.size}}return n.makeFragment(r)};w.styling=function(e,t){var r={display:i.DISPLAY,text:i.TEXT,script:i.SCRIPT,scriptscript:i.SCRIPTSCRIPT};var a=r[e.value.style];var s=t.withStyle(a);var l=v(e.value.value,s,false);for(var o=0;o<l.length;o++){var p=u.indexOf(l[o].classes,a.reset());if(p<0){l[o].classes.push(t.style.reset(),a.cls())}else{l[o].classes[p]=t.style.reset()}}return new n.makeFragment(l)};w.font=function(e,t){var r=e.value.font;return z(e.value.body,t.withFont(r))};w.delimsizing=function(e,t){var r=e.value.value;if(r==="."){return p([e.value.mclass])}return s.sizedDelim(r,e.value.size,t,e.mode,[e.value.mclass])};w.leftright=function(e,t){var r=v(e.value.body,t.reset(),true);var a=0;var i=0;var n=false;for(var l=0;l<r.length;l++){if(r[l].isMiddle){n=true}else{a=Math.max(r[l].height,a);i=Math.max(r[l].depth,i)}}var o=t.style;a*=o.sizeMultiplier;i*=o.sizeMultiplier;var u;if(e.value.left==="."){u=b(t,["mopen"])}else{u=s.leftRightDelim(e.value.left,a,i,t,e.mode,["mopen"])}r.unshift(u);if(n){for(l=1;l<r.length;l++){if(r[l].isMiddle){r[l]=s.leftRightDelim(r[l].isMiddle.value,a,i,r[l].isMiddle.options,e.mode,[])}}}var h;if(e.value.right==="."){h=b(t,["mclose"])}else{h=s.leftRightDelim(e.value.right,a,i,t,e.mode,["mclose"])}r.push(h);return p(["minner",o.cls()],r,t)};w.middle=function(e,t){var r;if(e.value.value==="."){r=b(t,[])}else{r=s.sizedDelim(e.value.value,1,t,e.mode,[]);r.isMiddle={value:e.value.value,options:t}}return r};w.rule=function(e,t){var r=p(["mord","rule"],[],t);var a=t.style;var i=0;if(e.value.shift){i=k(e.value.shift,a)}var n=k(e.value.width,a);var s=k(e.value.height,a);i/=a.sizeMultiplier;n/=a.sizeMultiplier;s/=a.sizeMultiplier;r.style.borderRightWidth=n+"em";r.style.borderTopWidth=s+"em";r.style.bottom=i+"em";r.width=n;r.height=s+i;r.depth=-i;return r};w.kern=function(e,t){var r=p(["mord","rule"],[],t);var a=t.style;var i=0;if(e.value.dimension){i=k(e.value.dimension,a)}i/=a.sizeMultiplier;r.style.marginLeft=i+"em";return r};w.accent=function(e,t){var r=e.value.base;var a=t.style;var i;if(e.type==="supsub"){var s=e;e=s.value.base;r=e.value.base;s.value.base=r;i=z(s,t.reset())}var l=z(r,t.withStyle(a.cramp()));var o;if(x(r)){var u=y(r);var h=z(u,t.withStyle(a.cramp()));o=h.skew}else{o=0}var c=Math.min(l.height,a.metrics.xHeight);var m=n.makeSymbol(e.value.accent,"Main-Regular","math",t);m.italic=0;var f=e.value.accent==="\\vec"?"accent-vec":null;var v=p(["accent-body",f],[p([],[m])]);v=n.makeVList([{type:"elem",elem:l},{type:"kern",size:-c},{type:"elem",elem:v}],"firstBaseline",null,t);v.children[1].style.marginLeft=2*o+"em";var d=p(["mord","accent"],[v],t);if(i){i.children[0]=d;i.height=Math.max(d.height,i.height);i.classes[0]="mord";return i}else{return d}};w.phantom=function(e,t){var r=v(e.value.value,t.withPhantom(),false);return new n.makeFragment(r)};w.mclass=function(e,t){var r=v(e.value.value,t,true);return p([e.value.mclass],r,t)};var z=function(e,t){if(!e){return p()}if(w[e.type]){var r=w[e.type](e,t);var i;if(t.style!==t.parentStyle){i=t.style.sizeMultiplier/t.parentStyle.sizeMultiplier;r.height*=i;r.depth*=i}if(t.size!==t.parentSize){i=n.sizingMultiplier[t.size]/n.sizingMultiplier[t.parentSize];r.height*=i;r.depth*=i}return r}else{throw new a("Got group of unknown type: '"+e.type+"'")}};var S=function(e,t){e=JSON.parse(JSON.stringify(e));var r=v(e,t,true);var a=p(["base",t.style.cls()],r,t);var i=p(["strut"]);var n=p(["strut","bottom"]);i.style.height=a.height+"em";n.style.height=a.height+a.depth+"em";n.style.verticalAlign=-a.depth+"em";var s=p(["katex-html"],[i,n,a]);s.setAttribute("aria-hidden","true");return s};t.exports=S},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./delimiter":14,"./domTree":15,"./fontMetrics":17,"./utils":25}],12:[function(e,t,r){var a=e("./buildCommon");var i=e("./fontMetrics");var n=e("./mathMLTree");var s=e("./ParseError");var l=e("./symbols");var o=e("./utils");var u=a.makeSpan;var p=a.fontMap;var h=function(e,t){if(l[t][e]&&l[t][e].replace){e=l[t][e].replace}return new n.TextNode(e)};var c=function(e,t){var r=t.font;if(!r){return null}var a=e.mode;if(r==="mathit"){return"italic"}var n=e.value;if(o.contains(["\\imath","\\jmath"],n)){return null}if(l[a][n]&&l[a][n].replace){n=l[a][n].replace}var s=p[r].fontName;if(i.getCharacterMetrics(n,s)){return p[t.font].variant}return null};var m={};m.mathord=function(e,t){var r=new n.MathNode("mi",[h(e.value,e.mode)]);var a=c(e,t);if(a){r.setAttribute("mathvariant",a)}return r};m.textord=function(e,t){var r=h(e.value,e.mode);var a=c(e,t)||"normal";var i;if(/[0-9]/.test(e.value)){i=new n.MathNode("mn",[r]);if(t.font){i.setAttribute("mathvariant",a)}}else{i=new n.MathNode("mi",[r]);i.setAttribute("mathvariant",a)}return i};m.bin=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.rel=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.open=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.close=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.inner=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);return t};m.punct=function(e){var t=new n.MathNode("mo",[h(e.value,e.mode)]);t.setAttribute("separator","true");return t};m.ordgroup=function(e,t){var r=f(e.value,t);var a=new n.MathNode("mrow",r);return a};m.text=function(e,t){var r=f(e.value.body,t);var a=new n.MathNode("mtext",r);return a};m.color=function(e,t){var r=f(e.value.value,t);var a=new n.MathNode("mstyle",r);a.setAttribute("mathcolor",e.value.color);return a};m.supsub=function(e,t){var r=[v(e.value.base,t)];if(e.value.sub){r.push(v(e.value.sub,t))}if(e.value.sup){r.push(v(e.value.sup,t))}var a;if(!e.value.sub){a="msup"}else if(!e.value.sup){a="msub"}else{a="msubsup"}var i=new n.MathNode(a,r);return i};m.genfrac=function(e,t){var r=new n.MathNode("mfrac",[v(e.value.numer,t),v(e.value.denom,t)]);if(!e.value.hasBarLine){r.setAttribute("linethickness","0px")}if(e.value.leftDelim!=null||e.value.rightDelim!=null){var a=[];if(e.value.leftDelim!=null){var i=new n.MathNode("mo",[new n.TextNode(e.value.leftDelim)]);i.setAttribute("fence","true");a.push(i)}a.push(r);if(e.value.rightDelim!=null){var s=new n.MathNode("mo",[new n.TextNode(e.value.rightDelim)]);s.setAttribute("fence","true");a.push(s)}var l=new n.MathNode("mrow",a);return l}return r};m.array=function(e,t){return new n.MathNode("mtable",e.value.body.map(function(e){return new n.MathNode("mtr",e.map(function(e){return new n.MathNode("mtd",[v(e,t)])}))}))};m.sqrt=function(e,t){var r;if(e.value.index){r=new n.MathNode("mroot",[v(e.value.body,t),v(e.value.index,t)])}else{r=new n.MathNode("msqrt",[v(e.value.body,t)])}return r};m.leftright=function(e,t){var r=f(e.value.body,t);if(e.value.left!=="."){var a=new n.MathNode("mo",[h(e.value.left,e.mode)]);a.setAttribute("fence","true");r.unshift(a)}if(e.value.right!=="."){var i=new n.MathNode("mo",[h(e.value.right,e.mode)]);i.setAttribute("fence","true");r.push(i)}var s=new n.MathNode("mrow",r);return s};m.middle=function(e,t){var r=new n.MathNode("mo",[h(e.value.middle,e.mode)]);r.setAttribute("fence","true");return r};m.accent=function(e,t){var r=new n.MathNode("mo",[h(e.value.accent,e.mode)]);var a=new n.MathNode("mover",[v(e.value.base,t),r]);a.setAttribute("accent","true");return a};m.spacing=function(e){var t;if(e.value==="\\ "||e.value==="\\space"||e.value===" "||e.value==="~"){t=new n.MathNode("mtext",[new n.TextNode("\xa0")])}else{t=new n.MathNode("mspace");t.setAttribute("width",a.spacingFunctions[e.value].size)}return t};m.op=function(e,t){var r;if(e.value.symbol){r=new n.MathNode("mo",[h(e.value.body,e.mode)])}else if(e.value.value){r=new n.MathNode("mo",f(e.value.value,t))}else{r=new n.MathNode("mi",[new n.TextNode(e.value.body.slice(1))])}return r};m.mod=function(e,t){var r=[];if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(new n.MathNode("mo",[h("(",e.mode)]))}if(e.value.modType!=="pod"){r.push(new n.MathNode("mo",[h("mod",e.mode)]))}if(e.value.value){var a=new n.MathNode("mspace");a.setAttribute("width","0.333333em");r.push(a);r=r.concat(f(e.value.value,t))}if(e.value.modType==="pod"||e.value.modType==="pmod"){r.push(new n.MathNode("mo",[h(")",e.mode)]))}return new n.MathNode("mo",r)};m.katex=function(e){var t=new n.MathNode("mtext",[new n.TextNode("KaTeX")]);return t};m.font=function(e,t){var r=e.value.font;return v(e.value.body,t.withFont(r))};m.delimsizing=function(e){var t=[];if(e.value.value!=="."){t.push(h(e.value.value,e.mode))}var r=new n.MathNode("mo",t);if(e.value.mclass==="mopen"||e.value.mclass==="mclose"){r.setAttribute("fence","true")}else{r.setAttribute("fence","false")}return r};m.styling=function(e,t){var r=f(e.value.value,t);var a=new n.MathNode("mstyle",r);var i={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]};var s=i[e.value.style];a.setAttribute("scriptlevel",s[0]);a.setAttribute("displaystyle",s[1]);return a};m.sizing=function(e,t){var r=f(e.value.value,t);var i=new n.MathNode("mstyle",r);i.setAttribute("mathsize",a.sizingMultiplier[e.value.size]+"em");return i};m.overline=function(e,t){var r=new n.MathNode("mo",[new n.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new n.MathNode("mover",[v(e.value.body,t),r]);a.setAttribute("accent","true");return a};m.underline=function(e,t){var r=new n.MathNode("mo",[new n.TextNode("\u203e")]);r.setAttribute("stretchy","true");var a=new n.MathNode("munder",[v(e.value.body,t),r]);a.setAttribute("accentunder","true");return a};m.rule=function(e){var t=new n.MathNode("mrow");return t};m.kern=function(e){var t=new n.MathNode("mrow");return t};m.llap=function(e,t){var r=new n.MathNode("mpadded",[v(e.value.body,t)]);r.setAttribute("lspace","-1width");r.setAttribute("width","0px");return r};m.rlap=function(e,t){var r=new n.MathNode("mpadded",[v(e.value.body,t)]);r.setAttribute("width","0px");return r};m.phantom=function(e,t){var r=f(e.value.value,t);return new n.MathNode("mphantom",r)};m.mclass=function(e,t){var r=f(e.value.value,t);return new n.MathNode("mstyle",r)};var f=function(e,t){var r=[];for(var a=0;a<e.length;a++){var i=e[a];r.push(v(i,t))}return r};var v=function(e,t){if(!e){return new n.MathNode("mrow")}if(m[e.type]){return m[e.type](e,t)}else{throw new s("Got group of unknown type: '"+e.type+"'")}};var d=function(e,t,r){var a=f(e,r);var i=new n.MathNode("mrow",a);var s=new n.MathNode("annotation",[new n.TextNode(t)]);s.setAttribute("encoding","application/x-tex");var l=new n.MathNode("semantics",[i,s]);var o=new n.MathNode("math",[l]);return u(["katex-mathml"],[o])};t.exports=d},{"./ParseError":6,"./buildCommon":10,"./fontMetrics":17,"./mathMLTree":20,"./symbols":23,"./utils":25}],13:[function(e,t,r){var a=e("./buildHTML");var i=e("./buildMathML");var n=e("./buildCommon");var s=e("./Options");var l=e("./Settings");var o=e("./Style");var u=n.makeSpan;var p=function(e,t,r){r=r||new l({});var n=o.TEXT;if(r.displayMode){n=o.DISPLAY}var p=new s({style:n,size:"size5"});var h=i(e,t,p);var c=a(e,p);var m=u(["katex"],[h,c]);if(r.displayMode){return u(["katex-display"],[m])}else{return m}};t.exports=p},{"./Options":5,"./Settings":8,"./Style":9,"./buildCommon":10,"./buildHTML":11,"./buildMathML":12}],14:[function(e,t,r){var a=e("./ParseError");var i=e("./Style");var n=e("./buildCommon");var s=e("./fontMetrics");var l=e("./symbols");var o=e("./utils");var u=n.makeSpan;var p=function(e,t){if(l.math[e]&&l.math[e].replace){return s.getCharacterMetrics(l.math[e].replace,t)}else{return s.getCharacterMetrics(e,t)}};var h=function(e,t,r,a){return n.makeSymbol(e,"Size"+t+"-Regular",r,a)};var c=function(e,t,r,a){a=a||[];var i=u(a.concat(["style-wrap",r.style.reset(),t.cls()]),[e],r);var n=t.sizeMultiplier/r.style.sizeMultiplier;i.height*=n;i.depth*=n;i.maxFontSize=t.sizeMultiplier;return i};var m=function(e,t,r,a,i,s){var l=n.makeSymbol(e,"Main-Regular",i,a);var o=c(l,t,a,s);if(r){var u=(1-a.style.sizeMultiplier/t.sizeMultiplier)*a.style.metrics.axisHeight;o.style.top=u+"em";o.height-=u;o.depth+=u}return o};var f=function(e,t,r,a,n,s){var l=h(e,t,n,a);var o=c(u(["delimsizing","size"+t],[l],a),i.TEXT,a,s);if(r){var p=(1-a.style.sizeMultiplier)*a.style.metrics.axisHeight;o.style.top=p+"em";o.height-=p;o.depth+=p}return o};var v=function(e,t,r){var a;if(t==="Size1-Regular"){a="delim-size1"}else if(t==="Size4-Regular"){a="delim-size4"}var i=u(["delimsizinginner",a],[u([],[n.makeSymbol(e,t,r)])]);return{type:"elem",elem:i}};var d=function(e,t,r,a,s,l){var o;var h;var m;var f;o=m=f=e;h=null;var d="Size1-Regular";if(e==="\\uparrow"){m=f="\u23d0"}else if(e==="\\Uparrow"){m=f="\u2016"}else if(e==="\\downarrow"){o=m="\u23d0"}else if(e==="\\Downarrow"){o=m="\u2016"}else if(e==="\\updownarrow"){o="\\uparrow";m="\u23d0";f="\\downarrow"}else if(e==="\\Updownarrow"){o="\\Uparrow";m="\u2016";f="\\Downarrow"}else if(e==="["||e==="\\lbrack"){o="\u23a1";m="\u23a2";f="\u23a3";d="Size4-Regular"}else if(e==="]"||e==="\\rbrack"){o="\u23a4";m="\u23a5";f="\u23a6";d="Size4-Regular"}else if(e==="\\lfloor"){m=o="\u23a2";f="\u23a3";d="Size4-Regular"}else if(e==="\\lceil"){o="\u23a1";m=f="\u23a2";d="Size4-Regular"}else if(e==="\\rfloor"){m=o="\u23a5";f="\u23a6";d="Size4-Regular"}else if(e==="\\rceil"){o="\u23a4";m=f="\u23a5";d="Size4-Regular"}else if(e==="("){o="\u239b";m="\u239c";f="\u239d";d="Size4-Regular"}else if(e===")"){o="\u239e";m="\u239f";f="\u23a0";d="Size4-Regular"}else if(e==="\\{"||e==="\\lbrace"){o="\u23a7";h="\u23a8";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\}"||e==="\\rbrace"){o="\u23ab";h="\u23ac";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\lgroup"){o="\u23a7";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\rgroup"){o="\u23ab";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\lmoustache"){o="\u23a7";f="\u23ad";m="\u23aa";d="Size4-Regular"}else if(e==="\\rmoustache"){o="\u23ab";f="\u23a9";m="\u23aa";d="Size4-Regular"}else if(e==="\\surd"){o="\ue001";f="\u23b7";m="\ue000";d="Size4-Regular"}var g=p(o,d);var y=g.height+g.depth;var x=p(m,d);var b=x.height+x.depth;var w=p(f,d);var k=w.height+w.depth;var z=0;var S=1;if(h!==null){var M=p(h,d);z=M.height+M.depth;S=2}var T=y+k+z;var A=Math.ceil((t-T)/(S*b));var N=T+A*S*b;var q=a.style.metrics.axisHeight;if(r){q*=a.style.sizeMultiplier}var R=N/2-q;var E=[];E.push(v(f,d,s));var C;if(h===null){for(C=0;C<A;C++){E.push(v(m,d,s))}}else{for(C=0;C<A;C++){E.push(v(m,d,s))}E.push(v(h,d,s));for(C=0;C<A;C++){E.push(v(m,d,s))}}E.push(v(o,d,s));var D=n.makeVList(E,"bottom",R,a);return c(u(["delimsizing","mult"],[D],a),i.TEXT,a,l)};var g=["(",")","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\\lceil","\\rceil","\\surd"];var y=["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\\lmoustache","\\rmoustache"];var x=["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"];var b=[0,1.2,1.8,2.4,3];var w=function(e,t,r,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}if(o.contains(g,e)||o.contains(x,e)){return f(e,t,false,r,i,n)}else if(o.contains(y,e)){return d(e,b[t],false,r,i,n)}else{throw new a("Illegal delimiter: '"+e+"'")}};var k=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}];var z=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"stack"}];var S=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}];var M=function(e){if(e.type==="small"){return"Main-Regular"}else if(e.type==="large"){return"Size"+e.size+"-Regular"}else if(e.type==="stack"){return"Size4-Regular"}};var T=function(e,t,r,a){var i=Math.min(2,3-a.style.size);for(var n=i;n<r.length;n++){if(r[n].type==="stack"){break}var s=p(e,M(r[n]));var l=s.height+s.depth;if(r[n].type==="small"){l*=r[n].style.sizeMultiplier}if(l>t){return r[n]}}return r[r.length-1]};var A=function(e,t,r,a,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}var s;if(o.contains(x,e)){s=k}else if(o.contains(g,e)){s=S}else{s=z}var l=T(e,t,s,a);if(l.type==="small"){return m(e,l.style,r,a,i,n)}else if(l.type==="large"){return f(e,l.size,r,a,i,n)}else if(l.type==="stack"){return d(e,t,r,a,i,n)}};var N=function(e,t,r,a,i,n){var l=a.style.metrics.axisHeight*a.style.sizeMultiplier;var o=901;var u=5/s.metrics.ptPerEm;var p=Math.max(t-l,r+l);var h=Math.max(p/500*o,2*p-u);return A(e,h,true,a,i,n)};t.exports={sizedDelim:w,customSizedDelim:A,leftRightDelim:N}},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(e,t,r){var a=e("./unicodeRegexes");var i=e("./utils");var n=function(e){e=e.slice();for(var t=e.length-1;t>=0;t--){if(!e[t]){e.splice(t,1)}}return e.join(" ")};function s(e,t,r){this.classes=e||[];this.children=t||[];this.height=0;this.depth=0;this.maxFontSize=0;this.style={};this.attributes={};if(r){if(r.style.isTight()){this.classes.push("mtight")}if(r.getColor()){this.style.color=r.getColor()}}}s.prototype.setAttribute=function(e,t){this.attributes[e]=t};s.prototype.tryCombine=function(e){return false};s.prototype.toNode=function(){var e=document.createElement("span");e.className=n(this.classes);for(var t in this.style){if(Object.prototype.hasOwnProperty.call(this.style,t)){e.style[t]=this.style[t]}}for(var r in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,r)){e.setAttribute(r,this.attributes[r])}}for(var a=0;a<this.children.length;a++){e.appendChild(this.children[a].toNode())}return e};s.prototype.toMarkup=function(){var e="<span";if(this.classes.length){e+=' class="';e+=i.escape(n(this.classes));e+='"'}var t="";for(var r in this.style){if(this.style.hasOwnProperty(r)){t+=i.hyphenate(r)+":"+this.style[r]+";"}}if(t){e+=' style="'+i.escape(t)+'"'}for(var a in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,a)){e+=" "+a+'="';e+=i.escape(this.attributes[a]);e+='"'}}e+=">";for(var s=0;s<this.children.length;s++){e+=this.children[s].toMarkup()}e+="</span>";return e};function l(e){this.children=e||[];this.height=0;this.depth=0;this.maxFontSize=0}l.prototype.toNode=function(){var e=document.createDocumentFragment();for(var t=0;t<this.children.length;t++){e.appendChild(this.children[t].toNode())}return e};l.prototype.toMarkup=function(){var e="";for(var t=0;t<this.children.length;t++){e+=this.children[t].toMarkup()}return e};var o={"\xee":"\u0131\u0302","\xef":"\u0131\u0308","\xed":"\u0131\u0301","\xec":"\u0131\u0300"};function u(e,t,r,i,n,s,l){this.value=e||"";this.height=t||0;this.depth=r||0;this.italic=i||0;this.skew=n||0;this.classes=s||[];this.style=l||{};this.maxFontSize=0;if(a.cjkRegex.test(e)){if(a.hangulRegex.test(e)){this.classes.push("hangul_fallback")}else{this.classes.push("cjk_fallback")}}if(/[\xee\xef\xed\xec]/.test(this.value)){this.value=o[this.value]}}u.prototype.tryCombine=function(e){if(!e||!(e instanceof u)||this.italic>0||n(this.classes)!==n(e.classes)||this.skew!==e.skew||this.maxFontSize!==e.maxFontSize){return false}for(var t in this.style){if(this.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}for(t in e.style){if(e.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}this.value+=e.value;this.height=Math.max(this.height,e.height);this.depth=Math.max(this.depth,e.depth);this.italic=e.italic;return true};u.prototype.toNode=function(){var e=document.createTextNode(this.value);var t=null;if(this.italic>0){t=document.createElement("span");t.style.marginRight=this.italic+"em"}if(this.classes.length>0){t=t||document.createElement("span");t.className=n(this.classes)}for(var r in this.style){if(this.style.hasOwnProperty(r)){t=t||document.createElement("span");t.style[r]=this.style[r]}}if(t){t.appendChild(e);return t}else{return e}};u.prototype.toMarkup=function(){var e=false;var t="<span";if(this.classes.length){e=true;t+=' class="';t+=i.escape(n(this.classes));t+='"'}var r="";if(this.italic>0){r+="margin-right:"+this.italic+"em;"}for(var a in this.style){if(this.style.hasOwnProperty(a)){r+=i.hyphenate(a)+":"+this.style[a]+";"}}if(r){e=true;t+=' style="'+i.escape(r)+'"'}var s=i.escape(this.value);if(e){t+=">";t+=s;t+="</span>";return t}else{return s}};t.exports={span:s,documentFragment:l,symbolNode:u}},{"./unicodeRegexes":24,"./utils":25}],16:[function(e,t,r){var a=e("./parseData");var i=e("./ParseError");var n=e("./Style");var s=a.ParseNode;function l(e,t){var r=[];var a=[r];var n=[];while(true){var l=e.parseExpression(false,null);r.push(new s("ordgroup",l,e.mode));var o=e.nextToken.text;if(o==="&"){e.consume()}else if(o==="\\end"){break}else if(o==="\\\\"||o==="\\cr"){var u=e.parseFunction();n.push(u.value.size);r=[];a.push(r)}else{throw new i("Expected & or \\\\ or \\end",e.nextToken)}}t.body=a;t.rowGaps=n;return new s(t.type,t,e.mode)}function o(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs||0,argTypes:r.argTypes,greediness:1,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,handler:a};for(var n=0;n<e.length;++n){t.exports[e[n]]=i}}o("array",{numArgs:1},function(e,t){var r=t[0];r=r.value.map?r.value:[r];var a=r.map(function(e){var t=e.value;if("lcr".indexOf(t)!==-1){return{type:"align",align:t}}else if(t==="|"){return{type:"separator",separator:"|"}}throw new i("Unknown column alignment: "+e.value,e)});var n={type:"array",cols:a,hskipBeforeAndAfter:true};n=l(e.parser,n);return n});o(["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix"],{},function(e){var t={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[e.envName];var r={type:"array",hskipBeforeAndAfter:false};r=l(e.parser,r);if(t){r=new s("leftright",{body:[r],left:t[0],right:t[1]},e.mode)}return r});o("cases",{},function(e){var t={type:"array",arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:n.TEXT.metrics.quad},{type:"align",align:"l",pregap:0,postgap:0}]};t=l(e.parser,t);t=new s("leftright",{body:[t],left:"\\{",right:"."},e.mode);return t});o("aligned",{},function(e){var t={type:"array",cols:[]};t=l(e.parser,t);var r=new s("ordgroup",[],e.mode);var a=0;t.value.body.forEach(function(e){var t;for(t=1;t<e.length;t+=2){e[t].value.unshift(r)}if(a<e.length){a=e.length}});for(var i=0;i<a;++i){var n="r";var o=0;if(i%2===1){n="l"}else if(i>0){o=2}t.value.cols[i]={type:"align",align:n,pregap:o,postgap:0}}return t})},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(e,t,r){var a=e("./Style");var i=e("./unicodeRegexes").cjkRegex;var n={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25]};var s=0;var l=0;var o=0;var u=0;var p=.431;var h=1;var c=0;var m=.04;var f=.111;var v=.166;var d=.2;var g=.6;var y=.1;var x=10;var b=2/x;var w={defaultRuleThickness:m,bigOpSpacing1:f,bigOpSpacing2:v,bigOpSpacing3:d,bigOpSpacing4:g,bigOpSpacing5:y,ptPerEm:x,doubleRuleSep:b};var k=e("./fontMetricsData");var z={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xc6":"A","\xc7":"C","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xd0":"D","\xd1":"N","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xdd":"Y","\xde":"o","\xdf":"B","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xe6":"a","\xe7":"c","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xf0":"d","\xf1":"n","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xfd":"y","\xfe":"o","\xff":"y","\u0410":"A","\u0411":"B","\u0412":"B","\u0413":"F","\u0414":"A","\u0415":"E","\u0416":"K","\u0417":"3","\u0418":"N","\u0419":"N","\u041a":"K","\u041b":"N","\u041c":"M","\u041d":"H","\u041e":"O","\u041f":"N","\u0420":"P","\u0421":"C","\u0422":"T","\u0423":"y","\u0424":"O","\u0425":"X","\u0426":"U","\u0427":"h","\u0428":"W","\u0429":"W","\u042a":"B","\u042b":"X","\u042c":"B","\u042d":"3","\u042e":"X","\u042f":"R","\u0430":"a","\u0431":"b","\u0432":"a","\u0433":"r","\u0434":"y","\u0435":"e","\u0436":"m","\u0437":"e","\u0438":"n","\u0439":"n","\u043a":"n","\u043b":"n","\u043c":"m","\u043d":"n","\u043e":"o","\u043f":"n","\u0440":"p","\u0441":"c","\u0442":"o","\u0443":"y","\u0444":"b","\u0445":"x","\u0446":"n","\u0447":"n","\u0448":"w","\u0449":"w","\u044a":"a","\u044b":"m","\u044c":"a","\u044d":"e","\u044e":"m","\u044f":"r"};var S=function(e,t){var r=e.charCodeAt(0);if(e[0]in z){r=z[e[0]].charCodeAt(0)}else if(i.test(e[0])){r="M".charCodeAt(0)}var a=k[t][r];if(a){return{depth:a[0],height:a[1],italic:a[2],skew:a[3],width:a[4]}}};t.exports={metrics:w,sigmas:n,getCharacterMetrics:S}},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(e,t,r){t.exports={"AMS-Regular":{65:[0,.68889,0,0],66:[0,.68889,0,0],67:[0,.68889,0,0],68:[0,.68889,0,0],69:[0,.68889,0,0],70:[0,.68889,0,0],71:[0,.68889,0,0],72:[0,.68889,0,0],73:[0,.68889,0,0],74:[.16667,.68889,0,0],75:[0,.68889,0,0],76:[0,.68889,0,0],77:[0,.68889,0,0],78:[0,.68889,0,0],79:[.16667,.68889,0,0],80:[0,.68889,0,0],81:[.16667,.68889,0,0],82:[0,.68889,0,0],83:[0,.68889,0,0],84:[0,.68889,0,0],85:[0,.68889,0,0],86:[0,.68889,0,0],87:[0,.68889,0,0],88:[0,.68889,0,0],89:[0,.68889,0,0],90:[0,.68889,0,0],107:[0,.68889,0,0],165:[0,.675,.025,0],174:[.15559,.69224,0,0],240:[0,.68889,0,0],295:[0,.68889,0,0],710:[0,.825,0,0],732:[0,.9,0,0],770:[0,.825,0,0],771:[0,.9,0,0],989:[.08167,.58167,0,0],1008:[0,.43056,.04028,0],8245:[0,.54986,0,0],8463:[0,.68889,0,0],8487:[0,.68889,0,0],8498:[0,.68889,0,0],8502:[0,.68889,0,0],8503:[0,.68889,0,0],8504:[0,.68889,0,0],8513:[0,.68889,0,0],8592:[-.03598,.46402,0,0],8594:[-.03598,.46402,0,0],8602:[-.13313,.36687,0,0],8603:[-.13313,.36687,0,0],8606:[.01354,.52239,0,0],8608:[.01354,.52239,0,0],8610:[.01354,.52239,0,0],8611:[.01354,.52239,0,0],8619:[0,.54986,0,0],8620:[0,.54986,0,0],8621:[-.13313,.37788,0,0],8622:[-.13313,.36687,0,0],8624:[0,.69224,0,0],8625:[0,.69224,0,0],8630:[0,.43056,0,0],8631:[0,.43056,0,0],8634:[.08198,.58198,0,0],8635:[.08198,.58198,0,0],8638:[.19444,.69224,0,0],8639:[.19444,.69224,0,0],8642:[.19444,.69224,0,0],8643:[.19444,.69224,0,0],8644:[.1808,.675,0,0],8646:[.1808,.675,0,0],8647:[.1808,.675,0,0],8648:[.19444,.69224,0,0],8649:[.1808,.675,0,0],8650:[.19444,.69224,0,0],8651:[.01354,.52239,0,0],8652:[.01354,.52239,0,0],8653:[-.13313,.36687,0,0],8654:[-.13313,.36687,0,0],8655:[-.13313,.36687,0,0],8666:[.13667,.63667,0,0],8667:[.13667,.63667,0,0],8669:[-.13313,.37788,0,0],8672:[-.064,.437,0,0],8674:[-.064,.437,0,0],8705:[0,.825,0,0],8708:[0,.68889,0,0],8709:[.08167,.58167,0,0],8717:[0,.43056,0,0],8722:[-.03598,.46402,0,0],8724:[.08198,.69224,0,0],8726:[.08167,.58167,0,0],8733:[0,.69224,0,0],8736:[0,.69224,0,0],8737:[0,.69224,0,0],8738:[.03517,.52239,0,0],8739:[.08167,.58167,0,0],8740:[.25142,.74111,0,0],8741:[.08167,.58167,0,0],8742:[.25142,.74111,0,0],8756:[0,.69224,0,0],8757:[0,.69224,0,0],8764:[-.13313,.36687,0,0],8765:[-.13313,.37788,0,0],8769:[-.13313,.36687,0,0],8770:[-.03625,.46375,0,0],8774:[.30274,.79383,0,0],8776:[-.01688,.48312,0,0],8778:[.08167,.58167,0,0],8782:[.06062,.54986,0,0],8783:[.06062,.54986,0,0],8785:[.08198,.58198,0,0],8786:[.08198,.58198,0,0],8787:[.08198,.58198,0,0],8790:[0,.69224,0,0],8791:[.22958,.72958,0,0],8796:[.08198,.91667,0,0],8806:[.25583,.75583,0,0],
+8807:[.25583,.75583,0,0],8808:[.25142,.75726,0,0],8809:[.25142,.75726,0,0],8812:[.25583,.75583,0,0],8814:[.20576,.70576,0,0],8815:[.20576,.70576,0,0],8816:[.30274,.79383,0,0],8817:[.30274,.79383,0,0],8818:[.22958,.72958,0,0],8819:[.22958,.72958,0,0],8822:[.1808,.675,0,0],8823:[.1808,.675,0,0],8828:[.13667,.63667,0,0],8829:[.13667,.63667,0,0],8830:[.22958,.72958,0,0],8831:[.22958,.72958,0,0],8832:[.20576,.70576,0,0],8833:[.20576,.70576,0,0],8840:[.30274,.79383,0,0],8841:[.30274,.79383,0,0],8842:[.13597,.63597,0,0],8843:[.13597,.63597,0,0],8847:[.03517,.54986,0,0],8848:[.03517,.54986,0,0],8858:[.08198,.58198,0,0],8859:[.08198,.58198,0,0],8861:[.08198,.58198,0,0],8862:[0,.675,0,0],8863:[0,.675,0,0],8864:[0,.675,0,0],8865:[0,.675,0,0],8872:[0,.69224,0,0],8873:[0,.69224,0,0],8874:[0,.69224,0,0],8876:[0,.68889,0,0],8877:[0,.68889,0,0],8878:[0,.68889,0,0],8879:[0,.68889,0,0],8882:[.03517,.54986,0,0],8883:[.03517,.54986,0,0],8884:[.13667,.63667,0,0],8885:[.13667,.63667,0,0],8888:[0,.54986,0,0],8890:[.19444,.43056,0,0],8891:[.19444,.69224,0,0],8892:[.19444,.69224,0,0],8901:[0,.54986,0,0],8903:[.08167,.58167,0,0],8905:[.08167,.58167,0,0],8906:[.08167,.58167,0,0],8907:[0,.69224,0,0],8908:[0,.69224,0,0],8909:[-.03598,.46402,0,0],8910:[0,.54986,0,0],8911:[0,.54986,0,0],8912:[.03517,.54986,0,0],8913:[.03517,.54986,0,0],8914:[0,.54986,0,0],8915:[0,.54986,0,0],8916:[0,.69224,0,0],8918:[.0391,.5391,0,0],8919:[.0391,.5391,0,0],8920:[.03517,.54986,0,0],8921:[.03517,.54986,0,0],8922:[.38569,.88569,0,0],8923:[.38569,.88569,0,0],8926:[.13667,.63667,0,0],8927:[.13667,.63667,0,0],8928:[.30274,.79383,0,0],8929:[.30274,.79383,0,0],8934:[.23222,.74111,0,0],8935:[.23222,.74111,0,0],8936:[.23222,.74111,0,0],8937:[.23222,.74111,0,0],8938:[.20576,.70576,0,0],8939:[.20576,.70576,0,0],8940:[.30274,.79383,0,0],8941:[.30274,.79383,0,0],8994:[.19444,.69224,0,0],8995:[.19444,.69224,0,0],9416:[.15559,.69224,0,0],9484:[0,.69224,0,0],9488:[0,.69224,0,0],9492:[0,.37788,0,0],9496:[0,.37788,0,0],9585:[.19444,.68889,0,0],9586:[.19444,.74111,0,0],9632:[0,.675,0,0],9633:[0,.675,0,0],9650:[0,.54986,0,0],9651:[0,.54986,0,0],9654:[.03517,.54986,0,0],9660:[0,.54986,0,0],9661:[0,.54986,0,0],9664:[.03517,.54986,0,0],9674:[.11111,.69224,0,0],9733:[.19444,.69224,0,0],10003:[0,.69224,0,0],10016:[0,.69224,0,0],10731:[.11111,.69224,0,0],10846:[.19444,.75583,0,0],10877:[.13667,.63667,0,0],10878:[.13667,.63667,0,0],10885:[.25583,.75583,0,0],10886:[.25583,.75583,0,0],10887:[.13597,.63597,0,0],10888:[.13597,.63597,0,0],10889:[.26167,.75726,0,0],10890:[.26167,.75726,0,0],10891:[.48256,.98256,0,0],10892:[.48256,.98256,0,0],10901:[.13667,.63667,0,0],10902:[.13667,.63667,0,0],10933:[.25142,.75726,0,0],10934:[.25142,.75726,0,0],10935:[.26167,.75726,0,0],10936:[.26167,.75726,0,0],10937:[.26167,.75726,0,0],10938:[.26167,.75726,0,0],10949:[.25583,.75583,0,0],10950:[.25583,.75583,0,0],10955:[.28481,.79383,0,0],10956:[.28481,.79383,0,0],57350:[.08167,.58167,0,0],57351:[.08167,.58167,0,0],57352:[.08167,.58167,0,0],57353:[0,.43056,.04028,0],57356:[.25142,.75726,0,0],57357:[.25142,.75726,0,0],57358:[.41951,.91951,0,0],57359:[.30274,.79383,0,0],57360:[.30274,.79383,0,0],57361:[.41951,.91951,0,0],57366:[.25142,.75726,0,0],57367:[.25142,.75726,0,0],57368:[.25142,.75726,0,0],57369:[.25142,.75726,0,0],57370:[.13597,.63597,0,0],57371:[.13597,.63597,0,0]},"Caligraphic-Regular":{48:[0,.43056,0,0],49:[0,.43056,0,0],50:[0,.43056,0,0],51:[.19444,.43056,0,0],52:[.19444,.43056,0,0],53:[.19444,.43056,0,0],54:[0,.64444,0,0],55:[.19444,.43056,0,0],56:[0,.64444,0,0],57:[.19444,.43056,0,0],65:[0,.68333,0,.19445],66:[0,.68333,.03041,.13889],67:[0,.68333,.05834,.13889],68:[0,.68333,.02778,.08334],69:[0,.68333,.08944,.11111],70:[0,.68333,.09931,.11111],71:[.09722,.68333,.0593,.11111],72:[0,.68333,.00965,.11111],73:[0,.68333,.07382,0],74:[.09722,.68333,.18472,.16667],75:[0,.68333,.01445,.05556],76:[0,.68333,0,.13889],77:[0,.68333,0,.13889],78:[0,.68333,.14736,.08334],79:[0,.68333,.02778,.11111],80:[0,.68333,.08222,.08334],81:[.09722,.68333,0,.11111],82:[0,.68333,0,.08334],83:[0,.68333,.075,.13889],84:[0,.68333,.25417,0],85:[0,.68333,.09931,.08334],86:[0,.68333,.08222,0],87:[0,.68333,.08222,.08334],88:[0,.68333,.14643,.13889],89:[.09722,.68333,.08222,.08334],90:[0,.68333,.07944,.13889]},"Fraktur-Regular":{33:[0,.69141,0,0],34:[0,.69141,0,0],38:[0,.69141,0,0],39:[0,.69141,0,0],40:[.24982,.74947,0,0],41:[.24982,.74947,0,0],42:[0,.62119,0,0],43:[.08319,.58283,0,0],44:[0,.10803,0,0],45:[.08319,.58283,0,0],46:[0,.10803,0,0],47:[.24982,.74947,0,0],48:[0,.47534,0,0],49:[0,.47534,0,0],50:[0,.47534,0,0],51:[.18906,.47534,0,0],52:[.18906,.47534,0,0],53:[.18906,.47534,0,0],54:[0,.69141,0,0],55:[.18906,.47534,0,0],56:[0,.69141,0,0],57:[.18906,.47534,0,0],58:[0,.47534,0,0],59:[.12604,.47534,0,0],61:[-.13099,.36866,0,0],63:[0,.69141,0,0],65:[0,.69141,0,0],66:[0,.69141,0,0],67:[0,.69141,0,0],68:[0,.69141,0,0],69:[0,.69141,0,0],70:[.12604,.69141,0,0],71:[0,.69141,0,0],72:[.06302,.69141,0,0],73:[0,.69141,0,0],74:[.12604,.69141,0,0],75:[0,.69141,0,0],76:[0,.69141,0,0],77:[0,.69141,0,0],78:[0,.69141,0,0],79:[0,.69141,0,0],80:[.18906,.69141,0,0],81:[.03781,.69141,0,0],82:[0,.69141,0,0],83:[0,.69141,0,0],84:[0,.69141,0,0],85:[0,.69141,0,0],86:[0,.69141,0,0],87:[0,.69141,0,0],88:[0,.69141,0,0],89:[.18906,.69141,0,0],90:[.12604,.69141,0,0],91:[.24982,.74947,0,0],93:[.24982,.74947,0,0],94:[0,.69141,0,0],97:[0,.47534,0,0],98:[0,.69141,0,0],99:[0,.47534,0,0],100:[0,.62119,0,0],101:[0,.47534,0,0],102:[.18906,.69141,0,0],103:[.18906,.47534,0,0],104:[.18906,.69141,0,0],105:[0,.69141,0,0],106:[0,.69141,0,0],107:[0,.69141,0,0],108:[0,.69141,0,0],109:[0,.47534,0,0],110:[0,.47534,0,0],111:[0,.47534,0,0],112:[.18906,.52396,0,0],113:[.18906,.47534,0,0],114:[0,.47534,0,0],115:[0,.47534,0,0],116:[0,.62119,0,0],117:[0,.47534,0,0],118:[0,.52396,0,0],119:[0,.52396,0,0],120:[.18906,.47534,0,0],121:[.18906,.47534,0,0],122:[.18906,.47534,0,0],8216:[0,.69141,0,0],8217:[0,.69141,0,0],58112:[0,.62119,0,0],58113:[0,.62119,0,0],58114:[.18906,.69141,0,0],58115:[.18906,.69141,0,0],58116:[.18906,.47534,0,0],58117:[0,.69141,0,0],58118:[0,.62119,0,0],58119:[0,.47534,0,0]},"Main-Bold":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.13333,.63333,0,0],44:[.19444,.15556,0,0],45:[0,.44444,0,0],46:[0,.15556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.44444,0,0],59:[.19444,.44444,0,0],60:[.08556,.58556,0,0],61:[-.10889,.39111,0,0],62:[.08556,.58556,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,0,0],67:[0,.68611,0,0],68:[0,.68611,0,0],69:[0,.68611,0,0],70:[0,.68611,0,0],71:[0,.68611,0,0],72:[0,.68611,0,0],73:[0,.68611,0,0],74:[0,.68611,0,0],75:[0,.68611,0,0],76:[0,.68611,0,0],77:[0,.68611,0,0],78:[0,.68611,0,0],79:[0,.68611,0,0],80:[0,.68611,0,0],81:[.19444,.68611,0,0],82:[0,.68611,0,0],83:[0,.68611,0,0],84:[0,.68611,0,0],85:[0,.68611,0,0],86:[0,.68611,.01597,0],87:[0,.68611,.01597,0],88:[0,.68611,0,0],89:[0,.68611,.02875,0],90:[0,.68611,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.13444,.03194,0],96:[0,.69444,0,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.10903,0],103:[.19444,.44444,.01597,0],104:[0,.69444,0,0],105:[0,.69444,0,0],106:[.19444,.69444,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,0,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.01597,0],119:[0,.44444,.01597,0],120:[0,.44444,0,0],121:[.19444,.44444,.01597,0],122:[0,.44444,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.34444,0,0],168:[0,.69444,0,0],172:[0,.44444,0,0],175:[0,.59611,0,0],176:[0,.69444,0,0],177:[.13333,.63333,0,0],180:[0,.69444,0,0],215:[.13333,.63333,0,0],247:[.13333,.63333,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],710:[0,.69444,0,0],711:[0,.63194,0,0],713:[0,.59611,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.69444,0,0],730:[0,.69444,0,0],732:[0,.69444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.69444,0,0],772:[0,.59611,0,0],774:[0,.69444,0,0],775:[0,.69444,0,0],776:[0,.69444,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],824:[.19444,.69444,0,0],915:[0,.68611,0,0],916:[0,.68611,0,0],920:[0,.68611,0,0],923:[0,.68611,0,0],926:[0,.68611,0,0],928:[0,.68611,0,0],931:[0,.68611,0,0],933:[0,.68611,0,0],934:[0,.68611,0,0],936:[0,.68611,0,0],937:[0,.68611,0,0],8211:[0,.44444,.03194,0],8212:[0,.44444,.03194,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8242:[0,.55556,0,0],8407:[0,.72444,.15486,0],8463:[0,.69444,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,0],8472:[.19444,.44444,0,0],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.10889,.39111,0,0],8593:[.19444,.69444,0,0],8594:[-.10889,.39111,0,0],8595:[.19444,.69444,0,0],8596:[-.10889,.39111,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8636:[-.10889,.39111,0,0],8637:[-.10889,.39111,0,0],8640:[-.10889,.39111,0,0],8641:[-.10889,.39111,0,0],8656:[-.10889,.39111,0,0],8657:[.19444,.69444,0,0],8658:[-.10889,.39111,0,0],8659:[.19444,.69444,0,0],8660:[-.10889,.39111,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.06389,0],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68611,0,0],8712:[.08556,.58556,0,0],8715:[.08556,.58556,0,0],8722:[.13333,.63333,0,0],8723:[.13333,.63333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.02778,.47222,0,0],8728:[-.02639,.47361,0,0],8729:[-.02639,.47361,0,0],8730:[.18,.82,0,0],8733:[0,.44444,0,0],8734:[0,.44444,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.12778,0],8764:[-.10889,.39111,0,0],8768:[.19444,.69444,0,0],8771:[.00222,.50222,0,0],8776:[.02444,.52444,0,0],8781:[.00222,.50222,0,0],8801:[.00222,.50222,0,0],8804:[.19667,.69667,0,0],8805:[.19667,.69667,0,0],8810:[.08556,.58556,0,0],8811:[.08556,.58556,0,0],8826:[.08556,.58556,0,0],8827:[.08556,.58556,0,0],8834:[.08556,.58556,0,0],8835:[.08556,.58556,0,0],8838:[.19667,.69667,0,0],8839:[.19667,.69667,0,0],8846:[0,.55556,0,0],8849:[.19667,.69667,0,0],8850:[.19667,.69667,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.13333,.63333,0,0],8854:[.13333,.63333,0,0],8855:[.13333,.63333,0,0],8856:[.13333,.63333,0,0],8857:[.13333,.63333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8900:[-.02639,.47361,0,0],8901:[-.02639,.47361,0,0],8902:[-.02778,.47222,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.13889,.36111,0,0],8995:[-.13889,.36111,0,0],9651:[.19444,.69444,0,0],9657:[-.02778,.47222,0,0],9661:[.19444,.69444,0,0],9667:[-.02778,.47222,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10815:[0,.68611,0,0],10927:[.19667,.69667,0,0],10928:[.19667,.69667,0,0]},"Main-Italic":{33:[0,.69444,.12417,0],34:[0,.69444,.06961,0],35:[.19444,.69444,.06616,0],37:[.05556,.75,.13639,0],38:[0,.69444,.09694,0],39:[0,.69444,.12417,0],40:[.25,.75,.16194,0],41:[.25,.75,.03694,0],42:[0,.75,.14917,0],43:[.05667,.56167,.03694,0],44:[.19444,.10556,0,0],45:[0,.43056,.02826,0],46:[0,.10556,0,0],47:[.25,.75,.16194,0],48:[0,.64444,.13556,0],49:[0,.64444,.13556,0],50:[0,.64444,.13556,0],51:[0,.64444,.13556,0],52:[.19444,.64444,.13556,0],53:[0,.64444,.13556,0],54:[0,.64444,.13556,0],55:[.19444,.64444,.13556,0],56:[0,.64444,.13556,0],57:[0,.64444,.13556,0],58:[0,.43056,.0582,0],59:[.19444,.43056,.0582,0],61:[-.13313,.36687,.06616,0],63:[0,.69444,.1225,0],64:[0,.69444,.09597,0],65:[0,.68333,0,0],66:[0,.68333,.10257,0],67:[0,.68333,.14528,0],68:[0,.68333,.09403,0],69:[0,.68333,.12028,0],70:[0,.68333,.13305,0],71:[0,.68333,.08722,0],72:[0,.68333,.16389,0],73:[0,.68333,.15806,0],74:[0,.68333,.14028,0],75:[0,.68333,.14528,0],76:[0,.68333,0,0],77:[0,.68333,.16389,0],78:[0,.68333,.16389,0],79:[0,.68333,.09403,0],80:[0,.68333,.10257,0],81:[.19444,.68333,.09403,0],82:[0,.68333,.03868,0],83:[0,.68333,.11972,0],84:[0,.68333,.13305,0],85:[0,.68333,.16389,0],86:[0,.68333,.18361,0],87:[0,.68333,.18361,0],88:[0,.68333,.15806,0],89:[0,.68333,.19383,0],90:[0,.68333,.14528,0],91:[.25,.75,.1875,0],93:[.25,.75,.10528,0],94:[0,.69444,.06646,0],95:[.31,.12056,.09208,0],97:[0,.43056,.07671,0],98:[0,.69444,.06312,0],99:[0,.43056,.05653,0],100:[0,.69444,.10333,0],101:[0,.43056,.07514,0],102:[.19444,.69444,.21194,0],103:[.19444,.43056,.08847,0],104:[0,.69444,.07671,0],105:[0,.65536,.1019,0],106:[.19444,.65536,.14467,0],107:[0,.69444,.10764,0],108:[0,.69444,.10333,0],109:[0,.43056,.07671,0],110:[0,.43056,.07671,0],111:[0,.43056,.06312,0],112:[.19444,.43056,.06312,0],113:[.19444,.43056,.08847,0],114:[0,.43056,.10764,0],115:[0,.43056,.08208,0],116:[0,.61508,.09486,0],117:[0,.43056,.07671,0],118:[0,.43056,.10764,0],119:[0,.43056,.10764,0],120:[0,.43056,.12042,0],121:[.19444,.43056,.08847,0],122:[0,.43056,.12292,0],126:[.35,.31786,.11585,0],163:[0,.69444,0,0],305:[0,.43056,0,.02778],567:[.19444,.43056,0,.08334],768:[0,.69444,0,0],769:[0,.69444,.09694,0],770:[0,.69444,.06646,0],771:[0,.66786,.11585,0],772:[0,.56167,.10333,0],774:[0,.69444,.10806,0],775:[0,.66786,.11752,0],776:[0,.66786,.10474,0],778:[0,.69444,0,0],779:[0,.69444,.1225,0],780:[0,.62847,.08295,0],915:[0,.68333,.13305,0],916:[0,.68333,0,0],920:[0,.68333,.09403,0],923:[0,.68333,0,0],926:[0,.68333,.15294,0],928:[0,.68333,.16389,0],931:[0,.68333,.12028,0],933:[0,.68333,.11111,0],934:[0,.68333,.05986,0],936:[0,.68333,.11111,0],937:[0,.68333,.10257,0],8211:[0,.43056,.09208,0],8212:[0,.43056,.09208,0],8216:[0,.69444,.12417,0],8217:[0,.69444,.12417,0],8220:[0,.69444,.1685,0],8221:[0,.69444,.06961,0],8463:[0,.68889,0,0]},"Main-Regular":{32:[0,0,0,0],33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.19444,.10556,0,0],45:[0,.43056,0,0],46:[0,.10556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.43056,0,0],59:[.19444,.43056,0,0],60:[.0391,.5391,0,0],61:[-.13313,.36687,0,0],62:[.0391,.5391,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68333,0,0],66:[0,.68333,0,0],67:[0,.68333,0,0],68:[0,.68333,0,0],69:[0,.68333,0,0],70:[0,.68333,0,0],71:[0,.68333,0,0],72:[0,.68333,0,0],73:[0,.68333,0,0],74:[0,.68333,0,0],75:[0,.68333,0,0],76:[0,.68333,0,0],77:[0,.68333,0,0],78:[0,.68333,0,0],79:[0,.68333,0,0],80:[0,.68333,0,0],81:[.19444,.68333,0,0],82:[0,.68333,0,0],83:[0,.68333,0,0],84:[0,.68333,0,0],85:[0,.68333,0,0],86:[0,.68333,.01389,0],87:[0,.68333,.01389,0],88:[0,.68333,0,0],89:[0,.68333,.025,0],90:[0,.68333,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.12056,.02778,0],96:[0,.69444,0,0],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,0],100:[0,.69444,0,0],101:[0,.43056,0,0],102:[0,.69444,.07778,0],103:[.19444,.43056,.01389,0],104:[0,.69444,0,0],105:[0,.66786,0,0],106:[.19444,.66786,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.19444,.43056,0,0],113:[.19444,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.61508,0,0],117:[0,.43056,0,0],118:[0,.43056,.01389,0],119:[0,.43056,.01389,0],120:[0,.43056,0,0],121:[.19444,.43056,.01389,0],122:[0,.43056,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.31786,0,0],160:[0,0,0,0],168:[0,.66786,0,0],172:[0,.43056,0,0],175:[0,.56778,0,0],176:[0,.69444,0,0],177:[.08333,.58333,0,0],180:[0,.69444,0,0],215:[.08333,.58333,0,0],247:[.08333,.58333,0,0],305:[0,.43056,0,0],567:[.19444,.43056,0,0],710:[0,.69444,0,0],711:[0,.62847,0,0],713:[0,.56778,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.66786,0,0],730:[0,.69444,0,0],732:[0,.66786,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.66786,0,0],772:[0,.56778,0,0],774:[0,.69444,0,0],775:[0,.66786,0,0],776:[0,.66786,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.62847,0,0],824:[.19444,.69444,0,0],915:[0,.68333,0,0],916:[0,.68333,0,0],920:[0,.68333,0,0],923:[0,.68333,0,0],926:[0,.68333,0,0],928:[0,.68333,0,0],931:[0,.68333,0,0],933:[0,.68333,0,0],934:[0,.68333,0,0],936:[0,.68333,0,0],937:[0,.68333,0,0],8211:[0,.43056,.02778,0],8212:[0,.43056,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8230:[0,.12,0,0],8242:[0,.55556,0,0],8407:[0,.71444,.15382,0],8463:[0,.68889,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,.11111],8472:[.19444,.43056,0,.11111],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.13313,.36687,0,0],8593:[.19444,.69444,0,0],8594:[-.13313,.36687,0,0],8595:[.19444,.69444,0,0],8596:[-.13313,.36687,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8614:[.011,.511,0,0],8617:[.011,.511,0,0],8618:[.011,.511,0,0],8636:[-.13313,.36687,0,0],8637:[-.13313,.36687,0,0],8640:[-.13313,.36687,0,0],8641:[-.13313,.36687,0,0],8652:[.011,.671,0,0],8656:[-.13313,.36687,0,0],8657:[.19444,.69444,0,0],8658:[-.13313,.36687,0,0],8659:[.19444,.69444,0,0],8660:[-.13313,.36687,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.05556,.08334],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68333,0,0],8712:[.0391,.5391,0,0],8715:[.0391,.5391,0,0],8722:[.08333,.58333,0,0],8723:[.08333,.58333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.03472,.46528,0,0],8728:[-.05555,.44445,0,0],8729:[-.05555,.44445,0,0],8730:[.2,.8,0,0],8733:[0,.43056,0,0],8734:[0,.43056,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.11111,0],8764:[-.13313,.36687,0,0],8768:[.19444,.69444,0,0],8771:[-.03625,.46375,0,0],8773:[-.022,.589,0,0],8776:[-.01688,.48312,0,0],8781:[-.03625,.46375,0,0],8784:[-.133,.67,0,0],8800:[.215,.716,0,0],8801:[-.03625,.46375,0,0],8804:[.13597,.63597,0,0],8805:[.13597,.63597,0,0],8810:[.0391,.5391,0,0],8811:[.0391,.5391,0,0],8826:[.0391,.5391,0,0],8827:[.0391,.5391,0,0],8834:[.0391,.5391,0,0],8835:[.0391,.5391,0,0],8838:[.13597,.63597,0,0],8839:[.13597,.63597,0,0],8846:[0,.55556,0,0],8849:[.13597,.63597,0,0],8850:[.13597,.63597,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.08333,.58333,0,0],8854:[.08333,.58333,0,0],8855:[.08333,.58333,0,0],8856:[.08333,.58333,0,0],8857:[.08333,.58333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8872:[.249,.75,0,0],8900:[-.05555,.44445,0,0],8901:[-.05555,.44445,0,0],8902:[-.03472,.46528,0,0],8904:[.005,.505,0,0],8942:[.03,.9,0,0],8943:[-.19,.31,0,0],8945:[-.1,.82,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.14236,.35764,0,0],8995:[-.14236,.35764,0,0],9136:[.244,.744,0,0],9137:[.244,.744,0,0],9651:[.19444,.69444,0,0],9657:[-.03472,.46528,0,0],9661:[.19444,.69444,0,0],9667:[-.03472,.46528,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10222:[.244,.744,0,0],10223:[.244,.744,0,0],10229:[.011,.511,0,0],10230:[.011,.511,0,0],10231:[.011,.511,0,0],10232:[.024,.525,0,0],10233:[.024,.525,0,0],10234:[.024,.525,0,0],10236:[.011,.511,0,0],10815:[0,.68333,0,0],10927:[.13597,.63597,0,0],10928:[.13597,.63597,0,0]},"Math-BoldItalic":{47:[.19444,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,.04835,0],67:[0,.68611,.06979,0],68:[0,.68611,.03194,0],69:[0,.68611,.05451,0],70:[0,.68611,.15972,0],71:[0,.68611,0,0],72:[0,.68611,.08229,0],73:[0,.68611,.07778,0],74:[0,.68611,.10069,0],75:[0,.68611,.06979,0],76:[0,.68611,0,0],77:[0,.68611,.11424,0],78:[0,.68611,.11424,0],79:[0,.68611,.03194,0],80:[0,.68611,.15972,0],81:[.19444,.68611,0,0],82:[0,.68611,.00421,0],83:[0,.68611,.05382,0],84:[0,.68611,.15972,0],85:[0,.68611,.11424,0],86:[0,.68611,.25555,0],87:[0,.68611,.15972,0],88:[0,.68611,.07778,0],89:[0,.68611,.25555,0],90:[0,.68611,.06979,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[.19444,.69444,.11042,0],103:[.19444,.44444,.03704,0],104:[0,.69444,0,0],105:[0,.69326,0,0],106:[.19444,.69326,.0622,0],107:[0,.69444,.01852,0],108:[0,.69444,.0088,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,.03704,0],114:[0,.44444,.03194,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.03704,0],119:[0,.44444,.02778,0],120:[0,.44444,0,0],121:[.19444,.44444,.03704,0],122:[0,.44444,.04213,0],915:[0,.68611,.15972,0],916:[0,.68611,0,0],920:[0,.68611,.03194,0],923:[0,.68611,0,0],926:[0,.68611,.07458,0],928:[0,.68611,.08229,0],931:[0,.68611,.05451,0],933:[0,.68611,.15972,0],934:[0,.68611,0,0],936:[0,.68611,.11653,0],937:[0,.68611,.04835,0],945:[0,.44444,0,0],946:[.19444,.69444,.03403,0],947:[.19444,.44444,.06389,0],948:[0,.69444,.03819,0],949:[0,.44444,0,0],950:[.19444,.69444,.06215,0],951:[.19444,.44444,.03704,0],952:[0,.69444,.03194,0],953:[0,.44444,0,0],954:[0,.44444,0,0],955:[0,.69444,0,0],956:[.19444,.44444,0,0],957:[0,.44444,.06898,0],958:[.19444,.69444,.03021,0],959:[0,.44444,0,0],960:[0,.44444,.03704,0],961:[.19444,.44444,0,0],962:[.09722,.44444,.07917,0],963:[0,.44444,.03704,0],964:[0,.44444,.13472,0],965:[0,.44444,.03704,0],966:[.19444,.44444,0,0],967:[.19444,.44444,0,0],968:[.19444,.69444,.03704,0],969:[0,.44444,.03704,0],977:[0,.69444,0,0],981:[.19444,.69444,0,0],982:[0,.44444,.03194,0],1009:[.19444,.44444,0,0],1013:[0,.44444,0,0]},"Math-Italic":{47:[.19444,.69444,0,0],65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"Math-Regular":{65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"SansSerif-Regular":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.125,.08333,0,0],45:[0,.44444,0,0],46:[0,.08333,0,0],47:[.25,.75,0,0],48:[0,.65556,0,0],49:[0,.65556,0,0],50:[0,.65556,0,0],51:[0,.65556,0,0],52:[0,.65556,0,0],53:[0,.65556,0,0],54:[0,.65556,0,0],55:[0,.65556,0,0],56:[0,.65556,0,0],57:[0,.65556,0,0],58:[0,.44444,0,0],59:[.125,.44444,0,0],61:[-.13,.37,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.69444,0,0],66:[0,.69444,0,0],67:[0,.69444,0,0],68:[0,.69444,0,0],69:[0,.69444,0,0],70:[0,.69444,0,0],71:[0,.69444,0,0],72:[0,.69444,0,0],73:[0,.69444,0,0],74:[0,.69444,0,0],75:[0,.69444,0,0],76:[0,.69444,0,0],77:[0,.69444,0,0],78:[0,.69444,0,0],79:[0,.69444,0,0],80:[0,.69444,0,0],81:[.125,.69444,0,0],82:[0,.69444,0,0],83:[0,.69444,0,0],84:[0,.69444,0,0],85:[0,.69444,0,0],86:[0,.69444,.01389,0],87:[0,.69444,.01389,0],88:[0,.69444,0,0],89:[0,.69444,.025,0],90:[0,.69444,0,0],91:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.35,.09444,.02778,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.06944,0],103:[.19444,.44444,.01389,0],104:[0,.69444,0,0],105:[0,.67937,0,0],106:[.19444,.67937,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,.01389,0],115:[0,.44444,0,0],116:[0,.57143,0,0],117:[0,.44444,0,0],118:[0,.44444,.01389,0],119:[0,.44444,.01389,0],120:[0,.44444,0,0],121:[.19444,.44444,.01389,0],122:[0,.44444,0,0],126:[.35,.32659,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.67659,0,0],772:[0,.60889,0,0],774:[0,.69444,0,0],775:[0,.67937,0,0],776:[0,.67937,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],915:[0,.69444,0,0],916:[0,.69444,0,0],920:[0,.69444,0,0],923:[0,.69444,0,0],926:[0,.69444,0,0],928:[0,.69444,0,0],931:[0,.69444,0,0],933:[0,.69444,0,0],934:[0,.69444,0,0],936:[0,.69444,0,0],937:[0,.69444,0,0],8211:[0,.44444,.02778,0],8212:[0,.44444,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0]},"Script-Regular":{65:[0,.7,.22925,0],66:[0,.7,.04087,0],67:[0,.7,.1689,0],68:[0,.7,.09371,0],69:[0,.7,.18583,0],70:[0,.7,.13634,0],71:[0,.7,.17322,0],72:[0,.7,.29694,0],73:[0,.7,.19189,0],74:[.27778,.7,.19189,0],75:[0,.7,.31259,0],76:[0,.7,.19189,0],77:[0,.7,.15981,0],78:[0,.7,.3525,0],79:[0,.7,.08078,0],80:[0,.7,.08078,0],81:[0,.7,.03305,0],82:[0,.7,.06259,0],83:[0,.7,.19189,0],84:[0,.7,.29087,0],85:[0,.7,.25815,0],86:[0,.7,.27523,0],87:[0,.7,.27523,0],88:[0,.7,.26006,0],89:[0,.7,.2939,0],90:[0,.7,.24037,0]},"Size1-Regular":{40:[.35001,.85,0,0],41:[.35001,.85,0,0],47:[.35001,.85,0,0],91:[.35001,.85,0,0],92:[.35001,.85,0,0],93:[.35001,.85,0,0],123:[.35001,.85,0,0],125:[.35001,.85,0,0],710:[0,.72222,0,0],732:[0,.72222,0,0],770:[0,.72222,0,0],771:[0,.72222,0,0],8214:[-99e-5,.601,0,0],8593:[1e-5,.6,0,0],8595:[1e-5,.6,0,0],8657:[1e-5,.6,0,0],8659:[1e-5,.6,0,0],8719:[.25001,.75,0,0],8720:[.25001,.75,0,0],8721:[.25001,.75,0,0],8730:[.35001,.85,0,0],8739:[-.00599,.606,0,0],8741:[-.00599,.606,0,0],8747:[.30612,.805,.19445,0],8748:[.306,.805,.19445,0],8749:[.306,.805,.19445,0],8750:[.30612,.805,.19445,0],8896:[.25001,.75,0,0],8897:[.25001,.75,0,0],8898:[.25001,.75,0,0],8899:[.25001,.75,0,0],8968:[.35001,.85,0,0],8969:[.35001,.85,0,0],8970:[.35001,.85,0,0],8971:[.35001,.85,0,0],9168:[-99e-5,.601,0,0],10216:[.35001,.85,0,0],10217:[.35001,.85,0,0],10752:[.25001,.75,0,0],10753:[.25001,.75,0,0],10754:[.25001,.75,0,0],10756:[.25001,.75,0,0],10758:[.25001,.75,0,0]},"Size2-Regular":{40:[.65002,1.15,0,0],41:[.65002,1.15,0,0],47:[.65002,1.15,0,0],91:[.65002,1.15,0,0],92:[.65002,1.15,0,0],93:[.65002,1.15,0,0],123:[.65002,1.15,0,0],125:[.65002,1.15,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8719:[.55001,1.05,0,0],8720:[.55001,1.05,0,0],8721:[.55001,1.05,0,0],8730:[.65002,1.15,0,0],8747:[.86225,1.36,.44445,0],8748:[.862,1.36,.44445,0],8749:[.862,1.36,.44445,0],8750:[.86225,1.36,.44445,0],8896:[.55001,1.05,0,0],8897:[.55001,1.05,0,0],8898:[.55001,1.05,0,0],8899:[.55001,1.05,0,0],8968:[.65002,1.15,0,0],8969:[.65002,1.15,0,0],8970:[.65002,1.15,0,0],8971:[.65002,1.15,0,0],10216:[.65002,1.15,0,0],10217:[.65002,1.15,0,0],10752:[.55001,1.05,0,0],10753:[.55001,1.05,0,0],10754:[.55001,1.05,0,0],
+10756:[.55001,1.05,0,0],10758:[.55001,1.05,0,0]},"Size3-Regular":{40:[.95003,1.45,0,0],41:[.95003,1.45,0,0],47:[.95003,1.45,0,0],91:[.95003,1.45,0,0],92:[.95003,1.45,0,0],93:[.95003,1.45,0,0],123:[.95003,1.45,0,0],125:[.95003,1.45,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8730:[.95003,1.45,0,0],8968:[.95003,1.45,0,0],8969:[.95003,1.45,0,0],8970:[.95003,1.45,0,0],8971:[.95003,1.45,0,0],10216:[.95003,1.45,0,0],10217:[.95003,1.45,0,0]},"Size4-Regular":{40:[1.25003,1.75,0,0],41:[1.25003,1.75,0,0],47:[1.25003,1.75,0,0],91:[1.25003,1.75,0,0],92:[1.25003,1.75,0,0],93:[1.25003,1.75,0,0],123:[1.25003,1.75,0,0],125:[1.25003,1.75,0,0],710:[0,.825,0,0],732:[0,.825,0,0],770:[0,.825,0,0],771:[0,.825,0,0],8730:[1.25003,1.75,0,0],8968:[1.25003,1.75,0,0],8969:[1.25003,1.75,0,0],8970:[1.25003,1.75,0,0],8971:[1.25003,1.75,0,0],9115:[.64502,1.155,0,0],9116:[1e-5,.6,0,0],9117:[.64502,1.155,0,0],9118:[.64502,1.155,0,0],9119:[1e-5,.6,0,0],9120:[.64502,1.155,0,0],9121:[.64502,1.155,0,0],9122:[-99e-5,.601,0,0],9123:[.64502,1.155,0,0],9124:[.64502,1.155,0,0],9125:[-99e-5,.601,0,0],9126:[.64502,1.155,0,0],9127:[1e-5,.9,0,0],9128:[.65002,1.15,0,0],9129:[.90001,0,0,0],9130:[0,.3,0,0],9131:[1e-5,.9,0,0],9132:[.65002,1.15,0,0],9133:[.90001,0,0,0],9143:[.88502,.915,0,0],10216:[1.25003,1.75,0,0],10217:[1.25003,1.75,0,0],57344:[-.00499,.605,0,0],57345:[-.00499,.605,0,0],57680:[0,.12,0,0],57681:[0,.12,0,0],57682:[0,.12,0,0],57683:[0,.12,0,0]},"Typewriter-Regular":{33:[0,.61111,0,0],34:[0,.61111,0,0],35:[0,.61111,0,0],36:[.08333,.69444,0,0],37:[.08333,.69444,0,0],38:[0,.61111,0,0],39:[0,.61111,0,0],40:[.08333,.69444,0,0],41:[.08333,.69444,0,0],42:[0,.52083,0,0],43:[-.08056,.53055,0,0],44:[.13889,.125,0,0],45:[-.08056,.53055,0,0],46:[0,.125,0,0],47:[.08333,.69444,0,0],48:[0,.61111,0,0],49:[0,.61111,0,0],50:[0,.61111,0,0],51:[0,.61111,0,0],52:[0,.61111,0,0],53:[0,.61111,0,0],54:[0,.61111,0,0],55:[0,.61111,0,0],56:[0,.61111,0,0],57:[0,.61111,0,0],58:[0,.43056,0,0],59:[.13889,.43056,0,0],60:[-.05556,.55556,0,0],61:[-.19549,.41562,0,0],62:[-.05556,.55556,0,0],63:[0,.61111,0,0],64:[0,.61111,0,0],65:[0,.61111,0,0],66:[0,.61111,0,0],67:[0,.61111,0,0],68:[0,.61111,0,0],69:[0,.61111,0,0],70:[0,.61111,0,0],71:[0,.61111,0,0],72:[0,.61111,0,0],73:[0,.61111,0,0],74:[0,.61111,0,0],75:[0,.61111,0,0],76:[0,.61111,0,0],77:[0,.61111,0,0],78:[0,.61111,0,0],79:[0,.61111,0,0],80:[0,.61111,0,0],81:[.13889,.61111,0,0],82:[0,.61111,0,0],83:[0,.61111,0,0],84:[0,.61111,0,0],85:[0,.61111,0,0],86:[0,.61111,0,0],87:[0,.61111,0,0],88:[0,.61111,0,0],89:[0,.61111,0,0],90:[0,.61111,0,0],91:[.08333,.69444,0,0],92:[.08333,.69444,0,0],93:[.08333,.69444,0,0],94:[0,.61111,0,0],95:[.09514,0,0,0],96:[0,.61111,0,0],97:[0,.43056,0,0],98:[0,.61111,0,0],99:[0,.43056,0,0],100:[0,.61111,0,0],101:[0,.43056,0,0],102:[0,.61111,0,0],103:[.22222,.43056,0,0],104:[0,.61111,0,0],105:[0,.61111,0,0],106:[.22222,.61111,0,0],107:[0,.61111,0,0],108:[0,.61111,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.22222,.43056,0,0],113:[.22222,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.55358,0,0],117:[0,.43056,0,0],118:[0,.43056,0,0],119:[0,.43056,0,0],120:[0,.43056,0,0],121:[.22222,.43056,0,0],122:[0,.43056,0,0],123:[.08333,.69444,0,0],124:[.08333,.69444,0,0],125:[.08333,.69444,0,0],126:[0,.61111,0,0],127:[0,.61111,0,0],305:[0,.43056,0,0],567:[.22222,.43056,0,0],768:[0,.61111,0,0],769:[0,.61111,0,0],770:[0,.61111,0,0],771:[0,.61111,0,0],772:[0,.56555,0,0],774:[0,.61111,0,0],776:[0,.61111,0,0],778:[0,.61111,0,0],780:[0,.56597,0,0],915:[0,.61111,0,0],916:[0,.61111,0,0],920:[0,.61111,0,0],923:[0,.61111,0,0],926:[0,.61111,0,0],928:[0,.61111,0,0],931:[0,.61111,0,0],933:[0,.61111,0,0],934:[0,.61111,0,0],936:[0,.61111,0,0],937:[0,.61111,0,0],2018:[0,.61111,0,0],2019:[0,.61111,0,0],8242:[0,.61111,0,0]}}},{}],19:[function(e,t,r){var a=e("./utils");var i=e("./ParseError");var n=e("./parseData");var s=n.ParseNode;function l(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs,argTypes:r.argTypes,greediness:r.greediness===undefined?1:r.greediness,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,infix:!!r.infix,handler:a};for(var n=0;n<e.length;++n){t.exports[e[n]]=i}}var o=function(e){if(e.type==="ordgroup"){return e.value}else{return[e]}};l("\\sqrt",{numArgs:1,numOptionalArgs:1},function(e,t){var r=t[0];var a=t[1];return{type:"sqrt",body:a,index:r}});var u={"\\text":undefined,"\\textrm":"mathrm","\\textsf":"mathsf","\\texttt":"mathtt","\\textnormal":"mathrm","\\textbf":"mathbf","\\textit":"textit"};l(["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textit"],{numArgs:1,argTypes:["text"],greediness:2,allowedInText:true},function(e,t){var r=t[0];return{type:"text",body:o(r),style:u[e.funcName]}});l("\\color",{numArgs:2,allowedInText:true,greediness:3,argTypes:["color","original"]},function(e,t){var r=t[0];var a=t[1];return{type:"color",color:r.value,value:o(a)}});l("\\overline",{numArgs:1},function(e,t){var r=t[0];return{type:"overline",body:r}});l("\\underline",{numArgs:1},function(e,t){var r=t[0];return{type:"underline",body:r}});l("\\rule",{numArgs:2,numOptionalArgs:1,argTypes:["size","size","size"]},function(e,t){var r=t[0];var a=t[1];var i=t[2];return{type:"rule",shift:r&&r.value,width:a.value,height:i.value}});l(["\\kern","\\mkern"],{numArgs:1,argTypes:["size"]},function(e,t){return{type:"kern",dimension:t[0].value}});l("\\KaTeX",{numArgs:0},function(e){return{type:"katex"}});l("\\phantom",{numArgs:1},function(e,t){var r=t[0];return{type:"phantom",value:o(r)}});l(["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],{numArgs:1},function(e,t){var r=t[0];return{type:"mclass",mclass:"m"+e.funcName.substr(5),value:o(r)}});l("\\stackrel",{numArgs:2},function(e,t){var r=t[0];var a=t[1];var i=new s("op",{type:"op",limits:true,alwaysHandleSupSub:true,symbol:false,value:o(a)},a.mode);var n=new s("supsub",{base:i,sup:r,sub:null},r.mode);return{type:"mclass",mclass:"mrel",value:[n]}});l("\\bmod",{numArgs:0},function(e,t){return{type:"mod",modType:"bmod",value:null}});l(["\\pod","\\pmod","\\mod"],{numArgs:1},function(e,t){var r=t[0];return{type:"mod",modType:e.funcName.substr(1),value:o(r)}});var p={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}};var h=["(",")","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\\lceil","\\rceil","<",">","\\langle","\\rangle","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\\lmoustache","\\rmoustache","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];var c={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak"};l(["\\blue","\\orange","\\pink","\\red","\\green","\\gray","\\purple","\\blueA","\\blueB","\\blueC","\\blueD","\\blueE","\\tealA","\\tealB","\\tealC","\\tealD","\\tealE","\\greenA","\\greenB","\\greenC","\\greenD","\\greenE","\\goldA","\\goldB","\\goldC","\\goldD","\\goldE","\\redA","\\redB","\\redC","\\redD","\\redE","\\maroonA","\\maroonB","\\maroonC","\\maroonD","\\maroonE","\\purpleA","\\purpleB","\\purpleC","\\purpleD","\\purpleE","\\mintA","\\mintB","\\mintC","\\grayA","\\grayB","\\grayC","\\grayD","\\grayE","\\grayF","\\grayG","\\grayH","\\grayI","\\kaBlue","\\kaGreen"],{numArgs:1,allowedInText:true,greediness:3},function(e,t){var r=t[0];return{type:"color",color:"katex-"+e.funcName.slice(1),value:o(r)}});l(["\\arcsin","\\arccos","\\arctan","\\arg","\\cos","\\cosh","\\cot","\\coth","\\csc","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\tan","\\tanh"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:false,body:e.funcName}});l(["\\det","\\gcd","\\inf","\\lim","\\liminf","\\limsup","\\max","\\min","\\Pr","\\sup"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:false,body:e.funcName}});l(["\\int","\\iint","\\iiint","\\oint"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:true,body:e.funcName}});l(["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:true,body:e.funcName}});l("\\mathop",{numArgs:1},function(e,t){var r=t[0];return{type:"op",limits:false,symbol:false,value:o(r)}});l(["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac"],{numArgs:2,greediness:2},function(e,t){var r=t[0];var a=t[1];var i;var n=null;var s=null;var l="auto";switch(e.funcName){case"\\dfrac":case"\\frac":case"\\tfrac":i=true;break;case"\\\\atopfrac":i=false;break;case"\\dbinom":case"\\binom":case"\\tbinom":i=false;n="(";s=")";break;default:throw new Error("Unrecognized genfrac command")}switch(e.funcName){case"\\dfrac":case"\\dbinom":l="display";break;case"\\tfrac":case"\\tbinom":l="text";break}return{type:"genfrac",numer:r,denom:a,hasBarLine:i,leftDelim:n,rightDelim:s,size:l}});l(["\\llap","\\rlap"],{numArgs:1,allowedInText:true},function(e,t){var r=t[0];return{type:e.funcName.slice(1),body:r}});var m=function(e,t){if(a.contains(h,e.value)){return e}else{throw new i("Invalid delimiter: '"+e.value+"' after '"+t.funcName+"'",e)}};l(["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"delimsizing",size:p[e.funcName].size,mclass:p[e.funcName].mclass,value:r.value}});l(["\\left","\\right"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"leftright",value:r.value}});l("\\middle",{numArgs:1},function(e,t){var r=m(t[0],e);if(!e.parser.leftrightDepth){throw new i("\\middle without preceding \\left",r)}return{type:"middle",value:r.value}});l(["\\tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"],0,null);l(["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],0,null);l(["\\mathrm","\\mathit","\\mathbf","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],{numArgs:1,greediness:2},function(e,t){var r=t[0];var a=e.funcName;if(a in c){a=c[a]}return{type:"font",font:a.slice(1),body:r}});l(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot"],{numArgs:1},function(e,t){var r=t[0];return{type:"accent",accent:e.funcName,base:r}});l(["\\over","\\choose","\\atop"],{numArgs:0,infix:true},function(e){var t;switch(e.funcName){case"\\over":t="\\frac";break;case"\\choose":t="\\binom";break;case"\\atop":t="\\\\atopfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",replaceWith:t,token:e.token}});l(["\\\\","\\cr"],{numArgs:0,numOptionalArgs:1,argTypes:["size"]},function(e,t){var r=t[0];return{type:"cr",size:r}});l(["\\begin","\\end"],{numArgs:1,argTypes:["text"]},function(e,t){var r=t[0];if(r.type!=="ordgroup"){throw new i("Invalid environment name",r)}var a="";for(var n=0;n<r.value.length;++n){a+=r.value[n].value}return{type:"environment",name:a,nameGroup:r}})},{"./ParseError":6,"./parseData":21,"./utils":25}],20:[function(e,t,r){var a=e("./utils");function i(e,t){this.type=e;this.attributes={};this.children=t||[]}i.prototype.setAttribute=function(e,t){this.attributes[e]=t};i.prototype.toNode=function(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,t)){e.setAttribute(t,this.attributes[t])}}for(var r=0;r<this.children.length;r++){e.appendChild(this.children[r].toNode())}return e};i.prototype.toMarkup=function(){var e="<"+this.type;for(var t in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,t)){e+=" "+t+'="';e+=a.escape(this.attributes[t]);e+='"'}}e+=">";for(var r=0;r<this.children.length;r++){e+=this.children[r].toMarkup()}e+="</"+this.type+">";return e};function n(e){this.text=e}n.prototype.toNode=function(){return document.createTextNode(this.text)};n.prototype.toMarkup=function(){return a.escape(this.text)};t.exports={MathNode:i,TextNode:n}},{"./utils":25}],21:[function(e,t,r){function a(e,t,r,a,i){this.type=e;this.value=t;this.mode=r;if(a&&(!i||i.lexer===a.lexer)){this.lexer=a.lexer;this.start=a.start;this.end=(i||a).end}}t.exports={ParseNode:a}},{}],22:[function(e,t,r){var a=e("./Parser");var i=function(e,t){if(!(typeof e==="string"||e instanceof String)){throw new TypeError("KaTeX can only parse string typed expression")}var r=new a(e,t);return r.parse()};t.exports=i},{"./Parser":7}],23:[function(e,t,r){t.exports={math:{},text:{}};function a(e,r,a,i,n){t.exports[e][n]={font:r,group:a,replace:i}}var i="math";var n="text";var s="main";var l="ams";var o="accent";var u="bin";var p="close";var h="inner";var c="mathord";var m="op";var f="open";var v="punct";var d="rel";var g="spacing";var y="textord";a(i,s,d,"\u2261","\\equiv");a(i,s,d,"\u227a","\\prec");a(i,s,d,"\u227b","\\succ");a(i,s,d,"\u223c","\\sim");a(i,s,d,"\u22a5","\\perp");a(i,s,d,"\u2aaf","\\preceq");a(i,s,d,"\u2ab0","\\succeq");a(i,s,d,"\u2243","\\simeq");a(i,s,d,"\u2223","\\mid");a(i,s,d,"\u226a","\\ll");a(i,s,d,"\u226b","\\gg");a(i,s,d,"\u224d","\\asymp");a(i,s,d,"\u2225","\\parallel");a(i,s,d,"\u22c8","\\bowtie");a(i,s,d,"\u2323","\\smile");a(i,s,d,"\u2291","\\sqsubseteq");a(i,s,d,"\u2292","\\sqsupseteq");a(i,s,d,"\u2250","\\doteq");a(i,s,d,"\u2322","\\frown");a(i,s,d,"\u220b","\\ni");a(i,s,d,"\u221d","\\propto");a(i,s,d,"\u22a2","\\vdash");a(i,s,d,"\u22a3","\\dashv");a(i,s,d,"\u220b","\\owns");a(i,s,v,".","\\ldotp");a(i,s,v,"\u22c5","\\cdotp");a(i,s,y,"#","\\#");a(n,s,y,"#","\\#");a(i,s,y,"&","\\&");a(n,s,y,"&","\\&");a(i,s,y,"\u2135","\\aleph");a(i,s,y,"\u2200","\\forall");a(i,s,y,"\u210f","\\hbar");a(i,s,y,"\u2203","\\exists");a(i,s,y,"\u2207","\\nabla");a(i,s,y,"\u266d","\\flat");a(i,s,y,"\u2113","\\ell");a(i,s,y,"\u266e","\\natural");a(i,s,y,"\u2663","\\clubsuit");a(i,s,y,"\u2118","\\wp");a(i,s,y,"\u266f","\\sharp");a(i,s,y,"\u2662","\\diamondsuit");a(i,s,y,"\u211c","\\Re");a(i,s,y,"\u2661","\\heartsuit");a(i,s,y,"\u2111","\\Im");a(i,s,y,"\u2660","\\spadesuit");a(i,s,y,"\u2020","\\dag");a(i,s,y,"\u2021","\\ddag");a(i,s,p,"\u23b1","\\rmoustache");a(i,s,f,"\u23b0","\\lmoustache");a(i,s,p,"\u27ef","\\rgroup");a(i,s,f,"\u27ee","\\lgroup");a(i,s,u,"\u2213","\\mp");a(i,s,u,"\u2296","\\ominus");a(i,s,u,"\u228e","\\uplus");a(i,s,u,"\u2293","\\sqcap");a(i,s,u,"\u2217","\\ast");a(i,s,u,"\u2294","\\sqcup");a(i,s,u,"\u25ef","\\bigcirc");a(i,s,u,"\u2219","\\bullet");a(i,s,u,"\u2021","\\ddagger");a(i,s,u,"\u2240","\\wr");a(i,s,u,"\u2a3f","\\amalg");a(i,s,d,"\u27f5","\\longleftarrow");a(i,s,d,"\u21d0","\\Leftarrow");a(i,s,d,"\u27f8","\\Longleftarrow");a(i,s,d,"\u27f6","\\longrightarrow");a(i,s,d,"\u21d2","\\Rightarrow");a(i,s,d,"\u27f9","\\Longrightarrow");a(i,s,d,"\u2194","\\leftrightarrow");a(i,s,d,"\u27f7","\\longleftrightarrow");a(i,s,d,"\u21d4","\\Leftrightarrow");a(i,s,d,"\u27fa","\\Longleftrightarrow");a(i,s,d,"\u21a6","\\mapsto");a(i,s,d,"\u27fc","\\longmapsto");a(i,s,d,"\u2197","\\nearrow");a(i,s,d,"\u21a9","\\hookleftarrow");a(i,s,d,"\u21aa","\\hookrightarrow");a(i,s,d,"\u2198","\\searrow");a(i,s,d,"\u21bc","\\leftharpoonup");a(i,s,d,"\u21c0","\\rightharpoonup");a(i,s,d,"\u2199","\\swarrow");a(i,s,d,"\u21bd","\\leftharpoondown");a(i,s,d,"\u21c1","\\rightharpoondown");a(i,s,d,"\u2196","\\nwarrow");a(i,s,d,"\u21cc","\\rightleftharpoons");a(i,l,d,"\u226e","\\nless");a(i,l,d,"\ue010","\\nleqslant");a(i,l,d,"\ue011","\\nleqq");a(i,l,d,"\u2a87","\\lneq");a(i,l,d,"\u2268","\\lneqq");a(i,l,d,"\ue00c","\\lvertneqq");a(i,l,d,"\u22e6","\\lnsim");a(i,l,d,"\u2a89","\\lnapprox");a(i,l,d,"\u2280","\\nprec");a(i,l,d,"\u22e0","\\npreceq");a(i,l,d,"\u22e8","\\precnsim");a(i,l,d,"\u2ab9","\\precnapprox");a(i,l,d,"\u2241","\\nsim");a(i,l,d,"\ue006","\\nshortmid");a(i,l,d,"\u2224","\\nmid");a(i,l,d,"\u22ac","\\nvdash");a(i,l,d,"\u22ad","\\nvDash");a(i,l,d,"\u22ea","\\ntriangleleft");a(i,l,d,"\u22ec","\\ntrianglelefteq");a(i,l,d,"\u228a","\\subsetneq");a(i,l,d,"\ue01a","\\varsubsetneq");a(i,l,d,"\u2acb","\\subsetneqq");a(i,l,d,"\ue017","\\varsubsetneqq");a(i,l,d,"\u226f","\\ngtr");a(i,l,d,"\ue00f","\\ngeqslant");a(i,l,d,"\ue00e","\\ngeqq");a(i,l,d,"\u2a88","\\gneq");a(i,l,d,"\u2269","\\gneqq");a(i,l,d,"\ue00d","\\gvertneqq");a(i,l,d,"\u22e7","\\gnsim");a(i,l,d,"\u2a8a","\\gnapprox");a(i,l,d,"\u2281","\\nsucc");a(i,l,d,"\u22e1","\\nsucceq");a(i,l,d,"\u22e9","\\succnsim");a(i,l,d,"\u2aba","\\succnapprox");a(i,l,d,"\u2246","\\ncong");a(i,l,d,"\ue007","\\nshortparallel");a(i,l,d,"\u2226","\\nparallel");a(i,l,d,"\u22af","\\nVDash");a(i,l,d,"\u22eb","\\ntriangleright");a(i,l,d,"\u22ed","\\ntrianglerighteq");a(i,l,d,"\ue018","\\nsupseteqq");a(i,l,d,"\u228b","\\supsetneq");a(i,l,d,"\ue01b","\\varsupsetneq");a(i,l,d,"\u2acc","\\supsetneqq");a(i,l,d,"\ue019","\\varsupsetneqq");a(i,l,d,"\u22ae","\\nVdash");a(i,l,d,"\u2ab5","\\precneqq");a(i,l,d,"\u2ab6","\\succneqq");a(i,l,d,"\ue016","\\nsubseteqq");a(i,l,u,"\u22b4","\\unlhd");a(i,l,u,"\u22b5","\\unrhd");a(i,l,d,"\u219a","\\nleftarrow");a(i,l,d,"\u219b","\\nrightarrow");a(i,l,d,"\u21cd","\\nLeftarrow");a(i,l,d,"\u21cf","\\nRightarrow");a(i,l,d,"\u21ae","\\nleftrightarrow");a(i,l,d,"\u21ce","\\nLeftrightarrow");a(i,l,d,"\u25b3","\\vartriangle");a(i,l,y,"\u210f","\\hslash");a(i,l,y,"\u25bd","\\triangledown");a(i,l,y,"\u25ca","\\lozenge");a(i,l,y,"\u24c8","\\circledS");a(i,l,y,"\xae","\\circledR");a(i,l,y,"\u2221","\\measuredangle");a(i,l,y,"\u2204","\\nexists");a(i,l,y,"\u2127","\\mho");a(i,l,y,"\u2132","\\Finv");a(i,l,y,"\u2141","\\Game");a(i,l,y,"k","\\Bbbk");a(i,l,y,"\u2035","\\backprime");a(i,l,y,"\u25b2","\\blacktriangle");a(i,l,y,"\u25bc","\\blacktriangledown");a(i,l,y,"\u25a0","\\blacksquare");a(i,l,y,"\u29eb","\\blacklozenge");a(i,l,y,"\u2605","\\bigstar");a(i,l,y,"\u2222","\\sphericalangle");a(i,l,y,"\u2201","\\complement");a(i,l,y,"\xf0","\\eth");a(i,l,y,"\u2571","\\diagup");a(i,l,y,"\u2572","\\diagdown");a(i,l,y,"\u25a1","\\square");a(i,l,y,"\u25a1","\\Box");a(i,l,y,"\u25ca","\\Diamond");a(i,l,y,"\xa5","\\yen");a(i,l,y,"\u2713","\\checkmark");a(i,l,y,"\u2136","\\beth");a(i,l,y,"\u2138","\\daleth");a(i,l,y,"\u2137","\\gimel");a(i,l,y,"\u03dd","\\digamma");a(i,l,y,"\u03f0","\\varkappa");a(i,l,f,"\u250c","\\ulcorner");a(i,l,p,"\u2510","\\urcorner");a(i,l,f,"\u2514","\\llcorner");a(i,l,p,"\u2518","\\lrcorner");a(i,l,d,"\u2266","\\leqq");a(i,l,d,"\u2a7d","\\leqslant");a(i,l,d,"\u2a95","\\eqslantless");a(i,l,d,"\u2272","\\lesssim");a(i,l,d,"\u2a85","\\lessapprox");a(i,l,d,"\u224a","\\approxeq");a(i,l,u,"\u22d6","\\lessdot");a(i,l,d,"\u22d8","\\lll");a(i,l,d,"\u2276","\\lessgtr");a(i,l,d,"\u22da","\\lesseqgtr");a(i,l,d,"\u2a8b","\\lesseqqgtr");a(i,l,d,"\u2251","\\doteqdot");a(i,l,d,"\u2253","\\risingdotseq");a(i,l,d,"\u2252","\\fallingdotseq");a(i,l,d,"\u223d","\\backsim");a(i,l,d,"\u22cd","\\backsimeq");a(i,l,d,"\u2ac5","\\subseteqq");a(i,l,d,"\u22d0","\\Subset");a(i,l,d,"\u228f","\\sqsubset");a(i,l,d,"\u227c","\\preccurlyeq");a(i,l,d,"\u22de","\\curlyeqprec");a(i,l,d,"\u227e","\\precsim");a(i,l,d,"\u2ab7","\\precapprox");a(i,l,d,"\u22b2","\\vartriangleleft");a(i,l,d,"\u22b4","\\trianglelefteq");a(i,l,d,"\u22a8","\\vDash");a(i,l,d,"\u22aa","\\Vvdash");a(i,l,d,"\u2323","\\smallsmile");a(i,l,d,"\u2322","\\smallfrown");a(i,l,d,"\u224f","\\bumpeq");a(i,l,d,"\u224e","\\Bumpeq");a(i,l,d,"\u2267","\\geqq");a(i,l,d,"\u2a7e","\\geqslant");a(i,l,d,"\u2a96","\\eqslantgtr");a(i,l,d,"\u2273","\\gtrsim");a(i,l,d,"\u2a86","\\gtrapprox");a(i,l,u,"\u22d7","\\gtrdot");a(i,l,d,"\u22d9","\\ggg");a(i,l,d,"\u2277","\\gtrless");a(i,l,d,"\u22db","\\gtreqless");a(i,l,d,"\u2a8c","\\gtreqqless");a(i,l,d,"\u2256","\\eqcirc");a(i,l,d,"\u2257","\\circeq");a(i,l,d,"\u225c","\\triangleq");a(i,l,d,"\u223c","\\thicksim");a(i,l,d,"\u2248","\\thickapprox");a(i,l,d,"\u2ac6","\\supseteqq");a(i,l,d,"\u22d1","\\Supset");a(i,l,d,"\u2290","\\sqsupset");a(i,l,d,"\u227d","\\succcurlyeq");a(i,l,d,"\u22df","\\curlyeqsucc");a(i,l,d,"\u227f","\\succsim");a(i,l,d,"\u2ab8","\\succapprox");a(i,l,d,"\u22b3","\\vartriangleright");a(i,l,d,"\u22b5","\\trianglerighteq");a(i,l,d,"\u22a9","\\Vdash");a(i,l,d,"\u2223","\\shortmid");a(i,l,d,"\u2225","\\shortparallel");a(i,l,d,"\u226c","\\between");a(i,l,d,"\u22d4","\\pitchfork");a(i,l,d,"\u221d","\\varpropto");a(i,l,d,"\u25c0","\\blacktriangleleft");a(i,l,d,"\u2234","\\therefore");a(i,l,d,"\u220d","\\backepsilon");a(i,l,d,"\u25b6","\\blacktriangleright");a(i,l,d,"\u2235","\\because");a(i,l,d,"\u22d8","\\llless");a(i,l,d,"\u22d9","\\gggtr");a(i,l,u,"\u22b2","\\lhd");a(i,l,u,"\u22b3","\\rhd");a(i,l,d,"\u2242","\\eqsim");a(i,s,d,"\u22c8","\\Join");a(i,l,d,"\u2251","\\Doteq");a(i,l,u,"\u2214","\\dotplus");a(i,l,u,"\u2216","\\smallsetminus");a(i,l,u,"\u22d2","\\Cap");a(i,l,u,"\u22d3","\\Cup");a(i,l,u,"\u2a5e","\\doublebarwedge");a(i,l,u,"\u229f","\\boxminus");a(i,l,u,"\u229e","\\boxplus");a(i,l,u,"\u22c7","\\divideontimes");a(i,l,u,"\u22c9","\\ltimes");a(i,l,u,"\u22ca","\\rtimes");a(i,l,u,"\u22cb","\\leftthreetimes");a(i,l,u,"\u22cc","\\rightthreetimes");a(i,l,u,"\u22cf","\\curlywedge");a(i,l,u,"\u22ce","\\curlyvee");a(i,l,u,"\u229d","\\circleddash");a(i,l,u,"\u229b","\\circledast");a(i,l,u,"\u22c5","\\centerdot");a(i,l,u,"\u22ba","\\intercal");a(i,l,u,"\u22d2","\\doublecap");a(i,l,u,"\u22d3","\\doublecup");a(i,l,u,"\u22a0","\\boxtimes");a(i,l,d,"\u21e2","\\dashrightarrow");a(i,l,d,"\u21e0","\\dashleftarrow");a(i,l,d,"\u21c7","\\leftleftarrows");a(i,l,d,"\u21c6","\\leftrightarrows");a(i,l,d,"\u21da","\\Lleftarrow");a(i,l,d,"\u219e","\\twoheadleftarrow");a(i,l,d,"\u21a2","\\leftarrowtail");a(i,l,d,"\u21ab","\\looparrowleft");a(i,l,d,"\u21cb","\\leftrightharpoons");a(i,l,d,"\u21b6","\\curvearrowleft");a(i,l,d,"\u21ba","\\circlearrowleft");a(i,l,d,"\u21b0","\\Lsh");a(i,l,d,"\u21c8","\\upuparrows");a(i,l,d,"\u21bf","\\upharpoonleft");a(i,l,d,"\u21c3","\\downharpoonleft");a(i,l,d,"\u22b8","\\multimap");a(i,l,d,"\u21ad","\\leftrightsquigarrow");a(i,l,d,"\u21c9","\\rightrightarrows");a(i,l,d,"\u21c4","\\rightleftarrows");a(i,l,d,"\u21a0","\\twoheadrightarrow");a(i,l,d,"\u21a3","\\rightarrowtail");a(i,l,d,"\u21ac","\\looparrowright");a(i,l,d,"\u21b7","\\curvearrowright");a(i,l,d,"\u21bb","\\circlearrowright");a(i,l,d,"\u21b1","\\Rsh");a(i,l,d,"\u21ca","\\downdownarrows");a(i,l,d,"\u21be","\\upharpoonright");a(i,l,d,"\u21c2","\\downharpoonright");a(i,l,d,"\u21dd","\\rightsquigarrow");a(i,l,d,"\u21dd","\\leadsto");a(i,l,d,"\u21db","\\Rrightarrow");a(i,l,d,"\u21be","\\restriction");a(i,s,y,"\u2018","`");a(i,s,y,"$","\\$");a(n,s,y,"$","\\$");a(i,s,y,"%","\\%");a(n,s,y,"%","\\%");a(i,s,y,"_","\\_");a(n,s,y,"_","\\_");a(i,s,y,"\u2220","\\angle");a(i,s,y,"\u221e","\\infty");a(i,s,y,"\u2032","\\prime");a(i,s,y,"\u25b3","\\triangle");a(i,s,y,"\u0393","\\Gamma");a(i,s,y,"\u0394","\\Delta");a(i,s,y,"\u0398","\\Theta");a(i,s,y,"\u039b","\\Lambda");a(i,s,y,"\u039e","\\Xi");a(i,s,y,"\u03a0","\\Pi");a(i,s,y,"\u03a3","\\Sigma");a(i,s,y,"\u03a5","\\Upsilon");a(i,s,y,"\u03a6","\\Phi");a(i,s,y,"\u03a8","\\Psi");a(i,s,y,"\u03a9","\\Omega");a(i,s,y,"\xac","\\neg");a(i,s,y,"\xac","\\lnot");a(i,s,y,"\u22a4","\\top");a(i,s,y,"\u22a5","\\bot");a(i,s,y,"\u2205","\\emptyset");a(i,l,y,"\u2205","\\varnothing");a(i,s,c,"\u03b1","\\alpha");a(i,s,c,"\u03b2","\\beta");a(i,s,c,"\u03b3","\\gamma");a(i,s,c,"\u03b4","\\delta");a(i,s,c,"\u03f5","\\epsilon");a(i,s,c,"\u03b6","\\zeta");a(i,s,c,"\u03b7","\\eta");a(i,s,c,"\u03b8","\\theta");a(i,s,c,"\u03b9","\\iota");a(i,s,c,"\u03ba","\\kappa");a(i,s,c,"\u03bb","\\lambda");a(i,s,c,"\u03bc","\\mu");a(i,s,c,"\u03bd","\\nu");a(i,s,c,"\u03be","\\xi");a(i,s,c,"o","\\omicron");a(i,s,c,"\u03c0","\\pi");a(i,s,c,"\u03c1","\\rho");a(i,s,c,"\u03c3","\\sigma");a(i,s,c,"\u03c4","\\tau");a(i,s,c,"\u03c5","\\upsilon");a(i,s,c,"\u03d5","\\phi");a(i,s,c,"\u03c7","\\chi");a(i,s,c,"\u03c8","\\psi");a(i,s,c,"\u03c9","\\omega");a(i,s,c,"\u03b5","\\varepsilon");a(i,s,c,"\u03d1","\\vartheta");a(i,s,c,"\u03d6","\\varpi");a(i,s,c,"\u03f1","\\varrho");a(i,s,c,"\u03c2","\\varsigma");a(i,s,c,"\u03c6","\\varphi");a(i,s,u,"\u2217","*");a(i,s,u,"+","+");a(i,s,u,"\u2212","-");a(i,s,u,"\u22c5","\\cdot");a(i,s,u,"\u2218","\\circ");a(i,s,u,"\xf7","\\div");a(i,s,u,"\xb1","\\pm");a(i,s,u,"\xd7","\\times");a(i,s,u,"\u2229","\\cap");a(i,s,u,"\u222a","\\cup");a(i,s,u,"\u2216","\\setminus");a(i,s,u,"\u2227","\\land");a(i,s,u,"\u2228","\\lor");a(i,s,u,"\u2227","\\wedge");a(i,s,u,"\u2228","\\vee");a(i,s,y,"\u221a","\\surd");a(i,s,f,"(","(");a(i,s,f,"[","[");a(i,s,f,"\u27e8","\\langle");a(i,s,f,"\u2223","\\lvert");a(i,s,f,"\u2225","\\lVert");a(i,s,p,")",")");a(i,s,p,"]","]");a(i,s,p,"?","?");a(i,s,p,"!","!");a(i,s,p,"\u27e9","\\rangle");a(i,s,p,"\u2223","\\rvert");a(i,s,p,"\u2225","\\rVert");a(i,s,d,"=","=");a(i,s,d,"<","<");a(i,s,d,">",">");a(i,s,d,":",":");a(i,s,d,"\u2248","\\approx");a(i,s,d,"\u2245","\\cong");a(i,s,d,"\u2265","\\ge");a(i,s,d,"\u2265","\\geq");a(i,s,d,"\u2190","\\gets");a(i,s,d,">","\\gt");a(i,s,d,"\u2208","\\in");a(i,s,d,"\u2209","\\notin");a(i,s,d,"\u2282","\\subset");a(i,s,d,"\u2283","\\supset");a(i,s,d,"\u2286","\\subseteq");a(i,s,d,"\u2287","\\supseteq");a(i,l,d,"\u2288","\\nsubseteq");a(i,l,d,"\u2289","\\nsupseteq");a(i,s,d,"\u22a8","\\models");a(i,s,d,"\u2190","\\leftarrow");a(i,s,d,"\u2264","\\le");a(i,s,d,"\u2264","\\leq");a(i,s,d,"<","\\lt");a(i,s,d,"\u2260","\\ne");a(i,s,d,"\u2260","\\neq");a(i,s,d,"\u2192","\\rightarrow");a(i,s,d,"\u2192","\\to");a(i,l,d,"\u2271","\\ngeq");a(i,l,d,"\u2270","\\nleq");a(i,s,g,null,"\\!");a(i,s,g,"\xa0","\\ ");a(i,s,g,"\xa0","~");a(i,s,g,null,"\\,");a(i,s,g,null,"\\:");a(i,s,g,null,"\\;");a(i,s,g,null,"\\enspace");a(i,s,g,null,"\\qquad");a(i,s,g,null,"\\quad");a(i,s,g,"\xa0","\\space");a(i,s,v,",",",");a(i,s,v,";",";");a(i,s,v,":","\\colon");a(i,l,u,"\u22bc","\\barwedge");a(i,l,u,"\u22bb","\\veebar");a(i,s,u,"\u2299","\\odot");a(i,s,u,"\u2295","\\oplus");a(i,s,u,"\u2297","\\otimes");a(i,s,y,"\u2202","\\partial");a(i,s,u,"\u2298","\\oslash");a(i,l,u,"\u229a","\\circledcirc");a(i,l,u,"\u22a1","\\boxdot");a(i,s,u,"\u25b3","\\bigtriangleup");a(i,s,u,"\u25bd","\\bigtriangledown");a(i,s,u,"\u2020","\\dagger");a(i,s,u,"\u22c4","\\diamond");a(i,s,u,"\u22c6","\\star");a(i,s,u,"\u25c3","\\triangleleft");a(i,s,u,"\u25b9","\\triangleright");a(i,s,f,"{","\\{");a(n,s,y,"{","\\{");a(i,s,p,"}","\\}");a(n,s,y,"}","\\}");a(i,s,f,"{","\\lbrace");a(i,s,p,"}","\\rbrace");a(i,s,f,"[","\\lbrack");a(i,s,p,"]","\\rbrack");a(i,s,f,"\u230a","\\lfloor");a(i,s,p,"\u230b","\\rfloor");a(i,s,f,"\u2308","\\lceil");a(i,s,p,"\u2309","\\rceil");a(i,s,y,"\\","\\backslash");a(i,s,y,"\u2223","|");a(i,s,y,"\u2223","\\vert");a(i,s,y,"\u2225","\\|");a(i,s,y,"\u2225","\\Vert");a(i,s,d,"\u2191","\\uparrow");a(i,s,d,"\u21d1","\\Uparrow");a(i,s,d,"\u2193","\\downarrow");a(i,s,d,"\u21d3","\\Downarrow");a(i,s,d,"\u2195","\\updownarrow");a(i,s,d,"\u21d5","\\Updownarrow");a(i,i,m,"\u2210","\\coprod");a(i,i,m,"\u22c1","\\bigvee");a(i,i,m,"\u22c0","\\bigwedge");a(i,i,m,"\u2a04","\\biguplus");a(i,i,m,"\u22c2","\\bigcap");a(i,i,m,"\u22c3","\\bigcup");a(i,i,m,"\u222b","\\int");a(i,i,m,"\u222b","\\intop");a(i,i,m,"\u222c","\\iint");a(i,i,m,"\u222d","\\iiint");a(i,i,m,"\u220f","\\prod");a(i,i,m,"\u2211","\\sum");a(i,i,m,"\u2a02","\\bigotimes");a(i,i,m,"\u2a01","\\bigoplus");a(i,i,m,"\u2a00","\\bigodot");a(i,i,m,"\u222e","\\oint");a(i,i,m,"\u2a06","\\bigsqcup");a(i,i,m,"\u222b","\\smallint");a(n,s,h,"\u2026","\\textellipsis");a(i,s,h,"\u2026","\\mathellipsis");a(n,s,h,"\u2026","\\ldots");a(i,s,h,"\u2026","\\ldots");a(i,s,h,"\u22ef","\\cdots");a(i,s,h,"\u22f1","\\ddots");a(i,s,y,"\u22ee","\\vdots");a(i,s,o,"\xb4","\\acute");a(i,s,o,"`","\\grave");a(i,s,o,"\xa8","\\ddot");a(i,s,o,"~","\\tilde");a(i,s,o,"\xaf","\\bar");a(i,s,o,"\u02d8","\\breve");a(i,s,o,"\u02c7","\\check");a(i,s,o,"^","\\hat");a(i,s,o,"\u20d7","\\vec");a(i,s,o,"\u02d9","\\dot");a(i,s,c,"\u0131","\\imath");a(i,s,c,"\u0237","\\jmath");a(n,s,y,"\u2013","--");a(n,s,y,"\u2014","---");a(n,s,y,"\u2018","`");a(n,s,y,"\u2019","'");a(n,s,y,"\u201c","``");a(n,s,y,"\u201d","''");a(i,s,y,"\xb0","\\degree");a(n,s,y,"\xb0","\\degree");a(i,s,c,"\xa3","\\pounds");a(i,l,y,"\u2720","\\maltese");a(n,l,y,"\u2720","\\maltese");a(n,s,g,"\xa0","\\ ");a(n,s,g,"\xa0"," ");a(n,s,g,"\xa0","~");var x;var b;var w='0123456789/@."';for(x=0;x<w.length;x++){b=w.charAt(x);a(i,s,y,b,b)}var k='0123456789!@*()-=+[]";:?/.,';for(x=0;x<k.length;x++){b=k.charAt(x);a(n,s,y,b,b)}var z="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";for(x=0;x<z.length;x++){b=z.charAt(x);a(i,s,c,b,b);a(n,s,y,b,b)}for(x=192;x<=214;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=216;x<=246;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=248;x<=255;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}for(x=1040;x<=1103;x++){b=String.fromCharCode(x);a(n,s,y,b,b)}a(n,s,y,"\u2013","\u2013");a(n,s,y,"\u2014","\u2014");a(n,s,y,"\u2018","\u2018");a(n,s,y,"\u2019","\u2019");a(n,s,y,"\u201c","\u201c");a(n,s,y,"\u201d","\u201d")},{}],24:[function(e,t,r){var a=/[\uAC00-\uD7AF]/;var i=/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/;t.exports={cjkRegex:i,hangulRegex:a}},{}],25:[function(e,t,r){var a=Array.prototype.indexOf;var i=function(e,t){if(e==null){return-1}if(a&&e.indexOf===a){return e.indexOf(t)}var r=0;var i=e.length;for(;r<i;r++){if(e[r]===t){return r}}return-1};var n=function(e,t){return i(e,t)!==-1};var s=function(e,t){return e===undefined?t:e};var l=/([A-Z])/g;var o=function(e){return e.replace(l,"-$1").toLowerCase()};var u={"&":"&amp;",">":"&gt;","<":"&lt;",'"':"&quot;","'":"&#x27;"};var p=/[&><"']/g;function h(e){return u[e]}function c(e){return(""+e).replace(p,h)}var m;if(typeof document!=="undefined"){var f=document.createElement("span");if("textContent"in f){m=function(e,t){e.textContent=t}}else{m=function(e,t){e.innerText=t}}}function v(e){m(e,"")}t.exports={contains:n,deflt:s,escape:c,hyphenate:o,indexOf:i,setTextContent:m,clearNode:v}},{}]},{},[1])(1)});
diff --git a/xml/glx.xml b/xml/glx.xml
index 810d55f..6fadd17 100644
--- a/xml/glx.xml
+++ b/xml/glx.xml
@@ -1086,7 +1086,7 @@
             <param><ptype>Display</ptype> *<name>dpy</name></param>
             <param><ptype>Window</ptype> <name>overlay</name></param>
             <param><ptype>Window</ptype> <name>underlay</name></param>
-            <param>long *<name>pTransparentIndex</name></param>
+            <param>unsigned long *<name>pTransparentIndex</name></param>
         </command>
         <command>
             <proto>int <name>glXGetVideoDeviceNV</name></proto>
@@ -1252,7 +1252,7 @@
             <param><ptype>GLuint</ptype> *<name>count</name></param>
         </command>
         <command>
-            <proto>int <name>glXQueryGLXPbufferSGIX</name></proto>
+            <proto>void <name>glXQueryGLXPbufferSGIX</name></proto>
             <param><ptype>Display</ptype> *<name>dpy</name></param>
             <param><ptype>GLXPbufferSGIX</ptype> <name>pbuf</name></param>
             <param>int <name>attribute</name></param>
@@ -1393,8 +1393,8 @@
             <param><ptype>GLboolean</ptype> <name>bBlock</name></param>
         </command>
         <command>
-            <proto><ptype>Bool</ptype> <name>glXSet3DfxModeMESA</name></proto>
-            <param>int <name>mode</name></param>
+            <proto><ptype>GLboolean</ptype> <name>glXSet3DfxModeMESA</name></proto>
+            <param>GLint <name>mode</name></param>
         </command>
         <command>
             <proto>void <name>glXSwapBuffers</name></proto>
diff --git a/xml/wgl.xml b/xml/wgl.xml
index 49277ed..c3b3630 100644
--- a/xml/wgl.xml
+++ b/xml/wgl.xml
@@ -538,7 +538,7 @@
         </command>
         <command>
             <proto><ptype>BOOL</ptype> <name>wglBindVideoDeviceNV</name></proto>
-            <param><ptype>HDC</ptype> <name>hDC</name></param>
+            <param><ptype>HDC</ptype> <name>hDc</name></param>
             <param>unsigned int <name>uVideoSlot</name></param>
             <param><ptype>HVIDEOOUTPUTDEVICENV</ptype> <name>hVideoDevice</name></param>
             <param>const int *<name>piAttribList</name></param>
@@ -781,7 +781,7 @@
         </command>
         <command>
             <proto>int <name>wglEnumerateVideoDevicesNV</name></proto>
-            <param><ptype>HDC</ptype> <name>hDC</name></param>
+            <param><ptype>HDC</ptype> <name>hDc</name></param>
             <param><ptype>HVIDEOOUTPUTDEVICENV</ptype> *<name>phDeviceList</name></param>
         </command>
         <command>
@@ -912,7 +912,7 @@
         <command>
             <proto><ptype>INT</ptype> <name>wglGetGPUInfoAMD</name></proto>
             <param><ptype>UINT</ptype> <name>id</name></param>
-            <param>int <name>property</name></param>
+            <param><ptype>INT</ptype> <name>property</name></param>
             <param><ptype>GLenum</ptype> <name>dataType</name></param>
             <param><ptype>UINT</ptype> <name>size</name></param>
             <param>void *<name>data</name></param>
@@ -1235,7 +1235,7 @@
         <command>
             <proto><ptype>INT64</ptype> <name>wglSwapLayerBuffersMscOML</name></proto>
             <param><ptype>HDC</ptype> <name>hdc</name></param>
-            <param>int <name>fuPlanes</name></param>
+            <param><ptype>INT</ptype> <name>fuPlanes</name></param>
             <param><ptype>INT64</ptype> <name>target_msc</name></param>
             <param><ptype>INT64</ptype> <name>divisor</name></param>
             <param><ptype>INT64</ptype> <name>remainder</name></param>