|
@@ -16071,7 +16071,7 @@ function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
|
|
|
* @author Mugen87 / https://github.com/Mugen87
|
|
|
*/
|
|
|
|
|
|
-function WebGLInfo() {
|
|
|
+function WebGLInfo( gl ) {
|
|
|
|
|
|
var memory = {
|
|
|
geometries: 0,
|
|
@@ -19875,7 +19875,7 @@ function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
|
|
|
* @author mrdoob / http://mrdoob.com/
|
|
|
*/
|
|
|
|
|
|
-function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
+function WebGLState( gl, extensions, capabilities ) {
|
|
|
|
|
|
var isWebGL2 = capabilities.isWebGL2;
|
|
|
|
|
@@ -20195,8 +20195,6 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
var enabledCapabilities = {};
|
|
|
|
|
|
- var compressedTextureFormats = null;
|
|
|
-
|
|
|
var currentProgram = null;
|
|
|
|
|
|
var currentBlendingEnabled = null;
|
|
@@ -20356,33 +20354,6 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function getCompressedTextureFormats() {
|
|
|
-
|
|
|
- if ( compressedTextureFormats === null ) {
|
|
|
-
|
|
|
- compressedTextureFormats = [];
|
|
|
-
|
|
|
- if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
|
|
|
- extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
|
|
|
- extensions.get( 'WEBGL_compressed_texture_etc1' ) ||
|
|
|
- extensions.get( 'WEBGL_compressed_texture_astc' ) ) {
|
|
|
-
|
|
|
- var formats = gl.getParameter( 34467 );
|
|
|
-
|
|
|
- for ( var i = 0; i < formats.length; i ++ ) {
|
|
|
-
|
|
|
- compressedTextureFormats.push( formats[ i ] );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return compressedTextureFormats;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
function useProgram( program ) {
|
|
|
|
|
|
if ( currentProgram !== program ) {
|
|
@@ -20399,6 +20370,28 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ var equationToGL = {
|
|
|
+ [ AddEquation ]: 32774,
|
|
|
+ [ SubtractEquation ]: 32778,
|
|
|
+ [ ReverseSubtractEquation ]: 32779,
|
|
|
+ [ MinEquation ]: isWebGL2 ? 32775 : extensions.get( 'EXT_blend_minmax' ).MIN_EXT,
|
|
|
+ [ MaxEquation ]: isWebGL2 ? 32776 : extensions.get( 'EXT_blend_minmax' ).MAX_EXT
|
|
|
+ };
|
|
|
+
|
|
|
+ var factorToGL = {
|
|
|
+ [ ZeroFactor ]: 0,
|
|
|
+ [ OneFactor ]: 1,
|
|
|
+ [ SrcColorFactor ]: 768,
|
|
|
+ [ SrcAlphaFactor ]: 770,
|
|
|
+ [ SrcAlphaSaturateFactor ]: 776,
|
|
|
+ [ DstColorFactor ]: 774,
|
|
|
+ [ DstAlphaFactor ]: 772,
|
|
|
+ [ OneMinusSrcColorFactor ]: 769,
|
|
|
+ [ OneMinusSrcAlphaFactor ]: 771,
|
|
|
+ [ OneMinusDstColorFactor ]: 775,
|
|
|
+ [ OneMinusDstAlphaFactor ]: 773
|
|
|
+ };
|
|
|
+
|
|
|
function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
|
|
|
|
|
|
if ( blending === NoBlending ) {
|
|
@@ -20510,7 +20503,7 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
|
|
|
|
|
|
- gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );
|
|
|
+ gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
|
|
|
|
|
|
currentBlendEquation = blendEquation;
|
|
|
currentBlendEquationAlpha = blendEquationAlpha;
|
|
@@ -20519,7 +20512,7 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
|
|
|
|
|
|
- gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );
|
|
|
+ gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
|
|
|
|
|
|
currentBlendSrc = blendSrc;
|
|
|
currentBlendDst = blendDst;
|
|
@@ -20813,8 +20806,6 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
|
|
|
enabledCapabilities = {};
|
|
|
|
|
|
- compressedTextureFormats = null;
|
|
|
-
|
|
|
currentTextureSlot = null;
|
|
|
currentBoundTextures = {};
|
|
|
|
|
@@ -20845,7 +20836,6 @@ function WebGLState( gl, extensions, utils, capabilities ) {
|
|
|
disableUnusedAttributes: disableUnusedAttributes,
|
|
|
enable: enable,
|
|
|
disable: disable,
|
|
|
- getCompressedTextureFormats: getCompressedTextureFormats,
|
|
|
|
|
|
useProgram: useProgram,
|
|
|
|
|
@@ -21309,7 +21299,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
|
|
|
|
|
|
if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
|
|
|
|
|
|
- if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
|
|
|
+ if ( glFormat !== null ) {
|
|
|
|
|
|
state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
|
|
@@ -21397,23 +21387,37 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
|
|
|
|
|
|
}
|
|
|
|
|
|
- function setTextureParameters( textureType, texture, supportsMips ) {
|
|
|
+ var wrappingToGL = {
|
|
|
+ [ RepeatWrapping ]: 10497,
|
|
|
+ [ ClampToEdgeWrapping ]: 33071,
|
|
|
+ [ MirroredRepeatWrapping ]: 33648
|
|
|
+ };
|
|
|
|
|
|
- var extension;
|
|
|
+ var filterToGL = {
|
|
|
+ [ NearestFilter ]: 9728,
|
|
|
+ [ NearestMipmapNearestFilter ]: 9984,
|
|
|
+ [ NearestMipmapLinearFilter ]: 9986,
|
|
|
+
|
|
|
+ [ LinearFilter ]: 9729,
|
|
|
+ [ LinearMipmapNearestFilter ]: 9985,
|
|
|
+ [ LinearMipmapLinearFilter ]: 9987
|
|
|
+ };
|
|
|
+
|
|
|
+ function setTextureParameters( textureType, texture, supportsMips ) {
|
|
|
|
|
|
if ( supportsMips ) {
|
|
|
|
|
|
- _gl.texParameteri( textureType, 10242, utils.convert( texture.wrapS ) );
|
|
|
- _gl.texParameteri( textureType, 10243, utils.convert( texture.wrapT ) );
|
|
|
+ _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
|
|
|
+ _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
|
|
|
|
|
|
if ( textureType === 32879 || textureType === 35866 ) {
|
|
|
|
|
|
- _gl.texParameteri( textureType, 32882, utils.convert( texture.wrapR ) );
|
|
|
+ _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- _gl.texParameteri( textureType, 10240, utils.convert( texture.magFilter ) );
|
|
|
- _gl.texParameteri( textureType, 10241, utils.convert( texture.minFilter ) );
|
|
|
+ _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
|
|
|
+ _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -21443,7 +21447,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
|
|
|
|
|
|
}
|
|
|
|
|
|
- extension = extensions.get( 'EXT_texture_filter_anisotropic' );
|
|
|
+ var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
|
|
|
|
|
|
if ( extension ) {
|
|
|
|
|
@@ -21594,7 +21598,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
|
|
|
|
|
|
if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
|
|
|
|
|
|
- if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
|
|
|
+ if ( glFormat !== null ) {
|
|
|
|
|
|
state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
|
|
|
|
|
@@ -22147,18 +22151,6 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
|
|
|
var extension;
|
|
|
|
|
|
- if ( p === RepeatWrapping ) return 10497;
|
|
|
- if ( p === ClampToEdgeWrapping ) return 33071;
|
|
|
- if ( p === MirroredRepeatWrapping ) return 33648;
|
|
|
-
|
|
|
- if ( p === NearestFilter ) return 9728;
|
|
|
- if ( p === NearestMipmapNearestFilter ) return 9984;
|
|
|
- if ( p === NearestMipmapLinearFilter ) return 9986;
|
|
|
-
|
|
|
- if ( p === LinearFilter ) return 9729;
|
|
|
- if ( p === LinearMipmapNearestFilter ) return 9985;
|
|
|
- if ( p === LinearMipmapLinearFilter ) return 9987;
|
|
|
-
|
|
|
if ( p === UnsignedByteType ) return 5121;
|
|
|
if ( p === UnsignedShort4444Type ) return 32819;
|
|
|
if ( p === UnsignedShort5551Type ) return 32820;
|
|
@@ -22177,7 +22169,15 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
|
|
|
extension = extensions.get( 'OES_texture_half_float' );
|
|
|
|
|
|
- if ( extension !== null ) return extension.HALF_FLOAT_OES;
|
|
|
+ if ( extension !== null ) {
|
|
|
+
|
|
|
+ return extension.HALF_FLOAT_OES;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -22190,23 +22190,6 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
if ( p === DepthStencilFormat ) return 34041;
|
|
|
if ( p === RedFormat ) return 6403;
|
|
|
|
|
|
- if ( p === AddEquation ) return 32774;
|
|
|
- if ( p === SubtractEquation ) return 32778;
|
|
|
- if ( p === ReverseSubtractEquation ) return 32779;
|
|
|
-
|
|
|
- if ( p === ZeroFactor ) return 0;
|
|
|
- if ( p === OneFactor ) return 1;
|
|
|
- if ( p === SrcColorFactor ) return 768;
|
|
|
- if ( p === OneMinusSrcColorFactor ) return 769;
|
|
|
- if ( p === SrcAlphaFactor ) return 770;
|
|
|
- if ( p === OneMinusSrcAlphaFactor ) return 771;
|
|
|
- if ( p === DstAlphaFactor ) return 772;
|
|
|
- if ( p === OneMinusDstAlphaFactor ) return 773;
|
|
|
-
|
|
|
- if ( p === DstColorFactor ) return 774;
|
|
|
- if ( p === OneMinusDstColorFactor ) return 775;
|
|
|
- if ( p === SrcAlphaSaturateFactor ) return 776;
|
|
|
-
|
|
|
if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
|
|
|
p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
|
|
|
|
|
@@ -22219,6 +22202,10 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
|
if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
|
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -22235,6 +22222,10 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
|
|
|
if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
|
|
|
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -22243,7 +22234,15 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
|
|
|
extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
|
|
|
|
|
|
- if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
|
|
|
+ if ( extension !== null ) {
|
|
|
+
|
|
|
+ return extension.COMPRESSED_RGB_ETC1_WEBGL;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -22257,27 +22256,13 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
|
|
|
if ( extension !== null ) {
|
|
|
|
|
|
- return p;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( p === MinEquation || p === MaxEquation ) {
|
|
|
-
|
|
|
- if ( isWebGL2 ) {
|
|
|
-
|
|
|
- if ( p === MinEquation ) return 32775;
|
|
|
- if ( p === MaxEquation ) return 32776;
|
|
|
+ // TODO Complete?
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- extension = extensions.get( 'EXT_blend_minmax' );
|
|
|
+ return p;
|
|
|
|
|
|
- if ( extension !== null ) {
|
|
|
+ } else {
|
|
|
|
|
|
- if ( p === MinEquation ) return extension.MIN_EXT;
|
|
|
- if ( p === MaxEquation ) return extension.MAX_EXT;
|
|
|
+ return null;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -22289,11 +22274,17 @@ function WebGLUtils( gl, extensions, capabilities ) {
|
|
|
|
|
|
extension = extensions.get( 'WEBGL_depth_texture' );
|
|
|
|
|
|
- if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
|
|
|
+ if ( extension !== null ) {
|
|
|
|
|
|
- }
|
|
|
+ return extension.UNSIGNED_INT_24_8_WEBGL;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- return 0;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -23652,11 +23643,11 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
utils = new WebGLUtils( _gl, extensions, capabilities );
|
|
|
|
|
|
- state = new WebGLState( _gl, extensions, utils, capabilities );
|
|
|
+ state = new WebGLState( _gl, extensions, capabilities );
|
|
|
state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
|
|
|
state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
|
|
|
|
|
|
- info = new WebGLInfo();
|
|
|
+ info = new WebGLInfo( _gl );
|
|
|
properties = new WebGLProperties();
|
|
|
textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
|
|
|
attributes = new WebGLAttributes( _gl );
|
|
@@ -32444,6 +32435,7 @@ CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
|
|
|
|
|
|
|
|
|
var Geometries = /*#__PURE__*/Object.freeze({
|
|
|
+ __proto__: null,
|
|
|
WireframeGeometry: WireframeGeometry,
|
|
|
ParametricGeometry: ParametricGeometry,
|
|
|
ParametricBufferGeometry: ParametricBufferGeometry,
|
|
@@ -33357,6 +33349,7 @@ LineDashedMaterial.prototype.copy = function ( source ) {
|
|
|
|
|
|
|
|
|
var Materials = /*#__PURE__*/Object.freeze({
|
|
|
+ __proto__: null,
|
|
|
ShadowMaterial: ShadowMaterial,
|
|
|
SpriteMaterial: SpriteMaterial,
|
|
|
RawShaderMaterial: RawShaderMaterial,
|
|
@@ -37664,6 +37657,7 @@ SplineCurve.prototype.fromJSON = function ( json ) {
|
|
|
|
|
|
|
|
|
var Curves = /*#__PURE__*/Object.freeze({
|
|
|
+ __proto__: null,
|
|
|
ArcCurve: ArcCurve,
|
|
|
CatmullRomCurve3: CatmullRomCurve3,
|
|
|
CubicBezierCurve: CubicBezierCurve,
|
|
@@ -41800,7 +41794,6 @@ function Audio( listener ) {
|
|
|
this.loop = false;
|
|
|
this.loopStart = 0;
|
|
|
this.loopEnd = 0;
|
|
|
- this.startTime = 0;
|
|
|
this.offset = 0;
|
|
|
this.duration = undefined;
|
|
|
this.playbackRate = 1;
|
|
@@ -41808,6 +41801,9 @@ function Audio( listener ) {
|
|
|
this.hasPlaybackControl = true;
|
|
|
this.sourceType = 'empty';
|
|
|
|
|
|
+ this._startedAt = 0;
|
|
|
+ this._pausedAt = 0;
|
|
|
+
|
|
|
this.filters = [];
|
|
|
|
|
|
}
|
|
@@ -41866,7 +41862,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
|
|
|
|
|
},
|
|
|
|
|
|
- play: function () {
|
|
|
+ play: function ( delay ) {
|
|
|
+
|
|
|
+ if ( delay === undefined ) delay = 0;
|
|
|
|
|
|
if ( this.isPlaying === true ) {
|
|
|
|
|
@@ -41882,15 +41880,15 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
|
|
|
|
|
}
|
|
|
|
|
|
- var source = this.context.createBufferSource();
|
|
|
+ this._startedAt = this.context.currentTime + delay;
|
|
|
|
|
|
+ var source = this.context.createBufferSource();
|
|
|
source.buffer = this.buffer;
|
|
|
source.loop = this.loop;
|
|
|
source.loopStart = this.loopStart;
|
|
|
source.loopEnd = this.loopEnd;
|
|
|
source.onended = this.onEnded.bind( this );
|
|
|
- this.startTime = this.context.currentTime;
|
|
|
- source.start( this.startTime, this.offset, this.duration );
|
|
|
+ source.start( this._startedAt, this._pausedAt + this.offset, this.duration );
|
|
|
|
|
|
this.isPlaying = true;
|
|
|
|
|
@@ -41914,9 +41912,11 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
|
|
|
|
|
if ( this.isPlaying === true ) {
|
|
|
|
|
|
+ this._pausedAt = ( this.context.currentTime - this._startedAt ) * this.playbackRate;
|
|
|
+
|
|
|
this.source.stop();
|
|
|
this.source.onended = null;
|
|
|
- this.offset += ( this.context.currentTime - this.startTime ) * this.playbackRate;
|
|
|
+
|
|
|
this.isPlaying = false;
|
|
|
|
|
|
}
|
|
@@ -41934,9 +41934,10 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ this._pausedAt = 0;
|
|
|
+
|
|
|
this.source.stop();
|
|
|
this.source.onended = null;
|
|
|
- this.offset = 0;
|
|
|
this.isPlaying = false;
|
|
|
|
|
|
return this;
|
|
@@ -49352,19 +49353,32 @@ Object.defineProperties( WebVRManager.prototype, {
|
|
|
|
|
|
//
|
|
|
|
|
|
-Audio.prototype.load = function ( file ) {
|
|
|
+Object.defineProperties( Audio.prototype, {
|
|
|
|
|
|
- console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
|
|
|
- var scope = this;
|
|
|
- var audioLoader = new AudioLoader();
|
|
|
- audioLoader.load( file, function ( buffer ) {
|
|
|
+ load: {
|
|
|
+ value: function ( file ) {
|
|
|
|
|
|
- scope.setBuffer( buffer );
|
|
|
+ console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
|
|
|
+ var scope = this;
|
|
|
+ var audioLoader = new AudioLoader();
|
|
|
+ audioLoader.load( file, function ( buffer ) {
|
|
|
|
|
|
- } );
|
|
|
- return this;
|
|
|
+ scope.setBuffer( buffer );
|
|
|
|
|
|
-};
|
|
|
+ } );
|
|
|
+ return this;
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ startTime: {
|
|
|
+ set: function () {
|
|
|
+
|
|
|
+ console.warn( 'THREE.Audio: .startTime is now .play( delay ).' );
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+} );
|
|
|
|
|
|
AudioAnalyser.prototype.getData = function () {
|
|
|
|