text:
static CGFloat const kFullscreenTransitionDuration = 0.2;

NSString *const LMMediaPlayerViewPlayButtonImageKey = @"playButtonImageKey";
NSString *const LMMediaPlayerViewPlayButtonSelectedImageKey = @"playButtonSelectedImageKey";
NSString *const LMMediaPlayerViewStopButtonImageKey = @"stopButtonImageKey";
NSString *const LMMediaPlayerViewStopButtonSelectedImageKey = @"stopButtonSelectedImageKey";
NSString *const LMMediaPlayerViewFullscreenButtonImageKey = @"fullscreenButtonImageKey";
NSString *const LMMediaPlayerViewFullscreenButtonSelectedImageKey = @"fullscreenButtonSelectedImageKey";
NSString *const LMMediaPlayerViewUnfullscreenButtonImageKey = @"unfullscreenButtonImageKey";
NSString *const LMMediaPlayerViewUnfullscreenButtonSelectedImageKey = @"unfullscreenButtonSelectedImageKey";
NSString *const LMMediaPlayerViewShuffleButtonShuffledImageKey = @"shuffleButtonShuffledImageKey";
NSString *const LMMediaPlayerViewShuffleButtonShuffledSelectedImageKey = @"shuffleButtonShuffledSelectedImageKey";
NSString *const LMMediaPlayerViewShuffleButtonUnshuffledImageKey = @"shuffleButtonUnshuffledImageKey";
NSString *const LMMediaPlayerViewShuffleButtonUnshuffledSelectedImageKey = @"shuffleButtonUnshuffledSelectedImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatOneImageKey = @"repeatButtonRepeatOneImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatOneSelectedImageKey = @"repeatButtonRepeatOneSelectedImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatAllImageKey = @"repeatButtonRepeatAllImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatAllSelectedImageKey = @"repeatButtonRepeatAllSelectedImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatNoneImageKey = @"repeatButtonRepeatNoneImageKey";
NSString *const LMMediaPlayerViewRepeatButtonRepeatNoneSelectedImageKey = @"repeatButtonRepeatNoneSelectedImageKey";

@interface UIViewController (LMMediaPlayerPrefersStatusBarHidden)

- (void)mediaPlayerPrefersStatusBarHidden:(BOOL)hidden;

@end

@interface LMMediaPlayerFullscreenViewController : UIViewController

@end

@implementation LMMediaPlayerFullscreenViewController

-(BOOL)shouldAutorotate
{
	return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
	return UIInterfaceOrientationPortrait;
}

@end

@interface LMMediaPlayerView ()
{
	BOOL userInterfaceHidden_;
	IBOutlet UILabel *playbackTimeLabel_;
	IBOutlet UILabel *remainingTimeLabel_;
	IBOutlet UIView *headerView_;
	IBOutlet UIView *footerView_;
	IBOutlet UIImageView *artworkImageView_;
	IBOutlet UIButton *playButton_;
	IBOutlet UIButton *nextButton_;
	IBOutlet UIButton *previousButton_;
	IBOutlet UIButton *shuffleButton_;
	IBOutlet UIButton *repeatButton_;
	IBOutlet UIButton *fullscreenButton_;
	BOOL fullscreen_;
	BOOL seeking_;
	BOOL needToSetPlayer_;
	UIView *superView_;
	NSMutableDictionary *buttonImages_;
	AVPlayerLayer *playerLayer_;

	UIWindow *mainWindow_;
}

@end

@implementation LMMediaPlayerView

@synthesize isFullscreen = fullscreen_;

static LMMediaPlayerView *sharedPlayerView;

+ (instancetype)sharedPlayerView
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		sharedPlayerView = [[self class] create];
	});
	return sharedPlayerView;
}

+ (instancetype)create
{
	return [[UINib nibWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]] instantiateWithOwner:nil options:nil][0];
}

- (instancetype)initWithFrame:(CGRect)frame
{
	self = [super initWithFrame:frame];
	if (self) {
		[self setup];
	}

	return self;
}

- (void)drawRect:(CGRect)rect
{
	[super drawRect:rect];

	if (needToSetPlayer_) {
		[playerLayer_ setPlayer:self.mediaPlayer.corePlayer];
	}
}

- (void)dealloc
{
	_mediaPlayer.delegate = nil;
	[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
	[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];

	LM_RELEASE(playbackTimeLabel_);
	LM_RELEASE(remainingTimeLabel_);
	LM_RELEASE(headerView_);
	LM_RELEASE(footerView_);
	LM_RELEASE(artworkImageView_);
	LM_RELEASE(playButton_);
	LM_RELEASE(nextButton_);
	LM_RELEASE(previousButton_);
	LM_RELEASE(shuffleButton_);
	LM_RELEASE(repeatButton_);
	LM_RELEASE(fullscreenButton_);
	LM_RELEASE(_mediaPlayer);
	LM_RELEASE(buttonImages_);
	LM_DEALLOC(super);
}

- (void)awakeFromNib
{
	[super awakeFromNib];
	[self setup];
	[self setupUserInterface];
}

- (void)layoutSubviews
{
	// resize your layers based on the view's new bounds
	[super layoutSubviews];
	playerLayer_.frame = self.bounds;
}

#pragma mark -

- (void)setup
{
	UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reverseUserInterfaceHidden)];
	[self addGestureRecognizer:gesture];
	LM_RELEASE(gesture);

	[self setTranslatesAutoresizingMaskIntoConstraints:YES];
	self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

	mainWindow_ = [[UIApplication sharedApplication] keyWindow];
	if (mainWindow_ == nil) {
		mainWindow_ = [[UIApplication sharedApplication] windows][0];
	}
	LM_RETAIN(mainWindow_);

	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mediaPlayerBecomeForgroundMode:) name:UIApplicationWillEnterForegroundNotification object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mediaPlayerBecomeBackgroundMode:) name:UIApplicationDidEnterBackgroundNotification object:nil];

	needToSetPlayer_ = NO;
	userInterfaceHidden_ = NO;

	_mediaPlayer = [[LMMediaPlayer alloc] init];
	_mediaPlayer.delegate = self;
}

