text:
//
//  DLPhotoManager.m
//  DLPhotoPicker
//
//  Created by 沧海无际 on 16/2/20.
//  Copyright © 2016年 darling0825. All rights reserved.
//

#import "DLPhotoManager.h"
#import "DLPhotoPickerDefines.h"

static NSString * const AdjustmentFormatIdentifier = @"com.darlingcoder.DLPhotoPicker";
static NSString * const AdjustmentFormatVersion = @"1.0";

typedef void (^AddImageToCollectionBlock)(UIImage *, PHAssetCollection *);
typedef void (^AddVideoToCollectionBlock)(NSURL *, PHAssetCollection *);

@interface DLPhotoManager()

@property (nonatomic, strong) PHCachingImageManager *phCachingImageManager;
@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;

@property (nonatomic, strong) dispatch_semaphore_t semaphore;

@property (nonatomic, copy) void(^fetchCollectionCompletion)(BOOL success);
@property (nonatomic, copy) void(^checkAuthorizationCompletion)(DLAuthorizationStatus status);

@end

@implementation DLPhotoManager

+ (instancetype)sharedInstance
{
    static DLPhotoManager *photoManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        photoManager = [[[self class] alloc] init];
    });
    return photoManager;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setDefaults];
    }

    return self;
}

- (void)setDefaults
{
    _phCachingImageManager          = [PHCachingImageManager new];
    _assetsLibrary                  = [ALAssetsLibrary new];
    _showsEmptyAlbums               = YES;

    _semaphore = dispatch_semaphore_create(1);

    /**
     *  开启 Photo Stream 容易导致 exception
     */
    //[ALAssetsLibrary disableSharedPhotoStreamsSupport];
}

#pragma mark - setter
-(void)setFetchResults:(NSArray *)fetchResults
{
    _fetchResults = [NSArray arrayWithArray:fetchResults];
    [self __updateAssetCollections];
}

#pragma mark - Init properties
- (NSArray *)assetCollectionSubtypes
{
    if (!_assetCollectionSubtypes) {
        /**
         // PHAssetCollectionTypeAlbum regular subtypes
         PHAssetCollectionSubtypeAlbumRegular         = 2,
         PHAssetCollectionSubtypeAlbumSyncedEvent     = 3,
         PHAssetCollectionSubtypeAlbumSyncedFaces     = 4,
         PHAssetCollectionSubtypeAlbumSyncedAlbum     = 5,
         PHAssetCollectionSubtypeAlbumImported        = 6,

         // PHAssetCollectionTypeAlbum shared subtypes
         PHAssetCollectionSubtypeAlbumMyPhotoStream   = 100,
         PHAssetCollectionSubtypeAlbumCloudShared     = 101,

         // PHAssetCollectionTypeSmartAlbum subtypes
         PHAssetCollectionSubtypeSmartAlbumGeneric    = 200,
         PHAssetCollectionSubtypeSmartAlbumPanoramas  = 201,
         PHAssetCollectionSubtypeSmartAlbumVideos     = 202,
         PHAssetCollectionSubtypeSmartAlbumFavorites  = 203,
         PHAssetCollectionSubtypeSmartAlbumTimelapses = 204,
         PHAssetCollectionSubtypeSmartAlbumAllHidden  = 205,
         PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,
         PHAssetCollectionSubtypeSmartAlbumBursts     = 207,
         PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,
         PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,
         PHAssetCollectionSubtypeSmartAlbumSelfPortraits NS_AVAILABLE_IOS(9_0) = 210,
         PHAssetCollectionSubtypeSmartAlbumScreenshots NS_AVAILABLE_IOS(9_0) = 211,
         */
        _assetCollectionSubtypes =
        @[[NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumUserLibrary],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumMyPhotoStream],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumRecentlyAdded],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumFavorites],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumPanoramas],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumVideos],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumSlomoVideos],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumTimelapses],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumBursts],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumAllHidden],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumGeneric],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumRegular],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumSyncedAlbum],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumSyncedEvent],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumSyncedFaces],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumImported],
          [NSNumber numberWithInt:PHAssetCollectionSubtypeAlbumCloudShared]];

        // Add iOS 9's new albums
        if ([[PHAsset new] respondsToSelector:@selector(sourceType)])
        {
            NSMutableArray *subtypes = [NSMutableArray arrayWithArray:_assetCollectionSubtypes];
            [subtypes insertObject:[NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumSelfPortraits] atIndex:4];
            [subtypes insertObject:[NSNumber numberWithInt:PHAssetCollectionSubtypeSmartAlbumScreenshots] atIndex:10];

            _assetCollectionSubtypes = [NSArray arrayWithArray:subtypes];
        }
    }
    return _assetCollectionSubtypes;
}

- (PHImageRequestOptions *)thumbnailRequestOptions
{
    if (!_thumbnailRequestOptions) {
        PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
        options.resizeMode = PHImageRequestOptionsResizeModeFast;
        //options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
        _thumbnailRequestOptions = options;
    }
    return _thumbnailRequestOptions;
}

#pragma mark - Authorization
- (void)checkAuthorizationStatus:(void(^)(DLAuthorizationStatus status))completion
{
    self.checkAuthorizationCompletion = completion;
    if (UsePhotoKit) {
        [self checkAuthorizationStatus_AfteriOS8];
    }else{
        [self checkAuthorizationStatus_BeforeiOS8];
    }
}

- (void)requestAuthorization
{
    if (UsePhotoKit) {
        [self requestAuthorizationStatus_AfteriOS8];
    }else{
        [self requestAuthorizationStatus_BeforeiOS8];
    }
}

- (void)checkAuthorizationStatus_AfteriOS8
{
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    switch (status)
    {
        case PHAuthorizationStatusNotDetermined:
            [self requestAuthorizationStatus_AfteriOS8];
            break;
        case PHAuthorizationStatusRestricted:
        case PHAuthorizationStatusDenied:
        {
            [self showAccessDenied];
            break;
        }
        case PHAuthorizationStatusAuthorized:
        default:
        {
            [self checkAuthorizationSuccess];
            break;
        }
    }
}

- (void)requestAuthorizationStatus_AfteriOS8
{
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status){
        dispatch_async(dispatch_get_main_queue(), ^{
            switch (status) {
                case PHAuthorizationStatusAuthorized:
                {
                    [self checkAuthorizationSuccess];
                    break;
                }
                default:
                {
                    [self showAccessDenied];
                    break;
                }
            }
        });
    }];
}

- (void)checkAuthorizationStatus_BeforeiOS8
{
    ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
    switch (status)
    {
        case ALAuthorizationStatusNotDetermined:
            [self requestAuthorizationStatus_AfteriOS8];
            break;
        case ALAuthorizationStatusRestricted:
        case ALAuthorizationStatusDenied:
        {
            [self showAccessDenied];
            break;
        }
        case ALAuthorizationStatusAuthorized:
        default:
        {
            [self checkAuthorizationSuccess];
            break;
        }
    }
}

- (void)requestAuthorizationStatus_BeforeiOS8
{
    //do nothing
}

#pragma mark - DLPhotoManagerDelegate
- (void)checkAuthorizationSuccess
{
    if (self.checkAuthorizationCompletion) {
        self.checkAuthorizationCompletion(DLAuthorizationStatusSuccess);
    }
}

- (void)showAccessDenied
{
    if (self.checkAuthorizationCompletion) {
        self.checkAuthorizationCompletion(DLAuthorizationStatusAccessDenied);
    }
}

- (void)showNoAssets
{
    if (self.checkAuthorizationCompletion) {
        self.checkAuthorizationCompletion(DLAuthorizationStatusNoAssets);
    }
}

- (void)getAlbumsCompletion:(BOOL)success
{
    if (self.fetchCollectionCompletion) {
        self.fetchCollectionCompletion(success);
    }
}

#pragma mark - default album
- (NSString *)defaultAlbum
{
    return self.defaultCollection.title;
}

- (DLPhotoCollection *)defaultCollection
{
    if (self.photoCollections.count > 0) {
        return self.photoCollections[0];
    }
    return nil;
}

#pragma mark - favorite
- (void)favoriteAsset:(DLPhotoAsset *)photoAsset
           completion:(void(^)(BOOL success, NSError *error))completion
{
    if (UsePhotoKit) {
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:photoAsset.phAsset];
            [request setFavorite:!photoAsset.phAsset.favorite];

        } completionHandler:^(BOOL success, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    completion(success, error);
                }
            });
        }];
    }else{
        //  do nothimg
    }
}

#pragma mark - create album
- (void)createAlbumWithName:(NSString *)albumName
                resultBlock:(void(^)(DLPhotoCollection *collection))completion
               failureBlock:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        __block NSString *localIdentifier = nil;

        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName];
            localIdentifier = assetCollectionChangeRequest.placeholderForCreatedAssetCollection.localIdentifier;

        } completionHandler:^(BOOL success, NSError *error){
            dispatch_async(dispatch_get_main_queue(), ^{
                if (success) {
                    PHAssetCollection *assetCollection = [[PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
                    DLPhotoCollection *collection = [[DLPhotoCollection alloc] initWithAssetCollection:assetCollection];
                    completion(collection);
                }else{
                    completion(nil);
                }

                if (error && failure) {
                    failure(error);
                }
            });
        }];

    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self.assetsLibrary addAssetsGroupAlbumWithName:albumName resultBlock:^(ALAssetsGroup *group) {
            if (completion) {
                if (group) {
                    DLPhotoCollection *collection = [[DLPhotoCollection alloc] initWithAssetCollection:group];
                    completion(collection);
                }else{
                    completion(nil);
                }
            }
        } failureBlock:^(NSError *error) {
            if (error && failure) {
                failure(error);
            }
        }];
    }
#pragma clang diagnostic pop
}

