text:
#import "EaseChatToolbar.h"

#import "EaseFaceView.h"
#import "EaseEmoji.h"
#import "EaseEmotionEscape.h"
#import "EaseEmotionManager.h"
#import "EaseLocalDefine.h"

@interface EaseChatToolbar()<UITextViewDelegate, EMFaceDelegate>

@property (nonatomic) CGFloat version;
@property (strong, nonatomic) NSMutableArray *leftItems;
@property (strong, nonatomic) NSMutableArray *rightItems;
@property (strong, nonatomic) UIImageView *toolbarBackgroundImageView;
@property (strong, nonatomic) UIImageView *backgroundImageView;
@property (nonatomic) BOOL isShowButtomView;
@property (strong, nonatomic) UIView *activityButtomView;
@property (strong, nonatomic) UIView *toolbarView;
@property (strong, nonatomic) UIButton *recordButton;
@property (strong, nonatomic) UIButton *moreButton;
@property (strong, nonatomic) UIButton *faceButton;
@property (nonatomic) CGFloat previousTextViewContentHeight;//上一次inputTextView的contentSize.height
@property (nonatomic) NSLayoutConstraint *inputViewWidthItemsLeftConstraint;
@property (nonatomic) NSLayoutConstraint *inputViewWidthoutItemsLeftConstraint;

@end

@implementation EaseChatToolbar

