< Code />

Query Time datatype to locate shift by dotnetjunkie, Saturday, November 30, 2013.

I was recently working on a project for a manufacturing client where we were automating data collection on the plant floor. In order to categorize the data properly, we needed to be able to associate the data with several key aspects, such as process, shift and crew.

Because Shifts are time based, such as 6:30AM to 2:30PM, I decided to store the start and end times as TIME data types in SQL Server. Time datatypes essentially store only the time portion of a DateTime datatype. So 6:30AM would look like this: 06:30:00.000. What is nice is that because it is a Time datatype, you have access to all the DateTime functions in SQL Server.

So the scenario is that throughout the day, System Platform is running and monitoring production run change. Upon change, a stored procedure is fired off to go and generate an entry in a production parameter header table, with the production run number, shift, crew, process, timestamp, etc. The tricky part is determining what shift is the current shift based upon the current time and process. Because Time datatypes do not contain a date, we store the Day of Week along with each entry so that we can determine the shift from what day it is as well as the time and process. You might think, that sounds easy, just query and locate the start and end time where the current time falls between. Ahh, but there is a problem. What about shifts that start at night and span to the next day. The problem is, the start time is greater than the end time. For example, 22:30 to 06:30. So if the current time is between 22:30 and 00:00 or if the current time is between 00:00 and 06:30 we will have a hard time finding the correct shift.

What I have gone ahead and done is create a simplified shift table to demonstrate how to solve the problem. This is by no means an end to all solutions, this is simply how I solved it. My goal was to avoid using cursors. Let's go ahead and create a simple shift table.


CREATE TABLE #Shifts
(
	[ShiftID] [int] IDENTITY(1,1) NOT NULL,
	[Process] [nvarchar] (10) NOT NULL,
	[DayOfWeek] [nvarchar](20) NOT NULL,
	[ShiftName] [nvarchar] (10),
	[StartTime] [time](7) NOT NULL,
	[EndTime] [time](7) NOT NULL
)

-- Shifts for Process A
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 3', '22:30:00.000', '06:30:00.000')

-- Shifts for Process B
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 3', '22:30:00.000', '06:30:00.000')

In the actual production version, the setup is much more normalized, with process table, shift, crew, shift schedule, etc. However, for the purposes of this demo, we'll just use process and shift in a single table. In the SQL above, we create a shift table and insert some test data with a 7 day shift schedule for two processes.

Next we'll go ahead and create some local variables. Note. un-comment the @GetDate variable to test various times for shifts that span to the next day.


-- Declare Local Variables
DECLARE @StartDate DATETIME
DECLARE @GetDate DATETIME
DECLARE @DayOfWeekName NVARCHAR(20)
DECLARE @CurrentTime TIME
DECLARE @Process NVARCHAR(10)

-- Initialize GetDate
SET @GetDate = GetDate()
--SET @GetDate = '11/30/2013 23:23:32'
--SET @GetDate = '11/30/2013 02:23:32'

-- Set default process
SET @Process = 'Process B'

-- Initialize Day of Week
SET @DayOfWeekName = DATENAME(DW, @GetDate)

-- Initialize current time
SET @CurrentTime = CONVERT(TIME, @GetDate)

-- Set the Start Date
SET @StartDate = CAST(@GetDate AS DATE)

Next we'll build a query to determine if we are before midnight or after.


IF((SELECT TOP 1 
		T1.StartTime 
		FROM 
		(
			SELECT
				S.ShiftID, 
				S.StartTime, 
				S.EndTime
			FROM
				#Shifts S
			WHERE
				S.[Process] = @Process
		) AS T1 ORDER BY T1.StartTime) > @CurrentTime)
	BEGIN
		SET @StartDate = CAST(DATEADD(DAY, -1, @GetDate) AS DATE)
		SET @DayOfWeekName = DATENAME(DW, DATEADD(DAY, -1, @GetDate))
	END

The query above finds the first shift for a process by ordering by the start time. Wrapped in an if statement, the query checks to see if the first time is greater than the current time. If so, that means we are after midnight and before the first shift. In that case, we set the @StartDate and @DayOfWeekName to the day before. This is to setup the variables for the next query.