- (void)removeAlbum:(DLPhotoCollection *)photoCollection
        resultBlock:(void(^)(BOOL success))completion
       failureBlock:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            [PHAssetCollectionChangeRequest deleteAssetCollections:@[photoCollection.assetCollection]];
        } completionHandler:^(BOOL success, NSError *error){
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    if (success) {
                        completion(YES);
                    }else{
                        completion(NO);
                    }
                }

                if (error && failure) {
                    failure(error);
                }
            });
        }];
    }else{
        /**
         *  http://stackoverflow.com/questions/11054860/alassetslibrary-delete-alassetsgroup-alasset/11058934#11058934
         *  This is not possible using any documented API. Only the photos app can delete Albums.
         */
    }
}

#pragma mark - save/remove image

/**
 *  -writeImageToSavedPhotosAlbum: orientation: completionBlock:
 *  -writeImageToSavedPhotosAlbum: metadata: completionBlock:
 *  -writeImageDataToSavedPhotosAlbum: metadata: completionBlock:
 *
 *  第一个使用了我们传进去的方向,
 *  第二个可以通过传入image的metadata保留image的metadata,前两个都是把图片转成 CGImageRef 再保存,
 *  第三个是传入NSData所以可以完整保留image的信息,同时也有metadata传进去,如果image自带的信息与metadata冲突那metadata会覆盖图片本身所带的metadata。
 */

- (void)saveImage:(UIImage *)image
          toAlbum:(NSString *)albumName
       completion:(void(^)(BOOL success))completion
          failure:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        //  find album
        BOOL albumWasFound = NO;
        PHAssetCollection *savedAssetCollection = nil;
        for (PHFetchResult *fetchResult in self.fetchResults){
            if (albumWasFound) {
                break;
            }

            for (PHAssetCollection *assetCollection in fetchResult){
                // Compare the names of the albums
                if ([albumName isEqualToString:assetCollection.localizedTitle]) {

                    // Target album is found
                    albumWasFound = YES;
                    savedAssetCollection = assetCollection;
                    break;
                }
            }
        }

        //  a block to add assets to a album
        AddImageToCollectionBlock addAssetsBlock = [self _addImageBlockWithCompletion:completion failure:failure];

        if (!albumName.length) {
            //  add asset to default collection
            addAssetsBlock(image, nil);
        }else if (albumWasFound) {
            //  add asset
            addAssetsBlock(image, savedAssetCollection);
        }else{
            //  create a new album
            [self createAlbumWithName:albumName resultBlock:^(DLPhotoCollection *collection) {
                if (collection) {
                    //  add asset to new collection
                    addAssetsBlock(image, collection.assetCollection);
                }else{
                    //  add asset to default collection
                    addAssetsBlock(image, nil);
                }
            } failureBlock:failure];
        }

    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self.assetsLibrary writeImageToSavedPhotosAlbum:image.CGImage
                                             orientation:(ALAssetOrientation)image.imageOrientation
                                         completionBlock:[self _resultBlockOfAddingToAlbum:albumName
                                                                                completion:completion
                                                                                failure:failure]];
#pragma clang diagnostic pop
    }
}

- (void)saveVideo:(NSURL *)videoUrl
          toAlbum:(NSString *)albumName
       completion:(void(^)(BOOL success))completion
          failure:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        //  find album
        PHAssetCollection *savedAssetCollection = nil;
        for (PHFetchResult *fetchResult in self.fetchResults){
            if (savedAssetCollection) {
                break;
            }

            for (PHAssetCollection *assetCollection in fetchResult){
                // Compare the names of the albums
                if ([albumName compare:assetCollection.localizedTitle] == NSOrderedSame) {

                    // Target album is found
                    savedAssetCollection = assetCollection;
                    break;
                }
            }
        }

        //  a block to add assets to a album
        AddVideoToCollectionBlock addVideoBlock = [self _addVideoBlockWithCompletion:completion failure:failure];

        if (savedAssetCollection) {
            //  add asset
            addVideoBlock(videoUrl, savedAssetCollection);
        }else{
            //  create a new album
            [self createAlbumWithName:albumName resultBlock:^(DLPhotoCollection *collection) {
                if (collection) {
                    //  add asset
                    addVideoBlock(videoUrl, collection.assetCollection);
                }
            } failureBlock:failure];
        }
    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self.assetsLibrary writeVideoAtPathToSavedPhotosAlbum:videoUrl
                                               completionBlock:[self _resultBlockOfAddingToAlbum:albumName
                                                                                completion:completion
                                                                                failure:failure]];
#pragma clang diagnostic pop
    }
}

- (void)removeAsset:(NSArray<DLPhotoAsset *> *)photoAssets
         completion:(void(^)(BOOL success))completion
            failure:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            NSMutableArray *deleteAssets = [NSMutableArray arrayWithCapacity:photoAssets.count];
            for (DLPhotoAsset *asset in photoAssets) {
                [deleteAssets addObject:asset.phAsset];
            }
            [PHAssetChangeRequest deleteAssets:deleteAssets];
        } completionHandler:^(BOOL success, NSError *error){
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    if (success) {
                        completion(YES);
                    }else{
                        completion(NO);
                    }
                }

                if (error && failure) {
                    failure(error);
                }
            });
        }];
    }else{
        /**
         *  can not work
         */

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self removeAssetURL:photoAssets resultBlock:completion failureBlock:failure];
#pragma clang diagnostic pop
    }
}

- (void)saveImageData:(NSData *)imageData
              toAlbum:(NSString *)albumName
             metadata:(NSDictionary *)metadata
           completion:(void(^)(BOOL success))completion
              failure:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        //  find album
        BOOL albumWasFound = NO;
        PHAssetCollection *savedAssetCollection = nil;
        for (PHFetchResult *fetchResult in self.fetchResults){
            if (albumWasFound) {
                break;
            }

            for (PHAssetCollection *assetCollection in fetchResult){
                // Compare the names of the albums
                if ([albumName compare:assetCollection.localizedTitle] == NSOrderedSame) {

                    // Target album is found
                    albumWasFound = YES;
                    savedAssetCollection = assetCollection;
                    break;
                }
            }
        }

        //  a block to add assets to a album
        AddImageToCollectionBlock addAssetsBlock = [self _addImageBlockWithCompletion:completion failure:failure];

        UIImage *image = [UIImage imageWithData:imageData];
        if (albumWasFound) {
            //  add asset
            addAssetsBlock(image, savedAssetCollection);
        }else{
            //  create a new album
            [self createAlbumWithName:albumName resultBlock:^(DLPhotoCollection *collection) {
                if (collection) {
                    //  add asset
                    addAssetsBlock(image, collection.assetCollection);
                }
            } failureBlock:failure];
        }
    }else{
        [self.assetsLibrary writeImageDataToSavedPhotosAlbum:imageData
                                                    metadata:metadata
                                             completionBlock:[self _resultBlockOfAddingToAlbum:albumName
                                                                                completion:completion
                                                                                failure:failure]];
    }
}

- (void)addAssetURL:(NSURL *)assetUrl
            toAlbum:(NSString *)albumName
        resultBlock:(void(^)(BOOL success))completion
       failureBlock:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        //  do nothing
    }else{

        typeof(self) __weak weakSelf = self;
        __block BOOL albumWasFound = NO;

        //search all photo albums in the library
        [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
            // Compare the names of the albums
            if ([albumName compare: [group valueForProperty:ALAssetsGroupPropertyName]] == NSOrderedSame) {

                // Target album is found
                albumWasFound = YES;

                ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
                [weakSelf _addAssetUrlBlockWithGroup:group
                                            assetURL:assetUrl
                                          completion:completion
                                             failure:failure];

                //get a hold of the photo's asset instance
                [self.assetsLibrary assetForURL:assetUrl
                                    resultBlock:assetForURLResultBlock
                                   failureBlock:failure];

                // Album was found, bail out of the method
                *stop = YES;
            }

            //如果不存在该相册创建
            if (group == nil && albumWasFound == NO){
                typeof(self) __strong strongSelf = weakSelf;

                // code that always creates an album on iOS 7.x.x but fails
                // in certain situations such as if album has been deleted
                // previously on iOS 8.x.
                [strongSelf.assetsLibrary addAssetsGroupAlbumWithName:albumName resultBlock:^(ALAssetsGroup *group){

                    ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
                    [weakSelf _addAssetUrlBlockWithGroup:group assetURL:assetUrl completion:completion failure:failure];

                    //get a hold of the photo's asset instance
                    [self.assetsLibrary assetForURL:assetUrl
                                        resultBlock:assetForURLResultBlock
                                       failureBlock:failure];

                 } failureBlock:failure];
            }
        } failureBlock:failure];
    }
}

//  can not work
- (void)removeAssetURL:(NSArray<DLPhotoAsset *> *)photoAssets
        resultBlock:(void(^)(BOOL success))completion
       failureBlock:(void(^)(NSError *error))failure
{
    if (UsePhotoKit) {
        //  do nothing
    }else{
        for (DLPhotoAsset *asset in photoAssets) {
            ALAssetsLibraryAssetForURLResultBlock assetForURLResultBlock =
            [self _removeAssetUrlBlockWithAssetURL:asset.url completion:completion failure:failure];
            [self.assetsLibrary assetForURL:asset.url
                                resultBlock:assetForURLResultBlock
                               failureBlock:failure];
        }
    }
}

#pragma mark - Block

- (AddImageToCollectionBlock)_addImageBlockWithCompletion:(void(^)(BOOL))completion
                                                  failure:(void(^)(NSError *))failure
{
    return ^(UIImage *image, PHAssetCollection *assetCollection){
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            if (assetCollection) {
                // saved to assetCollection and CameraRoll
                PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
                PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
                [assetCollectionChangeRequest addAssets:@[assetChangeRequest.placeholderForCreatedAsset]];
            }else{
                // only saved to CameraRoll
                [PHAssetChangeRequest creationRequestForAssetFromImage:image];
            }

        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    if (success) {
                        completion(YES);
                    }else{
                        completion(NO);
                    }
                }

                if (error && failure) {
                    failure(error);
                }
            });
        }];
    };
}