- (void)setupUserInterface
{
	artworkImageView_.contentMode = UIViewContentModeScaleAspectFit;

	[_currentTimeSlider addTarget:self action:@selector(beginSeek:) forControlEvents:UIControlEventTouchDown];
	[_currentTimeSlider addTarget:self action:@selector(seekPositionChanged:) forControlEvents:UIControlEventValueChanged];
	[_currentTimeSlider addTarget:self action:@selector(endSeek:) forControlEvents:UIControlEventTouchUpInside];

	[playButton_ addTarget:self action:@selector(changePlaybackState:) forControlEvents:UIControlEventTouchUpInside];
	[nextButton_ addTarget:self action:@selector(fourcePlayNextMedia) forControlEvents:UIControlEventTouchUpInside];
	[previousButton_ addTarget:self	action:@selector(fourcePlayPreviousMedia) forControlEvents:UIControlEventTouchUpInside];

	UIColor *backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.400];
	footerView_.backgroundColor = headerView_.backgroundColor = backgroundColor;
	nextButton_.backgroundColor = previousButton_.backgroundColor = backgroundColor;

	[_mediaPlayer setShuffleEnabled:NO];
	[_mediaPlayer setRepeatMode:LMMediaRepeatModeNone];

	buttonImages_ = [@{LMMediaPlayerViewPlayButtonImageKey						:	[[self class] getImageForFilename:@"play"],
					   LMMediaPlayerViewPlayButtonSelectedImageKey				:	[[self class] getImageForFilename:@"play"],
					   LMMediaPlayerViewStopButtonImageKey						:	[[self class] getImageForFilename:@"pause"],
					   LMMediaPlayerViewStopButtonSelectedImageKey				:	[[self class] getImageForFilename:@"pause"],
					   LMMediaPlayerViewShuffleButtonShuffledImageKey			:	[[self class] getImageForFilename:@"shuffle"],
					   LMMediaPlayerViewShuffleButtonShuffledSelectedImageKey	:	[[self class] getImageForFilename:@"shuffle"],
					   LMMediaPlayerViewShuffleButtonUnshuffledImageKey			:	[[self class] getImageForFilename:@"unshuffle"],
					   LMMediaPlayerViewShuffleButtonUnshuffledSelectedImageKey	:	[[self class] getImageForFilename:@"unshuffle"],
					   LMMediaPlayerViewRepeatButtonRepeatNoneImageKey			:	[[self class] getImageForFilename:@"repeat_none"],
					   LMMediaPlayerViewRepeatButtonRepeatNoneSelectedImageKey	:	[[self class] getImageForFilename:@"repeat_none"],
					   LMMediaPlayerViewRepeatButtonRepeatOneImageKey			:	[[self class] getImageForFilename:@"repeat_one"],
					   LMMediaPlayerViewRepeatButtonRepeatOneSelectedImageKey	:	[[self class] getImageForFilename:@"repeat_one"],
					   LMMediaPlayerViewRepeatButtonRepeatAllImageKey			:	[[self class] getImageForFilename:@"repeat_all"],
					   LMMediaPlayerViewRepeatButtonRepeatAllSelectedImageKey	:	[[self class] getImageForFilename:@"repeat_all"],
					   LMMediaPlayerViewFullscreenButtonImageKey				:	[[self class] getImageForFilename:@"fullscreen"],
					   LMMediaPlayerViewFullscreenButtonSelectedImageKey		:	[[self class] getImageForFilename:@"fullscreen"],
					   LMMediaPlayerViewUnfullscreenButtonImageKey				:	[[self class] getImageForFilename:@"unfullscreen"],
					   LMMediaPlayerViewUnfullscreenButtonSelectedImageKey		:	[[self class] getImageForFilename:@"unfullscreen"]
					   } mutableCopy];

	[playButton_.imageView setContentMode:UIViewContentModeScaleAspectFit];
	[playButton_ setImage:buttonImages_[LMMediaPlayerViewPlayButtonImageKey] forState:UIControlStateNormal];
	[playButton_ setImage:buttonImages_[LMMediaPlayerViewPlayButtonSelectedImageKey] forState:UIControlStateSelected];

	[fullscreenButton_.imageView setContentMode:UIViewContentModeScaleAspectFit];
	[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewFullscreenButtonImageKey] forState:UIControlStateNormal];
	[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewFullscreenButtonSelectedImageKey] forState:UIControlStateSelected];

	[repeatButton_.imageView setContentMode:UIViewContentModeScaleAspectFit];
	[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneImageKey] forState:UIControlStateNormal];
	[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneSelectedImageKey] forState:UIControlStateSelected];

	[shuffleButton_.imageView setContentMode:UIViewContentModeScaleAspectFit];
	[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledImageKey] forState:UIControlStateNormal];
	[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledSelectedImageKey] forState:UIControlStateSelected];
}

- (void)mediaPlayerBecomeForgroundMode:(NSNotification *)notification
{
	needToSetPlayer_ = YES;
	[self setNeedsDisplay];
}

- (void)mediaPlayerBecomeBackgroundMode:(NSNotification *)notification
{
	double delayInSeconds = 0.01;
	dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
	dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
		[playerLayer_ setPlayer:nil];
		if (self.mediaPlayer.playbackState == LMMediaPlaybackStatePlaying) {
			[self.mediaPlayer play];
		}
	});
}

