--Normal VarChar versionCREATE FUNCTION dbo.fn_DelimitToTable_2D ( @String VarChar(8000), @Delimiter1 VarChar(1), @Delimiter2 VarChar(1) ) RETURNS TABLEASRETURN ( SELECT Counter2nd.Value AS Value FROM ( SELECT SUBSTRING(@String+@Delimiter1, PK_CountID, CHARINDEX(@Delimiter1, @String+@Delimiter1, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter1) AND SubString(@Delimiter1 + @String + @Delimiter1, PK_CountID, 1)=@Delimiter1 ) AS Counter1st CROSS APPLY ( SELECT SUBSTRING(Counter1st.Value+@Delimiter2, PK_CountID, CHARINDEX(@Delimiter2, Counter1st.Value+@Delimiter2, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(Counter1st.Value)+LEN(@Delimiter2) AND SubString(@Delimiter2 + Counter1st.Value + @Delimiter2, PK_CountID, 1)=@Delimiter2 ) AS Counter2nd )GO--Integer casting version when output is used to join to integer PK/FK columns.CREATE FUNCTION dbo.fn_DelimitToIntTable_2D ( @String VarChar(8000), @Delimiter1 VarChar(1), @Delimiter2 VarChar(1) ) RETURNS TABLEASRETURN ( SELECT CONVERT(int, Counter2nd.Value) AS PK_IntID FROM ( SELECT SUBSTRING(@String+@Delimiter1, PK_CountID, CHARINDEX(@Delimiter1, @String+@Delimiter1, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter1) AND SubString(@Delimiter1 + @String + @Delimiter1, PK_CountID, 1)=@Delimiter1 ) AS Counter1st CROSS APPLY ( SELECT SUBSTRING(Counter1st.Value+@Delimiter2, PK_CountID, CHARINDEX(@Delimiter2, Counter1st.Value+@Delimiter2, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(Counter1st.Value)+LEN(@Delimiter2) AND SubString(@Delimiter2 + Counter1st.Value + @Delimiter2, PK_CountID, 1)=@Delimiter2 ) AS Counter2nd )GO
--Normal VarChar versionCREATE FUNCTION dbo.fn_DelimitToArray_2D ( @String VarChar(8000), @Delimiter1 VarChar(1), @Delimiter2 VarChar(1) ) RETURNS TABLEASRETURN ( SELECT Counter1st.Pos AS RowPos, Counter2nd.Pos AS ColPos, Counter2nd.Value AS Value FROM ( SELECT PK_CountID - LEN(REPLACE(LEFT(@String, PK_CountID-1), @Delimiter1, '')) AS Pos, SUBSTRING(@String+@Delimiter1, PK_CountID, CHARINDEX(@Delimiter1, @String+@Delimiter1, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter1) AND SubString(@Delimiter1 + @String + @Delimiter1, PK_CountID, 1)=@Delimiter1 ) AS Counter1st CROSS APPLY ( SELECT PK_CountID - LEN(REPLACE(LEFT(Counter1st.Value, PK_CountID-1), @Delimiter2, '')) AS Pos, SUBSTRING(Counter1st.Value+@Delimiter2, PK_CountID, CHARINDEX(@Delimiter2, Counter1st.Value+@Delimiter2, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(Counter1st.Value)+LEN(@Delimiter2) AND SubString(@Delimiter2 + Counter1st.Value + @Delimiter2, PK_CountID, 1)=@Delimiter2 ) AS Counter2nd )GO--Integer casting version when output is used to join to integer PK/FK columns.CREATE FUNCTION dbo.fn_DelimitToIntArray_2D ( @String VarChar(8000), @Delimiter1 VarChar(1), @Delimiter2 VarChar(1) ) RETURNS TABLEASRETURN ( SELECT Counter1st.Pos AS RowPos, Counter2nd.Pos AS ColPos, CONVERT(int, Counter2nd.value) AS PK_IntID FROM ( SELECT PK_CountID - LEN(REPLACE(LEFT(@String, PK_CountID-1), @Delimiter1, '')) AS Pos, SUBSTRING(@String+@Delimiter1, PK_CountID, CHARINDEX(@Delimiter1, @String+@Delimiter1, PK_CountID)-PK_CountID) AS value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter1) AND SubString(@Delimiter1 + @String + @Delimiter1, PK_CountID, 1)=@Delimiter1 ) AS Counter1st CROSS APPLY ( SELECT PK_CountID - LEN(REPLACE(LEFT(Counter1st.value, PK_CountID-1), @Delimiter2, '')) AS Pos, SUBSTRING(Counter1st.value+@Delimiter2, PK_CountID, CHARINDEX(@Delimiter2, Counter1st.Value+@Delimiter2, PK_CountID)-PK_CountID) AS value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(Counter1st.value)+LEN(@Delimiter2) AND SubString(@Delimiter2 + Counter1st.value + @Delimiter2, PK_CountID, 1)=@Delimiter2 ) AS Counter2nd )GO
--Normal VarChar versionCREATE FUNCTION dbo.fn_DelimitToTable ( @String VarChar(8000), @Delimiter VarChar(1) ) RETURNS TABLEASRETURN ( SELECT SUBSTRING(@String+@Delimiter, PK_CountID, CHARINDEX(@Delimiter, @String+@Delimiter, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter) AND SubString(@Delimiter + @String + @Delimiter, PK_CountID, 1)=@Delimiter )GO--Integer casting version when output is used to join to integer PK/FK columns.CREATE FUNCTION dbo.fn_DelimitToIntTable ( @String VarChar(8000), @Delimiter VarChar(1) ) RETURNS TABLEASRETURN ( SELECT CONVERT(int, SUBSTRING(@String+@Delimiter, PK_CountID, CHARINDEX(@Delimiter, @String+@Delimiter, PK_CountID)-PK_CountID)) AS PK_IntID FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter) AND SubString(@Delimiter + @String + @Delimiter, PK_CountID, 1)=@Delimiter )GO
--Normal VarChar versionCREATE FUNCTION dbo.fn_DelimitToArray ( @String VarChar(8000), @Delimiter VarChar(1) ) RETURNS TABLEASRETURN ( SELECT PK_CountID - LEN(REPLACE(LEFT(@String, PK_CountID-1), @Delimiter, '')) AS Pos, SUBSTRING(@String+@Delimiter, PK_CountID, CHARINDEX(@Delimiter, @String+@Delimiter, PK_CountID)-PK_CountID) AS Value FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter) AND SubString(@Delimiter + @String + @Delimiter, PK_CountID, 1)=@Delimiter )GO--Integer casting version when output is used to join to integer PK/FK columns.CREATE FUNCTION dbo.fn_DelimitToIntArray ( @String VarChar(8000), @Delimiter VarChar(1) ) RETURNS TABLEASRETURN ( SELECT PK_CountID - LEN(REPLACE(LEFT(@String, PK_CountID-1), @Delimiter, '')) AS Pos, CONVERT(int, SUBSTRING(@String+@Delimiter, PK_CountID, CHARINDEX(@Delimiter, @String+@Delimiter, PK_CountID)-PK_CountID)) AS PK_IntID FROM dbo.counter WHERE PK_CountID >0 AND PK_CountID<LEN(@String)+LEN(@Delimiter) AND SubString(@Delimiter + @String + @Delimiter, PK_CountID, 1)=@Delimiter )
--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=--DDL--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SET NOCOUNT ON--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=IF EXISTS (SELECT * FROM sys.tables WHERE name='CounterSmall' AND schema_id=1) DROP TABLE dbo.CounterSmallIF EXISTS (SELECT * FROM sys.tables WHERE name='Counter' AND schema_id=1) DROP TABLE dbo.Counter--IF EXISTS (SELECT * FROM sys.tables WHERE name='CounterBig' AND schema_id=1) DROP TABLE dbo.CounterBigGO--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=CREATE TABLE dbo.CounterSmall( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__CounterSmall__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)CREATE TABLE dbo.Counter( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__Counter__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)/*CREATE TABLE dbo.CounterBig( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__CounterBig__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)*/GO--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=--Counter SQL 2005--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=DECLARE @Power intDECLARE @HeapRowsPerPage intDECLARE @ClusteredRowsPerPage intDECLARE @MaxRows intDECLARE @MaxPositive intDECLARE @MaxNegative intDECLARE @OldMaxNegative intSET @ClusteredRowsPerPage=622SET @HeapRowsPerPage=299SET @MaxPositive=621--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SET @MaxRows=@ClusteredRowsPerPageSET @MaxPositive=@MaxPositive-1SET @OldMaxNegative=0SET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativeSET @Power=1PRINT 'CounterSmall: ' + CONVERT(VarChar(10), @MaxNegative*-1+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 1-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterSmallBEGIN TRANSACTION/*INSERT INTO CounterSmall WITH (TABLOCKX) (PK_CountID)SELECT PK_CountID-@MaxNegativeFROM dbo.fn_Numbers(@MaxRows)*/INSERT INTO CounterSmall WITH (TABLOCKX) (PK_CountID) VALUES (1-@MaxNegative)WHILE @Power<=@MaxRowsBEGIN INSERT INTO CounterSmall WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM CounterSmall WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITALTER INDEX ALL ON CounterSmall REBUILD WITH (FillFactor=100)UPDATE STATISTICS CounterSmall WITH FULLSCAN--SELECT * FROM CounterSmall--*=*=*=*=*=*=*=*=*=*=SET @Power=@ClusteredRowsPerPageSET @MaxRows=@Power*@ClusteredRowsPerPageSET @OldMaxNegative=@MaxNegative+@OldMaxNegativeSET @MaxPositive=(@MaxPositive+1)*@ClusteredRowsPerPageSET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativePRINT 'Counter: ' + CONVERT(VarChar(10), @MaxNegative*-1-@OldMaxNegative+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 2-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterBEGIN TRANSACTIONINSERT INTO Counter WITH (TABLOCKX) (PK_CountID)SELECT PK_CountID-@MaxNegative FROM CounterSmallWHILE @Power<=@MaxRowsBEGIN INSERT INTO Counter WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM Counter WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITALTER INDEX ALL ON Counter REBUILD WITH (FillFactor=100)UPDATE STATISTICS Counter WITH FULLSCAN--SELECT * FROM Counter ORDER BY PK_CountID--*=*=*=*=*=*=*=*=*=*=/*SET @Power=@ClusteredRowsPerPage*@ClusteredRowsPerPageSET @MaxRows=@Power*(@ClusteredRowsPerPage-2)SET @OldMaxNegative=@MaxNegative+@OldMaxNegativeSET @MaxPositive=(@MaxPositive+1)*@ClusteredRowsPerPageSET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativePRINT 'CounterBig: ' + CONVERT(VarChar(10), @MaxNegative*-1-@OldMaxNegative+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 3-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterBigUPDATE STATISTICS CounterBig WITH FULLSCAN, NORECOMPUTEBEGIN TRANSACTIONINSERT INTO CounterBig WITH (TABLOCKX) (PK_CountID)SELECT PK_CountID-@MaxNegative FROM CounterWHILE @Power<=@MaxRowsBEGIN INSERT INTO CounterBig WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM CounterBig WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITALTER INDEX ALL ON CounterBig REBUILD WITH (FillFactor=100)UPDATE STATISTICS CounterBig WITH FULLSCAN--SELECT * FROM CounterBig ORDER BY PK_CountID*/--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SELECT * FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID('CounterSmall'), NULL, NULL, 'DETAILED')SELECT * FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID('Counter'), NULL, NULL, 'DETAILED')--SELECT * FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID('CounterBig'), NULL, NULL, 'DETAILED')--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=GO
--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=--DDL--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SET NOCOUNT ON--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=IF EXISTS (SELECT * FROM sysobjects WHERE name='CounterSmall' AND uid=1 AND xtype='u') DROP TABLE dbo.CounterSmallIF EXISTS (SELECT * FROM sysobjects WHERE name='Counter' AND uid=1 AND xtype='u') DROP TABLE dbo.Counter--IF EXISTS (SELECT * FROM sysobjects WHERE name='CounterBig' AND uid=1 AND xtype='u') DROP TABLE dbo.CounterBig--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=CREATE TABLE dbo.CounterSmall( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__CounterSmall__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)CREATE TABLE dbo.Counter( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__Counter__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)/*CREATE TABLE dbo.CounterBig( PK_CountID int NOT NULL, CONSTRAINT PK_C_IX__CounterBig__CountID PRIMARY KEY CLUSTERED (PK_CountID) WITH FILLFACTOR=100)*/--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=--Counter SQL 2000--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=DECLARE @Power intDECLARE @HeapRowsPerPage intDECLARE @ClusteredRowsPerPage intDECLARE @MaxRows intDECLARE @MaxPositive intDECLARE @MaxNegative intDECLARE @OldMaxNegative intSET @ClusteredRowsPerPage=620SET @HeapRowsPerPage=299SET @MaxPositive=619--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SET @MaxRows=@ClusteredRowsPerPageSET @MaxPositive=@MaxPositive-1SET @OldMaxNegative=0SET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativeSET @Power=1PRINT 'CounterSmall: ' + CONVERT(VarChar(10), @MaxNegative*-1+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 1-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterSmallBEGIN TRANSACTIONINSERT INTO CounterSmall WITH (TABLOCKX) (PK_CountID) VALUES (1-@MaxNegative)WHILE @Power<=@MaxRowsBEGIN INSERT INTO CounterSmall WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM CounterSmall WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITDBCC DBREINDEX (CounterSmall,'PK_C_IX__CounterSmall__CountID',100)UPDATE STATISTICS CounterSmall WITH FULLSCAN--SELECT * FROM CounterSmall--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=SET @Power=@ClusteredRowsPerPageSET @MaxRows=@Power*@ClusteredRowsPerPageSET @OldMaxNegative=@MaxNegative+@OldMaxNegativeSET @MaxPositive=(@MaxPositive+1)*@ClusteredRowsPerPageSET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativePRINT 'Counter: ' + CONVERT(VarChar(10), @MaxNegative*-1-@OldMaxNegative+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 2-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterBEGIN TRANSACTIONINSERT INTO Counter WITH (TABLOCKX) (PK_CountID)SELECT PK_CountID-@MaxNegative FROM CounterSmallWHILE @Power<=@MaxRowsBEGIN INSERT INTO Counter WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM Counter WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITDBCC DBREINDEX (Counter,'PK_C_IX__Counter__CountID',100)UPDATE STATISTICS Counter WITH FULLSCAN--SELECT * FROM Counter ORDER BY PK_CountID--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=/*SET @Power=@ClusteredRowsPerPage*@ClusteredRowsPerPageSET @MaxRows=@Power*(@ClusteredRowsPerPage-2)SET @OldMaxNegative=@MaxNegative+@OldMaxNegativeSET @MaxPositive=(@MaxPositive+1)*@ClusteredRowsPerPageSET @MaxNegative=@MaxRows-@MaxPositive-@OldMaxNegativePRINT 'CounterBig: ' + CONVERT(VarChar(10), @MaxNegative*-1-@OldMaxNegative+1) + ' to ' + CONVERT(VarChar(10), @MaxPositive) + ' - ' + CONVERT(VarChar(10), @MaxRows) + ' Rows - 3-Level Clustered Index'--SELECT @MaxNegative AS MaxNegative, @MaxPositive AS MaxPositive, @OldMaxNegative AS OldMaxNegative, @Power AS Power, @MaxRows AS MaxRowsTRUNCATE TABLE CounterBigUPDATE STATISTICS CounterBig WITH FULLSCAN, NORECOMPUTEBEGIN TRANSACTIONINSERT INTO CounterBig WITH (TABLOCKX) (PK_CountID)SELECT PK_CountID-@MaxNegative FROM CounterWHILE @Power<=@MaxRowsBEGIN INSERT INTO CounterBig WITH (TABLOCKX) (PK_CountID) SELECT @Power+PK_CountID FROM CounterBig WHERE @Power+PK_CountID<=@MaxPositive SET @Power=@Power*2ENDCOMMITDBCC DBREINDEX (Counter,'PK_C_IX__CounterBig__CountID',100)UPDATE STATISTICS CounterBig WITH FULLSCAN--SELECT * FROM CounterBig ORDER BY PK_CountID*/--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=DBCC SHOWCONTIG (CounterSmall) WITH ALL_LEVELS, TABLERESULTSDBCC SHOWCONTIG (Counter) WITH ALL_LEVELS, TABLERESULTS--DBCC SHOWCONTIG (CounterBig) WITH ALL_LEVELS, TABLERESULTS--*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=