- (AddVideoToCollectionBlock)_addVideoBlockWithCompletion:(void(^)(BOOL))completion
                                                  failure:(void(^)(NSError *))failure
{
    return ^(NSURL *videoUrl, PHAssetCollection *assetCollection){
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

            PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoUrl];
            PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
            [assetCollectionChangeRequest addAssets:@[assetChangeRequest.placeholderForCreatedAsset]];

        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    if (success) {
                        completion(YES);
                    }else{
                        completion(NO);
                    }
                }

                if (error && failure) {
                    failure(error);
                }
            });
        }];
    };
}

- (ALAssetsLibraryAssetForURLResultBlock)_addAssetUrlBlockWithGroup:(ALAssetsGroup *)group
                                                           assetURL:(NSURL *)assetUrl
                                                         completion:(void(^)(BOOL success))completion
                                                            failure:(void(^)(NSError *error))failure
{
    return ^(ALAsset *asset) {
        // Add photo to the target album
        if ([group addAsset:asset]) {
            // Run the completion block if the asset was added successfully
            if (completion) {
                completion(YES);
            }
        }

        // |-addAsset:| may fail (return NO) if the group is not editable,
        //   or if the asset could not be added to the group.
        else {
            NSString *message = [NSString stringWithFormat:@"ALAssetsGroup failed to add asset: %@.", asset];
            if (failure) {
                failure([NSError errorWithDomain:@"ALAssetsLibrary"
                                            code:0
                                        userInfo:@{NSLocalizedDescriptionKey : message}]);
            }
        }
    };
}

- (ALAssetsLibraryAssetForURLResultBlock)_removeAssetUrlBlockWithAssetURL:(NSURL *)assetUrl
                                                               completion:(void(^)(BOOL success))completion
                                                                  failure:(void(^)(NSError *error))failure
{
    return ^(ALAsset *asset) {
        if(asset.isEditable) {
            [asset setImageData:nil metadata:nil completionBlock:^(NSURL *assetUrl, NSError *error) {
                if (assetUrl && completion) {
                    completion(YES);
                }
                if (error && failure) {
                    failure(error);
                }
            }];
        }else{
            NSString *message = [NSString stringWithFormat:@"ALAssetsGroup failed to remove asset: %@.", asset];
            if (failure) {
                failure([NSError errorWithDomain:@"ALAsset"
                                            code:0
                                        userInfo:@{NSLocalizedDescriptionKey : message}]);
            }
        }
    };
}

- (ALAssetsLibraryWriteImageCompletionBlock)_resultBlockOfAddingToAlbum:(NSString *)albumName
                                                             completion:(void(^)(BOOL success))completion
                                                                failure:(void(^)(NSError *error))failure
{
    return ^(NSURL *assetURL, NSError *error) {
        // Run the completion block for writing image to saved
        //   photos album
        //if (completion) completion(assetURL, error);

        // If an error occured, do not try to add the asset to
        //   the custom photo album
        if (error != nil) {
            if (failure) failure(error);
            return;
        }

        if (albumName == nil) {
            if (completion) completion(YES);
            return;
        }

        // Add the asset to the custom photo album
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self addAssetURL:assetURL toAlbum:albumName resultBlock:completion failureBlock:failure];
#pragma clang diagnostic pop
    };
}

#pragma mark - Photo Edit
- (void)requestContentEditing:(DLPhotoAsset *)asset
                   completion:(void (^)(UIImage *image, PHContentEditingInput *contentEditingInput, NSDictionary *info))completion
{
    if ([asset.phAsset canPerformEditOperation:PHAssetEditOperationContent] &&
        !(asset.phAsset.mediaSubtypes & PHAssetMediaSubtypePhotoLive))
    {
        PHContentEditingInputRequestOptions *options = [[PHContentEditingInputRequestOptions alloc] init];
        [options setNetworkAccessAllowed:YES];
        [options setCanHandleAdjustmentData:^BOOL(PHAdjustmentData *adjustmentData) {
            //  origin image
            return [adjustmentData.formatIdentifier isEqualToString:AdjustmentFormatIdentifier] && [adjustmentData.formatVersion isEqualToString:AdjustmentFormatVersion];
        }];

        [asset.phAsset requestContentEditingInputWithOptions:options completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {

            //CIImage *fullImage = [CIImage imageWithContentsOfURL:contentEditingInput.fullSizeImageURL];
            //NSLog(@"%@", fullImage.properties.description);

            NSURL *url = [contentEditingInput fullSizeImageURL];
            UIImage *image = [[UIImage alloc] initWithContentsOfFile:url.path];
            //UIImage *image = contentEditingInput.displaySizeImage;

            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    completion(image, contentEditingInput, info);
                }
            });
        }];
    }
}

- (void)saveContentEditing:(DLPhotoAsset *)asset
                     image:(UIImage *)image
       contentEditingInput:(PHContentEditingInput *)contentEditingInput
     adjustmentDescription:(NSData *)adjustmentDescription
{
    /*
     *  Edit the origin image
     */
    PHAdjustmentData *adjustmentData =
    [[PHAdjustmentData alloc] initWithFormatIdentifier:AdjustmentFormatIdentifier formatVersion:AdjustmentFormatVersion data:adjustmentDescription];

    // Create a PHContentEditingOutput object and write a JPEG representation of the edited object to the renderedContentURL.
    PHContentEditingOutput *contentEditingOutput = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput];

    //NSData *imageData = UIImagePNGRepresentation(image);//not work
    NSData *imageData = UIImageJPEGRepresentation(image, 1.0f);
    [imageData writeToURL:[contentEditingOutput renderedContentURL] atomically:YES];
    [contentEditingOutput setAdjustmentData:adjustmentData];

    // Ask the shared PHPhotoLinrary to perform the changes.
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset.phAsset];
        request.contentEditingOutput = contentEditingOutput;
    } completionHandler:^(BOOL success, NSError *error) {
        if (!success) {
            NSLog(@">>> PHContentEditingInputRequest Error: %@", error);
        }else{
            /*
             *  use method -photoLibraryDidChange: instead
             */
            //[[self itemViewController] assetDidChanded:self.asset];
        }
    }];
}

#pragma mark - fetch album
- (void)fetchPhotoCollection:(void(^)(BOOL success))completion
{
    self.fetchCollectionCompletion = completion;
    if (UsePhotoKit) {
        [self getAlbumsFromDevice];
    }
    else{
        [self getAlbumsFromDevice_BeforeiOS8];
    }
}

- (void)getAlbumsFromDevice
{
    PHFetchResult *fetchResult = [PHAsset fetchAssetsWithOptions:self.assetsFetchOptions];
    if (fetchResult.count <= 0) {
        [self showNoAssets];
        return;
    }

    NSMutableArray *fetchResults = [NSMutableArray new];

    for (NSNumber *subtypeNumber in self.assetCollectionSubtypes)
    {
        PHAssetCollectionSubtype subtype = subtypeNumber.integerValue;
        PHAssetCollectionType type = [self __assetCollectionTypeOfSubtype:subtype];

        PHFetchResult *fetchResult =
        [PHAssetCollection fetchAssetCollectionsWithType:type
                                                 subtype:subtype
                                                 options:self.assetCollectionFetchOptions];

        [fetchResults addObject:fetchResult];
    }

    self.fetchResults = fetchResults;

    if (fetchResults.count > 0) {
        [self getAlbumsCompletion:YES];
    }else{
        [self getAlbumsCompletion:NO];
    }
}

- (void)getAlbumsFromDevice_BeforeiOS8
{
    NSMutableArray *albumsArray = [[NSMutableArray alloc] init];
    __weak typeof(self) weakSelf = self;
    [_assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (group) {
            /**
             *  allPhotos: Get all photos assets in the assets group.
             *  allVideos: Get all video assets in the assets group.
             *  allAssets: Get all assets in the group.
             */
            [group setAssetsFilter:[ALAssetsFilter allAssets]];

            if (!strongSelf.showsEmptyAlbums && group.numberOfAssets <= 0) {
                ;
            }else{
                DLPhotoCollection *collection = [[DLPhotoCollection alloc] initWithAssetCollection:group];
                NSInteger groupType = [[group valueForProperty:ALAssetsGroupPropertyType] integerValue];
                if(groupType == ALAssetsGroupSavedPhotos){
                    [albumsArray insertObject:collection atIndex:0];
                }
                else{
                    [albumsArray addObject:collection];
                }
            }

        } else {
            if ([albumsArray count] > 0) {
                strongSelf.photoCollections = [NSMutableArray arrayWithArray:albumsArray];
                // 把所有的相册储存完毕,可以展示相册列表
                [strongSelf getAlbumsCompletion:YES];
            } else {
                // 没有任何有资源的相册,输出提示
                [strongSelf showNoAssets];
            }
        }
    } failureBlock:^(NSError *error) {
        NSLog(@">>>Asset group not found!\n");
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf getAlbumsCompletion:NO];
    }];
}

#pragma mark - fetch asset
- (NSArray *)assetsForPhotoCollection:(DLPhotoCollection *)photoCollection
{
    NSMutableArray *photoAssets = [[NSMutableArray alloc] initWithCapacity:photoCollection.count];

    if (UsePhotoKit) {
        PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:photoCollection.assetCollection
                                                                   options:self.assetsFetchOptions];

        for (PHAsset *asset in fetchResult) {
            DLPhotoAsset *phAsset = [[DLPhotoAsset alloc] initWithAsset:asset];
            [photoAssets addObject:phAsset];
        }

        photoCollection.fetchResult = fetchResult;
    }
    else{
        /*
         __block NSUInteger photoCount = 0;
         __block NSUInteger videoCount = 0;
         */

        ALAssetsGroup *assetGroup = photoCollection.assetGroup;
        if (assetGroup) {
            [assetGroup enumerateAssetsWithOptions:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                if (result) {
                    /*
                     NSString *type = [result valueForProperty:ALAssetPropertyType];
                     if ([type isEqualToString:ALAssetTypePhoto]){
                     photoCount++;
                     }else if ([type isEqualToString:ALAssetTypeVideo] ){
                     videoCount++;
                     }
                     */
                    DLPhotoAsset *asset = [[DLPhotoAsset alloc] initWithAsset:result];
                    // Add @synchronized to fix a crash bug
                    @synchronized(photoAssets) {
                        [photoAssets addObject:asset];
                    }
                } else {
                    // finished

                    [photoAssets sortUsingComparator:^NSComparisonResult(DLPhotoAsset *obj1, DLPhotoAsset *obj2) {
                        return [obj1.createDate compare:obj2.createDate];
                    }];
                }
            }];
        }
    }
    return photoAssets;
}