#pragma mark LMMediaPlayerDelegate

- (void)mediaPlayerWillChangeState:(LMMediaPlaybackState)state
{
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewWillChangeState:state:)]) {
		[self.delegate mediaPlayerViewWillChangeState:self state:state];
	}

	if (state == LMMediaPlaybackStateStopped || state == LMMediaPlaybackStatePaused) {
		[playButton_ setImage:buttonImages_[LMMediaPlayerViewPlayButtonImageKey] ?: nil forState:UIControlStateNormal];
		[playButton_ setImage:buttonImages_[LMMediaPlayerViewPlayButtonSelectedImageKey] ?: nil forState:UIControlStateSelected];
	}
	else {
		[playButton_ setImage:buttonImages_[LMMediaPlayerViewStopButtonImageKey] ?: nil forState:UIControlStateNormal];
		[playButton_ setImage:buttonImages_[LMMediaPlayerViewStopButtonSelectedImageKey] ?: nil forState:UIControlStateSelected];
	}
}

- (BOOL)mediaPlayerWillStartPlaying:(LMMediaPlayer *)player media:(LMMediaItem *)media
{
	BOOL result = NO;
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewWillStartPlaying:media:)] == YES) {
		result = [self.delegate mediaPlayerViewWillStartPlaying:self media:media];
	}
	else {
		result = YES;
	}

	return result;
}

- (void)mediaPlayerDidStartPlaying:(LMMediaPlayer *)player media:(LMMediaItem *)media
{
	if (media.isVideo) {
		artworkImageView_.hidden = YES;
		self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
		[playerLayer_ removeFromSuperlayer];
		playerLayer_ = [AVPlayerLayer playerLayerWithPlayer:player.corePlayer];
		playerLayer_.frame = self.frame;
		[self.layer insertSublayer:playerLayer_ atIndex:0];

		playerLayer_.hidden = NO;
	}
	else {
		playerLayer_.hidden = YES;
		artworkImageView_.hidden = NO;
		artworkImageView_.image = [media getArtworkImageWithSize:self.frame.size];
	}
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidStartPlaying:media:)]) {
		[self.delegate mediaPlayerViewDidStartPlaying:self media:media];
	}
}

- (void)mediaPlayerDidFinishPlaying:(LMMediaPlayer *)player media:(LMMediaItem *)media
{
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidFinishPlaying:media:)]) {
		[self.delegate mediaPlayerViewDidFinishPlaying:self media:media];
	}
}

- (void)mediaPlayerDidChangeCurrentTime:(LMMediaPlayer *)player
{
	if (seeking_ == NO) {
		_currentTimeSlider.value = player.currentPlaybackTime / player.currentPlaybackDuration;

		NSMutableString *durationString = [NSMutableString new];
		NSInteger duration = (NSInteger)player.currentPlaybackTime;
		if (duration / (60 * 60) > 0) {
			[durationString appendFormat:@"%02ld:",
			 (long int)duration / (60 * 60)];
			duration /= 60 * 60;
		}
		[durationString appendFormat:@"%02ld:", (long int)duration / 60];
		duration %= 60;
		[durationString appendFormat:@"%02ld", (long int)duration];
		playbackTimeLabel_.text = durationString;
		LM_RELEASE(durationString);

		durationString = [[NSMutableString alloc] initWithString:@"-"];
		duration = (NSInteger)fabs(player.currentPlaybackTime - player.currentPlaybackDuration);
		if (duration / (60 * 60) > 0) {
			[durationString appendFormat:@"%02ld:",
			 (long int)duration / (60 * 60)];
			duration /= 60 * 60;
		}
		[durationString appendFormat:@"%02ld:", (long int)duration / 60];
		duration %= 60;
		[durationString appendFormat:@"%02ld", (long int)duration];
		remainingTimeLabel_.text = durationString;
		LM_RELEASE(durationString);
	}
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidChangeCurrentTime:)]) {
		[self.delegate mediaPlayerViewDidChangeCurrentTime:self];
	}
}

- (void)mediaPlayerDidChangeRepeatMode:(LMMediaRepeatMode)mode player:(LMMediaPlayer *)player
{
	[self setRepeatButtonImageWithRepeatMode:mode];
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidChangeRepeatMode:playerView:)]) {
		[self.delegate mediaPlayerViewDidChangeRepeatMode:mode playerView:self];
	}
}

- (void)mediaPlayerDidChangeShuffleMode:(BOOL)enabled player:(LMMediaPlayer *)player
{
	[self setShuggleButtonImageWithShuffleMode:enabled];
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidChangeShuffleMode:playerView:)]) {
		[self.delegate mediaPlayerViewDidChangeShuffleMode:enabled playerView:self];
	}
}

#pragma mark -

- (void)beginSeek:(id)sender
{
	seeking_ = YES;
}

- (void)seekPositionChanged:(id)sender
{
	NSMutableString *durationString = [NSMutableString new];
	NSInteger currentTime = (NSInteger)_mediaPlayer.currentPlaybackDuration * _currentTimeSlider.value;
	NSInteger duration = currentTime;
	if (duration / (60 * 60) > 0) {
		[durationString appendFormat:@"%02ld:",
		 (long int)duration / (60 * 60)];
		duration /= 60 * 60;
	}
	[durationString appendFormat:@"%02ld:", (long int)duration / 60];
	duration %= 60;
	[durationString appendFormat:@"%02ld", (long int)duration];
	playbackTimeLabel_.text = durationString;
	LM_RELEASE(durationString);

	durationString = [[NSMutableString alloc] initWithString:@"-"];
	duration = (NSInteger)_mediaPlayer.currentPlaybackDuration - currentTime;
	if (duration / (60 * 60) > 0) {
		[durationString appendFormat:@"%02ld:",
		 (long int)duration / (60 * 60)];
		duration /= 60 * 60;
	}
	[durationString appendFormat:@"%02ld:", (long int)duration / 60];
	duration %= 60;
	[durationString appendFormat:@"%02ld", (long int)duration];
	remainingTimeLabel_.text = durationString;
	LM_RELEASE(durationString);
}

