text:
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">
  <title>SB Admin - Start Bootstrap Template</title>

  <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

  <link href="vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">

  <link href="css/sb-admin.css" rel="stylesheet">

    Start Bootstrap
    <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">

    </button>

            Dashboard

            Charts

            Tables

            Components

              Navbar

              Cards

            Example Pages

              Login Page

              Registration Page

              Forgot Password Page

              Blank Page

            Menu Levels

              Second Level Item

              Second Level Item

              Second Level Item

              Third Level

                  Third Level Item

                  Third Level Item

                  Third Level Item

            Link

            Messages
              12 New

New Messages:

              David Miller
              11:21 AM

Hey there! This new version of SB Admin is pretty awesome! These messages clip off when they reach the end of the box so they don't overflow over to the sides!

              Jane Smith
              11:21 AM

I was wondering if you could meet for an appointment at 3:00 instead of 4:00. Thanks!

              John Doe
              11:21 AM

I've sent the final files over to you for review. When you're able to sign off of them let me know and we can discuss distribution.

            View all messages

            Alerts
              6 New

New Alerts:

                  Status Update

              11:21 AM

This is an automated server response message. All systems are online.

                  Status Update

              11:21 AM

This is an automated server response message. All systems are online.

                  Status Update

              11:21 AM

This is an automated server response message. All systems are online.

            View all alerts

          <form class="form-inline my-2 my-lg-0 mr-lg-2">

              <input class="form-control" type="text" placeholder="Search for...">

                <button class="btn btn-primary" type="button">

                </button>

          </form>

            Logout

          Dashboard

Cards

Cards

26 New Messages!

              View Details

11 New Tasks!

              View Details

123 New Orders!

              View Details

13 New Tickets!

              View Details

          Copyright © Your Website 2017

Ready to Leave?

            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
              ×
            </button>

Select "Logout" below if you are ready to end your current session.

            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
            Logout


text:
<!DOCTYPE html>

	<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
	<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"/>
	<meta name="apple-mobile-web-app-capable" content="yes"/>
	<title>RoundRectList - inherit</title>

	<link href="../themes/common/domButtons.css" rel="stylesheet"/>

News

Image Icon

					Image Icon.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 1

					Image Icon.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 2

Sprite Icon

					Sprite Icon.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 1

					Sprite Icon.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 2

Dom Button

					Dom Button.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 1

					Dom Button.

					Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 2

Check List

				Image Icon.

				Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 1

				Image Icon.

				Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 2

Check List (with unchecked icon)

				Image Icon.

				Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 1

				Image Icon.

				Explores advanced topics in the new Java framework for implementing and consuming REST-based Web services, Part 2

redpajama_set_name: RedPajamaGithub


text:
//
//  XLPhotoBrowser.m
//  XLPhotoBrowserDemo
//
//  Created by Liushannoon on 16/7/16.
//  Copyright © 2016年 LiuShannoon. All rights reserved.
//

#import "XLPhotoBrowser.h"
#import "XLZoomingScrollView.h"
#import "TAPageControl.h"
#import "FSActionSheetConfig.h"
#import "FSActionSheet.h"
#import "XLPhotoBrowserConfig.h"

#import <Photos/Photos.h>
#import "UIImage+GIF.h"

#define BaseTag 100

@interface XLPhotoBrowser () <XLZoomingScrollViewDelegate , UIScrollViewDelegate>

@property (nonatomic , strong) UIWindow *photoBrowserWindow;

/**
 *  存放所有图片的容器
 */
@property (nonatomic , strong) UIScrollView  *scrollView;
/**
 *   保存图片的过程指示菊花
 */
@property (nonatomic , strong) UIActivityIndicatorView  *indicatorView;
/**
 *   保存图片的结果指示label
 */
@property (nonatomic , strong) UILabel *savaImageTipLabel;
/**
 *  正在使用的XLZoomingScrollView对象集
 */
@property (nonatomic , strong) NSMutableSet  *visibleZoomingScrollViews;
/**
 *  循环利用池中的XLZoomingScrollView对象集,用于循环利用
 */
@property (nonatomic , strong) NSMutableSet  *reusableZoomingScrollViews;
/**
 *  pageControl
 */
@property (nonatomic , strong) UIControl  *pageControl;
/**
 *  index label
 */
@property (nonatomic , strong) UILabel  *indexLabel;
/**
 *  保存按钮
 */
@property (nonatomic , strong) UIButton *saveButton;
/**
 *  ActionSheet的otherbuttontitles
 */
@property (nonatomic , strong) NSArray  *actionOtherButtonTitles;
/**
 *  ActionSheet的title
 */
@property (nonatomic , strong) NSString  *actionSheetTitle;
/**
 *  actionSheet的取消按钮title
 */
@property (nonatomic , strong) NSString  *actionSheetCancelTitle;
/**
 *  actionSheet的高亮按钮title
 */
@property (nonatomic , strong) NSString  *actionSheetDeleteButtonTitle;
@property (nonatomic, assign) CGSize pageControlDotSize;
@property(nonatomic, strong) NSArray *images;

@end

@implementation XLPhotoBrowser

#pragma mark    -   set / get

- (UILabel *)savaImageTipLabel
{
    if (_savaImageTipLabel == nil) {
        _savaImageTipLabel = [[UILabel alloc] init];
        _savaImageTipLabel.textColor = [UIColor whiteColor];
        _savaImageTipLabel.backgroundColor = [UIColor colorWithRed:0.1f green:0.1f blue:0.1f alpha:0.90f];
        _savaImageTipLabel.textAlignment = NSTextAlignmentCenter;
        _savaImageTipLabel.font = [UIFont boldSystemFontOfSize:17];
    }
    return _savaImageTipLabel;
}

- (UIActivityIndicatorView *)indicatorView
{
    if (!_indicatorView) {
        _indicatorView = [[UIActivityIndicatorView alloc] init];
        _indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
    }
    return _indicatorView;
}

- (UIImage *)placeholderImage
{
    if (!_placeholderImage) {
        _placeholderImage = [UIImage xl_imageWithColor:[UIColor grayColor] size:CGSizeMake(100, 100)];
    }
    return _placeholderImage;
}

- (UIWindow *)photoBrowserWindow
{
    if (!_photoBrowserWindow) {
        _photoBrowserWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        _photoBrowserWindow.windowLevel = MAXFLOAT;
        UIViewController *tempVC = [[UIViewController alloc] init];
        tempVC.view.backgroundColor = XLPhotoBrowserBackgrounColor;
;
        _photoBrowserWindow.rootViewController = tempVC;
        //    NSEnumerator *frontToBackWindows = [UIApplication.sharedApplication.windows reverseObjectEnumerator];
        //    for (UIWindow *window in frontToBackWindows) {
        //        BOOL windowOnMainScreen = window.screen == UIScreen.mainScreen;
        //        BOOL windowIsVisible = !window.hidden && window.alpha > 0;
        //        BOOL windowLevelSupported = (window.windowLevel >= UIWindowLevelNormal);
        //        BOOL windowSizeIsEqualToScreen = (window.xl_width == XLScreenW && window.xl_height == XLScreenH);
        //        if(windowOnMainScreen && windowIsVisible && windowLevelSupported && windowSizeIsEqualToScreen) {
        //            return window;
        //        }
        //    }
        //
        //    XLPBLog(@"XLPhotoBrowser在当前工程未匹配到合适的window,请根据工程架构酌情调整此方法,匹配最优窗口");
        //    if (XLPhotoBrowserDebug) {
        //        NSAssert(false, @"XLPhotoBrowser在当前工程未匹配到window,请根据工程架构酌情调整findTheMainWindow方法,匹配最优窗口");
        //    }
        //
        //    UIWindow * delegateWindow = [[[UIApplication sharedApplication] delegate] window];
        //    return delegateWindow;

    }
    return _photoBrowserWindow;
}

- (void)setCurrentPageDotColor:(UIColor *)currentPageDotColor
{
    _currentPageDotColor = currentPageDotColor;
    if ([self.pageControl isKindOfClass:[TAPageControl class]]) {
        TAPageControl *pageControl = (TAPageControl *)_pageControl;
        pageControl.dotColor = currentPageDotColor;
    } else {
        UIPageControl *pageControl = (UIPageControl *)_pageControl;
        pageControl.currentPageIndicatorTintColor = currentPageDotColor;
    }
}

- (void)setPageDotColor:(UIColor *)pageDotColor
{
    _pageDotColor = pageDotColor;
    if ([self.pageDotColor isKindOfClass:[UIPageControl class]]) {
        UIPageControl *pageControl = (UIPageControl *)_pageControl;
        pageControl.pageIndicatorTintColor = pageDotColor;
    }
}

- (void)setCurrentPageDotImage:(UIImage *)currentPageDotImage
{
    _currentPageDotImage = currentPageDotImage;
    [self setCustomPageControlDotImage:currentPageDotImage isCurrentPageDot:YES];
}

- (void)setPageDotImage:(UIImage *)pageDotImage
{
    _pageDotImage = pageDotImage;
    [self setCustomPageControlDotImage:pageDotImage isCurrentPageDot:NO];
}

- (void)setCustomPageControlDotImage:(UIImage *)image isCurrentPageDot:(BOOL)isCurrentPageDot
{
    if (!image || !self.pageControl) return;
    if ([self.pageControl isKindOfClass:[TAPageControl class]]) {
        TAPageControl *pageControl = (TAPageControl *)_pageControl;
        if (isCurrentPageDot) {
            pageControl.currentDotImage = image;
        } else {
            pageControl.dotImage = image;
        }
    } else {
        UIPageControl *pageControl = (UIPageControl *)_pageControl;
        if (isCurrentPageDot) {
            [pageControl setValue:image forKey:@"_currentPageImage"];
        } else {
            [pageControl setValue:image forKey:@"_pageImage"];
        }
    }
}

- (void)setPageControlStyle:(XLPhotoBrowserPageControlStyle)pageControlStyle
{
    XLLogFunc;
    _pageControlStyle = pageControlStyle;
    [self setUpPageControl];
    [self updateIndexVisible];
}

- (void)setHidesForSinglePage:(BOOL)hidesForSinglePage
{
    _hidesForSinglePage = hidesForSinglePage;
    [self updateIndexVisible];
}

- (void)setBrowserStyle:(XLPhotoBrowserStyle)browserStyle
{
    _browserStyle = browserStyle;
    [self updateIndexVisible];
}

- (void)setPageControlAliment:(XLPhotoBrowserPageControlAliment)pageControlAliment
{
    _pageControlAliment = pageControlAliment;
    switch (self.pageControlAliment) {
        case XLPhotoBrowserPageControlAlimentLeft:
        {
            self.pageControl.xl_x = 10;
        }
            break;
        case XLPhotoBrowserPageControlAlimentRight:
        {
            self.pageControl.xl_x = (self.xl_width - self.pageControl.xl_width) - 10;
        }
            break;
        case XLPhotoBrowserPageControlAlimentCenter:
        default:
        {
            self.pageControl.xl_x = (self.xl_width - self.pageControl.xl_width) * 0.5;
        }
            break;
    }
}

#pragma mark    -   initial

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

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

- (void)initial
{
    self.backgroundColor = XLPhotoBrowserBackgrounColor;
    self.visibleZoomingScrollViews = [[NSMutableSet alloc] init];
    self.reusableZoomingScrollViews = [[NSMutableSet alloc] init];
    [self placeholderImage];

    _pageControlAliment = XLPhotoBrowserPageControlAlimentCenter;
    _pageControlDotSize = CGSizeMake(10, 10);
    _pageControlStyle = XLPhotoBrowserPageControlStyleAnimated;
    _hidesForSinglePage = YES;
    _currentPageDotColor = [UIColor whiteColor];
    _pageDotColor = [UIColor lightGrayColor];
    _browserStyle = XLPhotoBrowserStylePageControl;

    self.currentImageIndex = 0;
    self.imageCount = 0;

    [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(orientationDidChange) name:UIDeviceOrientationDidChangeNotification  object:nil];

}

