diff options
| -rw-r--r-- | indra/llrender/llshadermgr.cpp | 4 | ||||
| -rw-r--r-- | indra/llrender/llshadermgr.h | 3 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/materialV.glsl | 17 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl | 27 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class3/deferred/materialF.glsl | 30 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl | 6 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolmaterials.cpp | 13 | ||||
| -rw-r--r-- | indra/newview/llfetchedgltfmaterial.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llheroprobemanager.cpp | 33 | ||||
| -rw-r--r-- | indra/newview/llheroprobemanager.h | 11 | ||||
| -rw-r--r-- | indra/newview/llreflectionmap.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llreflectionmap.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerdisplay.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.cpp | 15 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.h | 3 | ||||
| -rwxr-xr-x | scripts/messages/message_template.msg.sha1 | 2 | 
16 files changed, 141 insertions, 32 deletions
| diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 645a78bfac..8ae23989c9 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -651,6 +651,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev      extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_SKIP_ATMOS   0.0 \n"); // atmo kill      extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_ATMOS    0.34\n"); // bit 0      extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR      0.67\n"); // bit 1 +    extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_MIRROR      1.0\n");  // bit 2      extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag)    (abs(norm.w-flag)< 0.1)\n");  	if (defines) @@ -1256,6 +1257,9 @@ void LLShaderMgr::initAttribsAndUniforms()      mReservedUniforms.push_back("emissiveColor");      mReservedUniforms.push_back("metallicFactor");      mReservedUniforms.push_back("roughnessFactor"); +    mReservedUniforms.push_back("mirror_flag"); +    mReservedUniforms.push_back("clipPlane"); +    mReservedUniforms.push_back("clipSign");  	mReservedUniforms.push_back("diffuseMap");      mReservedUniforms.push_back("altDiffuseMap"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index a326a5593d..5824c03e2a 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -85,6 +85,9 @@ public:          EMISSIVE_COLOR,                     //  "emissiveColor"          METALLIC_FACTOR,                    //  "metallicFactor"          ROUGHNESS_FACTOR,                   //  "roughnessFactor" +        MIRROR_FLAG,                        //  "mirror_flag" +        CLIP_PLANE,                         //  "clipPlane" +        CLIP_SIGN,                          //  "clipSign"          DIFFUSE_MAP,                        //  "diffuseMap"          ALTERNATE_DIFFUSE_MAP,              //  "altDiffuseMap"          SPECULAR_MAP,                       //  "specularMap" diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl index 7cdddfe8db..65706e2c3f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl @@ -28,25 +28,18 @@  #define DIFFUSE_ALPHA_MODE_MASK 2  #define DIFFUSE_ALPHA_MODE_EMISSIVE 3 -#ifdef HAS_SKIN  uniform mat4 modelview_matrix;  uniform mat4 projection_matrix; +uniform mat4 modelview_projection_matrix; + +#ifdef HAS_SKIN  mat4 getObjectSkinnedTransform();  #else  uniform mat3 normal_matrix; -uniform mat4 modelview_projection_matrix; -#endif - -#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) - -#if !defined(HAS_SKIN) -uniform mat4 modelview_matrix;  #endif  out vec3 vary_position; -#endif -  uniform mat4 texture_matrix0;  in vec3 position; @@ -133,10 +126,8 @@ void main()  	vertex_color = diffuse_color; -#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)  #if !defined(HAS_SKIN) -	vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; -#endif +	vary_position = (projection_matrix*vec4(position.xyz, 1.0)).xyz;  #endif  } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl index faa273b834..9b98a37925 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -58,10 +58,37 @@ vec2 encode_normal(vec3 n);  vec3 linear_to_srgb(vec3 c);  vec3 srgb_to_linear(vec3 c); +uniform vec4 clipPlane; +uniform float clipSign; +uniform float mirror_flag; +void applyClip(vec3 pos) +{ +    if (mirror_flag > 0) +    { +        // TODO: make this less branchy +        if (clipSign > 0) +        { +            if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) < 0.0) +            { +                discard; +            } +        } +        else +        { +            if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) > 0.0) +            { +                discard; +            } +        } +    } +} +  uniform mat3 normal_matrix;  void main()  { +    applyClip(vary_position); +      vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;      if (basecolor.a < minimum_alpha)      { diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 319f2f25b7..af49e76984 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -51,6 +51,23 @@ vec3 linear_to_srgb(vec3 cs);  vec3 legacy_adjust(vec3 c);  vec3 legacy_adjust_fullbright(vec3 c); +uniform vec4 clipPlane; +uniform float clipSign; +uniform float mirror_flag; +void applyClip(vec3 pos) +{ +    float funnyClip = 0; +    if (mirror_flag > 0) +    { +            if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) > 0.0) +            { +                discard; +            } +    } +} + +in vec3 vary_position; +  #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)  out vec4 frag_color; @@ -72,12 +89,12 @@ uniform vec4 morphFactor;  uniform vec3 camPosLocal;  uniform mat3 env_mat; +uniform float is_mirror; +  uniform vec3 sun_dir;  uniform vec3 moon_dir;  in vec2 vary_fragcoord; -in vec3 vary_position; -  uniform mat4 proj_mat;  uniform mat4 inv_proj;  uniform vec2 screen_res; @@ -291,6 +308,7 @@ float getShadow(vec3 pos, vec3 norm)  void main()  { +    applyClip(vary_position);      waterClip();      // diffcol == diffuse map combined with vertex color @@ -419,9 +437,15 @@ void main()  #else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer       // deferred path               // See: C++: addDeferredAttachment(), shader: softenLightF.glsl + +    float flag = GBUFFER_FLAG_HAS_ATMOS; + +    if (mirror_flag > 0) +        flag = 1; +      frag_data[0] = vec4(diffcol.rgb, emissive);        // gbuffer is sRGB for legacy materials      frag_data[1] = vec4(spec.rgb, glossiness);           // XYZ = Specular color. W = Specular exponent. -    frag_data[2] = vec4(encode_normal(norm), env, GBUFFER_FLAG_HAS_ATMOS);;   // XY = Normal.  Z = Env. intensity. W = 1 skip atmos (mask off fog) +    frag_data[2] = vec4(encode_normal(norm), env, flag);;   // XY = Normal.  Z = Env. intensity. W = 1 skip atmos (mask off fog)      frag_data[3] = vec4(0);  #endif  } diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 20a5ad66b6..d42388ae78 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -191,7 +191,7 @@ void main()      vec3  irradiance = vec3(0);      vec3  radiance  = vec3(0); -    if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) +    if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR) || GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_MIRROR))      {          vec3 orm = texture(specularRect, tc).rgb;          float perceptualRoughness = orm.g; @@ -214,7 +214,9 @@ void main()          color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);          vec3 refnormpersp = reflect(pos.xyz, norm.xyz); -        color = textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0 - gloss) * 11).xyz * specularColor; + +        if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_MIRROR)) +            color = textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0 - gloss) * 11).xyz * specularColor;          if (do_atmospherics)          { diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 6a7e05ac74..373103ce0a 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -190,6 +190,19 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)          glUniform4fv(specular, 1, lastSpecular.mV);      } +    if (gPipeline.mHeroProbeManager.isMirrorPass()) +    { +        glUniform1f(LLShaderMgr::MIRROR_FLAG, 1); +    } + +    LLVector4 clipPlane = LLVector4(gPipeline.mHeroProbeManager.currentMirrorClip()[0], +                                    gPipeline.mHeroProbeManager.currentMirrorClip()[1], +                                    gPipeline.mHeroProbeManager.currentMirrorClip()[2], +                                    gPipeline.mHeroProbeManager.currentMirrorClip()[3]); + +    mShader->uniform4fv(LLShaderMgr::CLIP_PLANE, +                 1, clipPlane.mV); +      LLVOAvatar* lastAvatar = nullptr;  	for (LLCullResult::drawinfo_iterator i = begin; i != end; ) diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 1fb3577dd7..9590066b55 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -128,6 +128,7 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)          shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mRoughnessFactor);          shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mMetallicFactor);          shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, mEmissiveColor.mV); +        shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 0);          F32 normal_packed[8];          mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index 91d5f9b800..b6db123cd9 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -141,13 +141,13 @@ void LLHeroProbeManager::update()              U8        mode     = mNearestHero->mirrorPlacementMode();              mode    = llmin(mNearestHero->mDrawable->getNumFaces() - 1, mode); -            LLFace   *face     = mNearestHero->mDrawable->getFace(mode); -            LLVector3 hero_pos = face->getPositionAgent(); +            mCurrentFace       = mNearestHero->mDrawable->getFace(mode); +            LLVector3 hero_pos = mCurrentFace->getPositionAgent();              // Calculate the average normal. -            LLVector4a *posp = face->getViewerObject()->getVolume()->getVolumeFace(face->getTEOffset()).mPositions; -            U16        *indp = face->getViewerObject()->getVolume()->getVolumeFace(face->getTEOffset()).mIndices; +            LLVector4a *posp = mCurrentFace->getViewerObject()->getVolume()->getVolumeFace(mCurrentFace->getTEOffset()).mPositions; +            U16        *indp = mCurrentFace->getViewerObject()->getVolume()->getVolumeFace(mCurrentFace->getTEOffset()).mIndices;              // get first three vertices (first triangle)              LLVector4a v0 = posp[indp[0]];              LLVector4a   v1 = posp[indp[1]]; @@ -158,14 +158,27 @@ void LLHeroProbeManager::update()              LLVector3 face_normal = LLVector3(v1[0], v1[1], v1[2]) % LLVector3(v2[0], v2[1], v2[2]);              face_normal.normalize(); -            face_normal *= face->getXform()->getWorldRotation(); +            face_normal *= mCurrentFace->getXform()->getWorldRotation();              LLVector3 offset = camera_pos - hero_pos;              LLVector3 project = face_normal * (offset * face_normal);              LLVector3 reject  = offset - project;              LLVector3 point   = (reject - project) + hero_pos; -            near_clip = abs(dist_vec(hero_pos, point)) - gSavedSettings.getF32("RenderHeroProbeNearClipOffset"); +            glh::matrix4f mat     = copy_matrix(gGLModelView); +            glh::vec4f    tc(face_normal.mV); +            mat.mult_matrix_vec(tc); + +            LLVector3 mirror_normal; +            mirror_normal.set(tc.v); + +            LLVector3 hero_pos_render; +            tc = glh::vec4f(hero_pos.mV); + +            mat.mult_matrix_vec(tc); +            hero_pos_render.set(tc.v); + +            mCurrentClipPlane.setVec(hero_pos_render, mirror_normal);              probe_pos.load3(point.mV);          } @@ -189,7 +202,7 @@ void LLHeroProbeManager::update()          bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass();          gPipeline.mReflectionMapManager.mRadiancePass = true; -         +        mRenderingMirror = true;          for (U32 j = 0; j < mProbes.size(); j++)          {              for (U32 i = 0; i < 6; ++i) @@ -197,6 +210,7 @@ void LLHeroProbeManager::update()                  updateProbeFace(mProbes[j], i, near_clip);              }          } +        mRenderingMirror = false;          gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass;      } @@ -563,3 +577,8 @@ void LLHeroProbeManager::unregisterHeroDrawable(LLVOVolume* drawablep)          mHeroVOList.erase(drawablep);      }  } + +bool LLHeroProbeManager::isViableMirror(LLFace* face) const +{ +    return face == mCurrentFace; +} diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h index 4a243e6cf2..68cfdbfd99 100644 --- a/indra/newview/llheroprobemanager.h +++ b/indra/newview/llheroprobemanager.h @@ -70,6 +70,12 @@ public:      void registerHeroDrawable(LLVOVolume* drawablep);      void unregisterHeroDrawable(LLVOVolume* drawablep); + +    bool isViableMirror(LLFace* face) const; + +    bool isMirrorPass() const { return mRenderingMirror; } + +    LLPlane currentMirrorClip() const { return mCurrentClipPlane; }  private:      friend class LLPipeline; @@ -94,6 +100,8 @@ private:      // vertex buffer for pushing verts to filter shaders      LLPointer<LLVertexBuffer> mVertexBuffer; +    LLPlane mCurrentClipPlane; +      // update the specified face of the specified probe      void updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip); @@ -124,8 +132,11 @@ private:      // if true, reset all probe render state on the next update (for teleports and sky changes)      bool mReset = false; + +    bool mRenderingMirror = false;      std::set<LLVOVolume*>               mHeroVOList;      LLVOVolume*                         mNearestHero; +    LLFace*                             mCurrentFace;  }; diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index 06624e8fea..5fc9851709 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -49,7 +49,7 @@ LLReflectionMap::~LLReflectionMap()      }  } -void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 near_clip) +void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 near_clip, bool useClipPlane, LLPlane clipPlane)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;      mLastUpdateTime = gFrameTimeSeconds; @@ -66,7 +66,7 @@ void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 n      F32 clip = (near_clip > 0) ? near_clip : getNearClip(); -    gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, clip, getIsDynamic() || force_dynamic); +    gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, clip, getIsDynamic() || force_dynamic, useClipPlane, clipPlane);  }  void LLReflectionMap::autoAdjustOrigin() diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h index e97b28c855..9e888f20d0 100644 --- a/indra/newview/llreflectionmap.h +++ b/indra/newview/llreflectionmap.h @@ -52,7 +52,7 @@ public:      // update this environment map      // resolution - size of cube map to generate -    void update(U32 resolution, U32 face, bool force_dynamic = false, F32 near_clip = -1.f); +    void update(U32 resolution, U32 face, bool force_dynamic = false, F32 near_clip = -1.f, bool useClipPlane = false, LLPlane clipPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1)));      // for volume partition probes, try to place this probe in the best spot      void autoAdjustOrigin(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 04ca62e0ec..a1e7d69ae4 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1063,7 +1063,7 @@ void display_cube_face()      LLSpatialGroup::sNoDelete = TRUE;      S32 occlusion = LLPipeline::sUseOcclusion; -    LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots +    LLPipeline::sUseOcclusion = 1; // occlusion data is from main camera point of view, don't read or write it during cube snapshots      //gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data      static LLCullResult result; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ba2b6e1c7c..e0ec8eec25 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5304,7 +5304,7 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_  void display_cube_face(); -BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render) +BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render, bool useCustomClipPlane, LLPlane clipPlane)  {      // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot      LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; @@ -5335,6 +5335,14 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea      camera->setOrigin(origin);      camera->setNear(near_clip); +	LLPlane previousClipPlane; + +	if (useCustomClipPlane) +	{ +        previousClipPlane = camera->getUserClipPlane(); +        camera->setUserClipPlane(clipPlane); +	} +      glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);      U32 dynamic_render_types[] = { @@ -5441,6 +5449,11 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea      gPipeline.resetDrawOrders();      mWorldViewRectRaw = window_rect; + +	if (useCustomClipPlane) +	{ +        camera->setUserClipPlane(previousClipPlane); +	}      // restore original view/camera/avatar settings settings      *camera = saved_camera; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 6e8a5b2f4e..4da6a1360f 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -374,7 +374,8 @@ public:      // index - cube index in the array to use (cube index, not face-layer)      // face - which cube face to update      // near_clip - near clip setting to use -    BOOL cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars); +    BOOL cubeSnapshot(const LLVector3 &origin, LLCubeMapArray *cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars, +                      bool customCullingPlane = false, LLPlane cullingPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1)));      // special implementation of simpleSnapshot for reflection maps diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index 5ad85458e9..8dd2aba32a 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -e3bd0529a647d938ab6d48f26d21dd52c07ebc6e
\ No newline at end of file +e11941c09b42eb7cc9c56dae08afc03cbf1a22d8
\ No newline at end of file | 