- (void)endSeek:(id)sender
{
	UISlider *slider = (UISlider *)sender;
	[_mediaPlayer seekTo:_mediaPlayer.currentPlaybackDuration * slider.value];
	seeking_ = NO;
}

- (void)changePlaybackState:(id)sender
{
	if ([_mediaPlayer playbackState] == LMMediaPlaybackStatePlaying) {
		[_mediaPlayer pause];
	}
	else if ([_mediaPlayer playbackState] == LMMediaPlaybackStatePaused || [_mediaPlayer playbackState] == LMMediaPlaybackStateStopped) {
		[_mediaPlayer play];
	}
}

- (void)reverseUserInterfaceHidden
{
	[self setUserInterfaceHidden:!userInterfaceHidden_];
}

- (void)fourcePlayNextMedia
{
	LMMediaRepeatMode repeatMode = _mediaPlayer.repeatMode;
	if (repeatMode == LMMediaRepeatModeOne) {
		_mediaPlayer.repeatMode = LMMediaRepeatModeNone;
	}
	[_mediaPlayer playNextMedia];
	_mediaPlayer.repeatMode = repeatMode;
}

- (void)fourcePlayPreviousMedia
{
	LMMediaRepeatMode repeatMode = _mediaPlayer.repeatMode;
	if (repeatMode == LMMediaRepeatModeOne) {
		_mediaPlayer.repeatMode = LMMediaRepeatModeNone;
	}
	[_mediaPlayer playPreviousMedia];
	_mediaPlayer.repeatMode = repeatMode;
}

- (IBAction)shuffleButtonPressed:(id)sender
{
	[_mediaPlayer setShuffleEnabled:!_mediaPlayer.shuffleMode];

	if (_mediaPlayer.shuffleMode) {
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonShuffledImageKey] forState:UIControlStateNormal];
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonShuffledSelectedImageKey] forState:UIControlStateSelected];
	}
	else {
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledImageKey] forState:UIControlStateNormal];
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledSelectedImageKey] forState:UIControlStateSelected];
	}
	[self setRepeatButtonImageWithRepeatMode:_mediaPlayer.repeatMode];
}

- (IBAction)repeatButtonPressed:(id)sender
{
	switch (_mediaPlayer.repeatMode) {
		case LMMediaRepeatModeAll: {
			_mediaPlayer.repeatMode = LMMediaRepeatModeOne;
		}
			break;
		case LMMediaRepeatModeOne: {
			_mediaPlayer.repeatMode = LMMediaRepeatModeNone;
		}
			break;
		case LMMediaRepeatModeNone: {
			_mediaPlayer.repeatMode = LMMediaRepeatModeAll;
		}
			break;
		default:
			break;
	}
	[self setRepeatButtonImageWithRepeatMode:_mediaPlayer.repeatMode];
}

- (void)setShuggleButtonImageWithShuffleMode:(BOOL)mode
{
	if (mode) {
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonShuffledImageKey] forState:UIControlStateNormal];
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonShuffledSelectedImageKey] forState:UIControlStateSelected];
	}
	else {
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledImageKey] forState:UIControlStateNormal];
		[shuffleButton_ setImage:buttonImages_[LMMediaPlayerViewShuffleButtonUnshuffledSelectedImageKey] forState:UIControlStateSelected];
	}
}

- (void)setRepeatButtonImageWithRepeatMode:(LMMediaRepeatMode)mode
{
	switch (_mediaPlayer.repeatMode) {
		case LMMediaRepeatModeAll: {
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatAllImageKey] forState:UIControlStateNormal];
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatAllSelectedImageKey] forState:UIControlStateSelected];
		}
			break;
		case LMMediaRepeatModeOne: {
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatOneImageKey] forState:UIControlStateNormal];
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatOneSelectedImageKey] forState:UIControlStateSelected];
		}
			break;
		case LMMediaRepeatModeNone: {
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneImageKey] forState:UIControlStateNormal];
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneSelectedImageKey] forState:UIControlStateSelected];
		}
			break;
		default: {
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneImageKey] forState:UIControlStateNormal];
			[repeatButton_ setImage:buttonImages_[LMMediaPlayerViewRepeatButtonRepeatNoneSelectedImageKey] forState:UIControlStateSelected];
		}
			break;
	}
}

- (IBAction)fullscreenButtonPressed:(id)sender
{
	[self setFullscreen:!fullscreen_];
}

#pragma mark -

- (void)setHeaderViewHidden:(BOOL)hidden
{
	headerView_.hidden = hidden;
}

- (void)setFooterViewHidden:(BOOL)hidden
{
	footerView_.hidden = hidden;
}

- (void)setUserInterfaceHidden:(BOOL)hidden
{
	userInterfaceHidden_ = hidden;
	if (hidden) {
		[UIView animateWithDuration:0.3 animations:^{
			headerView_.alpha = 0;
			footerView_.alpha = 0;
			_currentTimeSlider.alpha = 0;
			previousButton_.alpha = 0;
			nextButton_.alpha = 0;
		} completion:^(BOOL finished) {
		}];
	}
	else {
		[UIView animateWithDuration:0.3 animations:^{
			headerView_.alpha = 1;
			footerView_.alpha = 1;
			_currentTimeSlider.alpha = 1;
			previousButton_.alpha = 1;
			nextButton_.alpha = 1;
		} completion:^(BOOL finished) {
		}];
	}
}