- (NSUInteger)assetCountOfPhotoCollection:(DLPhotoCollection *)photoCollection
{
    if (UsePhotoKit) {
        return [[PHAsset fetchAssetsInAssetCollection:photoCollection.assetCollection options:self.assetsFetchOptions] count];
    }else{
        [photoCollection.assetGroup setAssetsFilter:[ALAssetsFilter allAssets]];
        return photoCollection.assetGroup.numberOfAssets;
    }
}

#pragma mark - poster images
- (NSArray *)posterImagesForPhotoCollection:(DLPhotoCollection *)photoCollection
                              thumbnailSize:(CGSize)thumbnailSize
                                      count:(NSUInteger)count
{
    if (UsePhotoKit) {
        PHFetchOptions *options = [PHFetchOptions new];
        options.predicate       = self.assetsFetchOptions.predicate; // aligned specified predicate
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

        PHFetchResult *result   = [PHAsset fetchKeyAssetsInAssetCollection:photoCollection.assetCollection options:options];

        NSUInteger location     = 0;
        NSUInteger length       = (result.count < count) ? result.count : count;
        NSArray *assets         = [self __itemsFromFetchResult:result range:NSMakeRange(location, length)];

        NSMutableArray *images  = [NSMutableArray arrayWithCapacity:length];

        for (PHAsset *asset in assets) {
            DLPhotoAsset *photoAsset = [[DLPhotoAsset alloc] initWithAsset:asset];
            [photoAsset requestThumbnailImageWithSize:thumbnailSize completion:^(UIImage *image, NSDictionary *info) {
                if (image) {
                    [images addObject:image];
                }
            }];
        }
        return images;
    }
    else{
        NSMutableArray *images = [NSMutableArray array];
        CGImageRef cgPosterImage = photoCollection.assetGroup.posterImage;
        if (cgPosterImage) {
            UIImage *posterImage = [[UIImage alloc] initWithCGImage:cgPosterImage];

            if (posterImage) {
                [images addObject:posterImage];
            }
        }
        return images;
    }

    return nil;
}

- (NSArray *)posterAssetsForPhotoCollection:(DLPhotoCollection *)photoCollection count:(NSUInteger)count
{
    if (UsePhotoKit) {
        PHFetchOptions *options = [PHFetchOptions new];
        options.predicate       = self.assetsFetchOptions.predicate; // aligned specified predicate
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

        PHFetchResult *result   = [PHAsset fetchKeyAssetsInAssetCollection:photoCollection.assetCollection options:options];

        NSUInteger location     = 0;
        NSUInteger length       = (result.count < count) ? result.count : count;
        NSArray *assets         = [self __itemsFromFetchResult:result range:NSMakeRange(location, length)];

        NSMutableArray *photoAssets = [NSMutableArray arrayWithCapacity:length];
        for (PHAsset *asset in assets) {
            DLPhotoAsset *phAsset = [[DLPhotoAsset alloc] initWithAsset:asset];
            [photoAssets addObject:phAsset];
        }

        return photoAssets;
    }
    else{
        __block NSUInteger length = (photoCollection.count < count) ? photoCollection.count : count;
        NSMutableArray *photoAssets = [NSMutableArray arrayWithCapacity:length];
        [photoCollection.assetGroup enumerateAssetsWithOptions:NSEnumerationReverse
                                                    usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                                                        if (result) {
                                                            length--;
                                                            DLPhotoAsset *asset = [[DLPhotoAsset alloc] initWithAsset:result];
                                                            [photoAssets addObject:asset];
                                                        }

                                                        if (length == 0) {
                                                            *stop = YES;
                                                        }
                                                    }];
        return photoAssets;
    }

    return nil;
}

#pragma mark - register change observer
- (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver,ALAssetsLibraryChangeObserver>)observer
{
    if (UsePhotoKit) {
        [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:observer];
    }else{
        [[NSNotificationCenter defaultCenter] addObserver:observer
                                                 selector:@selector(assetsLibraryChanged:)
                                                     name:ALAssetsLibraryChangedNotification
                                                   object:nil];
    }
}

- (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver,ALAssetsLibraryChangeObserver>)observer
{
    if (UsePhotoKit) {
        [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:observer];
    }else{
        [[NSNotificationCenter defaultCenter] removeObserver:observer name:ALAssetsLibraryChangedNotification object:nil];
    }
}

#pragma mark - caching images (iOS 8 or later)
- (void)startCachingImagesForAssets:(DLPhotoAsset *)asset targetSize:(CGSize)targetSize
{
    if (UsePhotoKit) {
        [self.phCachingImageManager startCachingImagesForAssets:@[asset.phAsset]
                                                     targetSize:targetSize
                                                    contentMode:PHImageContentModeAspectFill
                                                        options:self.thumbnailRequestOptions];
    }else{

    }
}

- (void)stopCachingImagesForAssets:(DLPhotoAsset *)asset targetSize:(CGSize)targetSize
{
    if (UsePhotoKit) {
        [self.phCachingImageManager stopCachingImagesForAssets:@[asset.phAsset]
                                                    targetSize:targetSize
                                                   contentMode:PHImageContentModeAspectFill
                                                       options:self.thumbnailRequestOptions];
    }else{

    }
}

- (void)stopCachingImagesForAllAssets
{
    if (UsePhotoKit) {
        [self.phCachingImageManager stopCachingImagesForAllAssets];
    }else{

    }
}

#pragma mark - Private Method
- (void)__updateAssetCollections
{
    NSMutableArray *assetCollections = [NSMutableArray new];

    for (PHFetchResult *fetchResult in self.fetchResults)
    {
        for (PHAssetCollection *assetCollection in fetchResult)
        {
            BOOL showsAssetCollection = YES;

            if (!self.showsEmptyAlbums){
                PHFetchOptions *options = [PHFetchOptions new];
                options.predicate = self.assetsFetchOptions.predicate;

                if ([options respondsToSelector:@selector(setFetchLimit:)]){
                    options.fetchLimit = 1;
                }

                NSInteger count = [self __countOfAssetsForCollection:assetCollection FetchedWithOptions:options];

                showsAssetCollection = (count > 0);
            }

            if (showsAssetCollection){
                DLPhotoCollection *photoCollection = [[DLPhotoCollection alloc] initWithAssetCollection:assetCollection];
                photoCollection.fetchResult = fetchResult;
                [assetCollections addObject:photoCollection];
            }
        }
    }

    self.photoCollections = [NSMutableArray arrayWithArray:assetCollections];
}

- (NSArray *)__itemsFromFetchResult:(PHFetchResult *)result range:(NSRange)range
{
    if (result.count == 0)
        return nil;

    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
    NSArray *array = [result objectsAtIndexes:indexSet];

    return array;
}

- (PHAssetCollectionType)__assetCollectionTypeOfSubtype:(PHAssetCollectionSubtype)subtype
{
    return (subtype >= PHAssetCollectionSubtypeSmartAlbumGeneric) ? PHAssetCollectionTypeSmartAlbum : PHAssetCollectionTypeAlbum;
}

- (NSUInteger)__countOfAssetsForCollection:(PHAssetCollection *)phAssetCollection FetchedWithOptions:(PHFetchOptions *)fetchOptions
{
    PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:phAssetCollection options:fetchOptions];
    return result.count;
}