- (void)iniaialUI
{
    XLLogFunc;

    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

    self.scrollView = [[UIScrollView alloc] init];
    self.scrollView.delegate = self;
    self.scrollView.showsHorizontalScrollIndicator = NO;
    self.scrollView.showsVerticalScrollIndicator = NO;
    self.scrollView.pagingEnabled = YES;
    self.scrollView.backgroundColor = [UIColor clearColor];
    [self addSubview:self.scrollView];

    if (self.currentImageIndex == 0) { // 如果刚进入的时候是0,不会调用scrollViewDidScroll:方法,不会展示第一张图片
        XLFormatLog(@"self.currentImageIndex == %zd",self.currentImageIndex);
        [self showPhotos];
    }

    [self setUpPageControl];

    // 添加XLPhotoBrowserStyleSimple相关控件
    UILabel *indexLabel = [[UILabel alloc] init];
    indexLabel.textAlignment = NSTextAlignmentCenter;
    indexLabel.textColor = [UIColor whiteColor];
    indexLabel.font = [UIFont systemFontOfSize:18];
    indexLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
    indexLabel.clipsToBounds = YES;
    self.indexLabel = indexLabel;
    [self addSubview:indexLabel];
    UIButton *saveButton = [[UIButton alloc] init];
    [saveButton setTitle:@"保存" forState:UIControlStateNormal];
    [saveButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    saveButton.backgroundColor = [UIColor colorWithRed:0.1f green:0.1f blue:0.1f alpha:0.90f];
    saveButton.layer.cornerRadius = 5;
    saveButton.clipsToBounds = YES;
    [saveButton addTarget:self action:@selector(saveImage) forControlEvents:UIControlEventTouchUpInside];
    self.saveButton = saveButton;
    [self addSubview:saveButton];

    [self showFirstImage];
    [self updateIndexContent];
    [self updateIndexVisible];
}

- (void)setUpPageControl
{
    XLLogFunc;
    if (_pageControl) {
        [_pageControl removeFromSuperview];
        _pageControl = nil;
        // 重新加载数据时调整
    }
    switch (self.pageControlStyle) {
        case XLPhotoBrowserPageControlStyleAnimated:
        {
            TAPageControl *pageControl = [[TAPageControl alloc] init];
            _pageControl = pageControl;
            pageControl.numberOfPages = self.imageCount;
            pageControl.dotColor = self.currentPageDotColor;
            pageControl.currentPage = self.currentImageIndex;
            pageControl.userInteractionEnabled = NO;
            [self addSubview:pageControl];
        }
            break;
        case XLPhotoBrowserPageControlStyleClassic:
        {
            UIPageControl *pageControl = [[UIPageControl alloc] init];
            _pageControl = pageControl;
            pageControl.numberOfPages = self.imageCount;
            pageControl.currentPageIndicatorTintColor = self.currentPageDotColor;
            pageControl.pageIndicatorTintColor = self.pageDotColor;
            pageControl.userInteractionEnabled = NO;
            [self addSubview:pageControl];
            pageControl.currentPage = self.currentImageIndex;
        }
            break;
        default:
            break;
    }

    // 重设pagecontroldot图片
    self.currentPageDotImage = self.currentPageDotImage;
    self.pageDotImage = self.pageDotImage;
}

- (void)dealloc
{
    [self.reusableZoomingScrollViews removeAllObjects];
    [self.visibleZoomingScrollViews removeAllObjects];
}

#pragma mark    -   layout

- (void)orientationDidChange
{
    XLLogFunc;
    self.scrollView.delegate = nil; // 旋转期间,禁止调用scrollView的代理事件等
    XLZoomingScrollView *temp = [self zoomingScrollViewAtIndex:self.currentImageIndex];
    [temp.scrollview setZoomScale:1.0 animated:YES];
    [self updateFrames];
    self.scrollView.delegate = self;
}

- (void)updateFrames
{
    XLLogFunc;
    self.frame = [UIScreen mainScreen].bounds;
    CGRect rect = self.bounds;
    rect.size.width += XLPhotoBrowserImageViewMargin;
    self.scrollView.frame = rect; // frame修改的时候,也会触发scrollViewDidScroll,不是每次都触发
    self.scrollView.xl_x = 0;
    self.scrollView.contentSize = CGSizeMake((self.scrollView.xl_width) * self.imageCount, 0);
    self.scrollView.contentOffset = CGPointMake(self.currentImageIndex * (self.scrollView.xl_width), 0);// 回触发scrollViewDidScroll
    [self.scrollView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.tag >= BaseTag) {
            obj.frame = CGRectMake((self.scrollView.xl_width) * (obj.tag - BaseTag), 0, self.xl_width, self.xl_height);
        }
    }];

    self.saveButton.frame = CGRectMake(30, self.xl_height - 70, 50, 25);
    self.indexLabel.bounds = CGRectMake(0, 0, 80, 30);
    self.indexLabel.xl_centerX = self.xl_width * 0.5;
    self.indexLabel.xl_centerY = 35;
    self.indexLabel.layer.cornerRadius = self.indexLabel.xl_height * 0.5;

    self.savaImageTipLabel.layer.cornerRadius = 5;
    self.savaImageTipLabel.clipsToBounds = YES;
    [self.savaImageTipLabel sizeToFit];
    self.savaImageTipLabel.xl_height = 30;
    self.savaImageTipLabel.xl_width += 20;
    self.savaImageTipLabel.center = self.center;

    self.indicatorView.center = self.center;

    CGSize size = CGSizeZero;
    if ([self.pageControl isKindOfClass:[TAPageControl class]]) {
        TAPageControl *pageControl = (TAPageControl *)_pageControl;
        size = [pageControl sizeForNumberOfPages:self.imageCount];
        // TAPageControl 本身设计的缺陷,如果TAPageControl在设置颜色等属性以后再给frame,里面的圆点位置可能不正确 , 但是调用sizeToFit 又会改变TAPageControl的显隐状态,所以还需要
        BOOL hidden = pageControl.hidden;
        [pageControl sizeToFit];
        pageControl.hidden = hidden;
    } else {
        size = CGSizeMake(self.imageCount * self.pageControlDotSize.width * 1.2, self.pageControlDotSize.height);
    }
    CGFloat x;
    switch (self.pageControlAliment) {
        case XLPhotoBrowserPageControlAlimentCenter:
        {
            x = (self.xl_width - size.width) * 0.5;
        }
            break;
        case XLPhotoBrowserPageControlAlimentLeft:
        {
            x = 10;
        }
            break;
        case XLPhotoBrowserPageControlAlimentRight:
        {
            x = self.xl_width - size.width - 10;
        }
            break;
        default:
            break;
    }
    CGFloat y = self.xl_height - size.height - 10;
    self.pageControl.frame = CGRectMake(x, y, size.width, size.height);
}

- (void)layoutSubviews
{
    XLLogFunc;
    [super layoutSubviews];
    [self updateFrames];
}

#pragma mark    -   private -- 长按图片相关

- (void)longPress:(UILongPressGestureRecognizer *)longPress
{
    XLZoomingScrollView *currentZoomingScrollView = [self zoomingScrollViewAtIndex:self.currentImageIndex];
    if (longPress.state == UIGestureRecognizerStateBegan) {
        XLPBLog(@"UIGestureRecognizerStateBegan , currentZoomingScrollView.progress %f",currentZoomingScrollView.progress);
        if (currentZoomingScrollView.progress < 1.0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self longPress:longPress];
            });
            return;
        }

        if (self.actionOtherButtonTitles.count <= 0 && self.actionSheetDeleteButtonTitle.length <= 0 && self.actionSheetTitle.length <= 0) {
            return;
        }
        FSActionSheet *actionSheet = [[FSActionSheet alloc] initWithTitle:self.actionSheetTitle delegate:nil cancelButtonTitle:self.actionSheetCancelTitle highlightedButtonTitle:self.actionSheetDeleteButtonTitle otherButtonTitles:self.actionOtherButtonTitles sourceWindow:self.photoBrowserWindow];
        __weak typeof(self) weakSelf = self;
        // 展示并绑定选择回调
        [actionSheet showWithSelectedCompletion:^(NSInteger selectedIndex) {
            if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(photoBrowser:clickActionSheetIndex:currentImageIndex:)]) {
                [weakSelf.delegate photoBrowser:weakSelf clickActionSheetIndex:selectedIndex currentImageIndex:weakSelf.currentImageIndex];
            }
        }];
    }
}

/**
 具体的删除逻辑,请根据自己项目的实际情况,自行处理
 */
//- (void)delete
//{
//    if (self.currentImageIndex == 0) {
//        XLZoomingScrollView *currentZoomingScrollView = [self zoomingScrollViewAtIndex:self.currentImageIndex];
//        [self.reusableZoomingScrollViews addObject:currentZoomingScrollView];
//        [currentZoomingScrollView prepareForReuse];
//        [currentZoomingScrollView removeFromSuperview];
//        [self.visibleZoomingScrollViews minusSet:self.reusableZoomingScrollViews];
//    }
//    self.currentImageIndex --;
//    self.imageCount --;
//    if (self.currentImageIndex == -1 && self.imageCount == 0) {
//        [self dismiss];
//    } else {
//        self.currentImageIndex = (self.currentImageIndex == (-1) ? 0 : self.currentImageIndex);
//        if (self.currentImageIndex == 0) {
//            [self setUpImageForZoomingScrollViewAtIndex:0];
//            [self updatePageControlIndex];
//            [self showPhotos];
//        }
//
//        self.scrollView.contentSize = CGSizeMake((self.scrollView.frame.size.width) * self.imageCount, 0);
//        self.scrollView.contentOffset = CGPointMake(self.currentImageIndex * (self.scrollView.frame.size.width), 0);
//    }
//    UIPageControl *pageControl = (UIPageControl *)self.pageControl;
//    pageControl.numberOfPages = self.imageCount;
//    [self updatePageControlIndex];
//}

#pragma mark    -   private -- save image