- (void)setFullscreen:(BOOL)fullscreen animated:(BOOL)animated
{
	if (fullscreen_ == fullscreen) {
		return;
	}

	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewWillChangeFullscreenMode:)]) {
		[self.delegate mediaPlayerViewWillChangeFullscreenMode:fullscreen];
	}

	LMMediaPlayerFullscreenViewController *viewController = [[LMMediaPlayerFullscreenViewController alloc] init];
	LM_AUTORELEASE(viewController);
	viewController.view.frame = [UIScreen mainScreen].bounds;

	if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_7_0) {
		viewController.extendedLayoutIncludesOpaqueBars = YES;
	}
	else {
		viewController.wantsFullScreenLayout = YES;
	}

	CGRect newRect;
	if (fullscreen == NO) {
		[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewFullscreenButtonImageKey] forState:UIControlStateNormal];
		[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewFullscreenButtonSelectedImageKey] forState:UIControlStateSelected];

		newRect = superView_.bounds;
		self.frame = newRect;
		[superView_ addSubview:self];
		LM_RELEASE(superView_);
		[mainWindow_ makeKeyAndVisible];
		[[[UIApplication sharedApplication] delegate] setWindow:mainWindow_];
		[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
		[[UIApplication sharedApplication] setStatusBarOrientation:[mainWindow_ rootViewController].interfaceOrientation];
		[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
	}
	else {
		[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewUnfullscreenButtonImageKey] forState:UIControlStateNormal];
		[fullscreenButton_ setImage:buttonImages_[LMMediaPlayerViewUnfullscreenButtonSelectedImageKey] forState:UIControlStateSelected];
		superView_ = self.superview;
		LM_RETAIN(superView_);
		newRect = mainWindow_.frame;

		UIViewController *rootViewController = [mainWindow_ rootViewController];
		UIInterfaceOrientation orientation = rootViewController.interfaceOrientation;

		if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft) {
			if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_7_0) {
				newRect = CGRectMake(0, 0, CGRectGetWidth(mainWindow_.frame), CGRectGetHeight(mainWindow_.frame));
			}
			else {
				newRect = CGRectMake(0, 0, CGRectGetHeight(mainWindow_.frame), CGRectGetWidth(mainWindow_.frame));
			}
		}

		[self removeFromSuperview];
		[viewController.view addSubview:self];
		UIWindow *newWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
		newWindow.windowLevel = UIWindowLevelAlert;
		newWindow.rootViewController = viewController;
		[newWindow addSubview:viewController.view];
		[newWindow makeKeyAndVisible];
		[[[UIApplication sharedApplication] delegate] setWindow:newWindow];
		LM_RELEASE(newWindow);
	}
	self.frame = newRect;
	if (animated) {
		self.alpha = 0;
		[UIView animateWithDuration:kFullscreenTransitionDuration animations:^{
			self.alpha = 1;
		}];
	}
	fullscreen_ = fullscreen;
	if ([self.delegate respondsToSelector:@selector(mediaPlayerViewDidChangeFullscreenMode:)]) {
		[self.delegate mediaPlayerViewDidChangeFullscreenMode:fullscreen];
	}
	[[UIApplication sharedApplication] setStatusBarHidden:fullscreen];
	[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];
}

- (void)setFullscreen:(BOOL)fullscreen
{
	[self setFullscreen:fullscreen animated:NO];
}

- (void)setButtonImages:(NSDictionary *)info
{
	for (NSString *key in info) {
		buttonImages_[key] = info[key];
	}
}

+ (UIImage *)getImageForFilename:(NSString *)filename
{
	NSString *version = @"7";
	if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
		version = @"6";
	}
	UIImage *image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@/%@.png", [[NSBundle mainBundle] pathForResource:@"LMMediaPlayerView" ofType:@"bundle"], version, filename]];

	return image;
}

@end


text:
{-# LANGUAGE TemplateHaskell  #-}
{-# LANGUAGE TypeApplications #-}

module Test.Pos.Infra.Bi
       ( tests
       ) where

import           Universum

import           Hedgehog (Property)
import qualified Hedgehog as H
import           Pos.Infra.Communication.Types.Protocol (HandlerSpec (..))
import qualified Prelude
import           Test.Pos.Binary.Helpers.GoldenRoundTrip (goldenTestBi,
                     roundTripsBiBuildable)
import           Test.Pos.Infra.Gen (genHandlerSpec)
import           Test.Pos.Util.Golden (discoverGolden, eachOf)
import           Test.Pos.Util.Tripping (discoverRoundTrip)

--------------------------------------------------------------------------------
-- HandlerSpec
--------------------------------------------------------------------------------

golden_HandlerSpec_ConvHandler :: Property
golden_HandlerSpec_ConvHandler =
    goldenTestBi exampleConvHandler "test/golden/HandlerSpec_ConvHandler"
  where
    exampleConvHandler = ConvHandler 15553

golden_HandlerSpec_UnknownHandler :: Property
golden_HandlerSpec_UnknownHandler =
    goldenTestBi exampleUnknownHandler "test/golden/HandlerSpec_UnknownHandler"
  where
    exampleUnknownHandler = UnknownHandler 104 Prelude.$ encodeUtf8 @String @ByteString "\248U=\232\167\t"

roundTripHandlerSpecBi :: Property
roundTripHandlerSpecBi = eachOf 1000 genHandlerSpec roundTripsBiBuildable

-----------------------------------------------------------------------
-- Main test export
-----------------------------------------------------------------------

tests :: IO Bool
tests = and <$> sequence
    [ H.checkSequential $$discoverGolden
    , H.checkParallel $$discoverRoundTrip
    ]

redpajama_set_name: RedPajamaGithub


text:
********************************************************************************
	Project owner:		RageQuit community
	Project name: 		GTW-RPG
	Developers:   		Mr_Moose

	Source code:		https://github.com/GTWCode/GTW-RPG/
	Bugtracker: 		http://forum.404rq.com/bug-reports/
	Suggestions:		http://forum.404rq.com/mta-servers-development/

	Version:    		Open source
	License:    		BSD 2-Clause
	Status:     		Stable release
********************************************************************************
]]--