- (UIImage *)originImage:(DLPhotoAsset *)photoAsset
{
    @autoreleasepool {
        __block UIImage *resultImage;

        if (UsePhotoKit) {

            @autoreleasepool {

                //  image after edited
                PHImageRequestOptions *originRequestOptions = [[PHImageRequestOptions alloc] init];
                originRequestOptions.version = PHImageRequestOptionsVersionCurrent;
                originRequestOptions.networkAccessAllowed = YES;
                originRequestOptions.synchronous = YES;

                //sync requests are automatically processed this way regardless of the specified mode
                //originRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;

                originRequestOptions.progressHandler = ^(double progress, NSError *__nullable error, BOOL *stop, NSDictionary *__nullable info){
                    dispatch_main_async_safe(^{

                    });
                };

                /*
                 Printing description of info:
                 {
                 PHImageResultDeliveredImageFormatKey = 9999;
                 PHImageResultIsDegradedKey = 0;
                 PHImageResultIsInCloudKey = 0;
                 PHImageResultIsPlaceholderKey = 0;
                 PHImageResultWantedImageFormatKey = 9999;
                 }
                 */

                [[[DLPhotoManager sharedInstance] phCachingImageManager] requestImageForAsset:photoAsset.phAsset
                                                                                targetSize:PHImageManagerMaximumSize
                                                                                contentMode:PHImageContentModeDefault
                                                                                options:originRequestOptions
                                                                                resultHandler:^(UIImage *result, NSDictionary *info) {

                                                                                @autoreleasepool {

                                                                                // 排除取消,错误,低清图三种情况,即已经获取到了高清图时,把这张高清图缓存到 _originImage 中
                                                                                BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] &&
                                                                                ![info objectForKey:PHImageErrorKey] &&
                                                                                ![[info objectForKey:PHImageResultIsDegradedKey] boolValue] && result;

                                                                                if (downloadFinined) {
                                                                                resultImage = result;
                                                                                }
                                                                                }
                                                                                }];
            }

            /*
             if ([self.phAsset canPerformEditOperation:PHAssetEditOperationContent] &&
             !(self.phAsset.mediaSubtypes & PHAssetMediaSubtypePhotoLive))
             {
             PHContentEditingInputRequestOptions *options = [[PHContentEditingInputRequestOptions alloc] init];
             options.networkAccessAllowed = YES;
             options.canHandleAdjustmentData = ^BOOL(PHAdjustmentData *adjustmentData) { return YES; };

             //  We synchronously have the asset
             dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

             [self.phAsset requestContentEditingInputWithOptions:options
             completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {

             //http://www.cnblogs.com/crazypebble/p/5259641.html

             NSURL *url = [contentEditingInput fullSizeImageURL];
             NSData *imageData = [NSData dataWithContentsOfURL:url];
             resultImage = [[UIImage alloc] initWithData:imageData];

             dispatch_semaphore_signal(semaphore);

             }];

             dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
             }
             */

        } else {

            CGImageRef fullResolutionImageRef = [[photoAsset.alAsset defaultRepresentation] fullResolutionImage];
            /*
             *通过 fullResolutionImage 获取到的的高清图实际上并不带上在照片应用中使用"编辑"处理的效果,
             *需要额外在 AlAssetRepresentation 中获取这些信息
             */
            NSString *adjustment = [[[photoAsset.alAsset defaultRepresentation] metadata] objectForKey:@"AdjustmentXMP"];
            if (adjustment) {
                // 如果有在照片应用中使用"编辑"效果,则需要获取这些编辑后的滤镜,手工叠加到原图中
                NSData *xmpData = [adjustment dataUsingEncoding:NSUTF8StringEncoding];
                CIImage *tempImage = [CIImage imageWithCGImage:fullResolutionImageRef];

                NSError *error;
                NSArray *filterArray = [CIFilter filterArrayFromSerializedXMP:xmpData
                                                             inputImageExtent:tempImage.extent
                                                                        error:&error];
                CIContext *context = [CIContext contextWithOptions:nil];
                if (filterArray && !error) {
                    for (CIFilter *filter in filterArray) {
                        [filter setValue:tempImage forKey:kCIInputImageKey];
                        tempImage = [filter outputImage];
                    }
                    fullResolutionImageRef = [context createCGImage:tempImage fromRect:[tempImage extent]];
                }
            }
            // 生成最终返回的 UIImage,同时把图片的 orientation 也补充上去
            resultImage = [UIImage imageWithCGImage:fullResolutionImageRef scale:[[photoAsset.alAsset defaultRepresentation] scale] orientation:(UIImageOrientation)[[photoAsset.alAsset defaultRepresentation] orientation]];
        }

        //return resultImage ? resultImage : [self originImage:photoAsset];
        return resultImage;
    }
}
@end


text:
var InitFormLogic = {

    rightSideMenu: function () {
        var HelpPanel = $(".HelpPanelWrapper");
        var Toggled = false;
        $(".flagIcon.flagIconHebrew").on('click', function () {

            // Set sideMenu visible
            if (!Toggled) {
                HelpPanel.css('visibility', 'visible');
                Toggled = true;
            }
            else {
                HelpPanel.css('visibility', 'hidden');
                Toggled = false;
            }
        });

        /// Todo: remove after production;
        HelpPanel.css('visibility', 'visible');
    },

    campStatusSelect: function () {
        $("#campStatusAccept").on('click', function () {
            $("#campStatusSelect").html(' Accept New Members ');
        });
        $("#campStatusClose").on('click', function () {
            $("#campStatusSelect").html(' Close To New Members ');
        });
        $("#campStatusInactive").on('click', function () {
            $("#campStatusSelect").html(' Inactive ');
        });
    },

    campNoiseLvlSelect: function () {

        $("#campNoiseNone").on('click', function () {
            $("#campNoiseLvlSelect").html(' No Noise ');
        });
        $("#campNoiseMed").on('click', function () {
            $("#campNoiseLvlSelect").html(' Medium Noise ');
        });
        $("#campNoiseHard").on('click', function () {
            $("#campNoiseLvlSelect").html(' Hard Noise ');
        });

    }
};

function InitAll() {
    InitFormLogic.campStatusSelect();
    InitFormLogic.rightSideMenu();
}

redpajama_set_name: RedPajamaGithub


text:
namespace base {
class HistogramTester;
}

// Retries fetching |histogram_name| until it contains at least |count| samples.
void RetryForHistogramUntilCountReached(
    const base::HistogramTester* histogram_tester,
    const std::string& histogram_name,
    int count);

#endif  // IOS_CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_TEST_UTILS_H_


text:
<!--

    Copyright (C) 2015 Born Informatik AG (www.born.ch)

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

            http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>wte4j-persistence</artifactId>
	<packaging>jar</packaging>

	<parent>
		<groupId>org.wte4j</groupId>
		<artifactId>wte4j-parent</artifactId>
		<version>0.1.4-SNAPSHOT</version>
	</parent>

	<build>
		<plugins>

			<plugin>
				<groupId>org.apache.openjpa</groupId>
				<artifactId>openjpa-maven-plugin</artifactId>
				<version>${openJPA.version}</version>

				<executions>
					<execution>
						<id>generate-sql</id>
						<goals>
							<goal>sql</goal>
						</goals>
						<phase />
						<configuration>
							<connectionDriverName>org.hsqldb.jdbc.JDBCDriver</connectionDriverName>
							<persistenceXmlFile>${project.basedir}/src/test/resources/META-INF/persistence.xml</persistenceXmlFile>
							<sqlFile>${project.basedir}/src/test/resources/sql/create-schema.sql</sqlFile>
						</configuration>
					</execution>
					<execution>
						<id>enhance-for-test</id>
						<phase>process-test-classes</phase>
						<goals>
							<goal>test-enhance</goal>
						</goals>
						<configuration>
							<persistenceXmlFile>${project.basedir}/src/test/resources/META-INF/persistence.xml</persistenceXmlFile>
							<includes>**/PersistentTemplate.class, **/User.class, **/MappingDetail.class</includes>
							<toolProperties>
								<directory>${project.build.testOutputDirectory}</directory>
							</toolProperties>
						</configuration>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>org.apache.openjpa</groupId>
						<artifactId>openjpa</artifactId>
						<version>${openJPA.version}</version>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>

	</build>

	<dependencies>
		<dependency>
			<groupId>${project.groupId}</groupId>
			<artifactId>wte4j-core</artifactId>
			<version>${project.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-jpa_2.0_spec</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
		</dependency>

		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-collections4</artifactId>
		</dependency>

		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
		</dependency>

		<!-- file access to microsoft format files -->
		<dependency>
			<groupId>org.docx4j</groupId>
			<artifactId>docx4j</artifactId>
			<version>3.2.2</version>
			<exclusions>
				<!-- Pptx export -->
				<exclusion>
					<artifactId>jaxb-svg11</artifactId>
					<groupId>org.plutext</groupId>
				</exclusion>
				<exclusion>
					<artifactId>wmf2svg</artifactId>
					<groupId>net.arnx</groupId>
				</exclusion>
				<!-- OpenDoPE -->
				<exclusion>
					<artifactId>stringtemplate</artifactId>
					<groupId>org.antlr</groupId>
				</exclusion>
				<exclusion>
					<artifactId>antlr-runtime</artifactId>
					<groupId>org.antlr</groupId>
				</exclusion>
				<exclusion>
					<artifactId>slf4j-log4j12</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- testing -->

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.openjpa</groupId>
			<artifactId>openjpa</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<scope>test</scope>
		</dependency>

	</dependencies>

</project>


text:
// Description: Entity Framework Bulk Operations & Utilities (EF Bulk SaveChanges, Insert, Update, Delete, Merge | LINQ Query Cache, Deferred, Filter, IncludeFilter, IncludeOptimize | Audit)
// Website & Documentation: https://github.com/zzzprojects/Entity-Framework-Plus
// Forum & Issues: https://github.com/zzzprojects/EntityFramework-Plus/issues
// License: https://github.com/zzzprojects/EntityFramework-Plus/blob/master/LICENSE
// More projects: http://www.zzzprojects.com/
// Copyright © ZZZ Projects Inc. 2014 - 2016. All rights reserved.

#if FULL
using System.Collections.Generic;
using System.Linq;

namespace Z.EntityFramework.Plus
{
    internal static partial class InternalExtensions
    {
        internal static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
        {
            return Order(source, propertyName, true, true);
        }

        internal static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, string propertyName, IComparer<TKey> comparer)
        {
            return Order(source, propertyName, true, true, comparer);
        }
    }
}
#endif


text:
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

namespace TwentyTwenty.Mvc.Http
{
    public static class HttpClientExtensions
    {
        public static async Task<TResponse> ReadJson<TResponse>(this HttpResponseMessage msg)
        {
            var responseString = await msg.Content.ReadAsStringAsync();

            return responseString == null ? default(TResponse) : JsonSerializer.Deserialize<TResponse>(responseString);
        }
    }
}


text:
<lcCorrectResponse>

The <lcCorrectResponse> element was deprecated in DITA version 1.3. It
         was replaced with the <lcCorrectResponse2> element. It was originally
         intended to indicate a correct response in an assessment interaction.

Category: Interactions domain content elements (DEPRECATED)