- (void)saveImage
{
    XLZoomingScrollView *zoomingScrollView = [self zoomingScrollViewAtIndex:self.currentImageIndex];
    if (zoomingScrollView.progress < 1.0) {
        self.savaImageTipLabel.text = XLPhotoBrowserLoadingImageText;
        [self addSubview:self.savaImageTipLabel];
        [self.savaImageTipLabel performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1.0];
        return;
    }
    UIImageWriteToSavedPhotosAlbum(zoomingScrollView.currentImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
    [self addSubview:self.indicatorView];
    [self.indicatorView startAnimating];
}

- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
{
    [self.indicatorView removeFromSuperview];
    [self addSubview:self.savaImageTipLabel];
    if (error) {
        self.savaImageTipLabel.text = XLPhotoBrowserSaveImageFailText;
    } else {
        self.savaImageTipLabel.text = XLPhotoBrowserSaveImageSuccessText;
    }
    [self.savaImageTipLabel performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1.0];
}

#pragma mark    -   private ---loadimage

- (void)showPhotos
{
    XLLogFunc;
    // 只有一张图片
    if (self.imageCount == 1) {
        [self setUpImageForZoomingScrollViewAtIndex:0];
        return;
    }

    CGRect visibleBounds = self.scrollView.bounds;
    NSInteger firstIndex = floor((CGRectGetMinX(visibleBounds)) / CGRectGetWidth(visibleBounds));
    NSInteger lastIndex  = floor((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));

    if (firstIndex < 0) {
        firstIndex = 0;
    }
    if (firstIndex >= self.imageCount) {
        firstIndex = self.imageCount - 1;
    }
    if (lastIndex < 0){
        lastIndex = 0;
    }
    if (lastIndex >= self.imageCount) {
        lastIndex = self.imageCount - 1;
    }

    // 回收不再显示的zoomingScrollView
    NSInteger zoomingScrollViewIndex = 0;
    for (XLZoomingScrollView *zoomingScrollView in self.visibleZoomingScrollViews) {
        zoomingScrollViewIndex = zoomingScrollView.tag - BaseTag;
        if (zoomingScrollViewIndex < firstIndex || zoomingScrollViewIndex > lastIndex) {
            [self.reusableZoomingScrollViews addObject:zoomingScrollView];
            [zoomingScrollView prepareForReuse];
            [zoomingScrollView removeFromSuperview];
        }
    }

    // _visiblePhotoViews 减去 _reusablePhotoViews中的元素
    [self.visibleZoomingScrollViews minusSet:self.reusableZoomingScrollViews];
    while (self.reusableZoomingScrollViews.count > 2) { // 循环利用池中最多保存两个可以用对象
        [self.reusableZoomingScrollViews removeObject:[self.reusableZoomingScrollViews anyObject]];
    }

    // 展示图片
    for (NSInteger index = firstIndex; index <= lastIndex; index++) {
        if (![self isShowingZoomingScrollViewAtIndex:index]) {
            [self setUpImageForZoomingScrollViewAtIndex:index];
        }
    }
}

/**
 *  判断指定的某个位置图片是否在显示
 */
- (BOOL)isShowingZoomingScrollViewAtIndex:(NSInteger)index
{
    for (XLZoomingScrollView* view in self.visibleZoomingScrollViews) {
        if ((view.tag - BaseTag) == index) {
            return YES;
        }
    }
    return NO;
}

/**
 *  获取指定位置的XLZoomingScrollView , 三级查找,正在显示的池,回收池,创建新的并赋值
 *
 *  @param index 指定位置索引
 */
- (XLZoomingScrollView *)zoomingScrollViewAtIndex:(NSInteger)index
{
    for (XLZoomingScrollView* zoomingScrollView in self.visibleZoomingScrollViews) {
        if ((zoomingScrollView.tag - BaseTag) == index) {
            return zoomingScrollView;
        }
    }
    XLZoomingScrollView* zoomingScrollView = [self dequeueReusableZoomingScrollView];
    [self setUpImageForZoomingScrollViewAtIndex:index];
    return zoomingScrollView;
}

/**
 *   加载指定位置的图片
 */
- (void)setUpImageForZoomingScrollViewAtIndex:(NSInteger)index
{
    XLLogFunc;
    XLZoomingScrollView *zoomingScrollView = [self dequeueReusableZoomingScrollView];
    zoomingScrollView.zoomingScrollViewdelegate = self;
    [zoomingScrollView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]];
    zoomingScrollView.tag = BaseTag + index;
    zoomingScrollView.frame = CGRectMake((self.scrollView.xl_width) * index, 0, self.xl_width, self.xl_height);
    self.currentImageIndex = index;
    if ([self highQualityImageURLForIndex:index]) { // 如果提供了高清大图数据源,就去加载
        [zoomingScrollView setShowHighQualityImageWithURL:[self highQualityImageURLForIndex:index] placeholderImage:[self placeholderImageForIndex:index]];
    } else if ([self assetForIndex:index]) {
        ALAsset *asset = [self assetForIndex:index];
        CGImageRef imageRef = asset.defaultRepresentation.fullScreenImage;
        [zoomingScrollView setShowImage:[UIImage imageWithCGImage:imageRef]];
        CGImageRelease(imageRef);
    } else if ([self assetPHForIndex:index]) { // 自己添加的PH
        PHAsset *assetPh = [self assetPHForIndex:index];
        PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
        imageRequestOptions.synchronous = YES;
        imageRequestOptions.version = PHImageRequestOptionsVersionOriginal;
        [[PHCachingImageManager defaultManager] requestImageDataForAsset:assetPh options:imageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
//            [zoomingScrollView setShowImage:[UIImage sd_animatedGIFWithData:imageData]]; // 这个只是动图的第一帧,坑人。。。
            [zoomingScrollView setShowImage:[UIImage testYCHUDImageWithSmallGIFData:imageData scale:1]];
        }];
    } else {
        [zoomingScrollView setShowImage:[self placeholderImageForIndex:index]];
    }

    [self.visibleZoomingScrollViews addObject:zoomingScrollView];
    [self.scrollView addSubview:zoomingScrollView];
}

/**
 *  从缓存池中获取一个XLZoomingScrollView对象
 */
- (XLZoomingScrollView *)dequeueReusableZoomingScrollView
{
    XLZoomingScrollView *photoView = [self.reusableZoomingScrollViews anyObject];
    if (photoView) {
        [self.reusableZoomingScrollViews removeObject:photoView];
    } else {
        photoView = [[XLZoomingScrollView alloc] init];
    }
    return photoView;
}

/**
 *  获取指定位置的占位图片,和外界的数据源交互
 */
- (UIImage *)placeholderImageForIndex:(NSInteger)index
{
    if (self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:placeholderImageForIndex:)]) {
        return [self.datasource photoBrowser:self placeholderImageForIndex:index];
    } else if(self.images.count>index) {
        if ([self.images[index] isKindOfClass:[UIImage class]]) {
            return self.images[index];
        } else {
            return self.placeholderImage;
        }
    }
    return self.placeholderImage;
}

/**
 *  获取指定位置的高清大图URL,和外界的数据源交互
 */
- (NSURL *)highQualityImageURLForIndex:(NSInteger)index
{
    if (self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:highQualityImageURLForIndex:)]) {
        NSURL *url = [self.datasource photoBrowser:self highQualityImageURLForIndex:index];
        if (!url) {
            XLPBLog(@"高清大图URL数据 为空,请检查代码 , 图片索引:%zd",index);
            return nil;
        }
        if ([url isKindOfClass:[NSString class]]) {
            url = [NSURL URLWithString:(NSString *)url];
        }
        if (![url isKindOfClass:[NSURL class]]) {
            //        NSAssert([url isKindOfClass:[NSURL class]], @"高清大图URL数据有问题,不是NSString也不是NSURL");
            XLPBLog(@"高清大图URL数据有问题,不是NSString也不是NSURL , 错误数据:%@ , 图片索引:%zd",url,index);
            return nil;
        }
        return url;
    } else if(self.images.count>index) {
        if ([self.images[index] isKindOfClass:[NSURL class]]) {
            return self.images[index];
        } else if ([self.images[index] isKindOfClass:[NSString class]]) {
            NSURL *url = [NSURL URLWithString:self.images[index]];
            return url;
        } else {
            return nil;
        }
    }
    return nil;
}

/**
 *  获取指定位置的 ALAsset,获取图片
 */
- (ALAsset *)assetForIndex:(NSInteger)index
{
    if (self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:assetForIndex:)]) {
        return [self.datasource photoBrowser:self assetForIndex:index];
    } else if (self.images.count > index) {
        if ([self.images[index] isKindOfClass:[ALAsset class]]) {
            return self.images[index];
        } else {
            return nil;
        }
    }
    return nil;
}

/**
 *  获取指定位置的 PHAsset,获取图片
 */
- (PHAsset *)assetPHForIndex:(NSInteger)index
{
//    if (self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:assetPHForIndex:)]) {
//        return [self.datasource photoBrowser:self assetPHForIndex:index];
//    } else
    if (self.images.count > index) {
        if ([self.images[index] isKindOfClass:[PHAsset class]]) {
            return self.images[index];
        } else {
            return nil;
        }
    }
    return nil;
}

/**
 *  获取多图浏览,指定位置图片的UIImageView视图,用于做弹出放大动画和回缩动画
 */
- (UIView *)sourceImageViewForIndex:(NSInteger)index
{
    if (self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:sourceImageViewForIndex:)]) {
        return [self.datasource photoBrowser:self sourceImageViewForIndex:index];
    }
    return nil;
}

/**
 *  第一个展示的图片 , 点击图片,放大的动画就是从这里来的
 */
- (void)showFirstImage
{
    // 获取到用户点击的那个UIImageView对象,进行坐标转化
    CGRect startRect;
    if (!self.sourceImageView) {
        if(self.datasource && [self.datasource respondsToSelector:@selector(photoBrowser:sourceImageViewForIndex:)]) {
            self.sourceImageView = [self.datasource photoBrowser:self sourceImageViewForIndex:self.currentImageIndex];
        } else {
            [UIView animateWithDuration:0.25 animations:^{
                self.alpha = 1.0;
            }];
            XLPBLog(@"需要提供源视图才能做弹出/退出图片浏览器的缩放动画");
            return;
        }
    }
    startRect = [self.sourceImageView.superview convertRect:self.sourceImageView.frame toView:self];

    UIImageView *tempView = [[UIImageView alloc] init];
    tempView.image = [self placeholderImageForIndex:self.currentImageIndex];
    tempView.frame = startRect;
    [self addSubview:tempView];

    CGRect targetRect; // 目标frame
    UIImage *image = self.sourceImageView.image;

    //TODO 完善image为空的闪退
    if (image == nil) {
        ///objc[1903]: Class PLBuildVersion is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/AssetsLibraryServices.framework/AssetsLibraryServices (0x1110ec998) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/PhotoLibraryServices.framework/PhotoLibraryServices (0x110e6b880). One of the two will be used. Which one is undefined.
        //(lldb)  po tempView.frame
        //        (origin = (x = 15, y = 100), size = (width = 100, height = 100))
        //
        //        (lldb) po targetRect
        //        (origin = (x = 0, y = NaN), size = (width = 414, height = NaN))

        XLPBLog(@"需要提供源视图才能做弹出/退出图片浏览器的缩放动画");
        return;
    }
    CGFloat imageWidthHeightRatio = image.size.width / image.size.height;
    CGFloat width = XLScreenW;
    CGFloat height = XLScreenW / imageWidthHeightRatio;
    CGFloat x = 0;
    CGFloat y;
    if (height > XLScreenH) {
        y = 0;
    } else {
        y = (XLScreenH - height ) * 0.5;
    }
    targetRect = CGRectMake(x, y, width, height);
    self.scrollView.hidden = YES;
    self.alpha = 1.0;

    // 动画修改图片视图的frame , 居中同时放大
    [UIView animateWithDuration:XLPhotoBrowserShowImageAnimationDuration animations:^{
        tempView.frame = targetRect;
    } completion:^(BOOL finished) {
        [tempView removeFromSuperview];
        self.scrollView.hidden = NO;
    }];
}

#pragma mark    -   XLZoomingScrollViewDelegate

/**
 *  单击图片,退出浏览
 */
- (void)zoomingScrollView:(XLZoomingScrollView *)zoomingScrollView singleTapDetected:(UITapGestureRecognizer *)singleTap
{
    [UIView animateWithDuration:0.15 animations:^{
        self.savaImageTipLabel.alpha = 0.0;
        self.indicatorView.alpha = 0.0;
    } completion:^(BOOL finished) {
        [self.savaImageTipLabel removeFromSuperview];
        [self.indicatorView removeFromSuperview];
    }];
    NSInteger currentIndex = zoomingScrollView.tag - BaseTag;
    UIView *sourceView = [self sourceImageViewForIndex:currentIndex];
    if (sourceView == nil) {
        [self dismiss];
        return;
    }
    self.scrollView.hidden = YES;
    self.pageControl.hidden = YES;
    self.indexLabel.hidden = YES;
    self.saveButton.hidden = YES;

    CGRect targetTemp = [sourceView.superview convertRect:sourceView.frame toView:self];

    UIImageView *tempView = [[UIImageView alloc] init];
    tempView.contentMode = sourceView.contentMode;
    tempView.clipsToBounds = YES;
    tempView.image = zoomingScrollView.currentImage;
    tempView.frame = CGRectMake( - zoomingScrollView.scrollview.contentOffset.x + zoomingScrollView.imageView.xl_x,  - zoomingScrollView.scrollview.contentOffset.y + zoomingScrollView.imageView.xl_y, zoomingScrollView.imageView.xl_width, zoomingScrollView.imageView.xl_height);
    [self addSubview:tempView];

    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
    [UIView animateWithDuration:XLPhotoBrowserHideImageAnimationDuration animations:^{
        tempView.frame = targetTemp;
        self.backgroundColor = [UIColor clearColor];
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
    }];
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    XLLogFunc;
    [self showPhotos];
    NSInteger pageNum = floor((scrollView.contentOffset.x + scrollView.bounds.size.width * 0.5) / scrollView.bounds.size.width);
    self.currentImageIndex = pageNum == self.imageCount ? pageNum - 1 : pageNum;
    [self updateIndexContent];
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSInteger pageNum = floor((scrollView.contentOffset.x + scrollView.bounds.size.width * 0.5) / scrollView.bounds.size.width);
    self.currentImageIndex = pageNum == self.imageCount ? pageNum - 1 : pageNum;
    [self updateIndexContent];
}