-- Define the menu GUI window
local sx,sy = guiGetScreenSize()
local win_menu = guiCreateWindow((sx-320)/2, (sy-297)/2, 320, 297, "Restaurant menu", false)
guiSetVisible(win_menu, false)

-- Define the menu buttons
btn_close = guiCreateButton(210,257,100,36,"Close",false,win_menu)
btn_choice_1 = guiCreateButton(10,100,160,36, "Buster("..prices[1].."$)",false,win_menu)
btn_choice_2 = guiCreateButton(10,217,160,36, "Double D-Luxe("..prices[2].."$)",false,win_menu)
btn_choice_3 = guiCreateButton(170,100,160,36, "Full rack("..prices[3].."$)",false,win_menu)
btn_choice_4 = guiCreateButton(170,217,160,36, "Sallad meal("..prices[4].."$)",false,win_menu)

-- Apply GTWgui styles
exports.GTWgui:setDefaultFont(btn_close, 10)
exports.GTWgui:setDefaultFont(btn_choice_1, 10)
exports.GTWgui:setDefaultFont(btn_choice_2, 10)
exports.GTWgui:setDefaultFont(btn_choice_3, 10)
exports.GTWgui:setDefaultFont(btn_choice_4, 10)

--[[ Update the GUI depending on restaurant type ]]--
function initialize_menu_choices(r_type)
	-- Set the text and prices on buttons and window title
	guiSetText(win_menu, menu_choices[r_type]["title"])
	guiSetText(btn_choice_1, menu_choices[r_type]["choice_1"][1]..", "..prices[1].."$")
	guiSetText(btn_choice_2, menu_choices[r_type]["choice_2"][1]..", "..prices[2].."$)")
	guiSetText(btn_choice_3, menu_choices[r_type]["choice_3"][1]..", "..prices[3].."$)")
	guiSetText(btn_choice_4, menu_choices[r_type]["choice_4"][1]..", "..prices[4].."$)")

	-- Destroy current images if any
	if img1 and isElement(img1) then destroyElement(img1) end
	if img2 and isElement(img2) then destroyElement(img2) end
	if img3 and isElement(img3) then destroyElement(img3) end
	if img4 and isElement(img4) then destroyElement(img4) end

	-- Make new images, (load from files when needed)
	img1 = guiCreateStaticImage(10, 23, 160, 77, menu_choices[r_type]["choice_1"][2], false, win_menu)
	img2 = guiCreateStaticImage(10,140, 160, 77, menu_choices[r_type]["choice_2"][2], false, win_menu)
	img3 = guiCreateStaticImage(170, 23, 160, 77, menu_choices[r_type]["choice_3"][2], false, win_menu)
	img4 = guiCreateStaticImage(170, 140, 160, 77, menu_choices[r_type]["choice_4"][2], false, win_menu)
end

--[[ Open the menu GUI to choose food ]]--
function open_menu(plr, r_type)
	initialize_menu_choices(r_type)
	guiSetVisible(win_menu, true)
	showCursor(true)
end
addEvent("GTWfastfood.gui.show",true)
addEventHandler("GTWfastfood.gui.show", root, open_menu)

--[[ Close the menu ]]--
function close_menu()
	guiSetVisible(win_menu, false)
	showCursor(false)
end
addEvent("GTWfastfood.gui.hide", true)
addEventHandler("GTWfastfood.gui.hide", root, close_menu)

--[[ Handle menu click ]]--
function menu_click()
	-- Make sure that the player can afford his food
	local money = getPlayerMoney(localPlayer)

	-- Shall we close this menu?
   	if source == btn_close then
   		guiSetVisible(win_menu, false)
   		showCursor(false)
		return
	end

	-- Alright, let's continue shopping, can I take your order?
	local ID_choice = 1
   	if source == btn_choice_1 then ID_choice = 1 end
	if source == btn_choice_2 then ID_choice = 2 end
	if source == btn_choice_3 then ID_choice = 3 end
	if source == btn_choice_4 then ID_choice = 4 end

	-- Take care of the order server side
   	if money > prices[ID_choice] and not isTimer(cooldown) then
   		triggerServerEvent("GTWfastfood.buy", localPlayer, prices[ID_choice], health[ID_choice])
   		cooldown = setTimer(function() end, 200, 1)
  	end
end
addEventHandler("onClientGUIClick", btn_close, menu_click)
addEventHandler("onClientGUIClick", btn_choice_1, menu_click)
addEventHandler("onClientGUIClick", btn_choice_2, menu_click)
addEventHandler("onClientGUIClick", btn_choice_3, menu_click)
addEventHandler("onClientGUIClick", btn_choice_4, menu_click)

--[[ Protect fastfood workers from being killed ]]--
function protect_worker(attacker)
	if not getElementData(source, "GTWfastfood.isWorker") then return end
	cancelEvent() -- cancel any damage done to peds
end
addEventHandler("onClientPedWasted", root, protect_worker)