text:
LLVMValueRef gen_expr(compile_t* c, ast_t* ast)
{
  LLVMValueRef ret;
  bool has_scope = ast_has_scope(ast);

  if(has_scope)
    codegen_pushscope(c, ast);

  switch(ast_id(ast))
  {
    case TK_SEQ:
      ret = gen_seq(c, ast);
      break;

    case TK_FVARREF:
    case TK_FLETREF:
      ret = gen_fieldload(c, ast);
      break;

    case TK_TUPLEELEMREF:
    {
      ret = gen_tupleelemptr(c, ast);
      break;
    }

    case TK_EMBEDREF:
      ret = gen_fieldembed(c, ast);
      break;

    case TK_PARAMREF:
      ret = gen_param(c, ast);
      break;

    case TK_VAR:
    case TK_LET:
    case TK_MATCH_CAPTURE:
      ret = gen_localdecl(c, ast);
      break;

    case TK_VARREF:
    case TK_LETREF:
      ret = gen_localload(c, ast);
      break;

    case TK_TYPEREF:
    case TK_DONTCARE:
    case TK_DONTCAREREF:
    case TK_MATCH_DONTCARE:
      ret = GEN_NOTNEEDED;
      break;

    case TK_IF:
      ret = gen_if(c, ast);
      break;

    case TK_IFTYPE_SET:
      ret = gen_iftype(c, ast);
      break;

    case TK_WHILE:
      ret = gen_while(c, ast);
      break;

    case TK_REPEAT:
      ret = gen_repeat(c, ast);
      break;

    case TK_TRY:
    case TK_TRY_NO_CHECK:
      ret = gen_try(c, ast);
      break;

    case TK_MATCH:
      ret = gen_match(c, ast);
      break;

    case TK_CALL:
      ret = gen_call(c, ast);
      break;

    case TK_CONSUME:
    {
      ast_t* ref = ast_childidx(ast, 1);
      ret = gen_expr(c, ref);
      switch(ast_id(ref))
      {
        case TK_LETREF:
        case TK_VARREF:
        {
          const char* name = ast_name(ast_child(ref));
          codegen_local_lifetime_end(c, name);
          break;
        }
        case TK_THIS:
        case TK_PARAMREF:
          break;
        default:
          pony_assert(0);
          break;
      }
      break;
    }

    case TK_RECOVER:
      ret = gen_expr(c, ast_childidx(ast, 1));
      break;

    case TK_BREAK:
      ret = gen_break(c, ast);
      break;

    case TK_CONTINUE:
      ret = gen_continue(c, ast);
      break;

    case TK_RETURN:
      ret = gen_return(c, ast);
      break;

    case TK_ERROR:
      ret = gen_error(c, ast);
      break;

    case TK_IS:
      ret = gen_is(c, ast);
      break;

    case TK_ISNT:
      ret = gen_isnt(c, ast);
      break;

    case TK_ASSIGN:
      ret = gen_assign(c, ast);
      break;

    case TK_THIS:
      ret = gen_this(c, ast);
      break;

    case TK_TRUE:
      ret = LLVMConstInt(c->i1, 1, false);
      break;

    case TK_FALSE:
      ret = LLVMConstInt(c->i1, 0, false);
      break;

    case TK_INT:
      ret = gen_int(c, ast);
      break;

    case TK_FLOAT:
      ret = gen_float(c, ast);
      break;

    case TK_STRING:
      ret = gen_string(c, ast);
      break;

    case TK_TUPLE:
      ret = gen_tuple(c, ast);
      break;

    case TK_FFICALL:
      ret = gen_ffi(c, ast);
      break;

    case TK_ADDRESS:
      ret = gen_addressof(c, ast);
      break;

    case TK_DIGESTOF:
      ret = gen_digestof(c, ast);
      break;

    case TK_COMPILE_INTRINSIC:
      ast_error(c->opt->check.errors, ast, "unimplemented compile intrinsic");
      return NULL;

    case TK_COMPILE_ERROR:
    {
      ast_t* reason_seq = ast_child(ast);
      ast_t* reason = ast_child(reason_seq);
      ast_error(c->opt->check.errors, ast, "compile error: %s",
        ast_name(reason));
      return NULL;
    }

    default:
      ast_error(c->opt->check.errors, ast, "not implemented (codegen unknown)");
      return NULL;
  }

  if(has_scope)
  {
    LLVMBasicBlockRef current_bb = LLVMGetInsertBlock(c->builder);
    LLVMValueRef terminator = LLVMGetBasicBlockTerminator(current_bb);
    if(terminator == NULL)
      codegen_scope_lifetime_end(c);
    codegen_popscope(c);
  }

  return ret;
}

static LLVMValueRef assign_to_tuple(compile_t* c, LLVMTypeRef l_type,
  LLVMValueRef r_value, ast_t* type)
{
  // Cast each component.
  pony_assert(ast_id(type) == TK_TUPLETYPE);

  int count = LLVMCountStructElementTypes(l_type);
  size_t buf_size = count * sizeof(LLVMTypeRef);
  LLVMTypeRef* elements = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  LLVMGetStructElementTypes(l_type, elements);

  LLVMValueRef result = LLVMGetUndef(l_type);

  ast_t* type_child = ast_child(type);
  int i = 0;

  while(type_child != NULL)
  {
    LLVMValueRef r_child = LLVMBuildExtractValue(c->builder, r_value, i, "");
    LLVMValueRef cast_value = gen_assign_cast(c, elements[i], r_child,
      type_child);

    if(cast_value == NULL)
    {
      ponyint_pool_free_size(buf_size, elements);
      return NULL;
    }

    result = LLVMBuildInsertValue(c->builder, result, cast_value, i, "");
    type_child = ast_sibling(type_child);
    i++;
  }

  ponyint_pool_free_size(buf_size, elements);
  return result;
}

static LLVMValueRef assign_union_to_tuple(compile_t* c, LLVMTypeRef l_type,
  LLVMValueRef r_value, ast_t* type)
{
  reach_type_t* t = reach_type(c->reach, type);
  pony_assert(t != NULL);
  pony_assert(t->underlying == TK_UNIONTYPE);

  LLVMValueRef r_desc = gendesc_fetch(c, r_value);
  LLVMValueRef r_typeid = gendesc_typeid(c, r_desc);

  LLVMBasicBlockRef unreachable_block = codegen_block(c, "unreachable");
  LLVMBasicBlockRef post_block = codegen_block(c, "assign_union_tuple_post");
  LLVMValueRef type_switch = LLVMBuildSwitch(c->builder, r_typeid,
    unreachable_block, 0);

  LLVMPositionBuilderAtEnd(c->builder, post_block);
  LLVMValueRef phi = LLVMBuildPhi(c->builder, l_type, "");

  reach_type_t* sub;
  size_t i = HASHMAP_BEGIN;

  while((sub = reach_type_cache_next(&t->subtypes, &i)) != NULL)
  {
    pony_assert(sub->underlying == TK_TUPLETYPE);

    LLVMBasicBlockRef sub_block = codegen_block(c, "assign_union_tuple_sub");
    LLVMAddCase(type_switch, LLVMConstInt(c->i32, sub->type_id, false),
      sub_block);
    LLVMPositionBuilderAtEnd(c->builder, sub_block);

    LLVMValueRef r_unbox = gen_unbox(c, sub->ast_cap, r_value);
    r_unbox = assign_to_tuple(c, l_type, r_unbox, sub->ast_cap);
    LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder);
    LLVMAddIncoming(phi, &r_unbox, &this_block, 1);
    LLVMBuildBr(c->builder, post_block);
  }

  LLVMMoveBasicBlockAfter(unreachable_block, LLVMGetInsertBlock(c->builder));
  LLVMPositionBuilderAtEnd(c->builder, unreachable_block);
  LLVMBuildUnreachable(c->builder);

  LLVMMoveBasicBlockAfter(post_block, unreachable_block);
  LLVMPositionBuilderAtEnd(c->builder, post_block);
  return phi;
}

LLVMValueRef gen_assign_cast(compile_t* c, LLVMTypeRef l_type,
  LLVMValueRef r_value, ast_t* type)
{
  if(r_value <= GEN_NOVALUE)
    return r_value;

  pony_assert(r_value != GEN_NOTNEEDED);

  LLVMTypeRef r_type = LLVMTypeOf(r_value);

  if(r_type == l_type)
    return r_value;

  switch(LLVMGetTypeKind(l_type))
  {
    case LLVMIntegerTypeKind:
      // This can occur for Bool as its value type differs from its memory
      // representation type.
      if(LLVMGetTypeKind(r_type) == LLVMIntegerTypeKind)
      {
        unsigned l_width = LLVMGetIntTypeWidth(l_type);
        unsigned r_width = LLVMGetIntTypeWidth(r_type);

        if(l_width > r_width)
          return LLVMBuildZExt(c->builder, r_value, l_type, "");
        else
          return LLVMBuildTrunc(c->builder, r_value, l_type, "");
      }
      // fallthrough

    case LLVMHalfTypeKind:
    case LLVMFloatTypeKind:
    case LLVMDoubleTypeKind:
      pony_assert(LLVMGetTypeKind(r_type) == LLVMPointerTypeKind);
      r_value = gen_unbox(c, type, r_value);
      // The value could be needed in either its value representation type or
      // its memory representation type. Cast the unboxed value to ensure the
      // final type is correct.
      return gen_assign_cast(c, l_type, r_value, type);

    case LLVMPointerTypeKind:
      r_value = gen_box(c, type, r_value);

      if(r_value == NULL)
        return NULL;

      return LLVMBuildBitCast(c->builder, r_value, l_type, "");

    case LLVMStructTypeKind:
      if(LLVMGetTypeKind(r_type) == LLVMPointerTypeKind)
      {
        if(ast_id(type) == TK_TUPLETYPE)
          r_value = gen_unbox(c, type, r_value);
        else
          return assign_union_to_tuple(c, l_type, r_value, type);

        pony_assert(LLVMGetTypeKind(LLVMTypeOf(r_value)) == LLVMStructTypeKind);
      }

      return assign_to_tuple(c, l_type, r_value, type);

    default: {}
  }

  pony_assert(0);
  return NULL;
}


text:
ALTER TABLE `debts`
CHANGE `amount` `amount` double(15,3) NULL AFTER `currency_id`;


text:
using Portal.CMS.Web.Architecture.Helpers;
using System.Web.Optimization;

namespace Portal.CMS.Web
{
    public static class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.UseCdn = true;
            BundleTable.EnableOptimizations = true;

            var cdnRootAddress = SettingHelper.Get("CDN Address");