Now that we have determined the start date, we can issue a query to locate the appropriate shift. As mentioned above, Time datatypes do not have dates associated with them. So what we will do is transform the data in the Shift table to include a date along with the time. We accomplish this by using a nested select as the table for the query. The key is the CASE statement that builds the date based upon the end time being less than the start time.


SELECT	*
FROM (
		SELECT
			S.ShiftID,
			S.Process,
			S.[DayOfweek],
			@StartDate + S.StartTime AS StartTime, 
			CASE WHEN CAST(S.EndTime AS DATETIME) < CAST(S.StartTime AS DATETIME) THEN DATEADD(DAY, 1, @StartDate) + S.EndTime ELSE @StartDate + S.EndTime END AS EndTime
		FROM
			#Shifts S
		WHERE
			S.DayOfWeek = @DayOfWeekName AND S.Process = @Process
	) T1 WHERE T1.StartTime <= @GetDate AND T1.EndTime >= @GetDate

Lastly, we'll drop the table.


DROP TABLE #Shifts

Running the query as is, will take the current time and locate the correct shift. To test shifts after 10:30PM, comment out SET @GetDate = GetDate() and un-comment SET @GetDate = '11/30/2013 23:23:32'

Here is the full query. Hope this helps someone who has a similar task.




CREATE TABLE #Shifts
(
	[ShiftID] [int] IDENTITY(1,1) NOT NULL,
	[Process] [nvarchar] (10) NOT NULL,
	[DayOfWeek] [nvarchar](20) NOT NULL,
	[ShiftName] [nvarchar] (10),
	[StartTime] [time](7) NOT NULL,
	[EndTime] [time](7) NOT NULL
)

-- Shifts for Process A
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Sunday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Monday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Tuesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Wednesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Thursday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Friday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process A', 'Saturday', 'Shift 3', '22:30:00.000', '06:30:00.000')

-- Shifts for Process B
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Sunday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Monday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Tuesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Wednesday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Thursday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Friday', 'Shift 3', '22:30:00.000', '06:30:00.000')

INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 1', '06:30:00.000', '14:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 2', '14:30:00.000', '22:30:00.000')
INSERT INTO #Shifts ([Process], [DayOfWeek], ShiftName, StartTime, EndTime) VALUES('Process B', 'Saturday', 'Shift 3', '22:30:00.000', '06:30:00.000')


-- Declare Local Variables
DECLARE @StartDate DATETIME
DECLARE @GetDate DATETIME
DECLARE @DayOfWeekName NVARCHAR(20)
DECLARE @CurrentTime TIME
DECLARE @Process NVARCHAR(10)

-- Initialize GetDate
SET @GetDate = GetDate()
--SET @GetDate = '11/30/2013 23:23:32'
--SET @GetDate = '11/30/2013 02:23:32'

SET @Process = 'Process B'

-- Initialize Day of Week
SET @DayOfWeekName = DATENAME(DW, @GetDate)

-- Initialize current time
SET @CurrentTime = CONVERT(TIME, @GetDate)

-- Set the Start Date
SET @StartDate = CAST(@GetDate AS DATE)

IF((SELECT TOP 1 
		T1.StartTime 
		FROM 
		(
			SELECT
				S.ShiftID, 
				S.StartTime, 
				S.EndTime
			FROM
				#Shifts S
			WHERE
				S.[Process] = @Process
		) AS T1 ORDER BY T1.StartTime) > @CurrentTime)
	BEGIN
		SET @StartDate = CAST(DATEADD(DAY, -1, @GetDate) AS DATE)
		SET @DayOfWeekName = DATENAME(DW, DATEADD(DAY, -1, @GetDate))
	END

SELECT	*
FROM (
		SELECT
			S.ShiftID,
			S.Process,
			S.[DayOfweek],
			@StartDate + S.StartTime AS StartTime, 
			CASE WHEN CAST(S.EndTime AS DATETIME) < CAST(S.StartTime AS DATETIME) THEN DATEADD(DAY, 1, @StartDate) + S.EndTime ELSE @StartDate + S.EndTime END AS EndTime
		FROM
			#Shifts S
		WHERE
			S.DayOfWeek = @DayOfWeekName AND S.Process = @Process
	) T1 WHERE T1.StartTime <= @GetDate AND T1.EndTime >= @GetDate


DROP TABLE #Shifts

Comments

Be the first to comment!

Add Comment

Captcha