#pragma mark    -   图片索引的显示内容和显隐逻辑

/**
 更新索引指示控件的显隐逻辑
 */
- (void)updateIndexVisible
{
    switch (self.browserStyle) {
        case XLPhotoBrowserStylePageControl:
        {
            self.pageControl.hidden = NO;
            self.indexLabel.hidden = YES;
            self.saveButton.hidden = YES;
        }
            break;
        case XLPhotoBrowserStyleIndexLabel:
        {
            self.indexLabel.hidden = NO;
            self.pageControl.hidden = YES;
            self.saveButton.hidden = YES;
        }
            break;
        case XLPhotoBrowserStyleSimple:
        {
            self.indexLabel.hidden = NO;
            self.saveButton.hidden = NO;
            self.pageControl.hidden = YES;
        }
            break;
        default:
            break;
    }

    if (self.imageCount == 1 && self.hidesForSinglePage == YES) {
        self.indexLabel.hidden = YES;
        self.pageControl.hidden = YES;
    }
}

/**
 *  修改图片指示索引内容
 */
- (void)updateIndexContent
{
    UIPageControl *pageControl = (UIPageControl *)self.pageControl;
    pageControl.currentPage = self.currentImageIndex;
    NSString *title = [NSString stringWithFormat:@"%zd / %zd",self.currentImageIndex+1,self.imageCount];
    self.indexLabel.text = title;
}

#pragma mark    -   public method

/**
 *  快速创建并进入图片浏览器
 *
 *  @param currentImageIndex 开始展示的图片索引
 *  @param imageCount        图片数量
 *  @param datasource        数据源
 *
 */
+ (instancetype)showPhotoBrowserWithCurrentImageIndex:(NSInteger)currentImageIndex imageCount:(NSUInteger)imageCount datasource:(id<XLPhotoBrowserDatasource>)datasource
{
    XLPhotoBrowser *browser = [[XLPhotoBrowser alloc] init];
    browser.imageCount = imageCount;
    browser.currentImageIndex = currentImageIndex;
    browser.datasource = datasource;
    [browser show];
    return browser;
}

///**
// *  进入图片浏览器
// *
// *  @param index      从哪一张开始浏览,默认第一章
// *  @param imageCount 要浏览图片的总个数
// */
//- (void)showWithImageIndex:(NSInteger)index imageCount:(NSInteger)imageCount datasource:(id<XLPhotoBrowserDatasource>)datasource
//{
//    self.currentImageIndex = index;
//    self.imageCount = imageCount;
//    self.datasource = datasource;
//    [self show];
//}

- (void)show
{
    if (self.imageCount <= 0) {
        return;
    }
    if (self.currentImageIndex >= self.imageCount) {
        self.currentImageIndex = self.imageCount - 1;
    }
    if (self.currentImageIndex < 0) {
        self.currentImageIndex = 0;
    }

    self.frame = self.photoBrowserWindow.bounds;
    self.alpha = 0.0;
    [self.photoBrowserWindow.rootViewController.view addSubview:self];
    [self.photoBrowserWindow makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
    [self iniaialUI];
}

/**
 *  退出
 */
- (void)dismiss
{
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
    [UIView animateWithDuration:XLPhotoBrowserHideImageAnimationDuration animations:^{
        self.alpha = 0.0;
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
        self.photoBrowserWindow = nil;
    }];
}

/**
 *  初始化底部ActionSheet弹框数据
 *
 *  @param title                  ActionSheet的title
 *  @param delegate               XLPhotoBrowserDelegate
 *  @param cancelButtonTitle      取消按钮文字
 *  @param deleteButtonTitle      删除按钮文字
 *  @param otherButtonTitles      其他按钮数组
 */
- (void)setActionSheetWithTitle:(nullable NSString *)title delegate:(nullable id<XLPhotoBrowserDelegate>)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle deleteButtonTitle:(nullable NSString *)deleteButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitle, ...
{
    NSMutableArray *otherButtonTitlesArray = [NSMutableArray array];
    NSString *buttonTitle;
    va_list argumentList;
    if (otherButtonTitle) {
        [otherButtonTitlesArray addObject:otherButtonTitle];
        va_start(argumentList, otherButtonTitle);
        while ((buttonTitle = va_arg(argumentList, id))) {
            [otherButtonTitlesArray addObject:buttonTitle];
        }
        va_end(argumentList);
    }
    self.actionOtherButtonTitles = otherButtonTitlesArray;
    self.actionSheetTitle = title;
    self.actionSheetCancelTitle = cancelButtonTitle;
    self.actionSheetDeleteButtonTitle = deleteButtonTitle;
    if (delegate) {
        self.delegate = delegate;
    }
}

/**
 *  保存当前展示的图片
 */
- (void)saveCurrentShowImage
{
    [self saveImage];
}

#pragma mark    -   public method  -->  XLPhotoBrowser简易使用方式:一行代码展示

/**
 一行代码展示(在某些使用场景,不需要做很复杂的操作,例如不需要长按弹出actionSheet,从而不需要实现数据源方法和代理方法,那么可以选择这个方法,直接传数据源数组进来,框架内部做处理)

 @param images            图片数据源数组(,内部可以是UIImage/NSURL网络图片地址/ALAsset)
 @param currentImageIndex 展示第几张

 @return XLPhotoBrowser实例对象
 */
+ (instancetype)showPhotoBrowserWithImages:(NSArray *)images currentImageIndex:(NSInteger)currentImageIndex
{
    if (images.count <=0 || images ==nil) {
        XLPBLog(@"一行代码展示图片浏览的方法,传入的数据源为空,请检查传入数据源");
        return nil;
    }

    //检查数据源对象是否非法
    for (id image in images) {
        if (![image isKindOfClass:[UIImage class]] && ![image isKindOfClass:[NSString class]] && ![image isKindOfClass:[NSURL class]] && ![image isKindOfClass:[ALAsset class]] && ![image isKindOfClass:[PHAsset class]]) {
            XLPBLog(@"识别到非法数据格式,请检查传入数据是否为 NSString/NSURL/ALAsset 中一种");
            return nil;
        }
    }

    XLPhotoBrowser *browser = [[XLPhotoBrowser alloc] init];
    browser.imageCount = images.count;
    browser.currentImageIndex = currentImageIndex;
    browser.images = images;
    [browser show];
    return browser;
}

@end


text:
Graphics::TBitmap * CaraClasificada::bitmaps[11] =
{
    Cara::cargarBMP("Images/A pescar.bmp"),
    Cara::cargarBMP("Images/Abanicos.bmp"),
    Cara::cargarBMP("Images/Azteca.bmp"),
    Cara::cargarBMP("Images/Grano de cafe.bmp"),
    Cara::cargarBMP("Images/Lazo azul 16.bmp"),
    Cara::cargarBMP("Images/Plumas.bmp"),
    Cara::cargarBMP("Images/Pompas.bmp"),
    Cara::cargarBMP("Images/Rhododendron.bmp"),
    Cara::cargarBMP("Images/Roca verde.bmp"),
    Cara::cargarBMP("Images/Santa Fe.bmp"),
    Cara::cargarBMP("Images/Viento.bmp")
};

CaraClasificada::CaraClasificada () : Cara ()
{
}

CaraClasificada::CaraClasificada (Pelo unPelo, Ojos unosOjos, NarizYOrejas unaNarizYOrejas,
                      Boca unaBoca, Menton unMenton, std::string unFicheroRetina) :
    Cara (unPelo, unosOjos, unaNarizYOrejas, unaBoca, unMenton, unFicheroRetina)
{
}

CaraClasificada::CaraClasificada (const CaraClasificada & cara)
{
	(*this) = cara;
}

CaraClasificada::~CaraClasificada ()
{
}

std::string CaraClasificada::getClassName (void) const
{
    return "CaraClasificada";
}

Cara & CaraClasificada::operator = (const Cara & cara)
{
	this->Cara::operator = (cara);
	return (*this);
}

CaraClasificada & CaraClasificada::operator = (const CaraClasificada & cara)
{
	this->Cara::operator = (cara);
	return (*this);
}

Cara & CaraClasificada::clone (void) const
{
	CaraClasificada * aux = new CaraClasificada();
	(*aux) = (*this);
	return (*aux);
}

void CaraClasificada::dibujaRetratoRobot (TCanvas * canvas) const
{
    canvas->Draw(0, 0, CaraClasificada::bitmaps[random(11)]);
}

void CaraClasificada::dibujaRetina (Graphics::TBitmap *& canvas)
{
    canvas = CaraClasificada::bitmaps[random(11)];
}

void CaraClasificada::dibujaSupCara (TCanvas * canvas) const
{
    this->dibujarCara(canvas);
}

void CaraClasificada::dibujaSupRetina (Graphics::TBitmap *& canvas)
{
    this->dibujarRetina(canvas);
}


text:
<?php

namespace Assetic\Filter;

use Assetic\Asset\AssetInterface;
use Assetic\Exception\FilterException;
use Assetic\Filter\Sass\BaseSassFilter;

/**
 * Loads Compass files.
 *
 * @link http://compass-style.org/
 * @author Maxime Thirouin <maxime.thirouin@gmail.com>
 */
class CompassFilter extends BaseSassFilter
{
    private $compassPath;
    private $rubyPath;
    private $scss;

    // scss options
    private $unixNewlines;
    private $debugInfo;
    private $cacheLocation;
    private $noCache;

    // compass options
    private $force;
    private $style;
    private $quiet;
    private $boring;
    private $noLineComments;
    private $imagesDir;
    private $javascriptsDir;
    private $fontsDir;
    private $relativeAssets;

    // compass configuration file options
    private $plugins = array();
    private $httpPath;
    private $httpImagesPath;
    private $httpFontsPath;
    private $httpGeneratedImagesPath;
    private $generatedImagesPath;
    private $httpJavascriptsPath;
    private $homeEnv = true;

    public function __construct($compassPath = '/usr/bin/compass', $rubyPath = null)
    {
        $this->compassPath = $compassPath;
        $this->rubyPath = $rubyPath;
        $this->cacheLocation = sys_get_temp_dir();

        if ('cli' !== php_sapi_name()) {
            $this->boring = true;
        }
    }

    public function setScss($scss)
    {
        $this->scss = $scss;
    }

    // scss options setters
    public function setUnixNewlines($unixNewlines)
    {
        $this->unixNewlines = $unixNewlines;
    }

    public function setDebugInfo($debugInfo)
    {
        $this->debugInfo = $debugInfo;
    }

    public function setCacheLocation($cacheLocation)
    {
        $this->cacheLocation = $cacheLocation;
    }

    public function setNoCache($noCache)
    {
        $this->noCache = $noCache;
    }

    // compass options setters
    public function setForce($force)
    {
        $this->force = $force;
    }

    public function setStyle($style)
    {
        $this->style = $style;
    }

    public function setQuiet($quiet)
    {
        $this->quiet = $quiet;
    }

    public function setBoring($boring)
    {
        $this->boring = $boring;
    }

    public function setNoLineComments($noLineComments)
    {
        $this->noLineComments = $noLineComments;
    }

    public function setImagesDir($imagesDir)
    {
        $this->imagesDir = $imagesDir;
    }

    public function setJavascriptsDir($javascriptsDir)
    {
        $this->javascriptsDir = $javascriptsDir;
    }

    public function setFontsDir($fontsDir)
    {
        $this->fontsDir = $fontsDir;
    }

    // compass configuration file options setters
    public function setPlugins(array $plugins)
    {
        $this->plugins = $plugins;
    }

    public function addPlugin($plugin)
    {
        $this->plugins[] = $plugin;
    }

    public function setHttpPath($httpPath)
    {
        $this->httpPath = $httpPath;
    }

    public function setHttpImagesPath($httpImagesPath)
    {
        $this->httpImagesPath = $httpImagesPath;
    }

    public function setHttpFontsPath($httpFontsPath)
    {
        $this->httpFontsPath = $httpFontsPath;
    }

    public function setHttpGeneratedImagesPath($httpGeneratedImagesPath)
    {
        $this->httpGeneratedImagesPath = $httpGeneratedImagesPath;
    }

    public function setGeneratedImagesPath($generatedImagesPath)
    {
        $this->generatedImagesPath = $generatedImagesPath;
    }

    public function setHttpJavascriptsPath($httpJavascriptsPath)
    {
        $this->httpJavascriptsPath = $httpJavascriptsPath;
    }

    public function setHomeEnv($homeEnv)
    {
        $this->homeEnv = $homeEnv;
    }

    public function setRelativeAssets($relativeAssets)
    {
        $this->relativeAssets = $relativeAssets;
    }

    public function filterLoad(AssetInterface $asset)
    {
        $loadPaths = $this->loadPaths;
        if ($dir = $asset->getSourceDirectory()) {
            $loadPaths[] = $dir;
        }

        // compass does not seems to handle symlink, so we use realpath()
        $tempDir = realpath(sys_get_temp_dir());

        $compassProcessArgs = array(
            $this->compassPath,
            'compile',
            $tempDir,
        );
        if (null !== $this->rubyPath) {
            $compassProcessArgs = array_merge(explode(' ', $this->rubyPath), $compassProcessArgs);
        }

        $pb = $this->createProcessBuilder($compassProcessArgs);

        if ($this->force) {
            $pb->add('--force');
        }

        if ($this->style) {
            $pb->add('--output-style')->add($this->style);
        }

        if ($this->quiet) {
            $pb->add('--quiet');
        }

        if ($this->boring) {
            $pb->add('--boring');
        }

        if ($this->noLineComments) {
            $pb->add('--no-line-comments');
        }

        // these three options are not passed into the config file
        // because like this, compass adapts this to be xxx_dir or xxx_path
        // whether it's an absolute path or not
        if ($this->imagesDir) {
            $pb->add('--images-dir')->add($this->imagesDir);
        }

        if ($this->relativeAssets) {
            $pb->add('--relative-assets');
        }

        if ($this->javascriptsDir) {
            $pb->add('--javascripts-dir')->add($this->javascriptsDir);
        }

        if ($this->fontsDir) {
            $pb->add('--fonts-dir')->add($this->fontsDir);
        }

        // options in config file
        $optionsConfig = array();

        if (!empty($loadPaths)) {
            $optionsConfig['additional_import_paths'] = $loadPaths;
        }

        if ($this->unixNewlines) {
            $optionsConfig['sass_options']['unix_newlines'] = true;
        }

        if ($this->debugInfo) {
            $optionsConfig['sass_options']['debug_info'] = true;
        }

        if ($this->cacheLocation) {
            $optionsConfig['sass_options']['cache_location'] = $this->cacheLocation;
        }

        if ($this->noCache) {
            $optionsConfig['sass_options']['no_cache'] = true;
        }

        if ($this->httpPath) {
            $optionsConfig['http_path'] = $this->httpPath;
        }

        if ($this->httpImagesPath) {
            $optionsConfig['http_images_path'] = $this->httpImagesPath;
        }

        if ($this->httpFontsPath) {
            $optionsConfig['http_fonts_path'] = $this->httpFontsPath;
        }

        if ($this->httpGeneratedImagesPath) {
            $optionsConfig['http_generated_images_path'] = $this->httpGeneratedImagesPath;
        }

        if ($this->generatedImagesPath) {
            $optionsConfig['generated_images_path'] = $this->generatedImagesPath;
        }

        if ($this->httpJavascriptsPath) {
            $optionsConfig['http_javascripts_path'] = $this->httpJavascriptsPath;
        }

        // options in configuration file
        if (count($optionsConfig)) {
            $config = array();
            foreach ($this->plugins as $plugin) {
                $config[] = sprintf("require '%s'", addcslashes($plugin, '\\'));
            }
            foreach ($optionsConfig as $name => $value) {
                if (!is_array($value)) {
                    $config[] = sprintf('%s = "%s"', $name, addcslashes($value, '\\'));
                } elseif (!empty($value)) {
                    $config[] = sprintf('%s = %s', $name, $this->formatArrayToRuby($value));
                }
            }

            $configFile = tempnam($tempDir, 'assetic_compass');
            file_put_contents($configFile, implode("\n", $config)."\n");
            $pb->add('--config')->add($configFile);
        }

        $pb->add('--scss-dir')->add('')->add('--css-dir')->add('');

        // compass choose the type (scss or scss from the filename)
        if (null !== $this->scss) {
            $type = $this->scss ? 'scss' : 'scss';
        } elseif ($path = $asset->getSourcePath()) {
            // FIXME: what if the extension is something else?
            $type = pathinfo($path, PATHINFO_EXTENSION);
        } else {
            $type = 'scss';
        }

        $tempName = tempnam($tempDir, 'assetic_compass');
        unlink($tempName); // FIXME: don't use tempnam() here

        // input
        $input = $tempName.'.'.$type;

        // work-around for https://github.com/chriseppstein/compass/issues/748
        if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
            $input = str_replace('\\', '/', $input);
        }

        $pb->add($input);
        file_put_contents($input, $asset->getContent());

        // output
        $output = $tempName.'.css';

        if ($this->homeEnv) {
            // it's not really usefull but... https://github.com/chriseppstein/compass/issues/376
            $pb->setEnv('HOME', sys_get_temp_dir());
            $this->mergeEnv($pb);
        }

        $proc = $pb->getProcess();
        $code = $proc->run();

        if (0 !== $code) {
            unlink($input);
            if (isset($configFile)) {
                unlink($configFile);
            }

            throw FilterException::fromProcess($proc)->setInput($asset->getContent());
        }

        $asset->setContent(file_get_contents($output));

        unlink($input);
        unlink($output);
        if (isset($configFile)) {
            unlink($configFile);
        }
    }

    public function filterDump(AssetInterface $asset)
    {
    }

    private function formatArrayToRuby($array)
    {
        $output = array();

        // does we have an associative array ?
        if (count(array_filter(array_keys($array), "is_numeric")) != count($array)) {
            foreach ($array as $name => $value) {
                $output[] = sprintf('    :%s => "%s"', $name, addcslashes($value, '\\'));
            }
            $output = "{\n".implode(",\n", $output)."\n}";
        } else {
            foreach ($array as $name => $value) {
                $output[] = sprintf('    "%s"', addcslashes($value, '\\'));
            }
            $output = "[\n".implode(",\n", $output)."\n]";
        }

        return $output;
    }
}