@synthesize faceView = _faceView;
@synthesize moreView = _moreView;
@synthesize recordView = _recordView;

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [self initWithFrame:frame horizontalPadding:8 verticalPadding:5 inputViewMinHeight:36 inputViewMaxHeight:150 type:EMChatToolbarTypeGroup];
    if (self) {

    }

    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
                         type:(EMChatToolbarType)type
{
    self = [self initWithFrame:frame horizontalPadding:8 verticalPadding:5 inputViewMinHeight:36 inputViewMaxHeight:150 type:type];
    if (self) {

    }

    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
            horizontalPadding:(CGFloat)horizontalPadding
              verticalPadding:(CGFloat)verticalPadding
           inputViewMinHeight:(CGFloat)inputViewMinHeight
           inputViewMaxHeight:(CGFloat)inputViewMaxHeight
                         type:(EMChatToolbarType)type
{
    if (frame.size.height < (verticalPadding * 2 + inputViewMinHeight)) {
        frame.size.height = verticalPadding * 2 + inputViewMinHeight;
    }
    self = [super initWithFrame:frame];
    if (self) {
        self.accessibilityIdentifier = @"chatbar";

        _horizontalPadding = horizontalPadding;
        _verticalPadding = verticalPadding;
        _inputViewMinHeight = inputViewMinHeight;
        _inputViewMaxHeight = inputViewMaxHeight;
        _chatBarType = type;

        _leftItems = [NSMutableArray array];
        _rightItems = [NSMutableArray array];
        _version = [[[UIDevice currentDevice] systemVersion] floatValue];
        _activityButtomView = nil;
        _isShowButtomView = NO;

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(chatKeyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

        [self _setupSubviews];
    }
    return self;
}

#pragma mark - setup subviews

/*!
 @method
 @brief 加载视图
 @discussion
 @result
 */
- (void)_setupSubviews
{
    //backgroundImageView
    _backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
    _backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    _backgroundImageView.backgroundColor = [UIColor clearColor];
    _backgroundImageView.image = [[UIImage imageNamed:@"EaseUIResource.bundle/messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10];
    [self addSubview:_backgroundImageView];

    //toolbar
    _toolbarView = [[UIView alloc] initWithFrame:self.bounds];
    _toolbarView.backgroundColor = [UIColor clearColor];
    [self addSubview:_toolbarView];

    _toolbarBackgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _toolbarView.frame.size.width, _toolbarView.frame.size.height)];
    _toolbarBackgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    _toolbarBackgroundImageView.backgroundColor = [UIColor clearColor];
    [_toolbarView addSubview:_toolbarBackgroundImageView];

    //input textview
    _inputTextView = [[EaseTextView alloc] initWithFrame:CGRectMake(self.horizontalPadding, self.verticalPadding, self.frame.size.width - self.verticalPadding * 2, self.frame.size.height - self.verticalPadding * 2)];
    _inputTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    _inputTextView.scrollEnabled = YES;
    _inputTextView.returnKeyType = UIReturnKeySend;
    _inputTextView.enablesReturnKeyAutomatically = YES; // UITextView内部判断send按钮是否可以用
    _inputTextView.placeHolder = NSEaseLocalizedString(@"message.toolBar.inputPlaceHolder", @"input a new message");
    _inputTextView.delegate = self;
    _inputTextView.backgroundColor = [UIColor clearColor];
    _inputTextView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor;
    _inputTextView.layer.borderWidth = 0.65f;
    _inputTextView.layer.cornerRadius = 6.0f;
    _previousTextViewContentHeight = [self _getTextViewContentH:_inputTextView];
    [_toolbarView addSubview:_inputTextView];

    //change input type
    UIButton *styleChangeButton = [[UIButton alloc] init];
    styleChangeButton.accessibilityIdentifier = @"style";
    styleChangeButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    [styleChangeButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_record"] forState:UIControlStateNormal];
    [styleChangeButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected];
    [styleChangeButton addTarget:self action:@selector(styleButtonAction:) forControlEvents:UIControlEventTouchUpInside];

    EaseChatToolbarItem *styleItem = [[EaseChatToolbarItem alloc] initWithButton:styleChangeButton withView:nil];
    [self setInputViewLeftItems:@[styleItem]];

    //record
    self.recordButton = [[UIButton alloc] initWithFrame:self.inputTextView.frame];
    self.recordButton.accessibilityIdentifier = @"record";
    self.recordButton.titleLabel.font = [UIFont systemFontOfSize:15.0];
    [self.recordButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
    [self.recordButton setBackgroundImage:[[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_recordBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateNormal];
    [self.recordButton setBackgroundImage:[[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_recordSelectedBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateHighlighted];
    [self.recordButton setTitle:kTouchToRecord forState:UIControlStateNormal];
    [self.recordButton setTitle:kTouchToFinish forState:UIControlStateHighlighted];
    self.recordButton.hidden = YES;
    [self.recordButton addTarget:self action:@selector(recordButtonTouchDown) forControlEvents:UIControlEventTouchDown];
    [self.recordButton addTarget:self action:@selector(recordButtonTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside];
    [self.recordButton addTarget:self action:@selector(recordButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
    [self.recordButton addTarget:self action:@selector(recordDragOutside) forControlEvents:UIControlEventTouchDragExit];
    [self.recordButton addTarget:self action:@selector(recordDragInside) forControlEvents:UIControlEventTouchDragEnter];
    self.recordButton.hidden = YES;
    [self.toolbarView addSubview:self.recordButton];

    //emoji
    self.faceButton = [[UIButton alloc] init];
    self.faceButton.accessibilityIdentifier = @"face";
    self.faceButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    [self.faceButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_face"] forState:UIControlStateNormal];
    [self.faceButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_faceSelected"] forState:UIControlStateHighlighted];
    [self.faceButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected];
    [self.faceButton addTarget:self action:@selector(faceButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    EaseChatToolbarItem *faceItem = [[EaseChatToolbarItem alloc] initWithButton:self.faceButton withView:self.faceView];

    //more
    self.moreButton = [[UIButton alloc] init];
    self.moreButton.accessibilityIdentifier = @"more";
    self.moreButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    [self.moreButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_more"] forState:UIControlStateNormal];
    [self.moreButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_moreSelected"] forState:UIControlStateHighlighted];
    [self.moreButton setImage:[UIImage imageNamed:@"EaseUIResource.bundle/chatBar_keyboard"] forState:UIControlStateSelected];
    [self.moreButton addTarget:self action:@selector(moreButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    EaseChatToolbarItem *moreItem = [[EaseChatToolbarItem alloc] initWithButton:self.moreButton withView:self.moreView];

    [self setInputViewRightItems:@[faceItem, moreItem]];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];

    _delegate = nil;
    _inputTextView.delegate = nil;
    _inputTextView = nil;
}

#pragma mark - getter

- (UIView *)recordView
{
    if (_recordView == nil) {
        _recordView = [[EaseRecordView alloc] initWithFrame:CGRectMake(90, 130, 140, 140)];
    }

    return _recordView;
}

- (UIView *)faceView
{
    if (_faceView == nil) {
        _faceView = [[EaseFaceView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_toolbarView.frame), self.frame.size.width, 180)];
        [(EaseFaceView *)_faceView setDelegate:self];
        _faceView.backgroundColor = [UIColor colorWithRed:240 / 255.0 green:242 / 255.0 blue:247 / 255.0 alpha:1.0];
        _faceView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    }

    return _faceView;
}

- (UIView *)moreView
{
    if (_moreView == nil) {
        _moreView = [[EaseChatBarMoreView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_toolbarView.frame), self.frame.size.width, 80) type:self.chatBarType];
        _moreView.backgroundColor = [UIColor colorWithRed:240 / 255.0 green:242 / 255.0 blue:247 / 255.0 alpha:1.0];
        _moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
    }

    return _moreView;
}

#pragma mark - setter

- (void)setDelegate:(id)delegate
{
    _delegate = delegate;
    if ([_moreView isKindOfClass:[EaseChatBarMoreView class]]) {
        [(EaseChatBarMoreView *)_moreView setDelegate:delegate];
    }
}

- (void)setRecordView:(UIView *)recordView
{
    if(_recordView != recordView){
        _recordView = recordView;
    }
}

- (void)setMoreView:(UIView *)moreView
{
    if (_moreView != moreView) {
        _moreView = moreView;

        for (EaseChatToolbarItem *item in self.rightItems) {
            if (item.button == self.moreButton) {
                item.button2View = _moreView;
                break;
            }
        }
    }
}

- (void)setFaceView:(UIView *)faceView
{
    if (_faceView != faceView) {
        _faceView = faceView;

        for (EaseChatToolbarItem *item in self.rightItems) {
            if (item.button == self.faceButton) {
                item.button2View = _faceView;
                break;
            }
        }
    }
}

- (NSArray*)inputViewLeftItems
{
    return self.leftItems;
}

/*!
 @method
 @brief 设置toolBar左侧菜单选项
 @discussion
 @param inputViewLeftItems 左侧选项
 @result
 */
- (void)setInputViewLeftItems:(NSArray *)inputViewLeftItems
{
    for (EaseChatToolbarItem *item in self.leftItems) {
        [item.button removeFromSuperview];
        [item.button2View removeFromSuperview];
    }
    [self.leftItems removeAllObjects];

    CGFloat oX = self.horizontalPadding;
    CGFloat itemHeight = self.toolbarView.frame.size.height - self.verticalPadding * 2;
    for (id item in inputViewLeftItems) {
        if ([item isKindOfClass:[EaseChatToolbarItem class]]) {
            EaseChatToolbarItem *chatItem = (EaseChatToolbarItem *)item;
            if (chatItem.button) {
                CGRect itemFrame = chatItem.button.frame;
                if (itemFrame.size.height == 0) {
                    itemFrame.size.height = itemHeight;
                }

                if (itemFrame.size.width == 0) {
                    itemFrame.size.width = itemFrame.size.height;
                }

                itemFrame.origin.x = oX;
                itemFrame.origin.y = (self.toolbarView.frame.size.height - itemFrame.size.height) / 2;
                chatItem.button.frame = itemFrame;
                oX += (itemFrame.size.width + self.horizontalPadding);

                [self.toolbarView addSubview:chatItem.button];
                [self.leftItems addObject:chatItem];
            }
        }
    }

    CGRect inputFrame = self.inputTextView.frame;
    CGFloat value = inputFrame.origin.x - oX;
    inputFrame.origin.x = oX;
    inputFrame.size.width += value;
    self.inputTextView.frame = inputFrame;

    CGRect recordFrame = self.recordButton.frame;
    recordFrame.origin.x = inputFrame.origin.x;
    recordFrame.size.width = inputFrame.size.width;
    self.recordButton.frame = recordFrame;
}

- (NSArray*)inputViewRightItems
{
    return self.rightItems;
}

/*!
 @method
 @brief 设置toolBar右侧菜单选项
 @discussion
 @param inputViewLeftItems 右侧选项
 @result
 */
- (void)setInputViewRightItems:(NSArray *)inputViewRightItems
{
    for (EaseChatToolbarItem *item in self.rightItems) {
        [item.button removeFromSuperview];
        [item.button2View removeFromSuperview];
    }
    [self.rightItems removeAllObjects];

    CGFloat oMaxX = self.toolbarView.frame.size.width - self.horizontalPadding;
    CGFloat itemHeight = self.toolbarView.frame.size.height - self.verticalPadding * 2;
    if ([inputViewRightItems count] > 0) {
        for (NSInteger i = (inputViewRightItems.count - 1); i >= 0; i--) {
            id item = [inputViewRightItems objectAtIndex:i];
            if ([item isKindOfClass:[EaseChatToolbarItem class]]) {
                EaseChatToolbarItem *chatItem = (EaseChatToolbarItem *)item;
                if (chatItem.button) {
                    CGRect itemFrame = chatItem.button.frame;
                    if (itemFrame.size.height == 0) {
                        itemFrame.size.height = itemHeight;
                    }

                    if (itemFrame.size.width == 0) {
                        itemFrame.size.width = itemFrame.size.height;
                    }

                    oMaxX -= itemFrame.size.width;
                    itemFrame.origin.x = oMaxX;
                    itemFrame.origin.y = (self.toolbarView.frame.size.height - itemFrame.size.height) / 2;
                    chatItem.button.frame = itemFrame;
                    oMaxX -= self.horizontalPadding;

                    [self.toolbarView addSubview:chatItem.button];
                    [self.rightItems addObject:item];
                }
            }
        }
    }

    CGRect inputFrame = self.inputTextView.frame;
    CGFloat value = oMaxX - CGRectGetMaxX(inputFrame);
    inputFrame.size.width += value;
    self.inputTextView.frame = inputFrame;

    CGRect recordFrame = self.recordButton.frame;
    recordFrame.origin.x = inputFrame.origin.x;
    recordFrame.size.width = inputFrame.size.width;
    self.recordButton.frame = recordFrame;
}

#pragma mark - private input view

/*!
 @method
 @brief 获取textView的高度(实际为textView的contentSize的高度)
 @discussion
 @param textView 文本框
 @result
 */
- (CGFloat)_getTextViewContentH:(UITextView *)textView
{
    if (self.version >= 7.0)
    {
        return ceilf([textView sizeThatFits:textView.frame.size].height);
    } else {
        return textView.contentSize.height;
    }
}

/*!
 @method
 @brief 通过传入的toHeight,跳转toolBar的高度
 @discussion
 @param toHeight
 @result
 */
- (void)_willShowInputTextViewToHeight:(CGFloat)toHeight
{
    if (toHeight < self.inputViewMinHeight) {
        toHeight = self.inputViewMinHeight;
    }
    if (toHeight > self.inputViewMaxHeight) {
        toHeight = self.inputViewMaxHeight;
    }

    if (toHeight == _previousTextViewContentHeight)
    {
        return;
    }
    else{
        CGFloat changeHeight = toHeight - _previousTextViewContentHeight;

        CGRect rect = self.frame;
        rect.size.height += changeHeight;
        rect.origin.y -= changeHeight;
        self.frame = rect;

        rect = self.toolbarView.frame;
        rect.size.height += changeHeight;
        self.toolbarView.frame = rect;

        if (self.version < 7.0) {
            [self.inputTextView setContentOffset:CGPointMake(0.0f, (self.inputTextView.contentSize.height - self.inputTextView.frame.size.height) / 2) animated:YES];
        }
        _previousTextViewContentHeight = toHeight;

        if (_delegate && [_delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
            [_delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height];
        }
    }
}

#pragma mark - private bottom view

/*!
 @method
 @brief 调整toolBar的高度
 @discussion
 @param bottomHeight 底部菜单的高度
 @result
 */
- (void)_willShowBottomHeight:(CGFloat)bottomHeight
{
    CGRect fromFrame = self.frame;
    CGFloat toHeight = self.toolbarView.frame.size.height + bottomHeight;
    CGRect toFrame = CGRectMake(fromFrame.origin.x, fromFrame.origin.y + (fromFrame.size.height - toHeight), fromFrame.size.width, toHeight);

    if(bottomHeight == 0 && self.frame.size.height == self.toolbarView.frame.size.height)
    {
        return;
    }

    if (bottomHeight == 0) {
        self.isShowButtomView = NO;
    }
    else{
        self.isShowButtomView = YES;
    }

    self.frame = toFrame;

    if (_delegate && [_delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
        [_delegate chatToolbarDidChangeFrameToHeight:toHeight];
    }
}

/*!
 @method
 @brief 切换菜单视图
 @discussion
 @param bottomView 菜单视图
 @result
 */
- (void)_willShowBottomView:(UIView *)bottomView
{
    if (![self.activityButtomView isEqual:bottomView]) {
        CGFloat bottomHeight = bottomView ? bottomView.frame.size.height : 0;
        [self _willShowBottomHeight:bottomHeight];

        if (bottomView) {
            CGRect rect = bottomView.frame;
            rect.origin.y = CGRectGetMaxY(self.toolbarView.frame);
            bottomView.frame = rect;
            [self addSubview:bottomView];
        }

        if (self.activityButtomView) {
            [self.activityButtomView removeFromSuperview];
        }
        self.activityButtomView = bottomView;
    }
}

- (void)_willShowKeyboardFromFrame:(CGRect)beginFrame toFrame:(CGRect)toFrame
{
    if (beginFrame.origin.y == [[UIScreen mainScreen] bounds].size.height)
    {
        [self _willShowBottomHeight:toFrame.size.height];
        if (self.activityButtomView) {
            [self.activityButtomView removeFromSuperview];
        }
        self.activityButtomView = nil;
    }
    else if (toFrame.origin.y == [[UIScreen mainScreen] bounds].size.height)
    {
        [self _willShowBottomHeight:0];
    }
    else{
        [self _willShowBottomHeight:toFrame.size.height];
    }
}

#pragma mark - UITextViewDelegate

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
    if ([self.delegate respondsToSelector:@selector(inputTextViewWillBeginEditing:)]) {
        [self.delegate inputTextViewWillBeginEditing:self.inputTextView];
    }

    for (EaseChatToolbarItem *item in self.leftItems) {
        item.button.selected = NO;
    }

    for (EaseChatToolbarItem *item in self.rightItems) {
        item.button.selected = NO;
    }

    return YES;
}

- (void)textViewDidBeginEditing:(UITextView *)textView
{
    [textView becomeFirstResponder];

    if ([self.delegate respondsToSelector:@selector(inputTextViewDidBeginEditing:)]) {
        [self.delegate inputTextViewDidBeginEditing:self.inputTextView];
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    [textView resignFirstResponder];
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    if ([text isEqualToString:@"\n"]) {
        if ([self.delegate respondsToSelector:@selector(didSendText:)]) {
            [self.delegate didSendText:textView.text];
            self.inputTextView.text = @"";
            [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];
        }

        return NO;
    }
    else if ([text isEqualToString:@"@"]) {
        if ([self.delegate respondsToSelector:@selector(didInputAtInLocation:)]) {
            if ([self.delegate didInputAtInLocation:range.location]) {
                [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];
                return NO;
            }
        }
    }
    else if ([text length] == 0) {
        //delete one character
        if (range.length == 1 && [self.delegate respondsToSelector:@selector(didDeleteCharacterFromLocation:)]) {
            return ![self.delegate didDeleteCharacterFromLocation:range.location];
        }
    }
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView
{
    [self _willShowInputTextViewToHeight:[self _getTextViewContentH:textView]];
}

#pragma mark - DXFaceDelegate

- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete
{
    NSString *chatText = self.inputTextView.text;

    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithAttributedString:self.inputTextView.attributedText];

    if (!isDelete && str.length > 0) {
        if (self.version >= 7.0) {
            NSRange range = [self.inputTextView selectedRange];
            [attr insertAttributedString:[[EaseEmotionEscape sharedInstance] attStringFromTextForInputView:str textFont:self.inputTextView.font] atIndex:range.location];
            self.inputTextView.attributedText = attr;
        } else {
            self.inputTextView.text = @"";
            self.inputTextView.text = [NSString stringWithFormat:@"%@%@",chatText,str];
        }
    }
    else {
        if (self.version >= 7.0) {
            if (chatText.length > 0) {
                NSInteger length = 1;
                if (chatText.length >= 2) {
                    NSString *subStr = [chatText substringFromIndex:chatText.length-2];
                    if ([EaseEmoji stringContainsEmoji:subStr]) {
                        length = 2;
                    }
                }
                self.inputTextView.attributedText = [self backspaceText:attr length:length];
            }
        } else {
            if (chatText.length >= 2)
            {
                NSString *subStr = [chatText substringFromIndex:chatText.length-2];
                if ([(EaseFaceView *)self.faceView stringIsFace:subStr]) {
                    self.inputTextView.text = [chatText substringToIndex:chatText.length-2];
                    [self textViewDidChange:self.inputTextView];
                    return;
                }
            }

            if (chatText.length > 0) {
                self.inputTextView.text = [chatText substringToIndex:chatText.length-1];
            }
        }
    }

    [self textViewDidChange:self.inputTextView];
}

/*!
 @method
 @brief 删除文本光标前长度为length的字符串
 @discussion
 @param attr   待修改的富文本
 @param length 字符串长度
 @result   修改后的富文本
 */
-(NSMutableAttributedString*)backspaceText:(NSMutableAttributedString*) attr length:(NSInteger)length
{
    NSRange range = [self.inputTextView selectedRange];
    if (range.location == 0) {
        return attr;
    }
    [attr deleteCharactersInRange:NSMakeRange(range.location - length, length)];
    return attr;
}

- (void)sendFace
{
    NSString *chatText = self.inputTextView.text;
    if (chatText.length > 0) {
        if ([self.delegate respondsToSelector:@selector(didSendText:)]) {

            if (![_inputTextView.text isEqualToString:@""]) {

                //转义回来
                NSMutableString *attStr = [[NSMutableString alloc] initWithString:self.inputTextView.attributedText.string];
                [_inputTextView.attributedText enumerateAttribute:NSAttachmentAttributeName
                                                          inRange:NSMakeRange(0, self.inputTextView.attributedText.length)
                                                          options:NSAttributedStringEnumerationReverse
                                                       usingBlock:^(id value, NSRange range, BOOL *stop)
                 {
                     if (value) {
                         EMTextAttachment* attachment = (EMTextAttachment*)value;
                         NSString *str = [NSString stringWithFormat:@"%@",attachment.imageName];
                         [attStr replaceCharactersInRange:range withString:str];
                     }
                 }];
                [self.delegate didSendText:attStr];
                self.inputTextView.text = @"";
                [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];;
            }
        }
    }
}

- (void)sendFaceWithEmotion:(EaseEmotion *)emotion
{
    if (emotion) {
        if ([self.delegate respondsToSelector:@selector(didSendText:withExt:)]) {
            [self.delegate didSendText:emotion.emotionTitle withExt:@{EASEUI_EMOTION_DEFAULT_EXT:emotion}];
            [self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];;
        }
    }
}

#pragma mark - UIKeyboardNotification

- (void)chatKeyboardWillChangeFrame:(NSNotification *)notification
{
    NSDictionary *userInfo = notification.userInfo;
    CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect beginFrame = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    void(^animations)() = ^{
        [self _willShowKeyboardFromFrame:beginFrame toFrame:endFrame];
    };

    [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:nil];
}

#pragma mark - action

- (void)styleButtonAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    button.selected = !button.selected;
    if (button.selected) {
        for (EaseChatToolbarItem *item in self.rightItems) {
            item.button.selected = NO;
        }

        for (EaseChatToolbarItem *item in self.leftItems) {
            if (item.button != button) {
                item.button.selected = NO;
            }
        }

        [self _willShowBottomView:nil];

        self.inputTextView.text = @"";
        [self textViewDidChange:self.inputTextView];
        [self.inputTextView resignFirstResponder];
    }
    else{
        [self.inputTextView becomeFirstResponder];
    }

    [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        self.recordButton.hidden = !button.selected;
        self.inputTextView.hidden = button.selected;
    } completion:nil];
}

- (void)faceButtonAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    button.selected = !button.selected;

    EaseChatToolbarItem *faceItem = nil;
    for (EaseChatToolbarItem *item in self.rightItems) {
        if (item.button == button){
            faceItem = item;
            continue;
        }

        item.button.selected = NO;
    }

    for (EaseChatToolbarItem *item in self.leftItems) {
        item.button.selected = NO;
    }

    if (button.selected) {
        [self.inputTextView resignFirstResponder];

        [self _willShowBottomView:faceItem.button2View];
        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.recordButton.hidden = button.selected;
            self.inputTextView.hidden = !button.selected;
        } completion:^(BOOL finished) {

        }];
    } else {
        [self.inputTextView becomeFirstResponder];
    }
}

- (void)moreButtonAction:(id)sender
{
    UIButton *button = (UIButton *)sender;
    button.selected = !button.selected;

    EaseChatToolbarItem *moreItem = nil;
    for (EaseChatToolbarItem *item in self.rightItems) {
        if (item.button == button){
            moreItem = item;
            continue;
        }

        item.button.selected = NO;
    }

    for (EaseChatToolbarItem *item in self.leftItems) {
        item.button.selected = NO;
    }

    if (button.selected) {
        [self.inputTextView resignFirstResponder];

        [self _willShowBottomView:moreItem.button2View];
        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.recordButton.hidden = button.selected;
            self.inputTextView.hidden = !button.selected;
        } completion:nil];
    }
    else
    {
        [self.inputTextView becomeFirstResponder];
    }
}

- (void)recordButtonTouchDown
{
    if (_delegate && [_delegate respondsToSelector:@selector(didStartRecordingVoiceAction:)]) {
        [_delegate didStartRecordingVoiceAction:self.recordView];
    }
}

- (void)recordButtonTouchUpOutside
{
    if (_delegate && [_delegate respondsToSelector:@selector(didCancelRecordingVoiceAction:)])
    {
        [_delegate didCancelRecordingVoiceAction:self.recordView];
    }
}

- (void)recordButtonTouchUpInside
{
    self.recordButton.enabled = NO;
    if ([self.delegate respondsToSelector:@selector(didFinishRecoingVoiceAction:)])
    {
        [self.delegate didFinishRecoingVoiceAction:self.recordView];
    }
    self.recordButton.enabled = YES;
}

- (void)recordDragOutside
{
    if ([self.delegate respondsToSelector:@selector(didDragOutsideAction:)])
    {
        [self.delegate didDragOutsideAction:self.recordView];
    }
}

- (void)recordDragInside
{
    if ([self.delegate respondsToSelector:@selector(didDragInsideAction:)])
    {
        [self.delegate didDragInsideAction:self.recordView];
    }
}

#pragma mark - public

+ (CGFloat)defaultHeight
{
    return 5 * 2 + 36;
}

- (BOOL)endEditing:(BOOL)force
{
    BOOL result = [super endEditing:force];

    for (EaseChatToolbarItem *item in self.rightItems) {
        item.button.selected = NO;
    }
    [self _willShowBottomView:nil];

    return result;
}

- (void)cancelTouchRecord
{
    if ([_recordView isKindOfClass:[EaseRecordView class]]) {
        [(EaseRecordView *)_recordView recordButtonTouchUpInside];
        [_recordView removeFromSuperview];
    }
}

- (void)willShowBottomView:(UIView *)bottomView
{
    [self _willShowBottomView:bottomView];
}

@end


text:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
        <property name="hibernate.cache.region_prefix">hibernate.test</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.pool_size">1</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost/tpteam</property>
        <property name="hibernate.connection.username">tpteam</property>
        <property name="hibernate.connection.password">tpteam</property>
        <property name="hibernate.default_schema">TPTEAM</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.jdbc.batch_versioned_data">true</property>
        <property name="hibernate.jdbc.use_streams_for_binary">true</property>
        <property name="hibernate.max_fetch_depth">1</property>
        <property name="hibernate.proxool.pool_alias">pool1</property>
        <property name="hibernate.query.substitutions">yes 'Y', no 'N'</property>
        <property name="hibernate.show_sql">false</property>
        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/Test.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/Token.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/JunitTest.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/TpteamUser.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/Project.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/Product.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/Role.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/TestType.hbm.xml" />
        <mapping resource="edu/harvard/fas/rbrady/tpteam/tpbridge/hibernate/TestExecution.hbm.xml" />
    </session-factory>
</hibernate-configuration>

redpajama_set_name: RedPajamaGithub


text:
package raptor.connector.ics;

import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;

import raptor.Raptor;
import raptor.chat.Bugger.BuggerStatus;
import raptor.chat.ChatType;
import raptor.chess.AtomicGame;
import raptor.chess.BughouseGame;
import raptor.chess.ClassicGame;
import raptor.chess.CrazyhouseGame;
import raptor.chess.FischerRandomBughouseGame;
import raptor.chess.FischerRandomCrazyhouseGame;
import raptor.chess.FischerRandomGame;
import raptor.chess.Game;
import raptor.chess.GameConstants;
import raptor.chess.GameFactory;
import raptor.chess.LosersGame;
import raptor.chess.Move;
import raptor.chess.SetupGame;
import raptor.chess.SuicideGame;
import raptor.chess.Variant;
import raptor.chess.WildGame;
import raptor.chess.pgn.PgnHeader;
import raptor.chess.pgn.PgnUtils;
import raptor.chess.pgn.TimeTakenForMove;
import raptor.chess.util.GameUtils;
import raptor.chess.util.ZobristUtils;
import raptor.connector.Connector;
import raptor.connector.ics.game.message.G1Message;
import raptor.connector.ics.game.message.MovesMessage;
import raptor.connector.ics.game.message.Style12Message;
import raptor.swt.chess.ChessBoardController;
import raptor.swt.chess.ChessBoardUtils;
import raptor.swt.chess.controller.BughouseSuggestController;
import raptor.swt.chess.controller.ExamineController;
import raptor.swt.chess.controller.InactiveController;
import raptor.swt.chess.controller.ObserveController;
import raptor.swt.chess.controller.PlayingController;
import raptor.swt.chess.controller.SetupController;
import raptor.util.RaptorLogger;
import raptor.util.RaptorStringTokenizer;

public class IcsUtils implements GameConstants {
	public static final String ATOMIC_IDENTIFIER = "atomic";

	public static final String BLITZ_IDENTIFIER = "blitz";

	public static final String BUGHOUSE_IDENTIFIER = "bughouse";

	public static final String CHANNEL_STRIP_CHARS = "()~!@#$%^&*()-=+_`}{[]'\";/?<>.,:[]";

	public static final String CRAZYHOUSE_IDENTIFIER = "crazyhouse";

	public static final String FISCHER_RANDOM_IDENTIFIER = "wild/fr";

	public static final String LEGAL_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "
			+ "!@#$%^&*()-=_+`~[{]}\\|;:'\",<.>/?";

	public static final String LIGHTNING_IDENTIFIER = "lightning";

	private static final RaptorLogger LOG = RaptorLogger.getLog(IcsUtils.class);

	public static final String LOSERS_IDENTIFIER = "losers";

	public static final String STANDARD_IDENTIFIER = "standard";

	public static final String STRIP_CHARS = "()~!@#$%^&*()-=+_`}{[]'\";/?<>.,:[]1234567890";

	public static final String SUICIDE_IDENTIFIER = "suicide";

	public static final String UNTIMED_IDENTIFIER = "untimed";

	public static final String VALID_PERSON_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

	public static final String WILD_IDENTIFIER = "wild";

	/**
	 * Returns true if a move was added, false if no move was added (This can
	 * occur on a refresh or a game end.).
	 */
	public static boolean addCurrentMove(Game game, Style12Message message,
			Connector connector) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("addCurrentMove: " + message + "\n" + game);
		}
		boolean result = false;
		if (!message.isWhitesMoveAfterMoveIsMade
				&& game.getColorToMove() != WHITE
				|| message.isWhitesMoveAfterMoveIsMade
				&& game.getColorToMove() == WHITE) {
			// At the end of a game multiple <12> messages are sent.
			// The are also sent when a refresh is sent.
			game.setHeader(PgnHeader.WhiteRemainingMillis, String.valueOf(message.whiteRemainingTimeMillis));
			game.setHeader(PgnHeader.BlackRemainingMillis, String.valueOf(message.blackRemainingTimeMillis));

			if (message.timeTakenForLastMoveMillis != 0
					&& game.getMoveList().getSize() > 1) {
				game.getMoveList()
						.get(game.getMoveList().getSize() - 1)
						.addAnnotation(
								new TimeTakenForMove(
										message.timeTakenForLastMoveMillis));
			}
		} else {
			if (message.san.equals("none")) {
				Raptor.getInstance()
						.onError(
								"Received a none for san in a style 12 event. This should have contained a move.");
			} else {
				try {
					Move move = game.makeSanMove(message.san);
					move.addAnnotation(new TimeTakenForMove(
							message.timeTakenForLastMoveMillis));
				} catch (IllegalArgumentException iae) {
					connector
							.onError("Raptor thinks "
									+ message.san
									+ " is illegal. An attempt was made to correct the position.\n"  +iae);
					resetGame(game, message);
				}
			}

			game.setHeader(PgnHeader.WhiteRemainingMillis, String.valueOf(message.whiteRemainingTimeMillis));
			game.setHeader(PgnHeader.BlackRemainingMillis, String.valueOf(message.blackRemainingTimeMillis));

			if (message.isWhitesMoveAfterMoveIsMade) {
				String lag = StringUtils.defaultString(
						game.getHeader(PgnHeader.BlackLagMillis), "0");
				game.setHeader(PgnHeader.BlackLagMillis,
                        String.valueOf(Long.parseLong(lag) + message.lagInMillis));
			} else {
				String lag = StringUtils.defaultString(
						game.getHeader(PgnHeader.WhiteLagMillis), "0");
				game.setHeader(PgnHeader.WhiteLagMillis,
                        String.valueOf(Long.parseLong(lag) + message.lagInMillis));

			}
			result = true;
		}

		if (message.isClockTicking) {
			game.addState(Game.IS_CLOCK_TICKING_STATE);
		} else {
			game.clearState(Game.IS_CLOCK_TICKING_STATE);
		}
		if (LOG.isDebugEnabled()) {
			LOG.debug("after addCurrentMove: " + message + "\n" + game);
		}
		return result;
	}

	/**
	 * Returns true if the game was adjusted for takebacks. False otherwise.
	 */
	public static boolean adjustToTakebacks(Game game, Style12Message message,
			Connector connector) {
		boolean result = false;
		if (game.isInState(Game.EXAMINING_STATE)
				|| game.isInState(Game.OBSERVING_EXAMINED_STATE)
				|| game.isInState(Game.SETUP_STATE)) {
			return false;
		}

		// fics ----- game halfmove
		// 1 w b ---- 0 1
		// 2 w b ---- 2 3
		// 3 w b ---- 4 5
		// 4 w b ---- 6 7
		// 5 w b ---- 7 8
		int currentHalfMove = (message.fullMoveNumber - 1) * 2
				+ (message.isWhitesMoveAfterMoveIsMade ? 0 : 1);
		if (LOG.isDebugEnabled()) {
			LOG.debug("adjustToTakebacks calculatedHalfMove " + currentHalfMove
					+ " 12FulLMoveNumber " + message.fullMoveNumber
					+ " 12isWhitesMoveAfter "
					+ message.isWhitesMoveAfterMoveIsMade + " gameHalfMove "
					+ game.getHalfMoveCount());
		}

		if (currentHalfMove != game.getHalfMoveCount() + 1) {

			if (game.getHalfMoveCount() < currentHalfMove) {
				if (LOG.isDebugEnabled()) {
					LOG.debug("Didnt have all the moves needed for rollback. Resetting game and sending moves request.");
				}
				resetGame(game, message);
				connector.sendMessage("moves " + message.gameId, true,
						ChatType.MOVES);
				result = true;
			} else {

				while (game.getHalfMoveCount() > currentHalfMove) {
					if (game.getLastMove() != null) {
						if (LOG.isDebugEnabled()) {
							LOG.debug("Rolled back a move.");
						}
						game.rollback();
					} else {
						game.removeHeader(PgnHeader.ECO);
						game.removeHeader(PgnHeader.Opening);
						resetGame(game, message);
						connector.sendMessage("moves " + message.gameId, true,
								ChatType.MOVES);
						result = false;
						break;
					}
				}

				if (game.isInState(Game.OBSERVING_EXAMINED_STATE)
						&& game.getMoveList().getSize() == 0) {
					game.clear();
					updateNonPositionFields(game, message);
					updatePosition(game, message);
					game.removeHeader(PgnHeader.ECO);
					game.removeHeader(PgnHeader.Opening);
				}
				result = true;
			}

			// At the end of a game multiple <12> messages are sent.
			// The are also sent when a refresh is sent.
			game.setHeader(PgnHeader.WhiteRemainingMillis, String.valueOf(message.whiteRemainingTimeMillis));
			game.setHeader(PgnHeader.BlackRemainingMillis, String.valueOf(message.blackRemainingTimeMillis));
		}

		if (message.isClockTicking) {
			game.addState(Game.IS_CLOCK_TICKING_STATE);
		} else {
			game.clearState(Game.IS_CLOCK_TICKING_STATE);
		}
		return result;
	}

	public static ChessBoardController buildController(Game game,
			Connector connector) {
		return buildController(game, connector, false);
	}

	public static ChessBoardController buildController(Game game,
			Connector connector, boolean isBughouseOtherBoard) {
		ChessBoardController controller = null;

		if (game.isInState(Game.OBSERVING_STATE)
				|| game.isInState(Game.OBSERVING_EXAMINED_STATE)) {
			if (isBughouseOtherBoard) {
				if (((BughouseGame) game).getOtherBoard().isInState(
						Game.PLAYING_STATE)) {
					Game otherGame = ((BughouseGame) game).getOtherBoard();
					boolean isPartnerWhite = !StringUtils.equals(
							otherGame.getHeader(PgnHeader.White),
							connector.getUserName());
					controller = new BughouseSuggestController(game, connector,
							isPartnerWhite);
				} else {
					controller = new ObserveController(game,
							isBughouseOtherBoard, connector);
				}
			} else {
				controller = new ObserveController(game, connector);
			}

		} else if (game.isInState(Game.SETUP_STATE)) {
			controller = new SetupController(game, connector);
		} else if (game.isInState(Game.EXAMINING_STATE)) {
			controller = new ExamineController(game, connector);
		} else if (game.isInState(Game.PLAYING_STATE)) {
			controller = new PlayingController(game, connector);
		} else {
			// Used for sposition.
			controller = new InactiveController(game);
		}
		return controller;
	}

	/**
	 * Cleans up the message by ensuring only \n is used as a line terminator.
	 * \r\n and \r may be used depending on the operating system.
	 */
	public static String cleanupMessage(String message) {
		return StringUtils.remove(message, '\r');
	}

	/**
	 * Clears out all the games position state.
	 */
	public static void clearGamePosition(Game game) {
		game.clear();
	}

	public static Game createExaminedGame(
			Style12Message gameStateStyle12Message, MovesMessage movesMessage) {
		Game result = null;
		if (movesMessage.style12 == null) {
			result = GameFactory
					.createStartingPosition(identifierToGameType(movesMessage.gameType));
		} else {
			result = createGameFromVariant(
					identifierToGameType(movesMessage.gameType),
					gameStateStyle12Message, false);
			updatePosition(result, movesMessage.style12);
			if (result.getVariant() == Variant.fischerRandom) {
				((FischerRandomGame) result).initialPositionIsSet();
			} else if (result.getVariant() == Variant.fischerRandomBughouse) {
				((FischerRandomBughouseGame) result).initialPositionIsSet();
			} else if (result.getVariant() == Variant.fischerRandomCrazyhouse) {
				((FischerRandomCrazyhouseGame) result).initialPositionIsSet();
			}
			updateNonPositionFields(result, movesMessage.style12);
			result.setHeader(PgnHeader.FEN, result.toFen());
		}
		result.addState(Game.UPDATING_SAN_STATE);
		result.addState(Game.UPDATING_ECO_HEADERS_STATE);
		result.setId(movesMessage.gameId);

		for (int i = 0; i < movesMessage.moves.length; i++) {
			try {
				if (result.isInState(Game.DROPPABLE_STATE)) {
					result.setDropCount(WHITE, PAWN, 1);
					result.setDropCount(WHITE, QUEEN, 1);
					result.setDropCount(WHITE, ROOK, 1);
					result.setDropCount(WHITE, KNIGHT, 1);
					result.setDropCount(WHITE, BISHOP, 1);
					result.setDropCount(BLACK, PAWN, 1);
					result.setDropCount(BLACK, QUEEN, 1);
					result.setDropCount(BLACK, ROOK, 1);
					result.setDropCount(BLACK, KNIGHT, 1);
					result.setDropCount(BLACK, BISHOP, 1);
				}
				Move move = result.makeSanMove(movesMessage.moves[i]);
				move.addAnnotation(new TimeTakenForMove(
						movesMessage.timePerMove[i]));
			} catch (IllegalArgumentException iae) {
				LOG.error("Could not parse san", iae);
				Raptor.getInstance().onError("Error update game with moves",
						iae);
			}
		}
		updateNonPositionFields(result, gameStateStyle12Message);
		result.setHeader(PgnHeader.Date,
				PgnUtils.longToPgnDate(System.currentTimeMillis()));
		result.setHeader(PgnHeader.Round, "?");
		result.setHeader(PgnHeader.Site, "freechess.org");
		result.setHeader(PgnHeader.TimeControl,
				PgnUtils.timeIncMillisToTimeControl(0, 0));
		result.setHeader(PgnHeader.BlackRemainingMillis, "" + 0);
		result.setHeader(PgnHeader.WhiteRemainingMillis, "" + 0);
		result.setHeader(PgnHeader.WhiteClock, PgnUtils.timeToClock(0));
		result.setHeader(PgnHeader.BlackClock, PgnUtils.timeToClock(0));
		result.setHeader(PgnHeader.BlackElo, "");
		result.setHeader(PgnHeader.WhiteElo, "");
		result.setHeader(PgnHeader.Event, "Examining " + movesMessage.gameType
				+ " game");
		result.setHeader(PgnHeader.Variant, result.getVariant().toString());
		return result;
	}

	public static Game createGame(G1Message g1, Style12Message style12,
			boolean isBics) {
		Variant variant = IcsUtils.identifierToGameType(g1.gameTypeDescription);

		Game result = createGameFromVariant(variant, style12, isBics);
		result.setId(g1.gameId);
		result.addState(Game.UPDATING_SAN_STATE);
		result.addState(Game.UPDATING_ECO_HEADERS_STATE);
		result.setHeader(PgnHeader.Date,
				PgnUtils.longToPgnDate(System.currentTimeMillis()));
		result.setHeader(PgnHeader.Round, "?");
		result.setHeader(PgnHeader.Site, "freechess.org");
		result.setHeader(PgnHeader.TimeControl, PgnUtils
				.timeIncMillisToTimeControl(g1.initialWhiteTimeMillis,
						g1.initialWhiteIncMillis));
		result.setHeader(PgnHeader.BlackRemainingMillis, String.valueOf(g1.initialBlackTimeMillis));
		result.setHeader(PgnHeader.WhiteRemainingMillis, String.valueOf(g1.initialWhiteTimeMillis));
		result.setHeader(PgnHeader.WhiteClock,
				PgnUtils.timeToClock(g1.initialWhiteTimeMillis));
		result.setHeader(PgnHeader.BlackClock,
				PgnUtils.timeToClock(g1.initialBlackTimeMillis));
		result.setHeader(PgnHeader.BlackElo, g1.blackRating);
		result.setHeader(PgnHeader.WhiteElo, g1.whiteRating);
		result.setHeader(PgnHeader.Event, g1.initialWhiteTimeMillis / 60000
				+ " " + g1.initialWhiteIncMillis / 1000 + " "
				+ (!g1.isRated ? "unrated" : "rated") + " "
				+ (g1.isPrivate ? "private " : "") + g1.gameTypeDescription);

		return result;
	}

	public static Game createGame(Style12Message message, String entireMessage) {
		if (message.relation == Style12Message.EXAMINING_GAME_RELATION) {

			boolean isSetup = entireMessage.contains("setup mode");
			Game game = isSetup ? new SetupGame() : new ClassicGame();
			game.setId(message.gameId);
			game.addState(Game.UPDATING_SAN_STATE);
			game.addState(Game.UPDATING_ECO_HEADERS_STATE);
			game.setHeader(PgnHeader.Date,
					PgnUtils.longToPgnDate(System.currentTimeMillis()));
			game.setHeader(PgnHeader.Round, "?");
			game.setHeader(PgnHeader.Site, "freechess.org");
			game.setHeader(PgnHeader.TimeControl,
					PgnUtils.timeIncMillisToTimeControl(0, 0));
			game.setHeader(PgnHeader.BlackRemainingMillis, "" + 0);
			game.setHeader(PgnHeader.WhiteRemainingMillis, "" + 0);
			game.setHeader(PgnHeader.WhiteClock, PgnUtils.timeToClock(0));
			game.setHeader(PgnHeader.BlackClock, PgnUtils.timeToClock(0));
			game.setHeader(PgnHeader.BlackElo, "");
			game.setHeader(PgnHeader.WhiteElo, "");
			game.setHeader(PgnHeader.Event, isSetup ? "Setting Up Position"
					: "Examining Game");
			updateNonPositionFields(game, message);
			updatePosition(game, message);
			verifyLegal(game);
			return game;
		} else if (message.relation == Style12Message.ISOLATED_POSITION_RELATION) {
			Game game = new ClassicGame();
			game.setId(message.gameId);
			game.addState(Game.UPDATING_SAN_STATE);
			game.addState(Game.UPDATING_ECO_HEADERS_STATE);
			game.setHeader(PgnHeader.Date,
					PgnUtils.longToPgnDate(System.currentTimeMillis()));
			game.setHeader(PgnHeader.Round, "?");
			game.setHeader(PgnHeader.Site, "freechess.org");
			game.setHeader(PgnHeader.TimeControl,
					PgnUtils.timeIncMillisToTimeControl(0, 0));
			game.setHeader(PgnHeader.BlackRemainingMillis, "" + 0);
			game.setHeader(PgnHeader.WhiteRemainingMillis, "" + 0);
			game.setHeader(PgnHeader.WhiteClock, PgnUtils.timeToClock(0));
			game.setHeader(PgnHeader.BlackClock, PgnUtils.timeToClock(0));
			game.setHeader(PgnHeader.BlackElo, "");
			game.setHeader(PgnHeader.WhiteElo, "");
			game.setHeader(PgnHeader.Event, "Isolated Position");
			updateNonPositionFields(game, message);
			updatePosition(game, message);
			verifyLegal(game);
			return game;
		} else {
			LOG.error("Cant create an examined game for relation "
					+ message.relation);
			throw new IllegalStateException(
					"Cant created a examined or setup game from a game with relation "
							+ message.relation);
		}
	}

	public static Game createGameFromVariant(Variant variant, Game existingGame) {
		Game result = null;
		switch (variant) {
		case classic:
		case blitz:
		case lightning:
		case standard:
			result = new ClassicGame();
			result.setHeader(PgnHeader.Variant, variant.name());
			break;
		case wild:
			result = new WildGame();
			break;
		case suicide:
			result = new SuicideGame();
			break;
		case losers:
			result = new LosersGame();
			break;
		case atomic:
			result = new AtomicGame();
			break;
		case crazyhouse:
			result = existingGame instanceof FischerRandomCrazyhouseGame ? new FischerRandomCrazyhouseGame()
					: new CrazyhouseGame();
			break;
		case bughouse:
			result = existingGame instanceof FischerRandomBughouseGame ? new FischerRandomBughouseGame()
					: new BughouseGame();
			break;
		case fischerRandom:
			result = new FischerRandomGame();
			break;
		default:
			LOG.warn("Unknown variant: " + variant + " assuming its classical");
			result = new ClassicGame();
		}
		return result;
	}

	public static Game createGameFromVariant(Variant variant,
			Style12Message message, boolean isBicsMessage) {
		Game result = null;

		if (message.relation == Style12Message.OBSERVING_EXAMINED_GAME_RELATION) {
			result = new SetupGame();
			result.setHeader(PgnHeader.Variant, variant.name());
			return result;
		}

		boolean isFrBugOrFrZh = false;

		if (isBicsMessage
				&& (variant == Variant.bughouse || variant == Variant.crazyhouse)) {
			isFrBugOrFrZh = message.position[0][0] != ROOK
					|| message.position[0][1] != KNIGHT
					|| message.position[0][2] != BISHOP
					|| message.position[0][3] != QUEEN
					|| message.position[0][4] != KING
					|| message.position[0][5] != BISHOP
					|| message.position[0][6] != KNIGHT
					|| message.position[0][7] != ROOK;
		}

		switch (variant) {
		case classic:
		case blitz:
		case lightning:
		case standard:
			result = new ClassicGame();
			result.setHeader(PgnHeader.Variant, variant.name());
			break;
		case wild:
			result = new WildGame();
			break;
		case suicide:
			result = new SuicideGame();
			break;
		case losers:
			result = new LosersGame();
			break;
		case atomic:
			result = new AtomicGame();
			break;
		case crazyhouse:
			result = isFrBugOrFrZh ? new FischerRandomCrazyhouseGame()
					: new CrazyhouseGame();
			break;
		case bughouse:
			result = isFrBugOrFrZh ? new FischerRandomBughouseGame()
					: new BughouseGame();
			break;
		case fischerRandom:
			result = new FischerRandomGame();
			break;
		default:
			LOG.warn("Unsupported variant: " + variant
					+ " assuming its Classic");
			result = new ClassicGame();
		}
		return result;
	}

	/**
	 * Filters out illegal chars, and appends a \n to the passed in message.
	 * This also converts unicode chars into Maciejg format. See
	 * maciejgFormatToUnicode for more info.
	 */
	public static void filterOutbound(StringBuilder message) {
		for (int i = 0; i < message.length(); i++) {
			char currentChar = message.charAt(i);
			if (LEGAL_CHARACTERS.indexOf(currentChar) == -1) {
				if (currentChar > 256) {
					int charAsInt = currentChar;
					String stringVersion = Integer.toString(charAsInt, 16);
					String replacement = "&#x" + stringVersion + ";";
					message.replace(i, i + 1, replacement);
					i += replacement.length() - 1;
				} else {
					message.deleteCharAt(i);
					i--;
				}
			}
		}
	}

	public static BuggerStatus getBuggserStatus(String status) {
		if (status.equals(":")) {
			return BuggerStatus.Closed;
		} else if (status.equals("^")) {
			return BuggerStatus.Playing;
		} else if (status.equals(".")) {
			return BuggerStatus.Idle;
		} else if (status.equals("~")) {
			return BuggerStatus.Simul;
		} else if (status.equals("#")) {
			return BuggerStatus.Examining;
		} else if (status.equals("&")) {
			return BuggerStatus.InTourney;
		} else {
			return BuggerStatus.Available;
		}
	}

	/**
	 * Returns the game type constant for the specified identifier.
	 *
	 */
	public static Variant identifierToGameType(String identifier) {
		Variant result = null;

		if (identifier.indexOf(SUICIDE_IDENTIFIER) != -1) {
			result = Variant.suicide;
		} else if (identifier.indexOf(BUGHOUSE_IDENTIFIER) != -1) {
			result = Variant.bughouse;
		} else if (identifier.indexOf(CRAZYHOUSE_IDENTIFIER) != -1) {
			result = Variant.crazyhouse;
		} else if (identifier.indexOf(STANDARD_IDENTIFIER) != -1) {
			result = Variant.standard;
		} else if (identifier.indexOf(FISCHER_RANDOM_IDENTIFIER) != -1) {
			result = Variant.fischerRandom;
		} else if (identifier.indexOf(WILD_IDENTIFIER) != -1) {
			result = Variant.wild;
		} else if (identifier.indexOf(LIGHTNING_IDENTIFIER) != -1) {
			result = Variant.lightning;
		} else if (identifier.indexOf(BLITZ_IDENTIFIER) != -1) {
			result = Variant.blitz;
		} else if (identifier.indexOf(ATOMIC_IDENTIFIER) != -1) {
			result = Variant.atomic;
		} else if (identifier.indexOf(LOSERS_IDENTIFIER) != -1) {
			result = Variant.losers;
		} else if (identifier.indexOf(UNTIMED_IDENTIFIER) != -1) {
			result = Variant.classic;
		} else {
			LOG.warn("Unknown identifier " + identifier
					+ " encountered. Assuming its classic.");
			result = Variant.classic;
		}

		return result;
	}

	/**
	 * Removes the ICS channel wrapping around a specified channel word
	 * returning only the channel number.
	 *
	 * Returns -1 if the specified word is not a channel.
	 */
	public static boolean isLikelyChannel(String word) {
		boolean result = false;
		if (word != null) {
			RaptorStringTokenizer tok = new RaptorStringTokenizer(word,
					CHANNEL_STRIP_CHARS, true);
			if (tok.hasMoreTokens()) {
				String current = tok.nextToken();
				try {
					int channel = Integer.parseInt(current);
					return channel >= 0 && channel <= 255;
				} catch (NumberFormatException nfe) {
					if (tok.hasMoreTokens()) {
						try {
							current = tok.nextToken();
							int channel = Integer.parseInt(current);
							return channel >= 0 && channel <= 255;
						} catch (NumberFormatException nfe2) {
							if (tok.hasMoreTokens()) {
								try {
									current = tok.nextToken();
									int channel = Integer.parseInt(current);
									return channel >= 0 && channel <= 255;
								} catch (NumberFormatException nfe3) {
									if (tok.hasMoreTokens()) {
										try {
											current = tok.nextToken();
											int channel = Integer
													.parseInt(current);
											return channel >= 0
													&& channel <= 255;
										} catch (NumberFormatException nfe4) {
										}
									}
								}
							}
						}
					}
				}

			}
		}
		return result;
	}

	public static boolean isLikelyGameId(String word) {
		boolean result = false;
		if (word != null) {
			try {
				int gameId = Integer.parseInt(stripGameId(word));
				return gameId > 0 && gameId <= 5000;
			} catch (NumberFormatException nfe) {
				return false;
			}
		}
		return result;
	}

	/**
	 * Returns true if the specified word is probably a persons name.
	 */
	public static boolean isLikelyPerson(String word) {
		String strippedWord = stripWord(word);
		if (strippedWord != null && strippedWord.length() > 2
				&& strippedWord.length() <= 17) {
			boolean result = true;
			for (int i = 0; result && i < strippedWord.length(); i++) {
				result = VALID_PERSON_CHARS.indexOf(strippedWord.charAt(i)) != -1;
			}
			return result;
		} else {
			return false;
		}
	}

	/**
	 * Maciejg format, named after him because of his finger notes. Unicode
	 * chars are represented as α β γ δ ε ζ
	 * unicode equivalent \u03B1,\U03B2,...
	 */
	public static String maciejgFormatToUnicode(String inputString) {
		StringBuilder builder = new StringBuilder(inputString);
		int unicodePrefix = 0;
		while ((unicodePrefix = builder.indexOf("&#x", unicodePrefix)) != -1) {
			int endIndex = builder.indexOf(";", unicodePrefix);
			if (endIndex == -1) {
				break;
			}
			String maciejgWord = builder.substring(unicodePrefix + 3, endIndex);
			maciejgWord = StringUtils.replaceChars(maciejgWord, " \\\n", "")
					.toUpperCase();
			if (maciejgWord.length() <= 5) {
				try {
					int intValue = Integer.parseInt(maciejgWord, 16);
					String unicode = new String(new char[] { (char) intValue });
					builder.replace(unicodePrefix, endIndex + 1, unicode);
				} catch (NumberFormatException nfe) {
					unicodePrefix = endIndex + 1;
				}
			} else {
				unicodePrefix = endIndex + 1;
			}
		}
		return builder.toString();
	}

	/**
	 * Removes all line breaks and excessive spaces from the specified message.
	 *
	 * @param msg
	 *            THe message to remove line breaks from.
	 * @return The message without any line breaks.
	 */
	public static String removeLineBreaks(String msg) {
		StringBuilder result = new StringBuilder(msg.length());
		RaptorStringTokenizer tok = new RaptorStringTokenizer(msg, "\n\\ ",
				true);
		if (tok.hasMoreTokens()) {
			result.append(tok.nextToken());
		}
		while (tok.hasMoreTokens()) {
            result.append(" ").append(tok.nextToken());
		}
		return result.toString();
	}

	public static void resetGame(Game game, Style12Message message) {
		IcsUtils.clearGamePosition(game);
		IcsUtils.updateNonPositionFields(game, message);
		IcsUtils.updatePosition(game, message);
		verifyLegal(game);
	}

	public static String stripChannel(String word) {
		String result = null;
		if (word != null) {
			RaptorStringTokenizer tok = new RaptorStringTokenizer(word,
					CHANNEL_STRIP_CHARS, true);
			if (tok.hasMoreTokens()) {
				String current = tok.nextToken();
				try {
					int channel = Integer.parseInt(current);
					if (channel >= 0 && channel <= 255) {
						return String.valueOf(channel);
					}
				} catch (NumberFormatException nfe) {
					if (tok.hasMoreTokens()) {
						try {
							current = tok.nextToken();
							int channel = Integer.parseInt(current);
							if (channel >= 0 && channel <= 255) {
								return String.valueOf(channel);
							}
						} catch (NumberFormatException nfe2) {
							if (tok.hasMoreTokens()) {
								try {
									current = tok.nextToken();
									int channel = Integer.parseInt(current);
									if (channel >= 0 && channel <= 255) {
										return String.valueOf(channel);
									}
								} catch (NumberFormatException nfe3) {
									if (tok.hasMoreTokens()) {
										try {
											current = tok.nextToken();
											int channel = Integer
													.parseInt(current);
											if (channel >= 0 && channel <= 255) {
												return String.valueOf(channel);
											}
										} catch (NumberFormatException nfe4) {
										}
									}
								}
							}
						}
					}
				}

			}
		}
		return result;
	}

	public static String stripGameId(String gameId) {
		if (gameId.endsWith(")") || gameId.endsWith(".")
				|| gameId.endsWith(":")) {
			return gameId.substring(0, gameId.length() - 1);
		} else if (gameId.endsWith("]")) {
			int i = gameId.lastIndexOf('[');
			if (i != -1) {
				return gameId.substring(i + 1, gameId.length() - 1);
			}
		}
		return gameId;
	}

	public static String stripTitles(String playerName) {
		StringTokenizer stringtokenizer = new StringTokenizer(playerName,
				"()[]'");
		if (stringtokenizer.hasMoreTokens()) {
			return stringtokenizer.nextToken();
		} else {
			return playerName;
		}
	}

	/**
	 * Returns the word with all characters in STRIP_CHARS removed. If word
	 * contains multiple tokens, the last word is returned.
	 */
	public static String stripWord(String word) {
		if (word != null) {
			word = stripTitles(word);
			return StringUtils.replaceChars(word, STRIP_CHARS, "");
		}
		return null;
	}

	/**
	 * Converts a time in: (0:00.000) mmm:ss.MMM format into a long value
	 * representing milliseconds.
	 *
	 * @param timeString
	 *            The time string.
	 * @return The result.
	 */
	public static final long timeToLong(String timeString) {
		RaptorStringTokenizer tok = new RaptorStringTokenizer(timeString,
				"(:.)", true);
		long minutes = Integer.parseInt(tok.nextToken());
		long seconds = Integer.parseInt(tok.nextToken());
		long millis = Integer.parseInt(tok.nextToken());
		return minutes * 1000 * 60 + seconds * 1000 + millis;
	}

	/**
	 * Updates the moves that are missing in the game to the ones in the move
	 * message.
	 */
	public static void updateGamesMoves(Game game, MovesMessage message) {
		int halfMoveCountGameStartedOn = game.getHalfMoveCount()
				- game.getMoveList().getSize();

		if (message.moves.length > 0 && halfMoveCountGameStartedOn != 0) {
			Game gameClone = null;
			if (message.style12 == null) {
				gameClone = GameFactory.createStartingPosition(game
						.getVariant());
			} else {
				gameClone = createGameFromVariant(game.getVariant(), game);
				updatePosition(gameClone, message.style12);
				if (gameClone.getVariant() == Variant.fischerRandom) {
					((FischerRandomGame) gameClone).initialPositionIsSet();
				} else if (gameClone.getVariant() == Variant.fischerRandomBughouse) {
					((FischerRandomBughouseGame) gameClone)
							.initialPositionIsSet();
				} else if (gameClone.getVariant() == Variant.fischerRandomCrazyhouse) {
					((FischerRandomCrazyhouseGame) gameClone)
							.initialPositionIsSet();
				} else if (gameClone.getVariant() == Variant.wild) {
					((WildGame) gameClone).initialPositionIsSet();
				}

				updateNonPositionFields(gameClone, message.style12);
				game.setHeader(PgnHeader.FEN, gameClone.toFen());
			}
			gameClone.addState(Game.UPDATING_SAN_STATE);
			gameClone.addState(Game.UPDATING_ECO_HEADERS_STATE);
			for (int i = 0; i < message.moves.length; i++) {
				try {
					if (gameClone.isInState(Game.DROPPABLE_STATE)) {
						gameClone.setDropCount(WHITE, PAWN, 1);
						gameClone.setDropCount(WHITE, QUEEN, 1);
						gameClone.setDropCount(WHITE, ROOK, 1);
						gameClone.setDropCount(WHITE, KNIGHT, 1);
						gameClone.setDropCount(WHITE, BISHOP, 1);
						gameClone.setDropCount(BLACK, PAWN, 1);
						gameClone.setDropCount(BLACK, QUEEN, 1);
						gameClone.setDropCount(BLACK, ROOK, 1);
						gameClone.setDropCount(BLACK, KNIGHT, 1);
						gameClone.setDropCount(BLACK, BISHOP, 1);
					}
					Move move = gameClone.makeSanMove(message.moves[i]);
					move.addAnnotation(new TimeTakenForMove(
							message.timePerMove[i]));
				} catch (IllegalArgumentException iae) {
					LOG.error("Could not parse san", iae);
					Raptor.getInstance().onError(
							"Error update game with moves", iae);
				}
			}

			Move[] moves = gameClone.getMoveList().asArray();
			game.getMoveList().prepend(moves);
			game.setInitialEpSquare(gameClone.getInitialEpSquare());
			if (StringUtils.isBlank(game.getHeader(PgnHeader.ECO))
					&& StringUtils.isNotBlank(gameClone
							.getHeader(PgnHeader.ECO))) {
				game.setHeader(PgnHeader.ECO,
						gameClone.getHeader(PgnHeader.ECO));
			}
			if (StringUtils.isBlank(game.getHeader(PgnHeader.Opening))
					&& StringUtils.isNotBlank(gameClone
							.getHeader(PgnHeader.Opening))) {
				game.setHeader(PgnHeader.Opening,
						gameClone.getHeader(PgnHeader.Opening));
			}
		} else if (message.moves.length == 0 && message.style12 != null) {
			game.clear();
			updateNonPositionFields(game, message.style12);
			updatePosition(game, message.style12);
			game.setHeader(PgnHeader.FEN, game.toFen());
			game.removeHeader(PgnHeader.ECO);
			game.removeHeader(PgnHeader.Opening);
		}
	}

	/**
	 * Handles updating everything but the position related fields in the game.
	 * i.e. the bitboards,pieces, etc.
	 */
	public static void updateNonPositionFields(Game game, Style12Message message) {
		switch (message.relation) {
		case Style12Message.EXAMINING_GAME_RELATION:
			game.addState(Game.EXAMINING_STATE);
			break;
		case Style12Message.ISOLATED_POSITION_RELATION:
			break;
		case Style12Message.OBSERVING_EXAMINED_GAME_RELATION:
			game.addState(Game.OBSERVING_EXAMINED_STATE);
			break;
		case Style12Message.OBSERVING_GAME_RELATION:
			game.addState(Game.OBSERVING_STATE);
			break;
		case Style12Message.PLAYING_MY_MOVE_RELATION:
		case Style12Message.PLAYING_OPPONENTS_MOVE_RELATION:
			game.addState(Game.PLAYING_STATE);
			break;
		}

		if (message.isClockTicking) {
			game.addState(Game.IS_CLOCK_TICKING_STATE);
		} else {
			game.clearState(Game.IS_CLOCK_TICKING_STATE);
		}

		game.addState(Game.ACTIVE_STATE);

		game.setHeader(PgnHeader.Black, IcsUtils.stripTitles(message.blackName));
		game.setHeader(PgnHeader.White, IcsUtils.stripTitles(message.whiteName));

		game.setHeader(PgnHeader.WhiteRemainingMillis, String.valueOf(message.whiteRemainingTimeMillis));
		game.setHeader(PgnHeader.BlackRemainingMillis, String.valueOf(message.blackRemainingTimeMillis));

		game.setColorToMove(message.isWhitesMoveAfterMoveIsMade ? WHITE : BLACK);

		game.setCastling(WHITE, message.canWhiteCastleKSide
				&& message.canWhiteCastleQSide ? CASTLE_BOTH
				: message.canWhiteCastleKSide ? CASTLE_SHORT
						: message.canWhiteCastleQSide ? CASTLE_LONG
								: CASTLE_NONE);
		game.setCastling(BLACK, message.canBlackCastleKSide
				&& message.canBlackCastleQSide ? CASTLE_BOTH
				: message.canBlackCastleKSide ? CASTLE_SHORT
						: message.canBlackCastleQSide ? CASTLE_LONG
								: CASTLE_NONE);

		if (message.doublePawnPushFile == -1) {
			game.setEpSquare(EMPTY_SQUARE);
			game.setInitialEpSquare(EMPTY_SQUARE);
		} else {
			int doublePawnPushSquare = GameUtils.getSquare(
					message.isWhitesMoveAfterMoveIsMade ? 4 : 5,
					message.doublePawnPushFile);
			game.setEpSquare(doublePawnPushSquare);
			game.setInitialEpSquare(doublePawnPushSquare);
		}

		game.setFiftyMoveCount(message.numberOfMovesSinceLastIrreversible);

		int fullMoveCount = message.fullMoveNumber;
		game.setHalfMoveCount(game.getColorToMove() == BLACK ? fullMoveCount * 2 - 1
				: fullMoveCount * 2 - 2);

		game.incrementRepCount();
	}

	/**
	 * Should be invoked after the castling,EP,and to move data has been set.
	 */
	public static void updatePosition(Game game, Style12Message style12) {
		for (int i = 0; i < style12.position.length; i++) {
			for (int j = 0; j < style12.position[i].length; j++) {
				if (style12.position[i][j] != EMPTY) {
					int square = GameUtils.getSquare(i, j);
					int pieceColor = ChessBoardUtils
							.isWhitePiece(style12.position[i][j]) ? WHITE
							: BLACK;
					int piece = ChessBoardUtils
							.pieceFromColoredPiece(style12.position[i][j]);
					long squareBB = GameUtils.getBitboard(square);

					game.setPieceCount(pieceColor, piece,
							game.getPieceCount(pieceColor, piece) + 1);

					game.getBoard()[square] = piece;
					game.setColorBB(pieceColor, game.getColorBB(pieceColor)
							| squareBB);
					game.setOccupiedBB(game.getOccupiedBB() | squareBB);
					game.setPieceBB(pieceColor, piece,
							game.getPieceBB(pieceColor, piece) | squareBB);
				}
			}
		}

		game.setEmptyBB(~game.getOccupiedBB());
		game.setNotColorToMoveBB(~game.getColorBB(game.getColorToMove()));

		game.setZobristPositionHash(ZobristUtils.zobristHashPositionOnly(game));
		game.setZobristGameHash(game.getZobristPositionHash()
				^ ZobristUtils.zobrist(game.getColorToMove(),
						game.getEpSquare(), game.getCastling(WHITE),
						game.getCastling(BLACK)));

		if (game.isInState(Game.SETUP_STATE)) {
			game.setPieceCount(WHITE, PAWN, 1);
			game.setPieceCount(WHITE, KNIGHT, 1);
			game.setPieceCount(WHITE, BISHOP, 1);
			game.setPieceCount(WHITE, ROOK, 1);
			game.setPieceCount(WHITE, QUEEN, 1);
			game.setPieceCount(WHITE, KING, 1);
			game.setPieceCount(BLACK, PAWN, 1);
			game.setPieceCount(BLACK, KNIGHT, 1);
			game.setPieceCount(BLACK, BISHOP, 1);
			game.setPieceCount(BLACK, ROOK, 1);
			game.setPieceCount(BLACK, QUEEN, 1);
			game.setPieceCount(BLACK, KING, 1);
		}
	}

	public static void verifyLegal(Game game) {
		if (!game.isLegalPosition()) {
			throw new IllegalStateException("Position is not legal: "
					+ game.toString());
		}
	}
}


text:
package org.uberfire.ext.preferences.client.form;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PreDestroy;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.inject.Inject;

import org.jboss.errai.common.client.api.Caller;
import org.jboss.errai.common.client.api.RemoteCallback;
import org.jboss.errai.ioc.client.container.SyncBeanManager;
import org.uberfire.client.mvp.UberElement;
import org.uberfire.ext.preferences.shared.PreferenceStore;
import org.uberfire.workbench.events.NotificationEvent;

@Dependent
public class PreferencesEditorFormPresenter {

    public interface View extends UberElement<PreferencesEditorFormPresenter> {

        String getNoChangesMessage();

        String getPreferencesSavedSuccessfullyMessage();

        String getUnexpectedErrorDuringSavingMessage( String details );
    }

    private final SyncBeanManager beanManager;

    private final View view;

    private final Caller<PreferenceStore> preferenceStoreCaller;

    private final Event<NotificationEvent> notification;

    private List<PreferenceItemEditorPresenter> preferencesEditors;

    @Inject
    public PreferencesEditorFormPresenter( final SyncBeanManager beanManager,
                                           final View view,
                                           final Caller<PreferenceStore> preferenceStoreCaller,
                                           final Event<NotificationEvent> notification ) {
        this.beanManager = beanManager;
        this.view = view;
        this.preferenceStoreCaller = preferenceStoreCaller;
        this.notification = notification;
    }

    public void setManagedKeys( final List<String> managedKeys ) {
        final PreferencesEditorFormPresenter presenter = this;

        preferenceStoreCaller.call( new RemoteCallback<Map<String, Object>>() {
            @Override
            public void callback( final Map<String, Object> preferences ) {
                preferencesEditors = new ArrayList<>();

                for ( final Map.Entry<String, Object> preference : preferences.entrySet() ) {
                    final PreferenceItemEditorPresenter preferenceEditor = beanManager.lookupBean( PreferenceItemEditorPresenter.class ).newInstance();
                    preferenceEditor.setPreferenceKey( preference.getKey() );
                    preferenceEditor.setPersistedPreferenceValue( preference.getValue().toString() );

                    preferencesEditors.add( preferenceEditor );
                }

                view.init( presenter );
            }
        } ).search( managedKeys );
    }

    public void save() {
        Map<String, String> preferencesToPersist = getPreferencesToPersist();

        if ( !preferencesToPersist.isEmpty() ) {
            preferenceStoreCaller.call( voidReturn -> {
                notification.fire( new NotificationEvent( view.getPreferencesSavedSuccessfullyMessage(), NotificationEvent.NotificationType.SUCCESS ) );
            }, ( o, throwable ) -> {
                notification.fire( new NotificationEvent( view.getUnexpectedErrorDuringSavingMessage( throwable.getMessage() ), NotificationEvent.NotificationType.ERROR ) );
                return false;
            } ).put( preferencesToPersist );
        } else {
            notification.fire( new NotificationEvent( view.getNoChangesMessage(), NotificationEvent.NotificationType.INFO ) );
        }
    }

    public void undoChanges() {
        for ( final PreferenceItemEditorPresenter preferenceEditor : preferencesEditors ) {
            preferenceEditor.undoChanges();
        }
    }

    protected Map<String, String> getPreferencesToPersist() {
        Map<String, String> preferencesToPersist = new HashMap<>();

        for ( final PreferenceItemEditorPresenter preference : preferencesEditors ) {
            if ( preference.shouldBePersisted() ) {
                final String key = preference.getPreferenceKey();
                final String newValue = preference.getNewPreferenceValue();
                preferencesToPersist.put( key, newValue );
                preference.setPersistedPreferenceValue( newValue );
            }
        }
        return preferencesToPersist;
    }

    public List<PreferenceItemEditorPresenter> getPreferencesEditors() {
        return preferencesEditors;
    }

    public View getView() {
        return view;
    }

    @PreDestroy
    public void destroy() {
        if ( preferencesEditors != null ) {
            for ( PreferenceItemEditorPresenter item : preferencesEditors ) {
                beanManager.destroyBean( item );
            }
        }
    }
}


text:
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

import { Component, PropTypes, createElement } from 'react';
import invariant from 'invariant';
import createConnectedFieldArray from './ConnectedFieldArray';
import shallowCompare from './util/shallowCompare';

var createFieldArray = function createFieldArray(_ref) {
  var deepEqual = _ref.deepEqual;
  var getIn = _ref.getIn;
  var size = _ref.size;

  var ConnectedFieldArray = createConnectedFieldArray({ deepEqual: deepEqual, getIn: getIn, size: size });

  var FieldArray = function (_Component) {
    _inherits(FieldArray, _Component);

    function FieldArray(props, context) {
      _classCallCheck(this, FieldArray);

      var _this = _possibleConstructorReturn(this, (FieldArray.__proto__ || Object.getPrototypeOf(FieldArray)).call(this, props, context));

      if (!context._reduxForm) {
        throw new Error('FieldArray must be inside a component decorated with reduxForm()');
      }
      return _this;
    }

    _createClass(FieldArray, [{
      key: 'shouldComponentUpdate',
      value: function shouldComponentUpdate(nextProps, nextState) {
        return shallowCompare(this, nextProps, nextState);
      }
    }, {
      key: 'componentWillMount',
      value: function componentWillMount() {
        this.context._reduxForm.register(this.name, 'FieldArray');
      }
    }, {
      key: 'componentWillReceiveProps',
      value: function componentWillReceiveProps(nextProps) {
        if (this.props.name !== nextProps.name) {
          // unregister old name
          this.context._reduxForm.unregister(this.props.name);
          // register new name
          this.context._reduxForm.register(nextProps.name, 'FieldArray');
        }
      }
    }, {
      key: 'componentWillUnmount',
      value: function componentWillUnmount() {
        this.context._reduxForm.unregister(this.name);
      }
    }, {
      key: 'getRenderedComponent',
      value: function getRenderedComponent() {
        invariant(this.props.withRef, 'If you want to access getRenderedComponent(), ' + 'you must specify a withRef prop to FieldArray');
        return this.refs.connected.getWrappedInstance().getRenderedComponent();
      }
    }, {
      key: 'render',
      value: function render() {
        return createElement(ConnectedFieldArray, _extends({}, this.props, {
          syncError: this.syncError,
          syncWarning: this.syncWarning,
          _reduxForm: this.context._reduxForm,
          ref: 'connected'
        }));
      }
    }, {
      key: 'name',
      get: function get() {
        return this.props.name;
      }
    }, {
      key: 'dirty',
      get: function get() {
        return this.refs.connected.getWrappedInstance().dirty;
      }
    }, {
      key: 'pristine',
      get: function get() {
        return this.refs.connected.getWrappedInstance().pristine;
      }
    }, {
      key: 'value',
      get: function get() {
        return this.refs.connected.getWrappedInstance().value;
      }
    }]);

    return FieldArray;
  }(Component);

  FieldArray.propTypes = {
    name: PropTypes.string.isRequired,
    component: PropTypes.func.isRequired,
    props: PropTypes.object
  };
  FieldArray.contextTypes = {
    _reduxForm: PropTypes.object
  };

  return FieldArray;
};

export default createFieldArray;


text:
module List where

data List a = Nil | Cons a (List a)
  deriving (Show)

instance Functor List where
  fmap f Nil = Nil
  fmap f (Cons head tail) = Cons (f head) (fmap f tail)

plus3 x = x + 3


text:
package it.uniroma2.sag.kelp.algorithms.binary;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import it.uniroma2.sag.kelp.data.dataset.SimpleDataset;
import it.uniroma2.sag.kelp.data.example.Example;
import it.uniroma2.sag.kelp.data.label.Label;
import it.uniroma2.sag.kelp.data.label.StringLabel;
import it.uniroma2.sag.kelp.kernel.Kernel;
import it.uniroma2.sag.kelp.kernel.cache.FixSizeKernelCache;
import it.uniroma2.sag.kelp.kernel.vector.LinearKernel;
import it.uniroma2.sag.kelp.learningalgorithm.classification.libsvm.BinaryCSvmClassification;
import it.uniroma2.sag.kelp.predictionfunction.classifier.ClassificationOutput;
import it.uniroma2.sag.kelp.predictionfunction.classifier.Classifier;
import it.uniroma2.sag.kelp.utils.evaluation.BinaryClassificationEvaluator;
import it.uniroma2.sag.kelp.utils.exception.NoSuchPerformanceMeasureException;

public class BinaryCSVMTest {
	// Accuracy: 0.9766667
	// F1 = 0.9769737
	private static Classifier f = null;
	private static SimpleDataset trainingSet;
	private static SimpleDataset testSet;
	private static ArrayList<Float> scores;

	private Label positiveClass = new StringLabel("+1");

	@BeforeClass
	public static void learnModel() {
		trainingSet = new SimpleDataset();
		testSet = new SimpleDataset();
		try {
			trainingSet.populate("src/test/resources/svmTest/binary/binary_train.klp");
			// Read a dataset into a test variable
			testSet.populate("src/test/resources/svmTest/binary/binary_test.klp");
		} catch (Exception e) {
			e.printStackTrace();
			Assert.assertTrue(false);
		}

		// define the positive class
		StringLabel positiveClass = new StringLabel("+1");

		// define the kernel
		Kernel kernel = new LinearKernel("0");

		// add a cache
		kernel.setKernelCache(new FixSizeKernelCache(trainingSet
				.getNumberOfExamples()));

		// define the learning algorithm
		BinaryCSvmClassification learner = new BinaryCSvmClassification(kernel,
				positiveClass, 1, 1);

		// learn and get the prediction function
		learner.learn(trainingSet);
		f = learner.getPredictionFunction();
	}

	@BeforeClass
	public static void loadClassificationScores() {
		try {
			scores = new ArrayList<Float>();
			String filepath = "src/test/resources/svmTest/binary/binaryCSvm/outScores_libsvm_c-svm.txt";
			BufferedReader in = null;
			String encoding = "UTF-8";
			if (filepath.endsWith(".gz")) {
				in = new BufferedReader(new InputStreamReader(
						new GZIPInputStream(new FileInputStream(filepath)),
						encoding));
			} else {
				in = new BufferedReader(new InputStreamReader(
						new FileInputStream(filepath), encoding));
			}

			String str = "";
			while ((str = in.readLine()) != null) {
				scores.add(Float.parseFloat(str));
			}

			in.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			Assert.assertTrue(false);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			Assert.assertTrue(false);
		} catch (IOException e) {
			e.printStackTrace();
			Assert.assertTrue(false);
		}
	}

	@Test
	public void testAccuracy() {
		BinaryClassificationEvaluator ev = new BinaryClassificationEvaluator(
				positiveClass);
		for (Example e : testSet.getExamples()) {
			ClassificationOutput p = f.predict(testSet.getNextExample());
			ev.addCount(e, p);
		}

		try {
			float acc = ev.getPerformanceMeasure("accuracy");
			Assert.assertEquals(0.9766667f, acc, 0.000001);
		} catch (NoSuchPerformanceMeasureException e1) {
			e1.printStackTrace();
		}
	}

	@Test
	public void testF1() {
		BinaryClassificationEvaluator ev = new BinaryClassificationEvaluator(
				positiveClass);
		for (Example e : testSet.getExamples()) {
			ClassificationOutput p = f.predict(e);
			ev.addCount(e, p);
		}

		try {
			float acc = ev.getPerformanceMeasure("f1");
			Assert.assertEquals(0.9769737f, acc, 0.000001);
		} catch (NoSuchPerformanceMeasureException e1) {
			e1.printStackTrace();
		}
	}

	@Test
	public void checkScores() {
		for (int i = 0; i < testSet.getExamples().size(); ++i) {
			Example e = testSet.getExample(i);
			ClassificationOutput p = f.predict(e);
			Float score = p.getScore(positiveClass);
			Assert.assertEquals(scores.get(i).floatValue(), score.floatValue(),
					0.001f);
		}
	}
}


text:
package org.jetbrains.idea.svn;

import com.intellij.openapi.vfs.VirtualFile;
import org.tmatesoft.svn.core.SVNURL;

public class RootMixedInfo {
  /**
   * working copy root path
   */
  private final String myFilePath;
  private final VirtualFile myFile;
  /**
   * url corresponding to working copy root
   */
  private final SVNURL myUrl;
  private final VirtualFile myParentVcsRoot;

  public RootMixedInfo(final String filePath, final VirtualFile file, final SVNURL url, final VirtualFile parentVcsRoot) {
    myFilePath = filePath;
    myFile = file;
    myUrl = url;
    myParentVcsRoot = parentVcsRoot;
  }

  public String getFilePath() {
    return myFilePath;
  }

  public VirtualFile getFile() {
    return myFile;
  }

  public SVNURL getUrl() {
    return myUrl;
  }

  public VirtualFile getParentVcsRoot() {
    return myParentVcsRoot;
  }
}


text:
define({
  root: ({
    _widgetLabel: "Screening", // Shown as label of widget
    geometryServicesNotFound: "Geometry service not available.", // Shown as error message if geometry service is not found
    unableToDrawBuffer: "Unable to draw buffer. Please try again.", // Shown as alert message if unable to draw buffer
    invalidConfiguration: "Invalid configuration.", // Shown as alert message if configuration settings failed on widget load
    clearAOIButtonLabel: "Start Over", // Shown as label for Clear AOI Button
    noGraphicsShapefile: "The uploaded shapefile contains no graphics.", // When no graphics is present in the layer
    zoomToLocationTooltipText: "Zoom to location", // Show on hover of the zoomToLocation button
    noGraphicsToZoomMessage: "No graphics found to zoom in.", // Show when no graphics found to zoom in on zoom button click
    placenameWidget: {
      placenameLabel: "Search for a location"
    }, // Shown as label to guide user to enter value in search box
    // Draw Tool widget
    drawToolWidget: {
      useDrawToolForAOILabel: "Select draw mode", // Shown as label to guide user to use draw tools to define AOI
      toggleSelectability: "Click to toggle selectability",
      chooseLayerTitle: "Choose selectable layers", // Shown as a title for list of layers
      selectAllLayersText: "Select All",
      layerSelectionWarningTooltip: "At least one layer should be selected for creating AOI",
      selectToolLabel: "Select tool"
    },
    // Shapefile widget
    shapefileWidget: {
      shapefileLabel: "Upload a zipped shapefile", // Shown as label to guide user to upload a shapefile to define AOI
      uploadShapefileButtonText: "Upload", // Shown as text for upload a shapefile Button
      unableToUploadShapefileMessage: "Unable to upload shapefile." // Shown as alert message if upload to shapefile fails
    },
    // Coordinates widget
    coordinatesWidget: {
      selectStartPointFromSearchText: "Define a starting point", // Shown as label to guide user to define a start point by entering address in search box
      addButtonTitle: "Add", // Shown as title for add button
      deleteButtonTitle: "Remove", // Shown as title for remove button
      mapTooltipForStartPoint: "Click on map to define a start point", // Shown as label to guide user to click on map to select start point
      mapTooltipForUpdateStartPoint: "Click on map to update the start point", // Shown as label to guide user to click on map to update start point
      locateText: "Locate", // Shown as label text locate
      locateByMapClickText: "Select initial coordinates", // Shown as label to select initial coordinates
      enterBearingAndDistanceLabel: "Enter bearing and distance from start point", // Shown as label to guide user to enter bearing and distance from start point
      bearingTitle: "Bearing", // Shown as label text Bearing
      distanceTitle: "Distance", // Shown as label text Distance
      planSettingTooltip: "Plan Settings", // Shown as label  text Plan Settings
      invalidLatLongMessage: "Please enter valid values." // Displayed when locate is clicked & lat, long is invalid
    },
    // Buffer Distance and Unit
    bufferDistanceAndUnit: { // Shown as buffer units
      bufferInputTitle: "Buffer distance (optional)",
      bufferInputLabel: "Show results within",
      bufferDistanceLabel: "Buffer distance",
      bufferUnitLabel: "Buffer unit",
    },
    // Traverse grid
    traverseSettings: {
      bearingLabel: "Bearing", // Shown as label for bearing column in traverse grid
      lengthLabel: "Length", // Shown as label for length column in traverse grid
      addButtonTitle: "Add", // Shown as title on add button
      deleteButtonTitle: "Remove", // Shown as title on delete button
      deleteBearingAndLengthLabel: "Remove bearing and length row",
      addButtonLabel: "Add bearing and length"
    },
    // Plan settings
    planSettings: {
      expandGridTooltipText: "Expand grid", // Show on hover of the expand grid button
      collapseGridTooltipText: "Collapse grid", // Show on hover of the collapse grid button
      directionUnitLabelText: "Directions Unit",
      distanceUnitLabelText: "Distance and Length Units",
      planSettingsComingSoonText: "Coming Soon" // Message displayed on click of plan settings icon
    },
    // New traverse lines
    newTraverse: {
      invalidBearingMessage: "Invalid Bearing.", // Shown when invalid bearing is entered
      invalidLengthMessage: "Invalid Length.", // Shown when invalid length is entered
      negativeLengthMessage: "Negative Length" // Shown when negative length is entered
    },
    // Reports tab
    reportsTab: {
      aoiAreaText: "AOI area", // Shown while displaying the aoi area
      downloadButtonTooltip: "Download", // Shown as a tooltip for download button
      printButtonTooltip: "Print", // Shown as a tooltip for print button
      uploadShapefileForAnalysisText: "Upload shapefile to include in analysis", // Shown as a message to upload shapefile to include in analysis
      uploadShapefileForButtonText: "Browse", // Shown as a label on upload shapefile button
      downloadLabelText: "Select Format :", // Shown as a helper text to select download format
      downloadBtnText: "Download",
      noDetailsAvailableText: "No results found", // Shown when no features are intersected in AOI
      featureCountText: "Count", // Shown as a prefix text to display count
      featureAreaText: "Area", // Shown as a prefix text to display area
      featureLengthText: "Length", // Shown as a prefix text to display length
      attributeChooserTooltip: "Choose attributes to display", // Shown as a tooltip on field chooser button
      csv: "CSV", // Shown as a download option
      filegdb: "File Geodatabase", // Shown as a download option
      shapefile: "Shapefile", // Shown as a download option
      noFeaturesFound: "No result found for selected file format",
      selectReportFieldTitle: "Select fields", // Shown as a title on field chooser dialog box
      noFieldsSelected: "No fields selected", // Shown when all the fields are de-selected
      intersectingFeatureExceedsMsgOnCompletion: "The maximum record count has been reached for one or more layers.", // Shown when number of features that intersects aoi exceeds its max record count
      unableToAnalyzeText: "Unable to analyze, maximum record count has been reached.", // Shown as a message on click of info button when number of features that intersects aoi exceeds its max record count
      errorInPrintingReport: "Unable to print the report. Please check if report settings are valid.", // Shown when report settings are invalid for print
      aoiInformationTitle: "Area of Interest (AOI) Information", // Shown as a title for aoi on print preview page
      summaryReportTitle: "Summary", // Shown as section title for summary report
      notApplicableText: "N/A", // Shown as text for not applicable
      downloadReportConfirmTitle: "Confirm download", // Shown as download popup title
      downloadReportConfirmMessage: "Are you sure you want to download ?", // Shown as download popup content
      noDataText: "No Data", // Shown when field data is empty in reports tab
      createReplicaFailedMessage: "Download operation failed for following layer(s) : <br/> ${layerNames}", // Shown when create replica operation fails for particular feature/map server
      extractDataTaskFailedMessage: "Download operation failed.", // Shown when extract data task operation fails for particular feature/map server
      printLayoutLabelText: "Layout", //Shown in the print dialog popup
      printBtnText: "Print", //Shown as button text in print dialog popup
      printDialogHint: "Note : The report title and comments can be edited in the report preview.", //Shown as hint text in print dialog popup
      unableToDownloadFileGDBText: "File geodatabase cannot be downloaded for AOI containing point or line locations", // Shown when user tries to download filegdb for point/line AOI
      unableToDownloadShapefileText: "Shapefile cannot be downloaded for AOI containing point or line locations", // Shown when user tries to download shapefile for point/line AOI
      analysisAreaUnitLabelText: "Show area results in :",
      analysisLengthUnitLabelText: "Show length results in :",
      analysisUnitButtonTooltip: "Choose units for analysis", // Analysis unit button tootip text
      analysisCloseBtnText: "Close", // analysis unit setting dialog button
      areaSquareFeetUnit: "Square Feet",
      areaAcresUnit: "Acres",
      areaSquareMetersUnit: "Square Meters",
      areaSquareKilometersUnit: "Square Kilometers",
      areaHectaresUnit: "Hectares",
      areaSquareMilesUnit: "Square Miles",
      lengthFeetUnit: "Feet",
      lengthMilesUnit: "Miles",
      lengthMetersUnit: "Meters",
      lengthKilometersUnit: "Kilometers",
      hectaresAbbr: "hectares", // hectare unit abbreviation
      squareMilesAbbr: "Square Miles",
      layerNotVisibleText: "Unable to analyze. Layer is turned off or is out of scale visibility range.", // Shown in the report panel when layer is not visible
      refreshBtnTooltip:"Refresh report",
      featureCSVAreaText: "Intersecting Area", // Shown as text to display area in csv column
      featureCSVLengthText: "Intersecting Length", // Shown as text to display length in csv column
      errorInFetchingPrintTask: "Error while fetching print task information. Please try again.", // shown as error message in fetching print task information
      selectAllLabel: "Select All", // Shown as a checkbox label to select all the fields
      errorInLoadingProjectionModule: "Error while loading the projection module's dependencies. Please try downloading the file again.",
      expandCollapseIconLabel: "Intersected features",
      intersectedFeatureLabel: "Intersected feature detail",
      valueAriaLabel: "Value",
      countAriaLabel: "Count"
    }
  }),
  "ar": 1,
  "bs": 1,
  "ca": 1,
  "cs": 1,
  "da": 1,
  "de": 1,
  "el": 1,
  "es": 1,
  "et": 1,
  "fi": 1,
  "fr": 1,
  "he": 1,
  "hr": 1,
  "hu": 1,
  "it": 1,
  "id": 1,
  "ja": 1,
  "ko": 1,
  "lt": 1,
  "lv": 1,
  "nb": 1,
  "nl": 1,
  "pl": 1,
  "pt-br": 1,
  "pt-pt": 1,
  "ro": 1,
  "ru": 1,
  "sl": 1,
  "sr": 1,
  "sv": 1,
  "th": 1,
  "tr": 1,
  "uk": 1,
  "vi": 1,
  "zh-cn": 1,
  "zh-hk": 1,
  "zh-tw": 1
});