/*
* wiringPi:
* Arduino compatable (ish) Wiring library for the Raspberry Pi
* Copyright (c) 2012 Gordon Henderson
*
* Thanks to code samples from Gert Jan van Loo and the
* BCM2835 ARM Peripherals manual, however it's missing
* the clock section /grr/mutter/
***********************************************************************
* This file is part of wiringPi:
* https://p...content-available-to-author-only...n.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wiringPi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wiringPi. If not, see <http://w...content-available-to-author-only...u.org/licenses/>.
***********************************************************************
*/
// Revisions:
// 11 Jun 2012:
// Fixed some typos.
// Added c++ support for the .h file
// Added a new function to allow for using my "pin" numbers, or native
// GPIO pin numbers.
// Removed my busy-loop delay and replaced it with a call to delayMicroseconds
//
// 02 May 2012:
// Added in the 2 UART pins
// Change maxPins to numPins to more accurately reflect purpose
// Pad drive current fiddling
#undef DEBUG_PADS
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/mman.h>
#include "wiringPi.h"
#ifndef TRUE
#define TRUE (1==1)
#define FALSE (1==2)
#endif
// Port function select bits
#define FSEL_INPT 0b000
#define FSEL_OUTP 0b001
#define FSEL_ALT0 0b100
#define FSEL_ALT0 0b100
#define FSEL_ALT1 0b101
#define FSEL_ALT2 0b110
#define FSEL_ALT3 0b111
#define FSEL_ALT4 0b011
#define FSEL_ALT5 0b010
// Access from ARM Running Linux
// Take from Gerts code. Some of this is not in the manual
// that I can find )-:
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000)
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000)
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000)
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
// PWM
#define PWM_CONTROL 0
#define PWM_STATUS 1
#define PWM0_RANGE 4
#define PWM0_DATA 5
#define PWM1_RANGE 8
#define PWM1_DATA 9
#define PWMCLK_CNTL 40
#define PWMCLK_DIV 41
#define PWM1_MS_MODE 0x8000 // Run in MS mode
#define PWM1_USEFIFO 0x2000 // Data from FIFO
#define PWM1_REVPOLAR 0x1000 // Reverse polarity
#define PWM1_OFFSTATE 0x0800 // Ouput Off state
#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty
#define PWM1_SERIAL 0x0200 // Run in serial mode
#define PWM1_ENABLE 0x0100 // Channel Enable
#define PWM0_MS_MODE 0x0080 // Run in MS mode
#define PWM0_USEFIFO 0x0020 // Data from FIFO
#define PWM0_REVPOLAR 0x0010 // Reverse polarity
#define PWM0_OFFSTATE 0x0008 // Ouput Off state
#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty
#define PWM0_SERIAL 0x0002 // Run in serial mode
#define PWM0_ENABLE 0x0001 // Channel Enable
// Locals to hold pointers to the hardware
static volatile uint32_t * gpio ;
static volatile uint32_t * pwm ;
static volatile uint32_t * clk ;
// The BCM2835 has 54 GPIO pins.
// BCM2835 data sheet, Page 90 onwards.
// There are 6 control registers, each control the functions of a block
// of 10 pins.
// Each control register has 10 sets of 3 bits per GPIO pin:
//
// 000 = GPIO Pin X is an input
// 001 = GPIO Pin X is an output
// 100 = GPIO Pin X takes alternate function 0
// 101 = GPIO Pin X takes alternate function 1
// 110 = GPIO Pin X takes alternate function 2
// 111 = GPIO Pin X takes alternate function 3
// 011 = GPIO Pin X takes alternate function 4
// 010 = GPIO Pin X takes alternate function 5
//
// So the 3 bits for port X are:
// X / 10 + ((X % 10) * 3)
// mode
static int gpioPinMode ;
// Doing it the Arduino way with lookup tables...
// Yes, it's probably more innefficient than all the bit-twidling, but it
// does tend to make it all a bit clearer. At least to me!
// pinToGpio:
// Take a Wiring pin (0 through X) and re-map it to the BCM_GPIO pin
static int pinToGpio [ ] =
{
17 , 18 , 21 , 22 , 23 , 24 , 25 , 4 , // From the Original Wiki - GPIO 0 through 7
0 , 1 , // I2C - SDA0, SCL0
8 , 7 , // SPI - CE1, CE0
10 , 9 , 11 , // SPI - MOSI, MISO, SCLK
14 , 15 , // UART - Tx, Rx
} ;
// gpioToGPFSEL:
// Map a BCM_GPIO pin to it's control port. (GPFSEL 0-5)
static uint8_t gpioToGPFSEL [ ] =
{
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 ,
5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 ,
} ;
// gpioToShift
// Define the shift up for the 3 bits per pin in each GPFSEL port
static uint8_t gpioToShift [ ] =
{
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 ,
0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 ,
} ;
// gpioToGPSET:
// (Word) offset to the GPIO Set registers for each GPIO pin
static uint8_t gpioToGPSET [ ] =
{
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 ,
} ;
// gpioToGPCLR:
// (Word) offset to the GPIO Clear registers for each GPIO pin
static uint8_t gpioToGPCLR [ ] =
{
10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 ,
11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 ,
} ;
// gpioToGPLEV:
// (Word) offset to the GPIO Input level registers for each GPIO pin
static uint8_t gpioToGPLEV [ ] =
{
13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 ,
14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 ,
} ;
// gpioToPUDCLK
// (Word) offset to the Pull Up Down Clock regsiter
static uint8_t gpioToPUDCLK [ ] =
{
38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 , 38 ,
39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 , 39 ,
} ;
// gpioToPwmALT
// the ALT value to put a GPIO pin into PWM mode
static uint8_t gpioToPwmALT [ ] =
{
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0 -> 7
0 , 0 , 0 , 0 , FSEL_ALT0, FSEL_ALT0, 0 , 0 , // 8 -> 15
0 , 0 , FSEL_ALT5, FSEL_ALT5, 0 , 0 , 0 , 0 , // 16 -> 23
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 24 -> 31
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 32 -> 39
FSEL_ALT0, FSEL_ALT0, 0 , 0 , 0 , FSEL_ALT0, 0 , 0 , // 40 -> 47
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 48 -> 55
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 56 -> 63
} ;
static uint8_t gpioToPwmPort [ ] =
{
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 0 -> 7
0 , 0 , 0 , 0 , PWM0_DATA, PWM1_DATA, 0 , 0 , // 8 -> 15
0 , 0 , PWM0_DATA, PWM1_DATA, 0 , 0 , 0 , 0 , // 16 -> 23
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 24 -> 31
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 32 -> 39
PWM0_DATA, PWM1_DATA, 0 , 0 , 0 , PWM1_DATA, 0 , 0 , // 40 -> 47
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 48 -> 55
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 56 -> 63
} ;
// Time for easy calculations
static unsigned long long epoch ;
//////////////////////////////////////////////////////////////////////////////////
/*
* wiringPiGpioMode:
* Set the mode - use Pin numbers (0-16) or GPIO number (seemingly random)
*********************************************************************************
*/
void wiringPiGpioMode ( int mode)
{
gpioPinMode = mode ;
}
/*
* wiringPiSetup:
* Must be called once at the start of your program execution.
*********************************************************************************
*/
int wiringPiSetup ( void )
{
int fd ;
uint8_t * gpioMem, * pwmMem, * clkMem ;
struct timeval tv ;
#ifdef DEBUG_PADS
uint8_t * gpioMem, * padsMem, * pwmMem, * clkMem ;
uint32_t * pads ;
#endif
// Set Pin mode by default
wiringPiGpioMode ( WPI_MODE_PINS) ;
// Open the master /dev/memory device
if ( ( fd = open ( "/dev/mem" , O_RDWR | O_SYNC) ) < 0 )
{
fprintf ( stderr
, "wiringPiSetup: Unable to open /dev/mem: %s\n " , strerror ( errno
) ) ; return - 1 ;
}
// GPIO:
// Allocate 2 pages - 1 ...
if ( ( gpioMem
= malloc ( BLOCK_SIZE
+ ( PAGE_SIZE
- 1 ) ) ) == NULL
) {
return - 1 ;
}
// ... presumably to make sure we can round it up to a whole page size
if ( ( ( uint32_t ) gpioMem % PAGE_SIZE) != 0 )
gpioMem += PAGE_SIZE - ( ( uint32_t ) gpioMem % PAGE_SIZE) ;
gpio = ( uint32_t * ) mmap( ( caddr_t) gpioMem, BLOCK_SIZE, PROT_READ| PROT_WRITE, MAP_SHARED| MAP_FIXED, fd, GPIO_BASE) ;
if ( ( int32_t ) gpio < 0 )
{
return - 1 ;
}
// PWM
if ( ( pwmMem
= malloc ( BLOCK_SIZE
+ ( PAGE_SIZE
- 1 ) ) ) == NULL
) {
fprintf ( stderr
, "wiringPiSetup: pwmMem malloc failed: %s\n " , strerror ( errno
) ) ; return - 1 ;
}
if ( ( ( uint32_t ) pwmMem % PAGE_SIZE) != 0 )
pwmMem += PAGE_SIZE - ( ( uint32_t ) pwmMem % PAGE_SIZE) ;
pwm = ( uint32_t * ) mmap( pwmMem, BLOCK_SIZE, PROT_READ| PROT_WRITE, MAP_SHARED| MAP_FIXED, fd, GPIO_PWM) ;
if ( ( int32_t ) pwm < 0 )
{
fprintf ( stderr
, "wiringPiSetup: mmap failed (pwm): %s\n " , strerror ( errno
) ) ; return - 1 ;
}
// Clock control (needed for PWM)
if ( ( clkMem
= malloc ( BLOCK_SIZE
+ ( PAGE_SIZE
- 1 ) ) ) == NULL
) {
fprintf ( stderr
, "wiringPiSetup: clkMem malloc failed: %s\n " , strerror ( errno
) ) ; return - 1 ;
}
if ( ( ( uint32_t ) clkMem % PAGE_SIZE) != 0 )
clkMem += PAGE_SIZE - ( ( uint32_t ) clkMem % PAGE_SIZE) ;
clk = ( uint32_t * ) mmap( clkMem, BLOCK_SIZE, PROT_READ| PROT_WRITE, MAP_SHARED| MAP_FIXED, fd, CLOCK_BASE) ;
if ( ( int32_t ) clk < 0 )
{
fprintf ( stderr
, "wiringPiSetup: mmap failed (clk): %s\n " , strerror ( errno
) ) ; return - 1 ;
}
#ifdef DEBUG_PADS
if ( ( padsMem
= malloc ( BLOCK_SIZE
+ ( PAGE_SIZE
- 1 ) ) ) == NULL
) {
fprintf ( stderr
, "wiringPiSetup: padsMem malloc failed: %s\n " , strerror ( errno
) ) ; return - 1 ;
}
if ( ( ( uint32_t ) padsMem % PAGE_SIZE) != 0 )
padsMem += PAGE_SIZE - ( ( uint32_t ) padsMem % PAGE_SIZE) ;
pads = ( uint32_t * ) mmap( padsMem, BLOCK_SIZE, PROT_READ| PROT_WRITE, MAP_SHARED| MAP_FIXED, fd, GPIO_PADS) ;
if ( ( int32_t ) pads < 0 )
{
fprintf ( stderr
, "wiringPiSetup: mmap failed (pads): %s\n " , strerror ( errno
) ) ; return - 1 ;
}
printf ( "Checking pads @ 0x%08X\n " , ( unsigned int ) pads
) ;
printf ( "%08X %08X %08X\n " , * ( pads
+ 11 ) , * ( pads
+ 12 ) , * ( pads
+ 13 ) ) ; // *(pads + 11) = 0x1F ;
printf ( "%08X %08X %08X\n " , * ( pads
+ 11 ) , * ( pads
+ 12 ) , * ( pads
+ 13 ) ) ; #endif
gettimeofday ( & tv, NULL) ;
epoch = ( tv.tv_sec * 1000000 + tv.tv_usec ) / 1000 ;
return 0 ;
}
/*
* pinMode:
* Sets the mode of a pin to be input, output or PWM output
*********************************************************************************
*/
void pinMode ( int pin, int mode)
{
static int pwmRunning = FALSE ;
int gpioPin, fSel, shift ;
int alt ;
if ( gpioPinMode == WPI_MODE_PINS)
{
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return ;
gpioPin = pinToGpio [ pin] ;
}
else
gpioPin = pin ;
fSel = gpioToGPFSEL [ gpioPin] ;
shift = gpioToShift [ gpioPin] ;
/**/ if ( mode == INPUT)
* ( gpio + fSel) = ( * ( gpio + fSel) & ~( 7 << shift) ) ; // Sets bits to zero = input
else if ( mode == OUTPUT)
* ( gpio + fSel) = ( * ( gpio + fSel) & ~( 7 << shift) ) | ( 1 << shift) ;
else if ( mode == PWM_OUTPUT)
{
if ( ( alt = gpioToPwmALT [ gpioPin] ) == 0 ) // Not a PWM pin
return ;
// Set pin to PWM mode
* ( gpio + fSel) = ( * ( gpio + fSel) & ~( 7 << shift) ) | ( alt << shift) ;
// We didn't initialise the PWM hardware at setup time - because it's possible that
// something else is using the PWM - e.g. the Audio systems! So if we use PWM
// here, then we're assuming that nothing else is, otherwise things are going
// to sound a bit funny...
if ( ! pwmRunning)
{
// Gert/Doms Values
//*(clk + PWMCLK_DIV) = 0x5A000000 | (32<<12) ; // set pwm div to 32 (19.2/3 = 600KHz)
// change counter clock to 1.2MHz
* ( clk + PWMCLK_DIV) = 0x5A000000 | ( 16 << 12 ) ; // set pwm div to 16 (19.2/16 = 1.2MHz)
* ( clk + PWMCLK_CNTL) = 0x5A000011 ; // Source=osc and enable
digitalWrite ( pin, LOW) ;
* ( pwm + PWM_CONTROL) = 0 ; // Disable PWM
delayMicroseconds ( 10 ) ;
* ( pwm + PWM0_RANGE) = 24000 ; //with a 1.2MHz timer clock, this range value gives a 50Hz signal
delayMicroseconds ( 10 ) ;
* ( pwm + PWM1_RANGE) = 24000 ;
delayMicroseconds ( 10 ) ;
// Enable PWMs
* ( pwm + PWM0_DATA) = 0 ;
* ( pwm + PWM1_DATA) = 0 ;
* ( pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE;
}
}
// When we change mode of any pin, we remove the pull up/downs
pullUpDnControl ( pin, PUD_OFF) ;
}
/*
* digitalWrite:
* Set an output bit
*********************************************************************************
*/
void digitalWrite ( int pin, int value)
{
int gpioPin ;
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return ;
if ( gpioPinMode == WPI_MODE_PINS)
{
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return ;
gpioPin = pinToGpio [ pin] ;
}
else
gpioPin = pin ;
if ( value == HIGH)
* ( gpio + gpioToGPSET [ gpioPin] ) = 1 << gpioPin ;
else
* ( gpio + gpioToGPCLR [ gpioPin] ) = 1 << gpioPin ;
}
/*
* pwnWrite:
* Set an output PWM value
*********************************************************************************
*/
void pwmWrite ( int pin, int value)
{
int port, gpioPin ;
if ( gpioPinMode == WPI_MODE_PINS)
{
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return ;
gpioPin = pinToGpio [ pin] ;
}
else
gpioPin = pin ;
port = gpioToPwmPort [ gpioPin] ;
* ( pwm + port) = value & ~0x400 ;
}
/*
* digitalRead:
* Read the value of a given Pin, returning HIGH or LOW
*********************************************************************************
*/
int digitalRead ( int pin)
{
int gpioPin ;
if ( gpioPinMode == WPI_MODE_PINS)
{
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return 0 ;
gpioPin = pinToGpio [ pin] ;
}
else
gpioPin = pin ;
if ( ( * ( gpio + gpioToGPLEV [ gpioPin] ) & ( 1 << gpioPin) ) != 0 )
return HIGH ;
else
return LOW ;
}
/*
* pullUpDownCtrl:
* Control the internal pull-up/down resistors on a GPIO pin
* The Arduino only has pull-ups and these are enabled by writing 1
* to a port when in input mode - this paradigm doesn't quite apply
* here though.
*********************************************************************************
*/
void pullUpDnControl ( int pin, int pud)
{
int gpioPin ;
if ( gpioPinMode == WPI_MODE_PINS)
{
if ( ( pin < 0 ) || ( pin >= NUM_PINS) )
return ;
gpioPin = pinToGpio [ pin] ;
}
else
gpioPin = pin ;
* ( gpio + 37 ) = pud ;
delayMicroseconds ( 10 ) ;
* ( gpio + gpioToPUDCLK [ gpioPin] ) = 1 << gpioPin ;
delayMicroseconds ( 10 ) ;
* ( gpio + 37 ) = 0 ;
* ( gpio + gpioToPUDCLK [ gpioPin] ) = 0 ;
}
/*
* delay: delayMicroseconds
* Wait for some number of milli/micro seconds
*********************************************************************************
*/
void delay ( unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = ( time_t) ( howLong / 1000 ) ;
sleeper.tv_nsec = ( long ) ( howLong % 1000 ) * 1000000 ;
nanosleep ( & sleeper, & dummy) ;
}
void delayMicroseconds ( unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = ( long ) ( howLong * 1000 ) ;
nanosleep ( & sleeper, & dummy) ;
}
/*
* millis:
* Return a number of milliseconds as an unsigned int.
*********************************************************************************
*/
unsigned int millis ( void )
{
struct timeval tv ;
unsigned long long t1 ;
gettimeofday ( & tv, NULL) ;
t1 = ( tv.tv_sec * 1000000 + tv.tv_usec ) / 1000 ;
return ( uint32_t ) ( t1 - epoch) ;
}
LyoKICogd2lyaW5nUGk6CiAqCUFyZHVpbm8gY29tcGF0YWJsZSAoaXNoKSBXaXJpbmcgbGlicmFyeSBmb3IgdGhlIFJhc3BiZXJyeSBQaQogKglDb3B5cmlnaHQgKGMpIDIwMTIgR29yZG9uIEhlbmRlcnNvbgogKgogKglUaGFua3MgdG8gY29kZSBzYW1wbGVzIGZyb20gR2VydCBKYW4gdmFuIExvbyBhbmQgdGhlCiAqCUJDTTI4MzUgQVJNIFBlcmlwaGVyYWxzIG1hbnVhbCwgaG93ZXZlciBpdCdzIG1pc3NpbmcKICoJdGhlIGNsb2NrIHNlY3Rpb24gL2dyci9tdXR0ZXIvCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKiBUaGlzIGZpbGUgaXMgcGFydCBvZiB3aXJpbmdQaToKICoJaHR0cHM6Ly9wLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5uLm5ldC9yYXNwYmVycnktcGkvd2lyaW5ncGkvCiAqCiAqICAgIHdpcmluZ1BpIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkKICogICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkKICogICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3IKICogICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4KICoKICogICAgd2lyaW5nUGkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKICogICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKICogICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQogKiAgICBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgogKgogKiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQogKiAgICBhbG9uZyB3aXRoIHdpcmluZ1BpLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi51Lm9yZy9saWNlbnNlcy8+LgogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICovCgovLyBSZXZpc2lvbnM6Ci8vCTExIEp1biAyMDEyOgovLwkJRml4ZWQgc29tZSB0eXBvcy4KLy8JCUFkZGVkIGMrKyBzdXBwb3J0IGZvciB0aGUgLmggZmlsZQovLwkJQWRkZWQgYSBuZXcgZnVuY3Rpb24gdG8gYWxsb3cgZm9yIHVzaW5nIG15ICJwaW4iIG51bWJlcnMsIG9yIG5hdGl2ZQovLwkJCUdQSU8gcGluIG51bWJlcnMuCi8vCQlSZW1vdmVkIG15IGJ1c3ktbG9vcCBkZWxheSBhbmQgcmVwbGFjZWQgaXQgd2l0aCBhIGNhbGwgdG8gZGVsYXlNaWNyb3NlY29uZHMKLy8KLy8JMDIgTWF5IDIwMTI6Ci8vCQlBZGRlZCBpbiB0aGUgMiBVQVJUIHBpbnMKLy8JCUNoYW5nZSBtYXhQaW5zIHRvIG51bVBpbnMgdG8gbW9yZSBhY2N1cmF0ZWx5IHJlZmxlY3QgcHVycG9zZQoKLy8gUGFkIGRyaXZlIGN1cnJlbnQgZmlkZGxpbmcKCiN1bmRlZglERUJVR19QQURTCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8ZXJybm8uaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8dGltZS5oPgojaW5jbHVkZSA8ZmNudGwuaD4KI2luY2x1ZGUgPHN5cy90aW1lLmg+CiNpbmNsdWRlIDxzeXMvbW1hbi5oPgoKI2luY2x1ZGUgIndpcmluZ1BpLmgiCgojaWZuZGVmCVRSVUUKI2RlZmluZQlUUlVFCSgxPT0xKQojZGVmaW5lCUZBTFNFCSgxPT0yKQojZW5kaWYKCi8vIFBvcnQgZnVuY3Rpb24gc2VsZWN0IGJpdHMKCiNkZWZpbmUJRlNFTF9JTlBUCQkwYjAwMAojZGVmaW5lCUZTRUxfT1VUUAkJMGIwMDEKI2RlZmluZQlGU0VMX0FMVDAJCTBiMTAwCiNkZWZpbmUJRlNFTF9BTFQwCQkwYjEwMAojZGVmaW5lCUZTRUxfQUxUMQkJMGIxMDEKI2RlZmluZQlGU0VMX0FMVDIJCTBiMTEwCiNkZWZpbmUJRlNFTF9BTFQzCQkwYjExMQojZGVmaW5lCUZTRUxfQUxUNAkJMGIwMTEKI2RlZmluZQlGU0VMX0FMVDUJCTBiMDEwCgovLyBBY2Nlc3MgZnJvbSBBUk0gUnVubmluZyBMaW51eAovLwlUYWtlIGZyb20gR2VydHMgY29kZS4gU29tZSBvZiB0aGlzIGlzIG5vdCBpbiB0aGUgbWFudWFsCi8vCXRoYXQgSSBjYW4gZmluZCApLToKCiNkZWZpbmUgQkNNMjcwOF9QRVJJX0JBU0UJMHgyMDAwMDAwMAojZGVmaW5lIEdQSU9fUEFEUwkJKEJDTTI3MDhfUEVSSV9CQVNFICsgMHgxMDAwMDApCiNkZWZpbmUgQ0xPQ0tfQkFTRQkJKEJDTTI3MDhfUEVSSV9CQVNFICsgMHgxMDEwMDApCiNkZWZpbmUgR1BJT19CQVNFCQkoQkNNMjcwOF9QRVJJX0JBU0UgKyAweDIwMDAwMCkKI2RlZmluZSBHUElPX1BXTQkJKEJDTTI3MDhfUEVSSV9CQVNFICsgMHgyMEMwMDApCgojZGVmaW5lCVBBR0VfU0laRQkJKDQqMTAyNCkKI2RlZmluZQlCTE9DS19TSVpFCQkoNCoxMDI0KQoKLy8gUFdNCgojZGVmaW5lCVBXTV9DT05UUk9MIDAKI2RlZmluZQlQV01fU1RBVFVTICAxCiNkZWZpbmUJUFdNMF9SQU5HRSAgNAojZGVmaW5lCVBXTTBfREFUQSAgIDUKI2RlZmluZQlQV00xX1JBTkdFICA4CiNkZWZpbmUJUFdNMV9EQVRBICAgOQoKI2RlZmluZQlQV01DTEtfQ05UTAk0MAojZGVmaW5lCVBXTUNMS19ESVYJNDEKCiNkZWZpbmUJUFdNMV9NU19NT0RFICAgIDB4ODAwMCAgLy8gUnVuIGluIE1TIG1vZGUKI2RlZmluZQlQV00xX1VTRUZJRk8gICAgMHgyMDAwICAvLyBEYXRhIGZyb20gRklGTwojZGVmaW5lCVBXTTFfUkVWUE9MQVIgICAweDEwMDAgIC8vIFJldmVyc2UgcG9sYXJpdHkKI2RlZmluZQlQV00xX09GRlNUQVRFICAgMHgwODAwICAvLyBPdXB1dCBPZmYgc3RhdGUKI2RlZmluZQlQV00xX1JFUEVBVEZGICAgMHgwNDAwICAvLyBSZXBlYXQgbGFzdCB2YWx1ZSBpZiBGSUZPIGVtcHR5CiNkZWZpbmUJUFdNMV9TRVJJQUwgICAgIDB4MDIwMCAgLy8gUnVuIGluIHNlcmlhbCBtb2RlCiNkZWZpbmUJUFdNMV9FTkFCTEUgICAgIDB4MDEwMCAgLy8gQ2hhbm5lbCBFbmFibGUKCiNkZWZpbmUJUFdNMF9NU19NT0RFICAgIDB4MDA4MCAgLy8gUnVuIGluIE1TIG1vZGUKI2RlZmluZQlQV00wX1VTRUZJRk8gICAgMHgwMDIwICAvLyBEYXRhIGZyb20gRklGTwojZGVmaW5lCVBXTTBfUkVWUE9MQVIgICAweDAwMTAgIC8vIFJldmVyc2UgcG9sYXJpdHkKI2RlZmluZQlQV00wX09GRlNUQVRFICAgMHgwMDA4ICAvLyBPdXB1dCBPZmYgc3RhdGUKI2RlZmluZQlQV00wX1JFUEVBVEZGICAgMHgwMDA0ICAvLyBSZXBlYXQgbGFzdCB2YWx1ZSBpZiBGSUZPIGVtcHR5CiNkZWZpbmUJUFdNMF9TRVJJQUwgICAgIDB4MDAwMiAgLy8gUnVuIGluIHNlcmlhbCBtb2RlCiNkZWZpbmUJUFdNMF9FTkFCTEUgICAgIDB4MDAwMSAgLy8gQ2hhbm5lbCBFbmFibGUKCgovLyBMb2NhbHMgdG8gaG9sZCBwb2ludGVycyB0byB0aGUgaGFyZHdhcmUKCnN0YXRpYyB2b2xhdGlsZSB1aW50MzJfdCAqZ3BpbyA7CnN0YXRpYyB2b2xhdGlsZSB1aW50MzJfdCAqcHdtIDsKc3RhdGljIHZvbGF0aWxlIHVpbnQzMl90ICpjbGsgOwoKLy8gVGhlIEJDTTI4MzUgaGFzIDU0IEdQSU8gcGlucy4KLy8JQkNNMjgzNSBkYXRhIHNoZWV0LCBQYWdlIDkwIG9ud2FyZHMuCi8vCVRoZXJlIGFyZSA2IGNvbnRyb2wgcmVnaXN0ZXJzLCBlYWNoIGNvbnRyb2wgdGhlIGZ1bmN0aW9ucyBvZiBhIGJsb2NrCi8vCW9mIDEwIHBpbnMuCi8vCUVhY2ggY29udHJvbCByZWdpc3RlciBoYXMgMTAgc2V0cyBvZiAzIGJpdHMgcGVyIEdQSU8gcGluOgovLwovLwkwMDAgPSBHUElPIFBpbiBYIGlzIGFuIGlucHV0Ci8vCTAwMSA9IEdQSU8gUGluIFggaXMgYW4gb3V0cHV0Ci8vCTEwMCA9IEdQSU8gUGluIFggdGFrZXMgYWx0ZXJuYXRlIGZ1bmN0aW9uIDAKLy8JMTAxID0gR1BJTyBQaW4gWCB0YWtlcyBhbHRlcm5hdGUgZnVuY3Rpb24gMQovLwkxMTAgPSBHUElPIFBpbiBYIHRha2VzIGFsdGVybmF0ZSBmdW5jdGlvbiAyCi8vCTExMSA9IEdQSU8gUGluIFggdGFrZXMgYWx0ZXJuYXRlIGZ1bmN0aW9uIDMKLy8JMDExID0gR1BJTyBQaW4gWCB0YWtlcyBhbHRlcm5hdGUgZnVuY3Rpb24gNAovLwkwMTAgPSBHUElPIFBpbiBYIHRha2VzIGFsdGVybmF0ZSBmdW5jdGlvbiA1Ci8vCi8vIFNvIHRoZSAzIGJpdHMgZm9yIHBvcnQgWCBhcmU6Ci8vCVggLyAxMCArICgoWCAlIDEwKSAqIDMpCgovLyBtb2RlCgpzdGF0aWMgaW50IGdwaW9QaW5Nb2RlIDsKCi8vIERvaW5nIGl0IHRoZSBBcmR1aW5vIHdheSB3aXRoIGxvb2t1cCB0YWJsZXMuLi4KLy8JWWVzLCBpdCdzIHByb2JhYmx5IG1vcmUgaW5uZWZmaWNpZW50IHRoYW4gYWxsIHRoZSBiaXQtdHdpZGxpbmcsIGJ1dCBpdAovLwlkb2VzIHRlbmQgdG8gbWFrZSBpdCBhbGwgYSBiaXQgY2xlYXJlci4gQXQgbGVhc3QgdG8gbWUhCgovLyBwaW5Ub0dwaW86Ci8vCVRha2UgYSBXaXJpbmcgcGluICgwIHRocm91Z2ggWCkgYW5kIHJlLW1hcCBpdCB0byB0aGUgQkNNX0dQSU8gcGluCgpzdGF0aWMgaW50IHBpblRvR3BpbyBbXSA9CnsKICAxNywgMTgsIDIxLCAyMiwgMjMsIDI0LCAyNSwgNCwJLy8gRnJvbSB0aGUgT3JpZ2luYWwgV2lraSAtIEdQSU8gMCB0aHJvdWdoIDcKICAgMCwgIDEsCQkJCS8vIEkyQyAgLSBTREEwLCBTQ0wwCiAgIDgsICA3LAkJCQkvLyBTUEkgIC0gQ0UxLCBDRTAKICAxMCwgIDksIDExLCAJCQkJLy8gU1BJICAtIE1PU0ksIE1JU08sIFNDTEsKICAxNCwgMTUsCQkJCS8vIFVBUlQgLSBUeCwgUngKfSA7CgovLyBncGlvVG9HUEZTRUw6Ci8vCU1hcCBhIEJDTV9HUElPIHBpbiB0byBpdCdzIGNvbnRyb2wgcG9ydC4gKEdQRlNFTCAwLTUpCgpzdGF0aWMgdWludDhfdCBncGlvVG9HUEZTRUwgW10gPQp7CiAgMCwwLDAsMCwwLDAsMCwwLDAsMCwKICAxLDEsMSwxLDEsMSwxLDEsMSwxLAogIDIsMiwyLDIsMiwyLDIsMiwyLDIsCiAgMywzLDMsMywzLDMsMywzLDMsMywKICA0LDQsNCw0LDQsNCw0LDQsNCw0LAogIDUsNSw1LDUsNSw1LDUsNSw1LDUsCn0gOwoKLy8gZ3Bpb1RvU2hpZnQKLy8JRGVmaW5lIHRoZSBzaGlmdCB1cCBmb3IgdGhlIDMgYml0cyBwZXIgcGluIGluIGVhY2ggR1BGU0VMIHBvcnQKCnN0YXRpYyB1aW50OF90IGdwaW9Ub1NoaWZ0IFtdID0KewogIDAsMyw2LDksMTIsMTUsMTgsMjEsMjQsMjcsCiAgMCwzLDYsOSwxMiwxNSwxOCwyMSwyNCwyNywKICAwLDMsNiw5LDEyLDE1LDE4LDIxLDI0LDI3LAogIDAsMyw2LDksMTIsMTUsMTgsMjEsMjQsMjcsCiAgMCwzLDYsOSwxMiwxNSwxOCwyMSwyNCwyNywKfSA7CgovLyBncGlvVG9HUFNFVDoKLy8JKFdvcmQpIG9mZnNldCB0byB0aGUgR1BJTyBTZXQgcmVnaXN0ZXJzIGZvciBlYWNoIEdQSU8gcGluCgpzdGF0aWMgdWludDhfdCBncGlvVG9HUFNFVCBbXSA9CnsKICAgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywgNywKICAgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwgOCwKfSA7CgovLyBncGlvVG9HUENMUjoKLy8JKFdvcmQpIG9mZnNldCB0byB0aGUgR1BJTyBDbGVhciByZWdpc3RlcnMgZm9yIGVhY2ggR1BJTyBwaW4KCnN0YXRpYyB1aW50OF90IGdwaW9Ub0dQQ0xSIFtdID0KewogIDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLDEwLAogIDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLDExLAp9IDsKCi8vIGdwaW9Ub0dQTEVWOgovLwkoV29yZCkgb2Zmc2V0IHRvIHRoZSBHUElPIElucHV0IGxldmVsIHJlZ2lzdGVycyBmb3IgZWFjaCBHUElPIHBpbgoKc3RhdGljIHVpbnQ4X3QgZ3Bpb1RvR1BMRVYgW10gPQp7CiAgMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsMTMsCiAgMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsMTQsCn0gOwoKLy8gZ3Bpb1RvUFVEQ0xLCi8vCShXb3JkKSBvZmZzZXQgdG8gdGhlIFB1bGwgVXAgRG93biBDbG9jayByZWdzaXRlcgoKc3RhdGljIHVpbnQ4X3QgZ3Bpb1RvUFVEQ0xLIFtdID0KewogIDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LDM4LAogIDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LDM5LAp9IDsKCi8vIGdwaW9Ub1B3bUFMVAovLwl0aGUgQUxUIHZhbHVlIHRvIHB1dCBhIEdQSU8gcGluIGludG8gUFdNIG1vZGUKCnN0YXRpYyB1aW50OF90IGdwaW9Ub1B3bUFMVCBbXSA9CnsKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gIDAgLT4gIDcKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsIEZTRUxfQUxUMCwgRlNFTF9BTFQwLCAgICAgICAgIDAsICAgICAgICAgMCwgCS8vICA4IC0+IDE1CiAgICAgICAgICAwLCAgICAgICAgIDAsIEZTRUxfQUxUNSwgRlNFTF9BTFQ1LCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsIAkvLyAxNiAtPiAyMwogICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLAkvLyAyNCAtPiAzMQogICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLAkvLyAzMiAtPiAzOQogIEZTRUxfQUxUMCwgRlNFTF9BTFQwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCBGU0VMX0FMVDAsICAgICAgICAgMCwgICAgICAgICAwLAkvLyA0MCAtPiA0NwogICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLAkvLyA0OCAtPiA1NQogICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLAkvLyA1NiAtPiA2Mwp9IDsKCnN0YXRpYyB1aW50OF90IGdwaW9Ub1B3bVBvcnQgW10gPQp7CiAgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsCS8vICAwIC0+ICA3CiAgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCBQV00wX0RBVEEsIFBXTTFfREFUQSwgICAgICAgICAwLCAgICAgICAgIDAsIAkvLyAgOCAtPiAxNQogICAgICAgICAgMCwgICAgICAgICAwLCBQV00wX0RBVEEsIFBXTTFfREFUQSwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAJLy8gMTYgLT4gMjMKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gMjQgLT4gMzEKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gMzIgLT4gMzkKICBQV00wX0RBVEEsIFBXTTFfREFUQSwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgUFdNMV9EQVRBLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gNDAgLT4gNDcKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gNDggLT4gNTUKICAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwgICAgICAgICAwLCAgICAgICAgIDAsICAgICAgICAgMCwJLy8gNTYgLT4gNjMKCn0gOwoKCi8vIFRpbWUgZm9yIGVhc3kgY2FsY3VsYXRpb25zCgpzdGF0aWMgdW5zaWduZWQgbG9uZyBsb25nIGVwb2NoIDsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCgovKgogKiB3aXJpbmdQaUdwaW9Nb2RlOgogKglTZXQgdGhlIG1vZGUgLSB1c2UgUGluIG51bWJlcnMgKDAtMTYpIG9yIEdQSU8gbnVtYmVyIChzZWVtaW5nbHkgcmFuZG9tKQogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqLwoKdm9pZCB3aXJpbmdQaUdwaW9Nb2RlIChpbnQgbW9kZSkKewogIGdwaW9QaW5Nb2RlID0gbW9kZSA7Cn0KCgovKgogKiB3aXJpbmdQaVNldHVwOgogKglNdXN0IGJlIGNhbGxlZCBvbmNlIGF0IHRoZSBzdGFydCBvZiB5b3VyIHByb2dyYW0gZXhlY3V0aW9uLgogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqLwoKaW50IHdpcmluZ1BpU2V0dXAgKHZvaWQpCnsKICBpbnQgICAgICBmZCA7CiAgdWludDhfdCAqZ3Bpb01lbSwgKnB3bU1lbSwgKmNsa01lbSA7CiAgc3RydWN0IHRpbWV2YWwgdHYgOwoKI2lmZGVmCURFQlVHX1BBRFMKICB1aW50OF90ICpncGlvTWVtLCAqcGFkc01lbSwgKnB3bU1lbSwgKmNsa01lbSA7CiAgdWludDMyX3QgKnBhZHMgOwojZW5kaWYKCi8vIFNldCBQaW4gbW9kZSBieSBkZWZhdWx0CgogIHdpcmluZ1BpR3Bpb01vZGUgKFdQSV9NT0RFX1BJTlMpIDsKICAKLy8gT3BlbiB0aGUgbWFzdGVyIC9kZXYvbWVtb3J5IGRldmljZQoKICBpZiAoKGZkID0gb3BlbiAoIi9kZXYvbWVtIiwgT19SRFdSIHwgT19TWU5DKSApIDwgMCkKICB7CiAgICBmcHJpbnRmIChzdGRlcnIsICJ3aXJpbmdQaVNldHVwOiBVbmFibGUgdG8gb3BlbiAvZGV2L21lbTogJXNcbiIsIHN0cmVycm9yIChlcnJubykpIDsKICAgIHJldHVybiAtMSA7CiAgfQoKLy8gR1BJTzoKCi8vIEFsbG9jYXRlIDIgcGFnZXMgLSAxIC4uLgoKICBpZiAoKGdwaW9NZW0gPSBtYWxsb2MgKEJMT0NLX1NJWkUgKyAoUEFHRV9TSVpFLTEpKSkgPT0gTlVMTCkKICB7CiAgICBmcHJpbnRmIChzdGRlcnIsICJ3aXJpbmdQaVNldHVwOiBtYWxsb2MgZmFpbGVkOiAlc1xuIiwgc3RyZXJyb3IgKGVycm5vKSkgOwogICAgcmV0dXJuIC0xIDsKICB9CgovLyAuLi4gcHJlc3VtYWJseSB0byBtYWtlIHN1cmUgd2UgY2FuIHJvdW5kIGl0IHVwIHRvIGEgd2hvbGUgcGFnZSBzaXplCgogIGlmICgoKHVpbnQzMl90KWdwaW9NZW0gJSBQQUdFX1NJWkUpICE9IDApCiAgICBncGlvTWVtICs9IFBBR0VfU0laRSAtICgodWludDMyX3QpZ3Bpb01lbSAlIFBBR0VfU0laRSkgOwoKICBncGlvID0gKHVpbnQzMl90ICopbW1hcCgoY2FkZHJfdClncGlvTWVtLCBCTE9DS19TSVpFLCBQUk9UX1JFQUR8UFJPVF9XUklURSwgTUFQX1NIQVJFRHxNQVBfRklYRUQsIGZkLCBHUElPX0JBU0UpIDsKCiAgaWYgKChpbnQzMl90KWdwaW8gPCAwKQogIHsKICAgIGZwcmludGYgKHN0ZGVyciwgIndpcmluZ1BpU2V0dXA6IG1tYXAgZmFpbGVkOiAlc1xuIiwgc3RyZXJyb3IgKGVycm5vKSkgOwogICAgcmV0dXJuIC0xIDsKICB9CgovLyBQV00KCiAgaWYgKChwd21NZW0gPSBtYWxsb2MgKEJMT0NLX1NJWkUgKyAoUEFHRV9TSVpFLTEpKSkgPT0gTlVMTCkKICB7CiAgICBmcHJpbnRmIChzdGRlcnIsICJ3aXJpbmdQaVNldHVwOiBwd21NZW0gbWFsbG9jIGZhaWxlZDogJXNcbiIsIHN0cmVycm9yIChlcnJubykpIDsKICAgIHJldHVybiAtMSA7CiAgfQoKICBpZiAoKCh1aW50MzJfdClwd21NZW0gJSBQQUdFX1NJWkUpICE9IDApCiAgICBwd21NZW0gKz0gUEFHRV9TSVpFIC0gKCh1aW50MzJfdClwd21NZW0gJSBQQUdFX1NJWkUpIDsKCiAgcHdtID0gKHVpbnQzMl90ICopbW1hcChwd21NZW0sIEJMT0NLX1NJWkUsIFBST1RfUkVBRHxQUk9UX1dSSVRFLCBNQVBfU0hBUkVEfE1BUF9GSVhFRCwgZmQsIEdQSU9fUFdNKSA7CgogIGlmICgoaW50MzJfdClwd20gPCAwKQogIHsKICAgIGZwcmludGYgKHN0ZGVyciwgIndpcmluZ1BpU2V0dXA6IG1tYXAgZmFpbGVkIChwd20pOiAlc1xuIiwgc3RyZXJyb3IgKGVycm5vKSkgOwogICAgcmV0dXJuIC0xIDsKICB9CiAKLy8gQ2xvY2sgY29udHJvbCAobmVlZGVkIGZvciBQV00pCgogIGlmICgoY2xrTWVtID0gbWFsbG9jIChCTE9DS19TSVpFICsgKFBBR0VfU0laRS0xKSkpID09IE5VTEwpCiAgewogICAgZnByaW50ZiAoc3RkZXJyLCAid2lyaW5nUGlTZXR1cDogY2xrTWVtIG1hbGxvYyBmYWlsZWQ6ICVzXG4iLCBzdHJlcnJvciAoZXJybm8pKSA7CiAgICByZXR1cm4gLTEgOwogIH0KCiAgaWYgKCgodWludDMyX3QpY2xrTWVtICUgUEFHRV9TSVpFKSAhPSAwKQogICAgY2xrTWVtICs9IFBBR0VfU0laRSAtICgodWludDMyX3QpY2xrTWVtICUgUEFHRV9TSVpFKSA7CgogIGNsayA9ICh1aW50MzJfdCAqKW1tYXAoY2xrTWVtLCBCTE9DS19TSVpFLCBQUk9UX1JFQUR8UFJPVF9XUklURSwgTUFQX1NIQVJFRHxNQVBfRklYRUQsIGZkLCBDTE9DS19CQVNFKSA7CgogIGlmICgoaW50MzJfdCljbGsgPCAwKQogIHsKICAgIGZwcmludGYgKHN0ZGVyciwgIndpcmluZ1BpU2V0dXA6IG1tYXAgZmFpbGVkIChjbGspOiAlc1xuIiwgc3RyZXJyb3IgKGVycm5vKSkgOwogICAgcmV0dXJuIC0xIDsKICB9CiAKI2lmZGVmCURFQlVHX1BBRFMKICBpZiAoKHBhZHNNZW0gPSBtYWxsb2MgKEJMT0NLX1NJWkUgKyAoUEFHRV9TSVpFLTEpKSkgPT0gTlVMTCkKICB7CiAgICBmcHJpbnRmIChzdGRlcnIsICJ3aXJpbmdQaVNldHVwOiBwYWRzTWVtIG1hbGxvYyBmYWlsZWQ6ICVzXG4iLCBzdHJlcnJvciAoZXJybm8pKSA7CiAgICByZXR1cm4gLTEgOwogIH0KCiAgaWYgKCgodWludDMyX3QpcGFkc01lbSAlIFBBR0VfU0laRSkgIT0gMCkKICAgIHBhZHNNZW0gKz0gUEFHRV9TSVpFIC0gKCh1aW50MzJfdClwYWRzTWVtICUgUEFHRV9TSVpFKSA7CgogIHBhZHMgPSAodWludDMyX3QgKiltbWFwKHBhZHNNZW0sIEJMT0NLX1NJWkUsIFBST1RfUkVBRHxQUk9UX1dSSVRFLCBNQVBfU0hBUkVEfE1BUF9GSVhFRCwgZmQsIEdQSU9fUEFEUykgOwoKICBpZiAoKGludDMyX3QpcGFkcyA8IDApCiAgewogICAgZnByaW50ZiAoc3RkZXJyLCAid2lyaW5nUGlTZXR1cDogbW1hcCBmYWlsZWQgKHBhZHMpOiAlc1xuIiwgc3RyZXJyb3IgKGVycm5vKSkgOwogICAgcmV0dXJuIC0xIDsKICB9CiAKICBwcmludGYgKCJDaGVja2luZyBwYWRzIEAgMHglMDhYXG4iLCAodW5zaWduZWQgaW50KXBhZHMpIDsKCiAgcHJpbnRmICgiJTA4WCAlMDhYICUwOFhcbiIsICoocGFkcyArIDExKSwgKihwYWRzICsgMTIpLCAqKHBhZHMgKyAxMykpIDsKLy8gICoocGFkcyArIDExKSA9IDB4MUYgOwogIHByaW50ZiAoIiUwOFggJTA4WCAlMDhYXG4iLCAqKHBhZHMgKyAxMSksICoocGFkcyArIDEyKSwgKihwYWRzICsgMTMpKSA7CiNlbmRpZgoKICBnZXR0aW1lb2ZkYXkgKCZ0diwgTlVMTCkgOwogIGVwb2NoID0gKHR2LnR2X3NlYyAqIDEwMDAwMDAgKyB0di50dl91c2VjKSAvIDEwMDAgOwoKICByZXR1cm4gMCA7Cn0KCgovKgogKiBwaW5Nb2RlOgogKglTZXRzIHRoZSBtb2RlIG9mIGEgcGluIHRvIGJlIGlucHV0LCBvdXRwdXQgb3IgUFdNIG91dHB1dAogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqLwoKdm9pZCBwaW5Nb2RlIChpbnQgcGluLCBpbnQgbW9kZSkKewogIHN0YXRpYyBpbnQgcHdtUnVubmluZyAgPSBGQUxTRSA7CgogIGludCBncGlvUGluLCBmU2VsLCBzaGlmdCA7CiAgaW50IGFsdCA7CgoKICBpZiAoZ3Bpb1Bpbk1vZGUgPT0gV1BJX01PREVfUElOUykKICB7CiAgICBpZiAoKHBpbiA8IDApIHx8IChwaW4gPj0gTlVNX1BJTlMpKQogICAgICByZXR1cm4gOwogICAgZ3Bpb1BpbiA9IHBpblRvR3BpbyAgICBbcGluXSA7CiAgfQogIGVsc2UKICAgIGdwaW9QaW4gPSBwaW4gOwoKICBmU2VsICAgID0gZ3Bpb1RvR1BGU0VMIFtncGlvUGluXSA7CiAgc2hpZnQgICA9IGdwaW9Ub1NoaWZ0ICBbZ3Bpb1Bpbl0gOwoKCiAgLyoqLyBpZiAobW9kZSA9PSBJTlBVVCkKICAgICooZ3BpbyArIGZTZWwpID0gKCooZ3BpbyArIGZTZWwpICYgfig3IDw8IHNoaWZ0KSkgOyAvLyBTZXRzIGJpdHMgdG8gemVybyA9IGlucHV0CiAgZWxzZSBpZiAobW9kZSA9PSBPVVRQVVQpCiAgICAqKGdwaW8gKyBmU2VsKSA9ICgqKGdwaW8gKyBmU2VsKSAmIH4oNyA8PCBzaGlmdCkpIHwgKDEgPDwgc2hpZnQpIDsKICBlbHNlIGlmIChtb2RlID09IFBXTV9PVVRQVVQpCiAgewogICAgaWYgKChhbHQgPSBncGlvVG9Qd21BTFQgW2dwaW9QaW5dKSA9PSAwKQkvLyBOb3QgYSBQV00gcGluCiAgICAgIHJldHVybiA7CgovLyBTZXQgcGluIHRvIFBXTSBtb2RlCgogICAgKihncGlvICsgZlNlbCkgPSAoKihncGlvICsgZlNlbCkgJiB+KDcgPDwgc2hpZnQpKSB8IChhbHQgPDwgc2hpZnQpIDsKCi8vIFdlIGRpZG4ndCBpbml0aWFsaXNlIHRoZSBQV00gaGFyZHdhcmUgYXQgc2V0dXAgdGltZSAtIGJlY2F1c2UgaXQncyBwb3NzaWJsZSB0aGF0Ci8vCXNvbWV0aGluZyBlbHNlIGlzIHVzaW5nIHRoZSBQV00gLSBlLmcuIHRoZSBBdWRpbyBzeXN0ZW1zISBTbyBpZiB3ZSB1c2UgUFdNCi8vCWhlcmUsIHRoZW4gd2UncmUgYXNzdW1pbmcgdGhhdCBub3RoaW5nIGVsc2UgaXMsIG90aGVyd2lzZSB0aGluZ3MgYXJlIGdvaW5nCi8vCXRvIHNvdW5kIGEgYml0IGZ1bm55Li4uCgogICAgaWYgKCFwd21SdW5uaW5nKQogICAgewoKLy8JR2VydC9Eb21zIFZhbHVlcwogICAgICAvLyooY2xrICsgUFdNQ0xLX0RJVikgID0gMHg1QTAwMDAwMCB8ICgzMjw8MTIpIDsJLy8gc2V0IHB3bSBkaXYgdG8gMzIgKDE5LjIvMyA9IDYwMEtIeikKICAgICAgLy8gY2hhbmdlIGNvdW50ZXIgY2xvY2sgdG8gMS4yTUh6CiAgICAgICooY2xrICsgUFdNQ0xLX0RJVikgID0gMHg1QTAwMDAwMCB8ICgxNjw8MTIpIDsgIC8vIHNldCBwd20gZGl2IHRvIDE2ICgxOS4yLzE2ID0gMS4yTUh6KQogICAgICAqKGNsayArIFBXTUNMS19DTlRMKSA9IDB4NUEwMDAwMTEgOwkJLy8gU291cmNlPW9zYyBhbmQgZW5hYmxlCiAgICAgIGRpZ2l0YWxXcml0ZSAocGluLCBMT1cpIDsKICAgICAgKihwd20gKyBQV01fQ09OVFJPTCkgPSAwIDsJCQkvLyBEaXNhYmxlIFBXTQogICAgICBkZWxheU1pY3Jvc2Vjb25kcyAoMTApIDsKICAgICAgKihwd20gKyBQV00wX1JBTkdFKSA9IDI0MDAwIDsgLy93aXRoIGEgMS4yTUh6IHRpbWVyIGNsb2NrLCB0aGlzIHJhbmdlIHZhbHVlIGdpdmVzIGEgNTBIeiBzaWduYWwKICAgICAgZGVsYXlNaWNyb3NlY29uZHMgKDEwKSA7CiAgICAgICoocHdtICsgUFdNMV9SQU5HRSkgPSAyNDAwMCA7CiAgICAgIGRlbGF5TWljcm9zZWNvbmRzICgxMCkgOwoKLy8gRW5hYmxlIFBXTXMKCiAgICAgICoocHdtICsgUFdNMF9EQVRBKSA9IDAgOwogICAgICAqKHB3bSArIFBXTTFfREFUQSkgPSAwIDsKCiAgICAgICoocHdtICsgUFdNX0NPTlRST0wpID0gUFdNMF9FTkFCTEUgfCBQV00xX0VOQUJMRSB8IFBXTTBfTVNfTU9ERSB8IFBXTTFfTVNfTU9ERTsKICAgIH0KCiAgfQoKLy8gV2hlbiB3ZSBjaGFuZ2UgbW9kZSBvZiBhbnkgcGluLCB3ZSByZW1vdmUgdGhlIHB1bGwgdXAvZG93bnMKCiAgcHVsbFVwRG5Db250cm9sIChwaW4sIFBVRF9PRkYpIDsKfQoKCi8qCiAqIGRpZ2l0YWxXcml0ZToKICoJU2V0IGFuIG91dHB1dCBiaXQKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKi8KCnZvaWQgZGlnaXRhbFdyaXRlIChpbnQgcGluLCBpbnQgdmFsdWUpCnsKICBpbnQgZ3Bpb1BpbiA7CgogIGlmICgocGluIDwgMCkgfHwgKHBpbiA+PSBOVU1fUElOUykpCiAgICByZXR1cm4gOwoKICBpZiAoZ3Bpb1Bpbk1vZGUgPT0gV1BJX01PREVfUElOUykKICB7CiAgICBpZiAoKHBpbiA8IDApIHx8IChwaW4gPj0gTlVNX1BJTlMpKQogICAgICByZXR1cm4gOwogICAgZ3Bpb1BpbiA9IHBpblRvR3BpbyBbcGluXSA7CiAgfQogIGVsc2UKICAgIGdwaW9QaW4gPSBwaW4gOwoKICBpZiAodmFsdWUgPT0gSElHSCkKICAgICooZ3BpbyArIGdwaW9Ub0dQU0VUIFtncGlvUGluXSkgPSAxIDw8IGdwaW9QaW4gOwogIGVsc2UKICAgICooZ3BpbyArIGdwaW9Ub0dQQ0xSIFtncGlvUGluXSkgPSAxIDw8IGdwaW9QaW4gOwp9CgoKLyoKICogcHduV3JpdGU6CiAqCVNldCBhbiBvdXRwdXQgUFdNIHZhbHVlCiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKICovCgp2b2lkIHB3bVdyaXRlIChpbnQgcGluLCBpbnQgdmFsdWUpCnsKICBpbnQgcG9ydCwgZ3Bpb1BpbiA7CgogIGlmIChncGlvUGluTW9kZSA9PSBXUElfTU9ERV9QSU5TKQogIHsKICAgIGlmICgocGluIDwgMCkgfHwgKHBpbiA+PSBOVU1fUElOUykpCiAgICAgIHJldHVybiA7CiAgICBncGlvUGluID0gcGluVG9HcGlvIFtwaW5dIDsKICB9CiAgZWxzZQogICAgZ3Bpb1BpbiA9IHBpbiA7CgogIHBvcnQgPSBncGlvVG9Qd21Qb3J0IFtncGlvUGluXSA7CgogICoocHdtICsgcG9ydCkgPSB2YWx1ZSAmIH4weDQwMCA7Cn0KCgovKgogKiBkaWdpdGFsUmVhZDoKICoJUmVhZCB0aGUgdmFsdWUgb2YgYSBnaXZlbiBQaW4sIHJldHVybmluZyBISUdIIG9yIExPVwogKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiAqLwoKaW50IGRpZ2l0YWxSZWFkIChpbnQgcGluKQp7CiAgaW50IGdwaW9QaW4gOwoKICBpZiAoZ3Bpb1Bpbk1vZGUgPT0gV1BJX01PREVfUElOUykKICB7CiAgICBpZiAoKHBpbiA8IDApIHx8IChwaW4gPj0gTlVNX1BJTlMpKQogICAgICByZXR1cm4gMCA7CiAgICBncGlvUGluID0gcGluVG9HcGlvIFtwaW5dIDsKICB9CiAgZWxzZQogICAgZ3Bpb1BpbiA9IHBpbiA7CgogIGlmICgoKihncGlvICsgZ3Bpb1RvR1BMRVYgW2dwaW9QaW5dKSAmICgxIDw8IGdwaW9QaW4pKSAhPSAwKQogICAgcmV0dXJuIEhJR0ggOwogIGVsc2UKICAgIHJldHVybiBMT1cgOwp9CgovKgogKiBwdWxsVXBEb3duQ3RybDoKICoJQ29udHJvbCB0aGUgaW50ZXJuYWwgcHVsbC11cC9kb3duIHJlc2lzdG9ycyBvbiBhIEdQSU8gcGluCiAqCVRoZSBBcmR1aW5vIG9ubHkgaGFzIHB1bGwtdXBzIGFuZCB0aGVzZSBhcmUgZW5hYmxlZCBieSB3cml0aW5nIDEKICoJdG8gYSBwb3J0IHdoZW4gaW4gaW5wdXQgbW9kZSAtIHRoaXMgcGFyYWRpZ20gZG9lc24ndCBxdWl0ZSBhcHBseQogKgloZXJlIHRob3VnaC4KICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKi8KCnZvaWQgcHVsbFVwRG5Db250cm9sIChpbnQgcGluLCBpbnQgcHVkKQp7CiAgaW50IGdwaW9QaW4gOwoKICBpZiAoZ3Bpb1Bpbk1vZGUgPT0gV1BJX01PREVfUElOUykKICB7CiAgICBpZiAoKHBpbiA8IDApIHx8IChwaW4gPj0gTlVNX1BJTlMpKQogICAgICByZXR1cm4gOwogICAgZ3Bpb1BpbiA9IHBpblRvR3BpbyBbcGluXSA7CiAgfQogIGVsc2UKICAgIGdwaW9QaW4gPSBwaW4gOwoKICAqKGdwaW8gKyAzNykgPSBwdWQgOwogIGRlbGF5TWljcm9zZWNvbmRzICgxMCkgOwogICooZ3BpbyArIGdwaW9Ub1BVRENMSyBbZ3Bpb1Bpbl0pID0gMSA8PCBncGlvUGluIDsKICBkZWxheU1pY3Jvc2Vjb25kcyAoMTApIDsKICAKICAqKGdwaW8gKyAzNykgPSAwIDsKICAqKGdwaW8gKyBncGlvVG9QVURDTEsgW2dwaW9QaW5dKSA9IDAgOwp9CgoKLyoKICogZGVsYXk6IGRlbGF5TWljcm9zZWNvbmRzCiAqCVdhaXQgZm9yIHNvbWUgbnVtYmVyIG9mIG1pbGxpL21pY3JvIHNlY29uZHMKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKi8KCnZvaWQgZGVsYXkgKHVuc2lnbmVkIGludCBob3dMb25nKQp7CiAgc3RydWN0IHRpbWVzcGVjIHNsZWVwZXIsIGR1bW15IDsKCiAgc2xlZXBlci50dl9zZWMgID0gKHRpbWVfdCkoaG93TG9uZyAvIDEwMDApIDsKICBzbGVlcGVyLnR2X25zZWMgPSAobG9uZykoaG93TG9uZyAlIDEwMDApICogMTAwMDAwMCA7CgogIG5hbm9zbGVlcCAoJnNsZWVwZXIsICZkdW1teSkgOwp9Cgp2b2lkIGRlbGF5TWljcm9zZWNvbmRzICh1bnNpZ25lZCBpbnQgaG93TG9uZykKewogIHN0cnVjdCB0aW1lc3BlYyBzbGVlcGVyLCBkdW1teSA7CgogIHNsZWVwZXIudHZfc2VjICA9IDAgOwogIHNsZWVwZXIudHZfbnNlYyA9IChsb25nKShob3dMb25nICogMTAwMCkgOwoKICBuYW5vc2xlZXAgKCZzbGVlcGVyLCAmZHVtbXkpIDsKfQoKLyoKICogbWlsbGlzOgogKglSZXR1cm4gYSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFzIGFuIHVuc2lnbmVkIGludC4KICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgogKi8KCnVuc2lnbmVkIGludCBtaWxsaXMgKHZvaWQpCnsKICBzdHJ1Y3QgdGltZXZhbCB0diA7CiAgdW5zaWduZWQgbG9uZyBsb25nIHQxIDsKCiAgZ2V0dGltZW9mZGF5ICgmdHYsIE5VTEwpIDsKCiAgdDEgPSAodHYudHZfc2VjICogMTAwMDAwMCArIHR2LnR2X3VzZWMpIC8gMTAwMCA7CgogIHJldHVybiAodWludDMyX3QpKHQxIC0gZXBvY2gpIDsKfQ==