text:
#ifndef BOOST_MPL_EQUAL_TO_HPP_INCLUDED
#define BOOST_MPL_EQUAL_TO_HPP_INCLUDED

// Copyright Aleksey Gurtovoy 2000-2004
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/mpl for documentation.

// $Id$
// $Date$
// $Revision$

#define AUX778076_OP_NAME equal_to
#define AUX778076_OP_TOKEN ==
#include <boost/mpl/aux_/comparison_op.hpp>

#endif // BOOST_MPL_EQUAL_TO_HPP_INCLUDED


text:
"""
Downloader Middleware manager

See documentation in docs/topics/downloader-middleware.rst
"""
from typing import Callable, Union, cast

from twisted.internet import defer
from twisted.python.failure import Failure

from scrapy import Spider
from scrapy.exceptions import _InvalidOutput
from scrapy.http import Request, Response
from scrapy.middleware import MiddlewareManager
from scrapy.utils.defer import mustbe_deferred, deferred_from_coro
from scrapy.utils.conf import build_component_list

class DownloaderMiddlewareManager(MiddlewareManager):

    component_name = 'downloader middleware'

    @classmethod
    def _get_mwlist_from_settings(cls, settings):
        return build_component_list(
            settings.getwithbase('DOWNLOADER_MIDDLEWARES'))

    def _add_middleware(self, mw):
        if hasattr(mw, 'process_request'):
            self.methods['process_request'].append(mw.process_request)
        if hasattr(mw, 'process_response'):
            self.methods['process_response'].appendleft(mw.process_response)
        if hasattr(mw, 'process_exception'):
            self.methods['process_exception'].appendleft(mw.process_exception)

    def download(self, download_func: Callable, request: Request, spider: Spider):
        @defer.inlineCallbacks
        def process_request(request: Request):
            for method in self.methods['process_request']:
                method = cast(Callable, method)
                response = yield deferred_from_coro(method(request=request, spider=spider))
                if response is not None and not isinstance(response, (Response, Request)):
                    raise _InvalidOutput(
                        f"Middleware {method.__qualname__} must return None, Response or "
                        f"Request, got {response.__class__.__name__}"
                    )
                if response:
                    return response
            return (yield download_func(request=request, spider=spider))

        @defer.inlineCallbacks
        def process_response(response: Union[Response, Request]):
            if response is None:
                raise TypeError("Received None in process_response")
            elif isinstance(response, Request):
                return response

            for method in self.methods['process_response']:
                method = cast(Callable, method)
                response = yield deferred_from_coro(method(request=request, response=response, spider=spider))
                if not isinstance(response, (Response, Request)):
                    raise _InvalidOutput(
                        f"Middleware {method.__qualname__} must return Response or Request, "
                        f"got {type(response)}"
                    )
                if isinstance(response, Request):
                    return response
            return response

        @defer.inlineCallbacks
        def process_exception(failure: Failure):
            exception = failure.value
            for method in self.methods['process_exception']:
                method = cast(Callable, method)
                response = yield deferred_from_coro(method(request=request, exception=exception, spider=spider))
                if response is not None and not isinstance(response, (Response, Request)):
                    raise _InvalidOutput(
                        f"Middleware {method.__qualname__} must return None, Response or "
                        f"Request, got {type(response)}"
                    )
                if response:
                    return response
            return failure

        deferred = mustbe_deferred(process_request, request)
        deferred.addErrback(process_exception)
        deferred.addCallback(process_response)
        return deferred


text:
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [v0.1-beta][v0.1-beta]
### Added
- First released version


text:
package org.apache.sis.referencing.operation.transform;

import java.io.Serializable;
import org.opengis.metadata.content.TransferFunctionType;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.MathTransform1D;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.Matrix;
import org.opengis.util.FactoryException;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.StringBuilders;
import org.apache.sis.util.Characters;
import org.apache.sis.referencing.operation.matrix.Matrix2;

/**
 * The function converting raster sample values to geophysics values.
 * The function is usually linear, but can sometimes be logarithmic or exponential.
 * The latter occur most often when measuring concentration of something.
 *
 *

 *
Supported transfer function types

 *
Type	Equation

 *
{@link TransferFunctionType#LINEAR LINEAR}
 *       <var>y</var> = scale⋅<var>x</var> + offset

 *
{@link TransferFunctionType#LOGARITHMIC LOGARITHMIC}
 *       <var>y</var> = scale⋅logbase(<var>x</var>) + offset

 *
{@link TransferFunctionType#EXPONENTIAL EXPONENTIAL}
 *       <var>y</var> = scale⋅base<var>x</var> + offset

 *

 *
 *
Missing values

 * This {@code TransferFunction} class handles only the continuous part of transfer functions.
 * This class does not handle missing values other than {@code NaN}.
 * For a more complete class with support for non-NaN missing values,
 * see {@code org.apache.sis.coverage.SampleDimension}.
 *
 *
Serialization

 * Serialized instances of this class are not guaranteed to be compatible with future SIS versions.
 * Serialization should be used only for short term storage or RMI between applications running the
 * same SIS version.
 *
 * @author  Martin Desruisseaux (Geomatys)
 * @version 1.0
 *
 * @see org.apache.sis.coverage.SampleDimension#getTransferFunction()
 *
 * @since 0.5
 * @module
 */