text:
class Tree
  include Mongoid::Document

  field :name
  field :evergreen, type: Boolean

  scope :verdant, where(evergreen: true)
  default_scope asc(:name)
end


text:
#!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
#
# virtiostat    Show virtio devices input/output statistics.
#               For Linux, uses BCC, eBPF.
#
# USAGE: virtiostat [-h] [-T] [-D] [-d DRIVER] [-n DEVNAME] [INTERVAL] [COUNT]
#
# Copyright (c) 2021 zhenwei pi
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 13-Feb-2021  zhenwei pi  Created this.

from __future__ import print_function
from bcc import BPF
from time import sleep, strftime
import argparse

# arguments
examples = """examples:
    ./virtiostat                 # print 3(default) second summaries
    ./virtiostat  1  10          # print 1 second summaries, 10 times
    ./virtiostat -T              # show timestamps
    ./virtiostat -d virtio_blk   # only show virtio block devices
    ./virtiostat -n virtio0      # only show virtio0 device
    ./virtiostat -D              # show debug bpf text
"""
parser = argparse.ArgumentParser(
    description="Show virtio devices input/output statistics",
    formatter_class=argparse.RawDescriptionHelpFormatter,
    epilog=examples)
parser.add_argument("interval", nargs="?", default=3,
    help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999,
    help="number of outputs")
parser.add_argument("-T", "--timestamp", action="store_true",
    help="show timestamp on output")
parser.add_argument("-d", "--driver",
    help="filter for driver name")
parser.add_argument("-n", "--devname",
    help="filter for device name")
parser.add_argument("-D", "--debug", action="store_true",
    help="print BPF program before starting (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
    help=argparse.SUPPRESS)
args = parser.parse_args()

# define BPF program
bpf_text = """
#ifndef KBUILD_MODNAME
#define KBUILD_MODNAME "bcc"
#endif
#include <linux/virtio.h>
#include <bcc/proto.h>

/* typically virtio scsi has max SGs of 6 */
#define VIRTIO_MAX_SGS  6
/* typically virtio blk has max SEG of 128 */
#define SG_MAX          128

/* local strcmp function, max length 16 to protect instruction loops */
#define CMPMAX	16

static int local_strcmp(const char *cs, const char *ct)
{
    int len = 0;
    unsigned char c1, c2;

    while (len++ < CMPMAX) {
        c1 = *cs++;
        c2 = *ct++;
        if (c1 != c2)
            return c1 < c2 ? -1 : 1;
        if (!c1)
            break;
    }
    return 0;
}

typedef struct virtio_stat {
    char driver[16];
    char dev[12];
    char vqname[12];
    u32 in_sgs;
    u32 out_sgs;
    u64 in_bw;
    u64 out_bw;
} virtio_stat_t;

BPF_HASH(stats, u64, virtio_stat_t);

static struct scatterlist *__sg_next(struct scatterlist *sgp)
{
    struct scatterlist sg;

    bpf_probe_read_kernel(&sg, sizeof(sg), sgp);
    if (sg_is_last(&sg))
        return NULL;

    sgp++;

    bpf_probe_read_kernel(&sg, sizeof(sg), sgp);
    if (unlikely(sg_is_chain(&sg)))
        sgp = sg_chain_ptr(&sg);

    return sgp;
}

static u64 count_len(struct scatterlist **sgs, unsigned int num)
{
    u64 length = 0;
    unsigned int i, n;
    struct scatterlist *sgp = NULL;

    for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) {
        for (n = 0, sgp = sgs[i]; sgp && (n < SG_MAX); sgp = __sg_next(sgp)) {
            length += sgp->length;
            n++;
        }

        /* Suggested by Yonghong Song:
         * IndVarSimplifyPass with clang 12 may cause verifier failure:
         *   ; for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) { // Line  60
         *   90:   15 08 15 00 00 00 00 00 if r8 == 0 goto +21
         *   91:   bf 81 00 00 00 00 00 00 r1 = r8
         *   92:   07 01 00 00 ff ff ff ff r1 += -1
         *   93:   67 01 00 00 20 00 00 00 r1 <<= 32
         *   94:   77 01 00 00 20 00 00 00 r1 >>= 32
         *   95:   b7 02 00 00 05 00 00 00 r2 = 5
         *   96:   2d 12 01 00 00 00 00 00 if r2 > r1 goto +1
         *   97:   b7 08 00 00 06 00 00 00 r8 = 6
         *   98:   b7 02 00 00 00 00 00 00 r2 = 0
         *   99:   b7 09 00 00 00 00 00 00 r9 = 0
         *  100:   7b 8a 68 ff 00 00 00 00 *(u64 *)(r10 - 152) = r8
         *  101:   05 00 35 00 00 00 00 00 goto +53
         * Note that r1 is refined by r8 is saved to stack for later use.
         * This will give verifier u64_max loop bound and eventually cause
         * verification failure. Workaround with the below asm code.
         */
#if __clang_major__ >= 7
        asm volatile("" : "=r"(i) : "0"(i));
#endif
    }

    return length;
}

static void record(struct virtqueue *vq, struct scatterlist **sgs,
                   unsigned int out_sgs, unsigned int in_sgs)
{
    virtio_stat_t newvs = {0};
    virtio_stat_t *vs;
    u64 key = (u64)vq;
    u64 in_bw = 0;

    DRIVERFILTER
    DEVNAMEFILTER

    /* Workaround: separate two count_len() calls, one here and the
     * other below. Otherwise, compiler may generate some spills which
     * harms verifier pruning. This happens in llvm12, but not llvm4.
     * Below code works on both cases.
     */
    if (in_sgs)
        in_bw = count_len(sgs + out_sgs, in_sgs);

    vs = stats.lookup(&key);
    if (!vs) {
        bpf_probe_read_kernel_str(newvs.driver, sizeof(newvs.driver), vq->vdev->dev.driver->name);
        bpf_probe_read_kernel_str(newvs.dev, sizeof(newvs.dev), vq->vdev->dev.kobj.name);
        bpf_probe_read_kernel_str(newvs.vqname, sizeof(newvs.vqname), vq->name);
        newvs.out_sgs = out_sgs;
        newvs.in_sgs = in_sgs;
        if (out_sgs)
            newvs.out_bw = count_len(sgs, out_sgs);
        newvs.in_bw = in_bw;
        stats.update(&key, &newvs);
    } else {
        vs->out_sgs += out_sgs;
        vs->in_sgs += in_sgs;
        if (out_sgs)
            vs->out_bw += count_len(sgs, out_sgs);
        vs->in_bw += in_bw;
    }
}

int trace_virtqueue_add_sgs(struct pt_regs *ctx, struct virtqueue *vq,
                            struct scatterlist **sgs, unsigned int out_sgs,
                            unsigned int in_sgs, void *data, gfp_t gfp)

{
    record(vq, sgs, out_sgs, in_sgs);

    return 0;
}

int trace_virtqueue_add_outbuf(struct pt_regs *ctx, struct virtqueue *vq,
                              struct scatterlist *sg, unsigned int num,
                              void *data, gfp_t gfp)
{
    record(vq, &sg, 1, 0);

    return 0;
}

int trace_virtqueue_add_inbuf(struct pt_regs *ctx, struct virtqueue *vq,
                             struct scatterlist *sg, unsigned int num,
                             void *data, gfp_t gfp)
{
    record(vq, &sg, 0, 1);

    return 0;
}

int trace_virtqueue_add_inbuf_ctx(struct pt_regs *ctx, struct virtqueue *vq,
                                  struct scatterlist *sg, unsigned int num,
                                  void *data, void *_ctx, gfp_t gfp)
{
    record(vq, &sg, 0, 1);

    return 0;
}
"""