            RegisterFramework(bundles, cdnRootAddress);
            RegisterPlugins(bundles, cdnRootAddress);
        }

        private static void RegisterFramework(BundleCollection bundles, string cdnRootAddress)
        {
            bundles.Add(new ScriptBundle("~/Resources/JavaScript/Framework").Include("~/Content/Scripts/Framework/*.js"));
            bundles.Add(new StyleBundle("~/Resources/CSS/Framework").Include("~/Content/Styles/Framework/*.css", new CssRewriteUrlTransform()));

            bundles.Add(new ScriptBundle("~/Resources/JavaScript/Framework/Administration").Include("~/Content/Scripts/Administration/*.js"));
            bundles.Add(new StyleBundle("~/Resources/CSS/Framework/Administration").Include("~/Content/Styles/Administration/*.css", new CssRewriteUrlTransform()));

            bundles.Add(GenerateCDNScriptBundle("~/Resources/JavaScript/Framework/Editor", "/Content/Scripts/Editor/QuickAccess.js", cdnRootAddress));
            bundles.Add(GenerateCDNStyleBundle("~/Resources/CSS/Framework/Editor", "/Content/Styles/AppDrawers/app-drawers.css", cdnRootAddress));

            bundles.Add(GenerateCDNScriptBundle("~/Plugins/Popover/Scripts/Editable", "/Content/Scripts/EditablePopover/editable.popover.js", cdnRootAddress));

            bundles.Add(GenerateCDNScriptBundle("~/Resources/JavaScript/Plugins/FAQ", "/Content/Scripts/Components/component.expand.js", cdnRootAddress));
            bundles.Add(GenerateCDNScriptBundle("~/Resources/JavaScript/Plugins/Pagination", "/Content/Scripts/Framework/pagination.js", cdnRootAddress));
            bundles.Add(GenerateCDNScriptBundle("~/Resources/JavaScript/Plugins/Sliders", "/Content/Scripts/Administration/ThemeManager-Admin.js", cdnRootAddress));
        }

        private static void RegisterPlugins(BundleCollection bundles, string cdnRootAddress)
        {
            bundles.Add(new ScriptBundle("~/Plugins/JQuery/Scripts", "https://code.jquery.com/jquery-2.2.1.min.js").Include("~/Content/Plugins/JQuery/jquery-2.2.1.min.js"));
            bundles.Add(GenerateCDNScriptBundle("~/Plugins/Touch/Scripts", "/Content/Plugins/JQueryUI/jquery.ui.touch-punch.min.js", cdnRootAddress));

            bundles.Add(new ScriptBundle("~/Plugins/JQueryUI/Scripts", "https://code.jquery.com/ui/1.12.0-beta.1/jquery-ui.min.js").Include("~/Content/Plugins/JQueryUI/jquery.ui.min.js"));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/JQueryUI/Styles", "/Content/Plugins/JQueryUI/jquery-ui.min.css", cdnRootAddress));

            bundles.Add(new ScriptBundle("~/Plugins/Bootstrap/Scripts", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js").Include("~/Content/Plugins/Bootstrap/bootstrap.min.js"));
            bundles.Add(new StyleBundle("~/Plugins/Bootstrap/Styles", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css").Include("~/Content/Plugins/Bootstrap/bootstrap.min.css", new CssRewriteUrlTransform()));

            bundles.Add(GenerateCDNScriptBundle("~/Plugins/Popover/Scripts", "/Content/Scripts/Popover/initialise.js", cdnRootAddress));
            bundles.Add(GenerateCDNScriptBundle("~/Plugins/Confirmation/Scripts", "/Content/Plugins/Confirmation/bootstrap-confirmation.min.js", cdnRootAddress));

            bundles.Add(new ScriptBundle("~/Plugins/Spectrum/Scripts").Include("~/Content/Plugins/Spectrum/spectrum.min.js").Include("~/Content/Plugins/Spectrum/initialise.js"));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/Spectrum/Styles", "/Content/Plugins/Spectrum/spectrum.css", cdnRootAddress));

            bundles.Add(new ScriptBundle("~/Plugins/C3Graphing/Scripts").Include("~/Content/Plugins/C3Graphing/c3.min.js").Include("~/Content/Plugins/C3Graphing/d3.min.js"));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/C3Graphing/Styles", "/Content/Plugins/C3Graphing/c3.min.css", cdnRootAddress));

            bundles.Add(GenerateCDNScriptBundle("~/Plugins/FontAwesome/Scripts", "/Content/Plugins/FontAwesome/fontawesome-iconpicker.min.js", cdnRootAddress));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/FontAwesome/Styles", "/Content/Plugins/FontAwesome/font-awesome.min.css", cdnRootAddress));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/FontAwesome/Styles/Picker", "/Content/Plugins/FontAwesome/fontawesome-iconpicker.min.css", cdnRootAddress));

            bundles.Add(new ScriptBundle("~/Plugins/FancyBox/Scripts").Include("~/Content/Plugins/FancyBox/jquery.fancybox.js").Include("~/Content/Plugins/FancyBox/jquery.fancybox-thumbs.js").Include("~/Content/Plugins/FancyBox/initialise.js"));
            bundles.Add(new StyleBundle("~/Plugins/FancyBox/Styles").Include("~/Content/Plugins/FancyBox/*.css", new CssRewriteUrlTransform()));

            bundles.Add(GenerateCDNStyleBundle("~/Plugins/HoverCSS/Styles", "/Content/Plugins/HoverCSS/hover-min.css", cdnRootAddress));
            bundles.Add(GenerateCDNStyleBundle("~/Plugins/Animate/Styles", "/Content/Plugins/Animate/animate.min.css", cdnRootAddress));

            bundles.Add(GenerateCDNScriptBundle("~/Plugins/ImageSelector/Scripts", "/Content/Plugins/ImageSelector/imageselector.js", cdnRootAddress));
        }

        private static Bundle GenerateCDNScriptBundle(string bundleName, string filePath, string cdnRootAddress)
        {
            if (string.IsNullOrEmpty(cdnRootAddress))
            {
                return new ScriptBundle(bundleName).Include($"~{filePath}");
            }

            return new ScriptBundle(bundleName, $"{cdnRootAddress}{filePath}").Include($"~{filePath}");
        }

        private static Bundle GenerateCDNStyleBundle(string bundleName, string filePath, string cdnRootAddress)
        {
            if (string.IsNullOrEmpty(cdnRootAddress))
            {
                return new StyleBundle(bundleName).Include($"~{filePath}");
            }

            var cdnFilePath = $"{cdnRootAddress}{filePath}";

            return new StyleBundle(bundleName, $"{cdnRootAddress}{filePath}").Include($"~{filePath}");
        }
    }
}


text:
layout:     project_page
title:      "Crazy toy city"
date:       2017-04-20 12:00:00 +0100
category: 	personal-project
thumb:      /assets/ceci_n_est_pas_un_jeu/thumb.png

excerpt:    "Arcade party game where you must capture buildings by surrounding them with your car."

type: "Platformer action"
platforms: "Windows"
inputs: "Gamepad"
tools: "Unity"

abstract: |
  Crazy toy city is an **arcade party game** made for the Gamers Assembly 2017's game jam. The theme was : "City-game" and we got 48h.

team:
  - {"name": "Axy Struggle", "role": "Artist"}
  - {"name": "Sylvain Antoine", "role": "Artist"}
  - {"name": "Nicolas Delamare", "role": "Producer"}
  - {"name": "Clément Rondeau", "role": "Developer"}

tasks:
  - Car driving mechanic
  - Building capture system
  - 3D models integration

screenshots: {"/assets/ceci_n_est_pas_un_jeu/1.png", "/assets/ceci_n_est_pas_un_jeu/2.png", "/assets/ceci_n_est_pas_un_jeu/4.png"}

project_url: "https://mykonos.itch.io/crazy-toy-city"
---

The main difficulty that I've encountered in this game was the capture system. To keep in memory the position that the player has been through, I've partitioned the world in a grid and I've saved the cells on which the player has driven.

In a big compound array I've stored the building GameObject and the cells around it, if a player's positions array contains all the cells around one building then he captures it.

Also, if a cell is going to be added to the player's positions array then we know that he looped and we can remove its path and check if he captures a building.


text:
int device_id = -1;                         // Device ID
int tenant_id = -1;                         // Tenant ID
int tsclients_socket[FD_SETSIZE];           // Telnet active clients (socket), tsclients_socket[0] is the index

int child_eth = 2;                          // Ethernet porgroups
int child_ser = 2;                          // Serial portgroups
int taps_number = 0;
int source_tap = -1;  // Number of the source TAP interface;

int  frames_processed = 0;
int  bytes_processed  = 0;

int ts_port = 32777;
int *tapHandles;
char xchangeBuffer[16000];
char *defaultTapPrefix = "vunl";

void usage(char * bin) {
  printf("Usage: %s <standard options>\n", bin);
  printf("Standard Options:\n");
  printf("-T <n>    *Tenant ID\n");
  printf("-D <n>    *Device ID\n");
  printf("-n <n>    *Number of TAP interfaces to try to open to\n");
  printf("-s <n>    *Source TAP interface\n");
  printf("-t <n>     Diagnostic port number. Default is %i\n", ts_port);
  printf("-v <s>     TAP interfaces' prefix. Default is %s\n", defaultTapPrefix);
  printf("* Mandatory option\n");
  printf("WARNING: use the above parameters' order!\n");
  printf("Description: %s translates frames from the source TAP interface to all the others\n", bin);
  printf("Example: %s -T 0 -D 1 -n 50 -s 16 -v vunl\n", bin);
  printf("  will translate frames from 'vunl0_1_16' TAP to all the other TAP interfaces in range [vunl0_1_0 .. vunl0_1_49] that have been successfully open by %s\n\n",bin);
  exit(1);
}

void openTaps() {
  char tapName[256];
  for(int i = 0; i < taps_number; i++) {
    //sprintf(tapName,"vnet%i_%i_%i",tenant_id,device_id,i);
    sprintf( tapName, "%s%i_%i_%i", defaultTapPrefix, tenant_id, device_id, i);
    if (tap_listen(tapName, &tapHandles[i]) != 0 ) {
      if ( i == source_tap ) {
        UNLLog(LLERROR,"Failed to open source tap:%s\n", tapName);
        exit(1);
      }
      tapHandles[i] = 0;
    } else {
      UNLLog(LLINFO,"Successfully open: %s\n", tapName);
    }
  }
}