public class TransferFunction implements Cloneable, Serializable {
    /**
     * For cross-version compatibility.
     */
    private static final long serialVersionUID = 185931909755748004L;

    /**
     * Whether the function is linear, logarithmic or exponential.
     */
    private TransferFunctionType type;

    /**
     * The logarithmic base. Ignored if {@link #type} is {@code LINEAR}.
     */
    private double base;

    /**
     * The scale factor, or {@code NaN} if unknown.
     */
    private double scale;

    /**
     * The scale factor, or {@code NaN} if unknown.
     */
    private double offset;

    /**
     * The transform created from above information, or {@code null} if not yet created.
     * Conversely, may be the transform given to the constructor from which above information
     * were inferred.
     *
     *
This field is serialized because the transform may be a user-provided one.

     */
    private MathTransform1D transform;

    /**
     * Creates a transfer function initialized to the identity transform.
     *
     * @see #isIdentity()
     */
    public TransferFunction() {
        type  = TransferFunctionType.LINEAR;
        base  = 10;
        scale =  1;
    }

    /**
     * Returns {@code true} if this transfer function is identity. The function is identity if
     * its {@linkplain #getType() type} is {@linkplain TransferFunctionType#LINEAR linear},
     * its {@linkplain #getScale() scale} is 1 and its {@linkplain #getOffset() offset} is 0.
     *
     * @return whether this transfer function is identity.
     *
     * @since 1.0
     */
    public boolean isIdentity() {
        return TransferFunctionType.LINEAR.equals(type) && scale == 1 && offset == 0;
    }

    /**
     * Returns the transfer function type (linear, logarithmic or exponential).
     *
     * @return the transfer function type.
     */
    public TransferFunctionType getType() {
        return type;
    }

    /**
     * Sets the transfer function type.
     * The default value is {@link TransferFunctionType#LINEAR}.
     *
     * @param  type  the transfer function type.
     */
    public void setType(final TransferFunctionType type) {
        ArgumentChecks.ensureNonNull("type", type);
        this.type = type;
        transform = null;
    }

    /**
     * Returns the logarithm or exponent base in the transfer function.
     * This value is always 1 for {@link TransferFunctionType#LINEAR},
     * and usually (but not necessarily) 10 for the logarithmic and exponential types.
     *
     * @return the logarithmic or exponent base.
     */
    public double getBase() {
        return TransferFunctionType.LINEAR.equals(type) ? 1 : base;
    }

    /**
     * Sets the logarithm or exponent base in the transfer function.
     * This value is ignored for {@link TransferFunctionType#LINEAR}.
     * For other supported types, the default value is 10.
     *
     * @param  base  the new logarithm or exponent base.
     * @throws IllegalArgumentException if the given base is NaN, negative, zero or infinite.
     */
    public void setBase(final double base) {
        ArgumentChecks.ensureStrictlyPositive("base", base);
        ArgumentChecks.ensureFinite("base", base);
        this.base = base;
        transform = null;
    }

    /**
     * Returns the scale factor of the transfer function.
     *
     * @return the scale factor.
     */
    public double getScale() {
        return scale;
    }

    /**
     * Sets the scale factor of the transfer function.
     * The default value is 1.
     *
     * @param  scale  the new scale factor.
     * @throws IllegalArgumentException if the given scale is NaN, zero or infinite.
     */
    public void setScale(final double scale) {
        ArgumentChecks.ensureFinite("scale", scale);
        if (scale == 0) {
            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "scale", scale));
        }
        this.scale = scale;
        transform = null;
    }

    /**
     * Returns the offset of the transfer function.
     *
     * @return the offset.
     */
    public double getOffset() {
        return offset;
    }

    /**
     * Sets the offset of the transfer function.
     * The default value is 0.
     *
     * @param  offset  the new offset.
     * @throws IllegalArgumentException if the given scale is NaN or infinite.
     */
    public void setOffset(final double offset) {
        ArgumentChecks.ensureFinite("offset",  offset);
        this.offset = offset;
        transform = null;
    }

    /**
     * Returns a linear transform created using the given factory.
     * This method is used only when the user specify explicitly a factory to use.
     *
     * @param  factory    the factory to use.
     * @param  withScale  {@code true} for using {@link #scale}, or {@code false} for replacing the scale by zero.
     */
    private MathTransform createAffineTransform(final MathTransformFactory factory, final boolean withScale) throws FactoryException {
        return factory.createAffineTransform(new Matrix2(withScale ? scale : 0, offset, 0, 1));
    }

    /**
     * Creates a transform from sample values to geophysics values using the given factory.
     * This method constructs a transform mathematically equivalent to the one returned by
     * {@link #getTransform()}, but allows to specify another factory than the default one.
     *
     * @param  factory  the factory to use for creating a transform.
     * @return the transform from sample to geophysics values.
     * @throws FactoryException if the given factory failed to create a transform.
     *
     * @since 1.0
     */
    public MathTransform createTransform(final MathTransformFactory factory) throws FactoryException {
        ArgumentChecks.ensureNonNull("factory", factory);
        MathTransform mt;
        if (TransferFunctionType.LINEAR.equals(type)) {
            mt = createAffineTransform(factory, true);
        } else if (TransferFunctionType.EXPONENTIAL.equals(type)) {
            mt = ExponentialTransform1D.create(base, scale);
            if (offset != 0) {
                mt = factory.createConcatenatedTransform(mt, createAffineTransform(factory, false));
            }
        } else if (TransferFunctionType.LOGARITHMIC.equals(type)) {
            if (scale == 1) {
                mt = LogarithmicTransform1D.create(base, offset);
            } else {
                mt = factory.createConcatenatedTransform(
                        LogarithmicTransform1D.create(base, 0),
                        createAffineTransform(factory, true));
            }
        } else {
            throw new IllegalStateException(Errors.format(Errors.Keys.UnknownType_1, type));
        }
        return mt;
    }

    /**
     * Returns the transform from sample values to geophysics values, as specified by the
     * current properties of this {@code TransferFunction}.
     *
     * @return the transform from sample to geophysics values.
     */
    public MathTransform1D getTransform() {
        MathTransform1D mt = transform;
        if (mt == null) {
            if (TransferFunctionType.LINEAR.equals(type)) {
                mt = LinearTransform1D.create(scale, offset);
            } else if (TransferFunctionType.EXPONENTIAL.equals(type)) {
                mt = ExponentialTransform1D.create(base, scale);
                if (offset != 0) {                                          // Rarely occurs in practice.
                    mt = MathTransforms.concatenate(mt, LinearTransform1D.create(0, offset));
                }
            } else if (TransferFunctionType.LOGARITHMIC.equals(type)) {
                if (scale == 1) {
                    mt = LogarithmicTransform1D.create(base, offset);
                } else {
                    /*
                     * This case rarely occurs in practice, so we do not provide optimized constructor.
                     * The ExponentialTransform1D.concatenate(…) method will rewrite the equation using
                     * mathematical identities. The result will be a function with a different base.
                     */
                    mt = MathTransforms.concatenate(
                            LogarithmicTransform1D.create(base, 0),
                            LinearTransform1D.create(scale, offset));
                }
            } else {
                throw new IllegalStateException(Errors.format(Errors.Keys.UnknownType_1, type));
            }
            transform = mt;     // Set only after all steps completed successfully.
        }
        return mt;
    }

    /**
     * Sets the transform from sample values to geophysics values.
     * This method infers the {@linkplain #getBase() base}, {@linkplain #getScale() scale} and
     * {@linkplain #getOffset() offset} values from the given transform.
     *
     * @param  function  the transform to set.
     * @throws IllegalArgumentException if this method does not recognize the given transform.
     */
    public void setTransform(final MathTransform1D function) throws IllegalArgumentException {
        ArgumentChecks.ensureNonNull("function", function);
        if (function instanceof LinearTransform) {
            setLinearTerms((LinearTransform) function);
            type = TransferFunctionType.LINEAR;
        } else if (function instanceof ExponentialTransform1D) {
            final ExponentialTransform1D f = (ExponentialTransform1D) function;
            type   = TransferFunctionType.EXPONENTIAL;
            base   = f.base;
            scale  = f.scale;
            offset = 0;
        } else if (function instanceof LogarithmicTransform1D) {
            final LogarithmicTransform1D f = (LogarithmicTransform1D) function;
            type   = TransferFunctionType.LOGARITHMIC;
            base   = f.base();
            offset = f.offset();
            scale  = 1;
        } else {
            /*
             * If we did not recognized one of the known types, maybe the given function
             * is the result of some concatenation. Try to concatenate a logarithmic or
             * exponential transform and see if the result is linear.
             */
            final LogarithmicTransform1D log = LogarithmicTransform1D.Base10.INSTANCE;
            MathTransform1D f = MathTransforms.concatenate(function, log);
            if (f instanceof LinearTransform) {
                setLinearTerms((LinearTransform) f);
                type = TransferFunctionType.EXPONENTIAL;
                base = 10;
            } else {
                f = MathTransforms.concatenate(log.inverse(), function);
                if (f instanceof LinearTransform) {
                    setLinearTerms((LinearTransform) f);
                    type = TransferFunctionType.LOGARITHMIC;
                    base = 10;
                } else {
                    throw new IllegalArgumentException(Errors.format(Errors.Keys.UnknownType_1, function.getClass()));
                }
            }
        }
        transform = function;
    }

    /**
     * Sets the {@link #scale} and {@link #offset} terms from the given function.
     *
     * @param  function  the transform to set.
     * @throws IllegalArgumentException if this method does not recognize the given transform.
     */
    private void setLinearTerms(final LinearTransform function) throws IllegalArgumentException {
        final Matrix m = function.getMatrix();
        final int numRow = m.getNumRow();
        final int numCol = m.getNumCol();
        if (numRow != 2 || numCol != 2) {
            final Integer two = 2;
            throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedMatrixSize_4, two, two, numRow, numCol));
        }
        scale  = m.getElement(0, 0);
        offset = m.getElement(0, 1);
    }

    /**
     * Returns a clone of this transfer function.
     *
     * @return a clone of this transfer function.
     *
     * @since 0.8
     */
    @Override
    public TransferFunction clone() {
        try {
            return (TransferFunction) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(e);                    // Should never happen since we are cloneable.
        }
    }

    /**
     * Returns a string representation of this transfer function for debugging purpose.
     * The string returned by this method may change in any future SIS version.
     *
     * @return a string representation of this transfer function.
     */
    @Override
    public String toString() {
        final StringBuilder b = new StringBuilder("y = ");
        if (scale != 1) {
            if (scale == -1) {
                b.append('−');
            } else {
                StringBuilders.trimFractionalPart(b.append(scale).append('⋅'));
            }
        }
        if (TransferFunctionType.LINEAR.equals(type)) {
            b.append('x');
        } else if (TransferFunctionType.EXPONENTIAL.equals(type)) {
            if (base == Math.E) {
                b.append('e');
            } else {
                StringBuilders.trimFractionalPart(b.append(base));
            }
            b.append('ˣ');
        } else if (TransferFunctionType.LOGARITHMIC.equals(type)) {
            if (base == Math.E) {
                b.append("ln");
            } else {
                b.append('㏒');
                if (base != 10) {
                    final int c = (int) base;
                    if (c == base && c >= 0 && c <= 9) {
                        b.append(Characters.toSubScript((char) (c - '0')));
                    } else {
                        StringBuilders.trimFractionalPart(b.append(base));
                    }
                }
            }
            b.append('⒳');
        } else {
            b.append('?');
        }
        if (offset != 0) {
            StringBuilders.trimFractionalPart(b.append(' ').append(offset < 0 ? '−' : '+').append(' ').append(Math.abs(offset)));
        }
        return b.toString();
    }
}