# filter for driver name
if args.driver:
    bpf_text = bpf_text.replace('DRIVERFILTER',
        """char filter_driver[] = \"%s\";
        char driver[16];
        bpf_probe_read_kernel_str(driver, sizeof(driver), vq->vdev->dev.driver->name);
        if (local_strcmp(filter_driver, driver))
        return;""" % (args.driver))
else:
    bpf_text = bpf_text.replace('DRIVERFILTER', '')

# filter for dev name
if args.devname:
    bpf_text = bpf_text.replace('DEVNAMEFILTER',
        """char filter_devname[] = \"%s\";
        char devname[16];
        bpf_probe_read_kernel_str(devname, sizeof(devname), vq->vdev->dev.kobj.name);
        if (local_strcmp(filter_devname, devname))
        return;""" % (args.devname))
else:
    bpf_text = bpf_text.replace('DEVNAMEFILTER', '')

# debug mode: print bpf text
if args.debug:
    print(bpf_text)

# dump mode: print bpf text and exit
if args.ebpf:
    print(bpf_text)
    exit()

# load BPF program
b = BPF(text=bpf_text)
b.attach_kprobe(event="virtqueue_add_sgs", fn_name="trace_virtqueue_add_sgs")
b.attach_kprobe(event="virtqueue_add_outbuf", fn_name="trace_virtqueue_add_outbuf")
b.attach_kprobe(event="virtqueue_add_inbuf", fn_name="trace_virtqueue_add_inbuf")
b.attach_kprobe(event="virtqueue_add_inbuf_ctx", fn_name="trace_virtqueue_add_inbuf_ctx")

print("Tracing virtio devices statistics ... Hit Ctrl-C to end.")

# start main loop
exiting = 0 if args.interval else 1
seconds = 0
while (1):
    try:
        sleep(int(args.interval))
        seconds = seconds + int(args.interval)
    except KeyboardInterrupt:
        exiting = 1

    if args.timestamp:
        print("%-8s\n" % strftime("%H:%M:%S"), end="")
    else:
        print("--------", end="\n")

    print("%14s %8s %10s %7s %7s %14s %14s" % ("Driver", "Device", "VQ Name", "In SGs", "Out SGs", "In BW", "Out BW"))
    stats = b.get_table("stats")
    for k, v in sorted(stats.items(), key=lambda vs: vs[1].dev):
        print("%14s %8s %10s %7d %7d %14d %14d" % (v.driver, v.dev, v.vqname, v.in_sgs, v.out_sgs, v.in_bw, v.out_bw))

    stats.clear()

    if exiting or seconds >= int(args.count):
        exit()


text:
@interface RVAnimationViewController : UIViewController

@end


text:
<?php

namespace PhpDocReader;

/**
 * Class Reflector
 * @author  Lucas A. de Araújo <lucas@painapp.com.br>
 * @package PhpDocReader
 */
class Reflector
{
    /**
     * Retorna a documentação de uma classe ou propriedade.
     * @param string $class
     * @param null $property
     * @return string
     */
    public static function getDoc($class, $property = null)
    {
        if(!is_null($property))
            return self::getPropertyDoc($class, $property);

        return self::getClassDoc($class);
    }

    /**
     * Retorna a documentação de classe
     * @param $class
     * @return string
     */
    private static function getClassDoc($class)
    {
        $reflection = new \ReflectionClass($class);
        return $reflection->getDocComment();
    }

    /**
     * Retorna a documentação da propriedade.
     * @param $class
     * @param $property
     * @return string
     */
    private static function getPropertyDoc($class, $property)
    {
        $reflection = new \ReflectionProperty($class, $property);
        return $reflection->getDocComment();
    }
}