int main(int argc, char *argv[]) {
  CheckLogLevelFileTrigger("/tmp/sf_ll_debug",LLDEBUG);
  CheckLogLevelFileTrigger("/tmp/sf_ll_verbose",LLVERBOSE);
  int rc;
  unsigned char client_input = '\0';      // Store single char from client
  fd_set active_fd_set;                   // Contains active FD using in select()
  FD_ZERO(&active_fd_set);
  fd_set read_fd_set;                     // Contains FD selected in current loop
  FD_ZERO(&read_fd_set);

  int opt;
  // Adding options to child's CMD line
  while ((opt = getopt(argc, argv, ":T:D:n:s:t:v:")) != -1) {
    switch (opt) {
      case 'T':
        // Mandatory: Tenant ID
        tenant_id = atoi(optarg);
        if (tenant_id < 0) {
          UNLLog(LLERROR,"tenant_id must be integer.\n");
          exit(1);
        }
        break;
      case 'D':
        // Mandatory: Device ID
        device_id = atoi(optarg);
        if (tenant_id < 0) {
          UNLLog(LLERROR,"device_id must be integer.\n");
          exit(1);
        }
        break;

        // Mandatory: number of TAP interfaces
      case 'n':
        taps_number = atoi(optarg);
        if (taps_number < 2) {
          UNLLog(LLERROR,"Number of TAP interfaces must be greater than 1\n");
          exit(1);
        }
        break;

        // Mandatory: Source TAP interface
      case 's':
        source_tap = atoi(optarg);
        if ((source_tap < 0) && (source_tap > taps_number - 1)) {
          UNLLog(LLERROR,"Number of TAP interfaces must be greater than 1, and come after -n CLI parameter\n");
          exit(1);
        }
        break;

        // Optional: diagnotic TCP port [default: 32777]
      case 't':
        ts_port = atoi(optarg);
        if ((ts_port < 0) || (ts_port > 0xFFFF)) {
          UNLLog(LLERROR,"Diagnotic port number must be in range [0..65K]\n");
          exit(1);
        }
        break;

        // Optional: TAP's prefix [default: vnet]
      case 'v':
        defaultTapPrefix = optarg;
        break;

      default:
        usage(argv[0]);
        exit(1);
    }
  }

  if (tenant_id < 0) {
    UNLLog(LLERROR,"No tenant id\n");
    usage(argv[0]);
  }
  if (device_id < 0) {
    UNLLog(LLERROR,"No device id\n");
    usage(argv[0]);
  }
  if (taps_number == 0) {
    UNLLog(LLERROR,"No TAPs number\n");
    usage(argv[0]);
  }
  if (source_tap == 0) {
    UNLLog(LLERROR,"No source TAP\n");
    usage(argv[0]);
  }

  tapHandles = (int*)calloc(taps_number,sizeof(int));

  int ts_socket = -1;
  tsclients_socket[0] = 0;
  if ((rc = ts_listen(ts_port, &ts_socket)) != 0) {
    UNLLog(LLERROR,"Failed to open TCP socket (%i).\n", rc);
    exit(1);
  }

  openTaps();

  FD_SET(ts_socket, &active_fd_set);
  FD_SET(tapHandles[source_tap], &active_fd_set);

  // main cycle:
  while(1) {
    read_fd_set = active_fd_set;
    int rc = -1;
    rc = select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
    if (rc == EINTR){
      UNLLog(LLINFO, "SimpleForwarder is terminated\n");
      break;
    } else if (rc <= 0) {
      UNLLog(LLERROR, "failed to select. Error: %i\n", rc);
    }

    // Check if new client is coming
    if (FD_ISSET(ts_socket, &read_fd_set)) {
      if ((rc = ts_accept(&active_fd_set, ts_socket, "", tsclients_socket, 0)) != 0) {
        UNLLog(LLERROR,"failed to accept a new client (%i).\n", rc);
      } else {
        UNLLog(LLINFO,"New telnet client is accepted\n");
      }
    }

    // Check for output from all telnet clients
    if (ts_receive(&client_input, &read_fd_set, &active_fd_set, tsclients_socket) == 0) {
      //printf("got %i\n",client_input);
      if (client_input == 'p') {  // 'p' stands for "ping"
        UNLLog(LLVERBOSE,"Got ping request, replying that we're still alive\n");
        ts_broadcast_string("alive\n", &active_fd_set, tsclients_socket);
      } else if (client_input == 's') { // 's' stands for "stat"
        char statInfo[256];
        snprintf(statInfo, sizeof(statInfo),"Frames: %i Bytes: %i\n",frames_processed,bytes_processed);
        UNLLog(LLVERBOSE,"Got stat request, reporting brief statistics: %s",statInfo);
        ts_broadcast_string(statInfo, &active_fd_set, tsclients_socket);
      }

    }

    if (FD_ISSET(tapHandles[source_tap],&read_fd_set)) {
      int lenght = read(tapHandles[source_tap],xchangeBuffer,sizeof(xchangeBuffer));
      if (lenght > 0) {
        frames_processed++;
        bytes_processed  += lenght;
        for (int i = 1; i < taps_number; i++) {
          if ((i != source_tap) && (tapHandles[i] != 0)) {
            if (write(tapHandles[i],xchangeBuffer,lenght) != lenght) {
              UNLLog(LLERROR,"Failed to write data to TAP n %i\n",i);
            }
          }
        }
      }
    }

  }

  return 0;
}


text:
const _ = require('lodash');
const CryptoJS = require('crypto-js');
const md5 = require('md5');
const url = require('url');

const headersDefaults = {
    scheme: 'x-apikey-scheme',
    credentials: 'x-apikey-credentials',
    nonce: 'x-apikey-nonce',
    timestamp: 'x-apikey-timestamp',
    signature: 'x-apikey-signature',
};

const ONE_HOUR = 60 * 60 * 1000;

/**
 * We don't check nonce if no outer callback is used at this point
 * @param nonce
 */
const checkNonceStub = (nonce) => true;

const APIKey = {
    settings: null,

    init(settings, callback) {
        const mySettings = _.defaults(settings || {}, {
            enabled: true,
            checkNonce: checkNonceStub,
            keys: {},
            headers: {},
        });

        const { keys, checkNonce } = mySettings;

        if (keys && !_.isEmpty(keys)) {
            this.keys = keys;
            this.headers = _.defaults(mySettings.headers, headersDefaults);
        } else {
            console.log('Warning: no API key pairs defined. Disabling API key check');
            mySettings.enabled = false;
        }
        this.checkNonce = checkNonce;
        this.settings = mySettings;

        // In case we need async init in the future
        if (_.isFunction(callback)) {
            callback();
        }
    },

    initAsync(settings) {
        const self = this;
        return new Promise((resolve, reject) => {
            self.init(settings, (err) => {
                if (err) {
                    console.error(err);
                    return reject(err);
                }
                return resolve();
            });
        });
    },

    validate(requestMethod, requestHeaders, requestUrl, requestBody, callback) {
        const { settings, headers, keys } = this;
        if (!settings.enabled) {
            return callback();
        }
        if (!headers || _.isEmpty(headers)) {
            return callback(new Error('Headers cannot be empty! Verify that the module was initialised'));
        }

        if (!(requestHeaders[headers.scheme]
                && requestHeaders[headers.nonce]
                && requestHeaders[headers.timestamp]
                && requestHeaders[headers.credentials]
                && requestHeaders[headers.signature])) {
            return callback(new Error('API key headers are missing'));
        }

        const nonceOK = this.checkNonce(requestHeaders[headers.nonce]);
        if (!nonceOK) {
            return callback(new Error('nonce is not ok'));
        }

        if (!requestMethod || !_.isString(requestMethod)) {
            return callback(new Error('request method is not ok'));
        }

        const timeDiff = Math.abs((new Date()) - requestHeaders[headers.timestamp]);
        if (timeDiff > ONE_HOUR || timeDiff < 0) {
            return callback(new Error('Your client has failed to follow Shadow Proclamation Temporal Regulations'));
        }
        const ln = '|'; // Line feed code
        const urlParts = _.isString(requestUrl) ? url.parse(requestUrl, true) : requestUrl;
        const queryString = [];

        const urlPartsKeys = (Object.keys(urlParts.query)).sort();
        _.each(urlPartsKeys, (key) => {
            const value = urlParts.query[key];
            if (_.isString(value) || _.isNumber(value) || _.isBoolean(value)) {
                const strValue = `${value}`;
                queryString.push(`${encodeURIComponent(key)}=${md5(strValue)}`);
            }
        });

        if (requestBody) {
            const bodyPartsKeys = (Object.keys(requestBody)).sort();
            _.each(bodyPartsKeys, (key) => {
                const value = requestBody[key];
                if (_.isString(value) || _.isNumber(value) || _.isBoolean(value)) {
                    const strValue = `${value}`;
                    queryString.push(`${encodeURIComponent(key)}=${md5(strValue)}`);
                }
            });
        }

        const canonicalQuery = queryString.join('&');

        const authenticationScheme =
            requestHeaders[headers.scheme] + ln +
            requestHeaders[headers.nonce] + ln +
            requestHeaders[headers.timestamp] + ln +
            requestMethod.toLowerCase() + ln +
            urlParts.pathname + ln +
            canonicalQuery + ln;

        let signature;
        const keyName = requestHeaders[headers.credentials];
        const keyValue = keys[keyName];
        if (keyName && keyValue) {
            signature = CryptoJS.HmacSHA256(authenticationScheme, keyValue).toString();
        } else {
            return callback(new Error('Credentials not found'));
        }

        if (!signature || requestHeaders[headers.signature] !== signature) {
            return callback(new Error('Incorrect request signature'));
        }

        // all good
        return callback(null, {
            valid: true,
            signature,
        });
    },

    async validateAsync(requestMethod, requestHeaders, requestUrl, requestBody) {
        const self = this;
        return new Promise((resolve, reject) => {
            self.validate(requestMethod, requestHeaders, requestUrl, requestBody, (err, res) => {
                if (err) {
                    console.error(err);
                    return reject(err);
                }
                return resolve(res);
            });
        });
    },

};

module.exports = APIKey;