text:
'use strict';

var ziti = require('../../index');

var Pasta = ziti.define('Pasta', {
    numero: ziti.Int().default(0),
    name: ziti.String
});

module.exports = Pasta;


text:
import * as React from 'react'
import { Button, Dropdown } from '../index'

export const BasicAssert = () => (
  <>
    <Button />
    <Button content='Foo' />
    <Button>Foo</Button>
  </>
)

export const ShorthandItemElementAssert = () => (
  <Dropdown additionLabel={Custom Language: } />
)

export const ShorthandItemFuncAssert = () => (
  <>
    <Button
      icon={{
        children: (Component, props) => (

            <Component name={props.name} />

        ),
      }}
    />
    <Button
      label={{
        children: (Component, props) => (

            <Component active={props.active}>{props.children}</Component>

        ),
      }}
    />
    <Button label={{ children: () =>
 }} />
  </>
)

export const ShorthandItemFuncNullAssert = () => (
  <Button content='Foo' icon={{ children: () => null }} />
)

export const ShorthandItemBooleanAssert = () => (
  <>
    <Button icon />
    <Button icon={false} />
    <Button label={false} />
  </>
)


text:
<?php

session_start();
function procheck() { return TRUE; }
include("path.php");
include(pathREL.'config/common/defCONFIG.php');
include(pathPRIVATE.'indexCALL.php');


text:
package avltree

import (
	"fmt"
	"sync"

	"github.com/golang/glog"
)

// Comparable is an interface used to pass compare functions to this avltree
type Comparable func(c1 interface{}, c2 interface{}) bool

// EachFunc is an interface used to pass a function to the each() method
type EachFunc func(node *TreeNode, vals ...interface{})

// Tree represents a tree
type Tree struct {
	root  *TreeNode
	lock  sync.RWMutex
	Count int
}

// TreeNode represents a node in a tree
type TreeNode struct {
	left      *TreeNode
	right     *TreeNode
	key       interface{}
	Value     interface{}
	height    int64
	issmaller Comparable
}

// max gives returns the maximum of a and b
func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

// getHeight return the height of tree with root `root`
func (root *TreeNode) getHeight() int64 {
	if root != nil {
		return root.height
	}
	return -1
}

// TreeMinValueNode returns the node with the minimal key in the tree
func (root *TreeNode) minValueNode() *TreeNode {
	for root.left != nil {
		return root.left.minValueNode()
	}
	return nil
}

// search searches element with key `key` in tree with root `root`
// in case the searched element doesn't exist nil is returned
func (root *TreeNode) search(key interface{}) *TreeNode {
	if root.key == key {
		return root
	}

	if root.issmaller(key, root.key) {
		if root.left == nil {
			return nil
		}
		return root.left.search(key)
	}

	if root.right == nil {
		return nil
	}
	return root.right.search(key)
}

// getBalance return difference of height of left and right
// subtrees of tree with root `root`
func (root *TreeNode) getBalance() int64 {
	if root == nil {
		return 0
	}
	return root.left.getHeight() - root.right.getHeight()
}

// leftRotate rotates tree with root `root` to the left and
// returns it's new root
func (root *TreeNode) leftRotate() *TreeNode {
	node := root.right
	root.right = node.left
	node.left = root

	root.height = max(root.left.getHeight(), root.right.getHeight()) + 1
	node.height = max(node.right.getHeight(), node.left.getHeight()) + 1
	return node
}

// leftRightRotate performs a left-right rotation of tree with root
// `root` and returns it's new root
func (root *TreeNode) leftRightRotate() *TreeNode {
	root.left = root.left.leftRotate()
	root = root.rightRotate()
	return root
}

// rightRotate performs a right rotation of tree with root `root`
// and returns it's new root
func (root *TreeNode) rightRotate() *TreeNode {
	node := root.left
	root.left = node.right
	node.right = root
	root.height = max(root.left.getHeight(), root.right.getHeight()) + 1
	node.height = max(node.left.getHeight(), node.right.getHeight()) + 1
	return node
}

// rightLeftRotate preforms a right-left rotation of tree with root
// `root` and returns it's new root
func (root *TreeNode) rightLeftRotate() *TreeNode {
	root.right = root.right.rightRotate()
	root = root.leftRotate()
	return root
}

// delete deletes node with key `key` from tree. If necessary rebalancing
// is done and new root is returned
func (root *TreeNode) delete(key interface{}) *TreeNode {
	if root == nil {
		return nil
	}

	if root.issmaller(key, root.key) {
		root.left = root.left.delete(key)
	} else if key == root.key {
		if root.left == nil && root.right == nil {
			return nil
		} else if root.left == nil {
			return root.left
		} else if root.right == nil {
			return root.right
		}

		tmp := root.minValueNode()
		root.key = tmp.key
		root.Value = tmp.Value
		root.right = root.right.delete(tmp.key)

		root.height = max(root.left.getHeight(), root.right.getHeight()) + 1
		balance := root.getBalance()
		if balance > 1 && root.left.getBalance() >= 0 {
			return root.rightRotate()
		} else if balance > 1 && root.left.getBalance() < 0 {
			return root.leftRightRotate()
		} else if balance < -1 && root.right.getBalance() <= 0 {
			return root.leftRotate()
		} else if balance < -1 && root.right.getBalance() > 0 {
			return root.rightLeftRotate()
		}
	} else {
		root.right = root.right.delete(key)
	}

	return root
}

// isEqual is a generic function that compares a and b of any comprable type
// return true if a and b are equal, otherwise false
func isEqual(a interface{}, b interface{}) bool {
	return a == b
}

// New simply returns a new (empty) tree
func New() *Tree {
	return &Tree{}
}

// Insert inserts an element to tree with root `t`
func (t *Tree) Insert(key interface{}, value interface{}, issmaller Comparable) (new *TreeNode, err error) {
	if t == nil {
		return nil, fmt.Errorf("unable to insert into nil tree")
	}
	t.lock.Lock()
	defer t.lock.Unlock()
	t.root, new = t.root.insert(key, value, issmaller)
	t.Count++
	return new, nil
}

// insert inserts an element into tree with root `root`
func (root *TreeNode) insert(key interface{}, value interface{}, issmaller Comparable) (*TreeNode, *TreeNode) {
	if root == nil {
		root = &TreeNode{
			left:      nil,
			right:     nil,
			key:       key,
			Value:     value,
			height:    0,
			issmaller: issmaller,
		}
		return root, root
	}

	if isEqual(key, root.key) {
		return root, root
	}

	var new *TreeNode
	if root.issmaller(key, root.key) {
		root.left, new = root.left.insert(key, value, issmaller)
		if root.left.getHeight()-root.right.getHeight() == 2 {
			if root.issmaller(key, root.left.key) {
				root = root.rightRotate()
			} else {
				root = root.leftRightRotate()
			}
		}
	} else {
		root.right, new = root.right.insert(key, value, issmaller)
		if root.right.getHeight()-root.left.getHeight() == 2 {
			if (!root.issmaller(key, root.right.key)) && !isEqual(key, root.right.key) {
				root = root.leftRotate()
			} else {
				root = root.rightLeftRotate()
			}
		}
	}

	root.height = max(root.left.getHeight(), root.right.getHeight()) + 1
	return root, new
}

// Exists checks if a node with key `key` exists in tree `t`
func (t *Tree) Exists(key interface{}) bool {
	if t == nil {
		return false
	}
	return t.root.exists(key)
}

// exists recursively searches through tree with root `root` for element with
// key `key`
func (root *TreeNode) exists(key interface{}) bool {
	if root == nil {
		return false
	}

	if isEqual(key, root.key) {
		return true
	}

	if root.issmaller(key, root.key) {
		if root.left == nil {
			return false
		}
		return root.left.exists(key)
	}
	if root.right == nil {
		return false
	}
	return root.right.exists(key)
}

// Intersection finds common elements in trees `t` and `x` and returns them in a new tree
func (t *Tree) Intersection(x *Tree) (res *Tree) {
	if t == nil || x == nil {
		return nil
	}
	res = New()
	t.lock.RLock()
	x.lock.RLock()
	defer t.lock.RUnlock()
	defer x.lock.RUnlock()

	n := 0
	newRoot := t.root.intersection(x.root, res.root, &n)

	return &Tree{
		root:  newRoot,
		Count: n,
	}
}

// Intersection builds a tree of common elements of all trees in `candidates`
func Intersection(candidates []*Tree) (res *Tree) {
	n := len(candidates)
	if n == 0 {
		return nil
	}

	if n == 1 {
		return candidates[0]
	}

	chA := make([]chan *Tree, n/2)
	chB := make([]chan *Tree, n/2)
	chRet := make([]chan *Tree, n/2)

	// Start a go routine that builds intersection of each pair of candidates
	for i := 0; i < n/2; i++ {
		chA[i] = make(chan *Tree)
		chB[i] = make(chan *Tree)
		chRet[i] = make(chan *Tree)
		go func(chA chan *Tree, chB chan *Tree, chRes chan *Tree) {
			a := <-chA
			b := <-chB
			if a == nil || b == nil {
				chRes <- nil
				return
			}

			glog.Infof("finding common elements in %d and %d elements", a.Count, b.Count)
			chRes <- a.Intersection(b)
		}(chA[i], chB[i], chRet[i])
		chA[i] <- candidates[i*2]
		chB[i] <- candidates[i*2+1]
	}

	results := make([]*Tree, 0)

	// If amount of candidate trees is uneven we have to add last tree to results
	if n%2 == 1 {
		results = append(results, candidates[n-1])
	}

	// Fetch results
	for i := 0; i < n/2; i++ {
		results = append(results, <-chRet[i])
	}

	// If we only have one tree left over, we're done
	if len(results) != 1 {
		return Intersection(results)
	}

	return results[0]
}

// intersection recursively finds common elements in tree with roots `root` and `b`
// and returns the result in a new tree
func (root *TreeNode) intersection(b *TreeNode, res *TreeNode, n *int) *TreeNode {
	if root == nil || b == nil {
		return res
	}

	if root.left != nil {
		res = root.left.intersection(b, res, n)
	}
	if root.right != nil {
		res = root.right.intersection(b, res, n)
	}
	if b.exists(root.key) {
		res, _ = res.insert(root.key, root.key, root.issmaller)
		*n++
	}

	return res
}

// Each can be used to traverse tree `t` and call function f with params vals...
// for each node in the tree
func (t *Tree) Each(f EachFunc, vals ...interface{}) {
	if t == nil {
		return
	}

	t.lock.RLock()
	defer t.lock.RUnlock()
	t.root.Each(f, vals...)
}

// Each recursively traverses tree `tree` and calls functions f with params vals...
// for each node in the tree
func (root *TreeNode) Each(f EachFunc, vals ...interface{}) {
	if root == nil {
		return
	}
	f(root, vals...)
	if root.left != nil {
		root.left.Each(f, vals...)
	}
	if root.right != nil {
		root.right.Each(f, vals...)
	}
}

// Dump dumps tree `t` into a slice and returns it
func (t *Tree) Dump() (res []interface{}) {
	if t == nil {
		return
	}

	t.lock.RLock()
	defer t.lock.RUnlock()
	return t.root.dump()
}

// dump recursively dumps all nodes of tree with root `t` into a slice and returns it
func (root *TreeNode) dump() (res []interface{}) {
	if root == nil {
		return res
	}
	if root.left != nil {
		tmp := root.left.dump()
		res = append(res, tmp...)
	}
	res = append(res, root.Value)
	if root.right != nil {
		tmp := root.right.dump()
		res = append(res, tmp...)
	}
	return res
}

// TopN finds the the `n` biggest elements in tree `t` and returns them in a slice
func (t *Tree) TopN(n int) (res []interface{}) {
	if t == nil {
		return
	}

	t.lock.RLock()
	defer t.lock.RUnlock()
	return t.root.topN(n)
}

// topN recursively traverses tree with root `t` to find biggest `n` elements.
// Top elements are returned as a slice
func (root *TreeNode) topN(n int) (res []interface{}) {
	if root == nil {
		return res
	}
	if root.right != nil {
		tmp := root.right.topN(n)
		for _, k := range tmp {
			if len(res) == n {
				return res
			}
			res = append(res, k)
		}
	}

	if len(res) < n {
		res = append(res, root.Value)
	}

	if len(res) == n {
		return res
	}

	if root.left != nil {
		tmp := root.left.topN(n - len(res))
		for _, k := range tmp {
			if len(res) == n {
				return res
			}
			res = append(res, k)
		}
	}
	return res
}


text:
package org.apache.samza.startpoint;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;

/**
 * A {@link Startpoint} that represents a timestamp offset in a stream partition.
 */
public final class StartpointTimestamp extends Startpoint {

  private final Long timestampOffset;

  // Default constructor needed by serde.
  private StartpointTimestamp() {
    this(null);
  }

  /**
   * Constructs a {@link Startpoint} that represents a timestamp offset in a stream partition.
   * @param timestampOffset in a stream partition in milliseconds.
   */
  public StartpointTimestamp(Long timestampOffset) {
    super();
    this.timestampOffset = timestampOffset;
  }

  @VisibleForTesting
  StartpointTimestamp(Long timestampOffset, Long creationTimeStamp) {
    super(creationTimeStamp);
    this.timestampOffset = timestampOffset;
  }

  /**
   * Getter for the timestamp offset.
   * @return the timestamp offset in milliseconds.
   */
  public Long getTimestampOffset() {
    return timestampOffset;
  }

  @Override
  public <IN, OUT> OUT apply(IN input, StartpointVisitor<IN, OUT> startpointVisitor) {
    return startpointVisitor.visit(input, this);
  }

  @Override
  public String toString() {
    return MoreObjects.toStringHelper(this).add("timestampOffset", timestampOffset).toString();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    if (!super.equals(o)) {
      return false;
    }
    StartpointTimestamp that = (StartpointTimestamp) o;
    return Objects.equal(timestampOffset, that.timestampOffset);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(super.hashCode(), timestampOffset);
  }
}


text:
#ifndef __WmeScValue_H__
#define __WmeScValue_H__

#include "BBase.h"
#include "persistent.h"
#include "dcscript.h"   // Added by ClassView
#include <map>
#include <string>
#include "wme_debugger.h"
#include "common/str.h"

namespace WinterMute {

class CScScript;
class CBScriptable;

class CScValue : public CBBase, public IWmeDebugProp {
public:
	HRESULT DbgSendVariables(IWmeDebugClient *Client, EWmeDebuggerVariableType Type, CScScript *Script, unsigned int ScopeID);

	static int Compare(CScValue *Val1, CScValue *Val2);
	static int CompareStrict(CScValue *Val1, CScValue *Val2);
	TValType GetTypeTolerant();
	void Cleanup(bool IgnoreNatives = false);
	DECLARE_PERSISTENT(CScValue, CBBase)

	bool m_IsConstVar;
	HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent);
	void SetValue(CScValue *Val);
	bool m_Persistent;
	bool PropExists(char *Name);
	void Copy(CScValue *orig, bool CopyWhole = false);
	void SetStringVal(const char *Val);
	TValType GetType();
	bool GetBool(bool Default = false);
	int GetInt(int Default = 0);
	double GetFloat(double Default = 0.0f);
	char *GetString();
	void *GetMemBuffer();
	CBScriptable *GetNative();
	HRESULT DeleteProp(char *Name);
	void DeleteProps();
	void CleanProps(bool IncludingNatives);
	void SetBool(bool Val);
	void SetInt(int Val);
	void SetFloat(double Val);
	void SetString(const char *Val);
	void SetNULL();
	void SetNative(CBScriptable *Val, bool Persistent = false);
	void SetObject();
	void SetReference(CScValue *Val);
	bool IsNULL();
	bool IsNative();
	bool IsString();
	bool IsBool();
	bool IsFloat();
	bool IsInt();
	bool IsObject();
	HRESULT SetProp(char *Name, CScValue *Val, bool CopyWhole = false, bool SetAsConst = false);
	CScValue *GetProp(char *Name);
	CBScriptable *m_ValNative;
	CScValue *m_ValRef;
	bool m_ValBool;
	int m_ValInt;
	double m_ValFloat;
	char *m_ValString;
	TValType m_Type;
	CScValue(CBGame *inGame);
	CScValue(CBGame *inGame, bool Val);
	CScValue(CBGame *inGame, int Val);
	CScValue(CBGame *inGame, double Val);
	CScValue(CBGame *inGame, const char *Val);
	virtual ~CScValue();
	std::map<std::string, CScValue *> m_ValObject;
	std::map<std::string, CScValue *>::iterator m_ValIter;

	bool SetProperty(const char *PropName, int Value);
	bool SetProperty(const char *PropName, const char *Value);
	bool SetProperty(const char *PropName, double Value);
	bool SetProperty(const char *PropName, bool Value);
	bool SetProperty(const char *PropName);

// IWmeDebugProp interface implementation
public:
	virtual EWmeDebuggerPropType DbgGetType();

	// getters
	virtual int DbgGetValInt();
	virtual double DbgGetValFloat();
	virtual bool DbgGetValBool();
	virtual const char *DbgGetValString();
	virtual IWmeDebugObject *DbgGetValNative();

	// setters
	virtual bool DbgSetVal(int Value);
	virtual bool DbgSetVal(double Value);
	virtual bool DbgSetVal(bool Value);
	virtual bool DbgSetVal(const char *Value);
	virtual bool DbgSetVal();

	// properties
	virtual int DbgGetNumProperties();
	virtual bool DbgGetProperty(int Index, const char **Name, IWmeDebugProp **Value);

	virtual bool DbgGetDescription(char *Buf, int BufSize);
};

} // end of namespace WinterMute

#endif


text:
require 'spec_helper'

describe 'DiabloApi::Tooltip' do
  it 'should get data' do
    url = DiabloApi::Tooltip.tooltip_url 'eu', 'de', 'rune/way-of-the-hundred-fists/b'
    expect(url).to eq 'https://eu.battle.net/d3/de/tooltip/rune/way-of-the-hundred-fists/b'
  end
end


text:
from django.conf.urls import url, include
from staff.views import UserBread

urlpatterns = [
    # /admin:
    url(r'', include(UserBread().get_urls())),
]


text:
// LICENSE : MIT
"use strict";
const Authentication = require('@electron/remote').require(__dirname + "/ESDailyAuthentication");
const Committer = require('@electron/remote').require(__dirname + "/ESDailyCommitter");
export default class HatenaClient {
    isLogin() {
        return Authentication.canAccess();
    }

    loginAsync(callback) {
        Authentication.requireAccess(callback);
    }

    /**
     *
     * @param options
     * @returns {*}
     * {
            url,
            comment,
            tags = []
        }
     */
    postLink(options = {}) {
        let { title, url, comment, tags, relatedItems } = options;
        let serializedObject = JSON.stringify({
            date: new Date(),
            title,
            url,
            content: comment,
            tags: tags,
            relatedLinks: relatedItems
        });
        let resolve, reject;
        const promise = new Promise((_resolve, _reject) => {
            resolve = _resolve;
            reject = _reject;
        });
        Committer.savePost(serializedObject, function(error) {
            if (error) {
                return reject(error);
            }
            resolve();
        });
        return promise;
    }
}


text:
ES5Harness.registerTest({
    id: "15.2.3.6-4-225",

    path: "TestCases/chapter15/15.2/15.2.3/15.2.3.6/15.2.3.6-4-225.js",

    description: "Object.defineProperty - 'O' is an Array, 'name' is an array index property, test TypeError is thrown when the [[Value]] field of 'desc' and the [[Value]] attribute value of 'name' are two booleans with different values (15.4.5.1 step 4.c)",

    test: function testcase() {
        var arrObj = [];

        Object.defineProperty(arrObj, 0, {
            value: true,
            writable: false,
            configurable: false
        });

        try {
            Object.defineProperty(arrObj, "0", { value: false });
            return false;
        } catch (e) {
            return e instanceof TypeError && dataPropertyAttributesAreCorrect(arrObj, "0", true, false, false, false);
        }
    },

    precondition: function prereq() {
        return fnExists(Object.defineProperty);
    }
});


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
null

#### Original name
Peccania corallina Hazsl.

### Remarks
null


text:
package org.endeavourhealth.dataassurance.dal;

import org.apache.commons.lang3.StringUtils;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

public class SqlUtils {
	public static List<List<String>> getStatementResultsAsCSV(PreparedStatement statement) throws SQLException {
		List<List<String>> result = new ArrayList<>();
		try {
			if (statement.execute()) {
				ResultSet resultSet = statement.getResultSet();
				List<String> row = new ArrayList<>();
				for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
					row.add(resultSet.getMetaData().getColumnLabel(i));
				}
				result.add(row);

				while (resultSet.next()) {
					row = new ArrayList<>();
					for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
						row.add(resultSet.getString(i));
					}

					result.add(row);
				}
			}
		} finally {
			statement.close();
		}
		return result;
	}

	public static String getCSVAsString(List<List<String>> csv) {
		List<String> rows = new ArrayList<>();
		for(List<String> row : csv) {
			rows.add(StringUtils.join(row.toArray(), ','));
		}
		String ret = StringUtils.join(rows, '\n');

		return ret;
	}

	public static Date sqlDateFromString(String dateString) throws ParseException {
		dateString = dateString.replace("'","");
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Date sqlDate = new Date(df.parse(dateString).getTime());
		return sqlDate;
	}
}


text:
module Spree
  CheckoutController.class_eval do
    def update
      if @order.update_attributes(object_params)
        fire_event('spree.checkout.update')

        unless @order.next
          flash[:error] = @order.errors[:base].join("\n")
          redirect_to checkout_state_path(@order.state) and return
        end

        if @order.completed?
          session[:order_id] = nil
          flash.notice = Spree.t(:your_bid_has_been_added_to_the_system)
          flash[:commerce_tracking] = "nothing special"
          redirect_to completion_route
        else
          redirect_to checkout_state_path(@order.state)
        end
      else
        render :edit
      end
    end
  end
end


text:
const Forum = require('./forum');
const User = require('./user');
const {Sequelize, db} = require('../connection');

const PostModel = db.define('post', {
  title: {
    type: Sequelize.TEXT,
    allowNull: false
  },
  body: {
    type: Sequelize.TEXT,
    allowNull: false
  },
  pinned: {
    type: Sequelize.BOOLEAN,
    defaultValue: false
  }
});

const Post = {model: PostModel};

Post.findAll = function(query = {}) {
  return PostModel.findAll({where: {}});
};

/**
 * Post crud methods.
 */
Post.create = ({title, body, pinned, userId, forumId}) => {
  if (!title) {
    throw new Error('Title must exist!', title);
  }
  if (!body) {
    throw new Error('body must exist!', body);
  }
  return PostModel.create({title, body, pinned, userId, forumId});
};

Post.read = Post.find = function(query) {
  return PostModel.findOne({where: query});
};

Post.update = function(query, values) {
  return Post.find(query)
    .then(post => {
      if (!post) {
        throw new Error('Post does not exist!');
      }
      return PostModel.update(values, {where: query});
    });
};

Post.delete = Post.destroy = function(query) {
  return PostModel.destroy({where: query});
};

module.exports = Post;


text:
Honestly

        We're trying to get the forms going