diff --git a/LFHeatMap.podspec b/LFHeatMap.podspec deleted file mode 100644 index a9222ad..0000000 --- a/LFHeatMap.podspec +++ /dev/null @@ -1,18 +0,0 @@ -Pod::Spec.new do |s| - - s.name = "LFHeatMap" - s.version = "1.0.2" - s.summary = "Extremely fast heat maps for iOS" - s.homepage = "https://github.com/gpolak/LFHeatMap" - s.license = { :type => "MIT", :file => "LICENSE" } - - s.author = { "George Polak" => "george.polak@gmail.com" } - - s.platform = :ios, "5.0" - - s.source = { :git => "https://github.com/gpolak/LFHeatMap.git", :tag => "1.0.2" } - - s.source_files = 'LFHeatMap' - s.requires_arc = true - -end diff --git a/LFHeatMap/LFHeatMap.h b/LFHeatMap/LFHeatMap.h index 60a6c3f..3ab0169 100644 --- a/LFHeatMap/LFHeatMap.h +++ b/LFHeatMap/LFHeatMap.h @@ -6,75 +6,46 @@ */ #import -#import +#import + +extern inline CGRect CGRectContainingPoints(NSArray *points); +extern inline CGPoint CGPointOffset(CGPoint point, CGFloat xOffset, CGFloat yOffset); + +@interface RMHeatmapAnnotation : RMAnnotation + +@property (nonatomic, strong) UIImage *heatmapImage; + +@end + +@interface RMHeatmapMarker : RMMarker + +- (instancetype)initWithHeatmapAnnotation:(RMHeatmapAnnotation *)heatmapAnnotation; + +@end @interface LFHeatMap : NSObject -{ +{ } /** - Generates a heat map image for the specified map view. - - There should be a one-to-one correspondence between the location and weight elements. - A nil weight parameter implies an even weight distribution. - - @params - mapView: Map view representing the heat map area. - boost: heat boost value - locations: array of CLLocation objects representing the data points - weights: array of NSNumber integer objects representing the weight of each point - - @returns - UIImage object representing the heatmap for the map region. - */ -+ (UIImage *)heatMapForMapView:(MKMapView *)mapView - boost:(float)boost - locations:(NSArray *)locations - weights:(NSArray *)weights; - -/** - Generates a heat map image for the specified rectangle. + Generates a heat map annotation for the specified map view. There should be a one-to-one correspondence between the location and weight elements. A nil weight parameter implies an even weight distribution. - @params - @rect: region frame - boost: heat boost value - points: array of NSValue CGPoint objects representing the data points - weights: array of NSNumber integer objects representing the weight of each point - - @returns - UIImage object representing the heatmap for the specified region. - */ -+ (UIImage *)heatMapWithRect:(CGRect)rect - boost:(float)boost - points:(NSArray *)points - weights:(NSArray *)weights; - -/** - Generates a heat map image for the specified rectangle. - - There should be a one-to-one correspondence between the location and weight elements. - A nil weight parameter implies an even weight distribution. + @param mapView Map view representing the heat map area. + @param boost heat boost value + @param locations array of CLLocation objects representing the data points + @param weights array of NSNumber integer objects representing the weight of each point - @params - @rect: region frame - boost: heat boost value - points: array of NSValue CGPoint objects representing the data points - weights: array of NSNumber integer objects representing the weight of each point - weightsAdjustmentEnabled: set YES for weight balancing and normalization - groupingEnabled: set YES for tighter visual grouping of dense areas + @warning If the heatmap image generated is too big, this method will return nil - @returns - UIImage object representing the heatmap for the specified region. + @return RMHeatmapAnnotation object representing the heatmap ready to be added to the map */ -+ (UIImage *)heatMapWithRect:(CGRect)rect - boost:(float)boost - points:(NSArray *)points - weights:(NSArray *)weights - weightsAdjustmentEnabled:(BOOL)weightsAdjustmentEnabled - groupingEnabled:(BOOL)groupingEnabled; ++ (RMHeatmapAnnotation *)heatMapAnnotationForMapView:(RMMapView *)mapView + boost:(float)boost + locations:(NSArray *)locations + weights:(NSArray *)weights; @end diff --git a/LFHeatMap/LFHeatMap.m b/LFHeatMap/LFHeatMap.m index 81d1d14..71dcfaf 100644 --- a/LFHeatMap/LFHeatMap.m +++ b/LFHeatMap/LFHeatMap.m @@ -6,7 +6,90 @@ */ #import "LFHeatMap.h" +@import CoreLocation.CLLocation; +/** + * Calculates the smallest CGRect containing the provided points + * @param points An Array of NSValue containing CGPoint structs + * @discussion If no points are provided, this method return CGRectNull + */ +inline CGRect CGRectContainingPoints(NSArray *points) { + + if (points.count == 0) return CGRectNull; + + CGPoint (^pointAtIndex)(NSUInteger index) = ^CGPoint(NSUInteger index) { + + NSValue *value = points[index]; + + return [value CGPointValue]; + }; + + CGFloat greatestXValue = pointAtIndex(0).x; + CGFloat greatestYValue = pointAtIndex(0).y; + CGFloat smallestXValue = pointAtIndex(0).x; + CGFloat smallestYValue = pointAtIndex(0).y; + + for(int i = 1; i < points.count; i++) + { + CGPoint point = pointAtIndex(i); + greatestXValue = MAX(greatestXValue, point.x); + greatestYValue = MAX(greatestYValue, point.y); + smallestXValue = MIN(smallestXValue, point.x); + smallestYValue = MIN(smallestYValue, point.y); + } + + CGRect rect; + rect.origin = CGPointMake(smallestXValue, smallestYValue); + rect.size.width = greatestXValue - smallestXValue; + rect.size.height = greatestYValue - smallestYValue; + + return rect; +} + +inline CGPoint CGPointOffset(CGPoint point, CGFloat xOffset, CGFloat yOffset) { + + return CGPointMake(point.x + xOffset, point.y + yOffset); + +} + +@implementation RMHeatmapAnnotation + +- (instancetype)initWithMapView:(RMMapView *)aMapView + coordinate:(CLLocationCoordinate2D)aCoordinate + title:(NSString *)aTitle + heatmapImage:(UIImage *)heatmapImage +{ + NSParameterAssert(heatmapImage); + + self = [super initWithMapView:aMapView coordinate:aCoordinate andTitle:aTitle]; + + if (!self) return nil; + + self.heatmapImage = heatmapImage; + + return self; +} + +- (instancetype)initWithMapView:(RMMapView *)aMapView coordinate:(CLLocationCoordinate2D)aCoordinate andTitle:(NSString *)aTitle +{ + @throw [NSException exceptionWithName:@"Invalid initializer" reason:@"Called invalid initializer on class RMHeatmapAnnotation" userInfo:nil]; +} + +@end + +@implementation RMHeatmapMarker + +- (instancetype)initWithHeatmapAnnotation:(RMHeatmapAnnotation *)heatmapAnnotation +{ + NSParameterAssert(heatmapAnnotation); + self = [super initWithUIImage:heatmapAnnotation.heatmapImage]; + + if (!self) return nil; + + return self; +} + +@end @implementation LFHeatMap @@ -141,10 +224,10 @@ inline static int isqrt(int x) } } -+ (UIImage *)heatMapForMapView:(MKMapView *)mapView - boost:(float)boost - locations:(NSArray *)locations - weights:(NSArray *)weights ++ (RMHeatmapAnnotation *)heatMapAnnotationForMapView:(RMMapView *)mapView + boost:(float)boost + locations:(NSArray *)locations + weights:(NSArray *)weights { if (!mapView || !locations) return nil; @@ -153,11 +236,43 @@ + (UIImage *)heatMapForMapView:(MKMapView *)mapView for (NSInteger i = 0; i < [locations count]; i++) { CLLocation *location = [locations objectAtIndex:i]; - CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:mapView]; + CGPoint point = [mapView coordinateToPixel:location.coordinate]; [points addObject:[NSValue valueWithCGPoint:point]]; } - return [LFHeatMap heatMapWithRect:mapView.frame boost:boost points:points weights:weights]; + CGRect containerRect = CGRectContainingPoints(points); + CGPoint centerPoint = CGPointMake(CGRectGetMidX(containerRect), CGRectGetMidY(containerRect)); + CLLocationCoordinate2D heatmapCenterLocation = [mapView pixelToCoordinate:centerPoint]; + + CGFloat xOffset = -containerRect.origin.x; + CGFloat yOffset = -containerRect.origin.y; + + NSMutableArray *translatedPoints = [[NSMutableArray alloc] initWithCapacity:points.count]; + CGRect translatedContainerRect = CGRectOffset(containerRect, xOffset, yOffset); + + CGFloat imagePadding = 40.0f; + + CGRect translatedContainerRectWithPadding = CGRectInset(translatedContainerRect, -imagePadding, -imagePadding); + + for (NSValue *value in points) + { + CGPoint translatedPoint = CGPointOffset([value CGPointValue], xOffset, yOffset); + [translatedPoints addObject:[NSValue valueWithCGPoint:translatedPoint]]; + } + + if (translatedContainerRectWithPadding.size.width > 2048 || translatedContainerRectWithPadding.size.height > 2048) + { + NSLog(@"LFHeatMap: resulting heatmap is too big, reduce zoom"); + return nil; + } + + UIImage *image = [LFHeatMap heatMapWithRect:translatedContainerRectWithPadding boost:boost points:translatedPoints weights:weights]; + RMHeatmapAnnotation *heatmapAnnotation = [[RMHeatmapAnnotation alloc] initWithMapView:mapView + coordinate:heatmapCenterLocation + title:@"Heatmap" + heatmapImage:image]; + + return heatmapAnnotation; } + (UIImage *)heatMapWithRect:(CGRect)rect diff --git a/LFHeatMapDemo/LFHeatMapDemo.xcodeproj/project.pbxproj b/LFHeatMapDemo/LFHeatMapDemo.xcodeproj/project.pbxproj index 0011b9b..e445905 100644 --- a/LFHeatMapDemo/LFHeatMapDemo.xcodeproj/project.pbxproj +++ b/LFHeatMapDemo/LFHeatMapDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1C63FAFDFF03073CA803D13F /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D57846224BDD2763E166E40 /* libPods.a */; }; 4EBFBA231979813800EB178F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EBFBA221979813800EB178F /* Foundation.framework */; }; 4EBFBA251979813800EB178F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EBFBA241979813800EB178F /* CoreGraphics.framework */; }; 4EBFBA271979813800EB178F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EBFBA261979813800EB178F /* UIKit.framework */; }; @@ -41,6 +42,9 @@ 4EBFBA5819799DD900EB178F /* LFHeadMapDemoViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LFHeadMapDemoViewController.xib; sourceTree = ""; }; 4EBFBA5D19799E3C00EB178F /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 4EBFBA5F1979A2DC00EB178F /* quake.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = quake.plist; sourceTree = ""; }; + 8D57846224BDD2763E166E40 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + A2DA8FBADFA65A42FC081B0D /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + BEDECF005B9A7F70D61D68BB /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -52,12 +56,22 @@ 4EBFBA251979813800EB178F /* CoreGraphics.framework in Frameworks */, 4EBFBA271979813800EB178F /* UIKit.framework in Frameworks */, 4EBFBA231979813800EB178F /* Foundation.framework in Frameworks */, + 1C63FAFDFF03073CA803D13F /* libPods.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 35BFF08A7E327FF19B84622B /* Pods */ = { + isa = PBXGroup; + children = ( + A2DA8FBADFA65A42FC081B0D /* Pods.debug.xcconfig */, + BEDECF005B9A7F70D61D68BB /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; 4EBFBA161979813800EB178F = { isa = PBXGroup; children = ( @@ -65,6 +79,7 @@ 4EBFBA281979813800EB178F /* LFHeatMapDemo */, 4EBFBA211979813800EB178F /* Frameworks */, 4EBFBA201979813800EB178F /* Products */, + 35BFF08A7E327FF19B84622B /* Pods */, ); sourceTree = ""; }; @@ -84,6 +99,7 @@ 4EBFBA241979813800EB178F /* CoreGraphics.framework */, 4EBFBA261979813800EB178F /* UIKit.framework */, 4EBFBA3B1979813800EB178F /* XCTest.framework */, + 8D57846224BDD2763E166E40 /* libPods.a */, ); name = Frameworks; sourceTree = ""; @@ -95,10 +111,10 @@ 4EBFBA311979813800EB178F /* AppDelegate.h */, 4EBFBA321979813800EB178F /* AppDelegate.m */, 4EBFBA341979813800EB178F /* Images.xcassets */, - 4EBFBA291979813800EB178F /* Supporting Files */, 4EBFBA5619799DD900EB178F /* LFHeadMapDemoViewController.h */, 4EBFBA5719799DD900EB178F /* LFHeadMapDemoViewController.m */, 4EBFBA5819799DD900EB178F /* LFHeadMapDemoViewController.xib */, + 4EBFBA291979813800EB178F /* Supporting Files */, ); path = LFHeatMapDemo; sourceTree = ""; @@ -131,9 +147,11 @@ isa = PBXNativeTarget; buildConfigurationList = 4EBFBA4B1979813800EB178F /* Build configuration list for PBXNativeTarget "LFHeatMapDemo" */; buildPhases = ( + E5312E7ECC8068B3AF5C1490 /* Check Pods Manifest.lock */, 4EBFBA1B1979813800EB178F /* Sources */, 4EBFBA1C1979813800EB178F /* Frameworks */, 4EBFBA1D1979813800EB178F /* Resources */, + 49A68B67C77F159CE6B672CC /* Copy Pods Resources */, ); buildRules = ( ); @@ -184,6 +202,39 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 49A68B67C77F159CE6B672CC /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + E5312E7ECC8068B3AF5C1490 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 4EBFBA1B1979813800EB178F /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -282,26 +333,35 @@ }; 4EBFBA4C1979813800EB178F /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A2DA8FBADFA65A42FC081B0D /* Pods.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "LFHeatMapDemo/LFHeatMapDemo-Prefix.pch"; INFOPLIST_FILE = "LFHeatMapDemo/LFHeatMapDemo-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "312a1c6e-25fb-4d65-8453-543f9d0a3c7b"; + TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Debug; }; 4EBFBA4D1979813800EB178F /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BEDECF005B9A7F70D61D68BB /* Pods.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Nicolas Amarelle (8NRF3XCN63)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "LFHeatMapDemo/LFHeatMapDemo-Prefix.pch"; INFOPLIST_FILE = "LFHeatMapDemo/LFHeatMapDemo-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "312a1c6e-25fb-4d65-8453-543f9d0a3c7b"; + TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/LFHeatMapDemo/LFHeatMapDemo.xcworkspace/contents.xcworkspacedata b/LFHeatMapDemo/LFHeatMapDemo.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5859300 --- /dev/null +++ b/LFHeatMapDemo/LFHeatMapDemo.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.m b/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.m index c8520a7..da07eb5 100644 --- a/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.m +++ b/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.m @@ -7,15 +7,16 @@ // #import "LFHeadMapDemoViewController.h" -#import #import "LFHeatMap.h" -@interface LFHeadMapDemoViewController () +@interface LFHeadMapDemoViewController () -@property (nonatomic, weak) IBOutlet MKMapView *mapView; @property (nonatomic, weak) IBOutlet UISlider *slider; +@property (nonatomic, weak) IBOutlet UILabel *heatmapWarningLabel; + +@property (nonatomic, strong) RMMapView *mapView; +@property (nonatomic, strong) RMAnnotation *heatmapAnnotation; -@property (nonatomic) UIImageView *imageView; @property (nonatomic) NSMutableArray *locations; @property (nonatomic) NSMutableArray *weights; @@ -32,7 +33,36 @@ - (void)viewDidLoad { [super viewDidLoad]; - // get data + [self setupMap]; + [self loadEarthquakeData]; + [self loadHeatmapAnnotation]; + + self.mapView.centerCoordinate = self.heatmapAnnotation.coordinate; +} + +- (void)setupMap +{ + if (self.mapView) return; + + //setup mapbox + NSString *mapId = @"jakunico.mbpa5ak4"; + NSString *accessToken = @"pk.eyJ1IjoiamFrdW5pY28iLCJhIjoiNjAwNDYyYjgxYjk0MTBjNjJiMDI5YmFjMDE2NWIzM2UifQ.KCo52mPGceAjzWvI5ushpQ"; + + NSAssert([mapId length], @"You must set a Mapbox mapId"); + NSAssert([accessToken length], @"You must set an access token"); + + [RMConfiguration sharedInstance].accessToken = accessToken; + RMMapboxSource *source = [[RMMapboxSource alloc] initWithMapID:mapId]; + + self.mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:source]; + self.mapView.zoom = 2; + self.mapView.delegate = self; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view insertSubview:self.mapView belowSubview:self.slider]; +} + +- (void)loadEarthquakeData +{ NSString *dataFile = [[NSBundle mainBundle] pathForResource:@"quake" ofType:@"plist"]; NSArray *quakeData = [[NSArray alloc] initWithContentsOfFile:dataFile]; @@ -49,26 +79,71 @@ - (void)viewDidLoad [self.weights addObject:[NSNumber numberWithInteger:(magnitude * 10)]]; } +} + +- (void)loadHeatmapAnnotation +{ + if (self.heatmapAnnotation) { + [self.mapView removeAnnotation:self.heatmapAnnotation]; + } - // set map region - MKCoordinateSpan span = MKCoordinateSpanMake(10.0, 13.0); - CLLocationCoordinate2D center = CLLocationCoordinate2DMake(39.0, -77.0); - self.mapView.region = MKCoordinateRegionMake(center, span); + self.heatmapAnnotation = [LFHeatMap heatMapAnnotationForMapView:self.mapView + boost:self.slider.value + locations:self.locations + weights:self.weights]; - // create overlay view for the heatmap image - self.imageView = [[UIImageView alloc] initWithFrame:_mapView.frame]; - self.imageView.contentMode = UIViewContentModeCenter; - [self.view addSubview:self.imageView]; + if (self.heatmapAnnotation) { + + [self.mapView addAnnotation:self.heatmapAnnotation]; + self.heatmapWarningLabel.hidden = YES; + + } else { + + self.heatmapWarningLabel.hidden = NO; + + } - // show initial heat map - [self sliderChanged:self.slider]; +} + +- (void)removeHeatmapAnnotation +{ + if (self.heatmapAnnotation) { + [self.mapView removeAnnotation:self.heatmapAnnotation]; + self.heatmapAnnotation = nil; + } } - (IBAction)sliderChanged:(UISlider *)slider { - float boost = slider.value; - UIImage *heatmap = [LFHeatMap heatMapForMapView:self.mapView boost:boost locations:self.locations weights:self.weights]; - self.imageView.image = heatmap; + [self loadHeatmapAnnotation]; +} + +#pragma mark RMMapView Delegate + +- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation +{ + if (annotation.isUserLocationAnnotation) return nil; + + if (annotation.class == [RMHeatmapAnnotation class]) + { + RMHeatmapMarker *heatmapMarker = [[RMHeatmapMarker alloc] initWithHeatmapAnnotation:(RMHeatmapAnnotation*)annotation]; + + return heatmapMarker; + } + + NSAssert(NO, @"Could not provide layer for annotation: %@", annotation); + + return nil; +} + +- (void)beforeMapZoom:(RMMapView *)map byUser:(BOOL)wasUserAction +{ + [self removeHeatmapAnnotation]; +} + +- (void)afterMapZoom:(RMMapView *)map byUser:(BOOL)wasUserAction +{ + [self sliderChanged:self.slider]; } @end diff --git a/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.xib b/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.xib index 49d5d7d..82fe647 100644 --- a/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.xib +++ b/LFHeatMapDemo/LFHeatMapDemo/LFHeadMapDemoViewController.xib @@ -1,13 +1,13 @@ - + - - + + - + @@ -17,21 +17,28 @@ - - - - - + + - - + + + + + diff --git a/LFHeatMapDemo/LFHeatMapDemo/LFHeatMapDemo-Info.plist b/LFHeatMapDemo/LFHeatMapDemo/LFHeatMapDemo-Info.plist index c6c60ef..f619b07 100644 --- a/LFHeatMapDemo/LFHeatMapDemo/LFHeatMapDemo-Info.plist +++ b/LFHeatMapDemo/LFHeatMapDemo/LFHeatMapDemo-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.georgepolak.${PRODUCT_NAME:rfc1034identifier} + com.codigodelsur.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/LFHeatMapDemo/Podfile b/LFHeatMapDemo/Podfile new file mode 100644 index 0000000..0743ef0 --- /dev/null +++ b/LFHeatMapDemo/Podfile @@ -0,0 +1,3 @@ +platform :ios, '8.0' + +pod 'Mapbox-iOS-SDK', '1.6.0' diff --git a/LFHeatMapDemo/Podfile.lock b/LFHeatMapDemo/Podfile.lock new file mode 100644 index 0000000..c5eb3eb --- /dev/null +++ b/LFHeatMapDemo/Podfile.lock @@ -0,0 +1,26 @@ +PODS: + - FMDB (2.3): + - FMDB/standard (= 2.3) + - FMDB/common (2.3) + - FMDB/standard (2.3): + - FMDB/common + - GRMustache (7.3.0): + - JRSwizzle (~> 1.0) + - JRSwizzle (1.0) + - Mapbox-iOS-SDK (1.6.0): + - FMDB (= 2.3) + - GRMustache (= 7.3.0) + - SMCalloutView (= 2.0) + - SMCalloutView (2.0) + +DEPENDENCIES: + - Mapbox-iOS-SDK (= 1.6.0) + +SPEC CHECKSUMS: + FMDB: 773d79bb74226959b7e2286b1d6e0bd857c88915 + GRMustache: 6baee020c5644416c034f5afb1607f6219e7f753 + JRSwizzle: dd5ead5d913a0f29e7f558200165849f006bb1e3 + Mapbox-iOS-SDK: ee136ca5b7f853456b50dfd7a7f0e243288cf86f + SMCalloutView: f758edd824b18bf4f42de00df1e299861a2d1950 + +COCOAPODS: 0.36.3 diff --git a/LFHeatMapDemo/Pods/FMDB/LICENSE.txt b/LFHeatMapDemo/Pods/FMDB/LICENSE.txt new file mode 100644 index 0000000..1cf79ee --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/LICENSE.txt @@ -0,0 +1,24 @@ +If you are using fmdb in your project, I'd love to hear about it. Let me +know at gus@flyingmeat.com. + +In short, this is the MIT License. + +Copyright (c) 2008 Flying Meat Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/LFHeatMapDemo/Pods/FMDB/README.markdown b/LFHeatMapDemo/Pods/FMDB/README.markdown new file mode 100644 index 0000000..927bb72 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/README.markdown @@ -0,0 +1,253 @@ +# FMDB v2.3 +This is an Objective-C wrapper around SQLite: http://sqlite.org/ + +## The FMDB Mailing List: +http://groups.google.com/group/fmdb + +## Read the SQLite FAQ: +http://www.sqlite.org/faq.html + +Since FMDB is built on top of SQLite, you're going to want to read this page top to bottom at least once. And while you're there, make sure to bookmark the SQLite Documentation page: http://www.sqlite.org/docs.html + +## CocoaPods + +FMDB can be installed using [CocoaPods](http://cocoapods.org/). + +``` +pod 'FMDB' +# pod 'FMDB/SQLCipher' # If using FMDB with SQLCipher +``` + +**If using FMDB with [SQLCipher](http://sqlcipher.net/) you must use the FMDB/SQLCipher subspec. The FMDB/SQLCipher subspec declares SQLCipher as a dependency, allowing FMDB to be compiled with the `-DSQLITE_HAS_CODEC` flag.** + +## FMDB Class Reference: +http://ccgus.github.io/fmdb/html/index.html + +## Automatic Reference Counting (ARC) or Manual Memory Management? +You can use either style in your Cocoa project. FMDB Will figure out which you are using at compile time and do the right thing. + +## Usage +There are three main classes in FMDB: + +1. `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. +2. `FMResultSet` - Represents the results of executing a query on an `FMDatabase`. +3. `FMDatabaseQueue` - If you're wanting to perform queries and updates on multiple threads, you'll want to use this class. It's described in the "Thread Safety" section below. + +### Database Creation +An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + +1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. +2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. +3. `NULL`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + +(For more information on temporary and in-memory databases, read the sqlite documentation on the subject: http://www.sqlite.org/inmemorydb.html) + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + +### Opening + +Before you can interact with the database, it must be opened. Opening fails if there are insufficient resources or permissions to open and/or create the database. + + if (![db open]) { + [db release]; + return; + } + +### Executing Updates + +Any sort of SQL statement which is not a `SELECT` statement qualifies as an update. This includes `CREATE`, `UPDATE`, `INSERT`, `ALTER`, `COMMIT`, `BEGIN`, `DETACH`, `DELETE`, `DROP`, `END`, `EXPLAIN`, `VACUUM`, and `REPLACE` statements (plus many more). Basically, if your SQL statement does not begin with `SELECT`, it is an update statement. + +Executing updates returns a single value, a `BOOL`. A return value of `YES` means the update was successfully executed, and a return value of `NO` means that some error was encountered. You may invoke the `-lastErrorMessage` and `-lastErrorCode` methods to retrieve more information. + +### Executing Queries + +A `SELECT` statement is a query and is executed via one of the `-executeQuery...` methods. + +Executing queries returns an `FMResultSet` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `-lastErrorMessage` and `-lastErrorCode` methods to determine why a query failed. + +In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" from one record to the other. With FMDB, the easiest way to do that is like this: + + FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"]; + while ([s next]) { + //retrieve values for each record + } + +You must always invoke `-[FMResultSet next]` before attempting to access the values returned in a query, even if you're only expecting one: + + FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"]; + if ([s next]) { + int totalCount = [s intForColumnIndex:0]; + } + +`FMResultSet` has many methods to retrieve data in an appropriate format: + +- `intForColumn:` +- `longForColumn:` +- `longLongIntForColumn:` +- `boolForColumn:` +- `doubleForColumn:` +- `stringForColumn:` +- `dateForColumn:` +- `dataForColumn:` +- `dataNoCopyForColumn:` +- `UTF8StringForColumnName:` +- `objectForColumnName:` + +Each of these methods also has a `{type}ForColumnIndex:` variant that is used to retrieve the data based on the position of the column in the results, as opposed to the column's name. + +Typically, there's no need to `-close` an `FMResultSet` yourself, since that happens when either the result set is deallocated, or the parent database is closed. + +### Closing + +When you have finished executing queries and updates on the database, you should `-close` the `FMDatabase` connection so that SQLite will relinquish any resources it has acquired during the course of its operation. + + [db close]; + +### Transactions + +`FMDatabase` can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement. + +### Multiple Statements and Batch Stuff + +You can use `FMDatabase`'s executeStatements:withResultBlock: to do multiple statements in a string: + +``` +NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);" + "create table bulktest2 (id integer primary key autoincrement, y text);" + "create table bulktest3 (id integer primary key autoincrement, z text);" + "insert into bulktest1 (x) values ('XXX');" + "insert into bulktest2 (y) values ('YYY');" + "insert into bulktest3 (z) values ('ZZZ');"; + +success = [db executeStatements:sql]; + +sql = @"select count(*) as count from bulktest1;" + "select count(*) as count from bulktest2;" + "select count(*) as count from bulktest3;"; + +success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) { + NSInteger count = [dictionary[@"count"] integerValue]; + XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary); + return 0; +}]; + +``` + +### Data Sanitization + +When providing a SQL statement to FMDB, you should not attempt to "sanitize" any values before insertion. Instead, you should use the standard SQLite binding syntax: + + INSERT INTO myTable VALUES (?, ?, ?) + +The `?` character is recognized by SQLite as a placeholder for a value to be inserted. The execution methods all accept a variable number of arguments (or a representation of those arguments, such as an `NSArray`, `NSDictionary`, or a `va_list`), which are properly escaped for you. + +Alternatively, you may use named parameters syntax: + + INSERT INTO myTable VALUES (:id, :name, :value) + +The parameters *must* start with a colon. SQLite itself supports other characters, but internally the Dictionary keys are prefixed with a colon, do **not** include the colon in your dictionary keys. + + NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name", @"name", nil]; + [db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict]; + +Thus, you SHOULD NOT do this (or anything like this): + + [db executeUpdate:[NSString stringWithFormat:@"INSERT INTO myTable VALUES (%@)", @"this has \" lots of ' bizarre \" quotes '"]]; + +Instead, you SHOULD do: + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has \" lots of ' bizarre \" quotes '"]; + +All arguments provided to the `-executeUpdate:` method (or any of the variants that accept a `va_list` as a parameter) must be objects. The following will not work (and will result in a crash): + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42]; + +The proper way to insert a number is to box it in an `NSNumber` object: + + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]]; + +Alternatively, you can use the `-execute*WithFormat:` variant to use `NSString`-style substitution: + + [db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)", 42]; + +Internally, the `-execute*WithFormat:` methods are properly boxing things for you. The following percent modifiers are recognized: `%@`, `%c`, `%s`, `%d`, `%D`, `%i`, `%u`, `%U`, `%hi`, `%hu`, `%qi`, `%qu`, `%f`, `%g`, `%ld`, `%lu`, `%lld`, and `%llu`. Using a modifier other than those will have unpredictable results. If, for some reason, you need the `%` character to appear in your SQL statement, you should use `%%`. + + +

Using FMDatabaseQueue and Thread Safety.

+ +Using a single instance of FMDatabase from multiple threads at once is a bad idea. It has always been OK to make a FMDatabase object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro. *This would suck*. + +**So don't instantiate a single FMDatabase object and use it across multiple threads.** + +Instead, use FMDatabaseQueue. It's your friend and it's here to help. Here's how to use it: + +First, make your queue. + + FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; + +Then use it like so: + + [queue inDatabase:^(FMDatabase *db) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + FMResultSet *rs = [db executeQuery:@"select * from foo"]; + while ([rs next]) { + … + } + }]; + +An easy way to wrap things up in a transaction can be done like this: + + [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + if (whoopsSomethingWrongHappened) { + *rollback = YES; + return; + } + // etc… + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; + }]; + + +FMDatabaseQueue will run the blocks on a serialized queue (hence the name of the class). So if you call FMDatabaseQueue's methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. + +**Note:** The calls to FMDatabaseQueue's methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. + +## Making custom sqlite functions, based on blocks. + +You can do this! For an example, look for "makeFunctionNamed:" in main.m + +## History + +The history and changes are availbe on its [GitHub page](https://github.com/ccgus/fmdb) and are summarized in the "CHANGES_AND_TODO_LIST.txt" file. + +## Contributors + +The contributors to FMDB are contained in the "Contributors.txt" file. + +## Reporting bugs + +Reduce your bug down to the smallest amount of code possible. You want to make it super easy for the developers to see and reproduce your bug. If it helps, pretend that the person who can fix your bug is active on shipping 3 major products, works on a handful of open source projects, has a newborn baby, and is generally very very busy. + +And we've even added a template function to main.m (FMDBReportABugFunction) in the FMDB distribution to help you out: + +* Open up fmdb project in Xcode. +* Open up main.m and modify the FMDBReportABugFunction to reproduce your bug. + * Setup your table(s) in the code. + * Make your query or update(s). + * Add some assertions which demonstrate the bug. + +Then you can bring it up on the FMDB mailing list by showing your nice and compact FMDBReportABugFunction, or you can report the bug via the github FMDB bug reporter. + +**Optional:** + +Figure out where the bug is, fix it, and send a patch in or bring that up on the mailing list. Make sure all the other tests run after your modifications. + +## License + +The license for FMDB is contained in the "License.txt" file. diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDB.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDB.h new file mode 100644 index 0000000..39e2f43 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDB.h @@ -0,0 +1,5 @@ +#import "FMDatabase.h" +#import "FMResultSet.h" +#import "FMDatabaseAdditions.h" +#import "FMDatabaseQueue.h" +#import "FMDatabasePool.h" diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.h new file mode 100644 index 0000000..96be64a --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.h @@ -0,0 +1,1057 @@ +#import +#import "sqlite3.h" +#import "FMResultSet.h" +#import "FMDatabasePool.h" + + +#if ! __has_feature(objc_arc) + #define FMDBAutorelease(__v) ([__v autorelease]); + #define FMDBReturnAutoreleased FMDBAutorelease + + #define FMDBRetain(__v) ([__v retain]); + #define FMDBReturnRetained FMDBRetain + + #define FMDBRelease(__v) ([__v release]); + + #define FMDBDispatchQueueRelease(__v) (dispatch_release(__v)); +#else + // -fobjc-arc + #define FMDBAutorelease(__v) + #define FMDBReturnAutoreleased(__v) (__v) + + #define FMDBRetain(__v) + #define FMDBReturnRetained(__v) (__v) + + #define FMDBRelease(__v) + +// If OS_OBJECT_USE_OBJC=1, then the dispatch objects will be treated like ObjC objects +// and will participate in ARC. +// See the section on "Dispatch Queues and Automatic Reference Counting" in "Grand Central Dispatch (GCD) Reference" for details. + #if OS_OBJECT_USE_OBJC + #define FMDBDispatchQueueRelease(__v) + #else + #define FMDBDispatchQueueRelease(__v) (dispatch_release(__v)); + #endif +#endif + +#if !__has_feature(objc_instancetype) + #define instancetype id +#endif + + +typedef int(^FMDBExecuteStatementsCallbackBlock)(NSDictionary *resultsDictionary); + + +/** A SQLite ([http://sqlite.org/](http://sqlite.org/)) Objective-C wrapper. + + ### Usage + The three main classes in FMDB are: + + - `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. + - `` - Represents the results of executing a query on an `FMDatabase`. + - `` - If you want to perform queries and updates on multiple threads, you'll want to use this class. + + ### See also + + - `` - A pool of `FMDatabase` objects. + - `` - A wrapper for `sqlite_stmt`. + + ### External links + + - [FMDB on GitHub](https://github.com/ccgus/fmdb) including introductory documentation + - [SQLite web site](http://sqlite.org/) + - [FMDB mailing list](http://groups.google.com/group/fmdb) + - [SQLite FAQ](http://www.sqlite.org/faq.html) + + @warning Do not instantiate a single `FMDatabase` object and use it across multiple threads. Instead, use ``. + + */ + +@interface FMDatabase : NSObject { + + sqlite3* _db; + NSString* _databasePath; + BOOL _logsErrors; + BOOL _crashOnErrors; + BOOL _traceExecution; + BOOL _checkedOut; + BOOL _shouldCacheStatements; + BOOL _isExecutingStatement; + BOOL _inTransaction; + NSTimeInterval _maxBusyRetryTimeInterval; + NSTimeInterval _startBusyRetryTime; + + NSMutableDictionary *_cachedStatements; + NSMutableSet *_openResultSets; + NSMutableSet *_openFunctions; + + NSDateFormatter *_dateFormat; +} + +///----------------- +/// @name Properties +///----------------- + +/** Whether should trace execution */ + +@property (atomic, assign) BOOL traceExecution; + +/** Whether checked out or not */ + +@property (atomic, assign) BOOL checkedOut; + +/** Crash on errors */ + +@property (atomic, assign) BOOL crashOnErrors; + +/** Logs errors */ + +@property (atomic, assign) BOOL logsErrors; + +/** Dictionary of cached statements */ + +@property (atomic, retain) NSMutableDictionary *cachedStatements; + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + ++ (instancetype)databaseWithPath:(NSString*)inPath; + +/** Initialize a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + +- (instancetype)initWithPath:(NSString*)inPath; + + +///----------------------------------- +/// @name Opening and closing database +///----------------------------------- + +/** Opening a new database connection + + The database is opened for reading and writing, and is created if it does not already exist. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open()](http://sqlite.org/c3ref/open.html) + @see openWithFlags: + @see close + */ + +- (BOOL)open; + +/** Opening a new database connection with flags + + @param flags one of the following three values, optionally combined with the `SQLITE_OPEN_NOMUTEX`, `SQLITE_OPEN_FULLMUTEX`, `SQLITE_OPEN_SHAREDCACHE`, `SQLITE_OPEN_PRIVATECACHE`, and/or `SQLITE_OPEN_URI` flags: + + `SQLITE_OPEN_READONLY` + + The database is opened in read-only mode. If the database does not already exist, an error is returned. + + `SQLITE_OPEN_READWRITE` + + The database is opened for reading and writing if possible, or reading only if the file is write protected by the operating system. In either case the database must already exist, otherwise an error is returned. + + `SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE` + + The database is opened for reading and writing, and is created if it does not already exist. This is the behavior that is always used for `open` method. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open_v2()](http://sqlite.org/c3ref/open.html) + @see open + @see close + */ + +#if SQLITE_VERSION_NUMBER >= 3005000 +- (BOOL)openWithFlags:(int)flags; +#endif + +/** Closing a database connection + + @return `YES` if success, `NO` on error. + + @see [sqlite3_close()](http://sqlite.org/c3ref/close.html) + @see open + @see openWithFlags: + */ + +- (BOOL)close; + +/** Test to see if we have a good connection to the database. + + This will confirm whether: + + - is database open + - if open, it will try a simple SELECT statement and confirm that it succeeds. + + @return `YES` if everything succeeds, `NO` on failure. + */ + +- (BOOL)goodConnection; + + +///---------------------- +/// @name Perform updates +///---------------------- + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param outErr A reference to the `NSError` pointer to be updated with an auto released `NSError` object if an error if an error occurs. If `nil`, no `NSError` object will be returned. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + */ + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ...; + +/** Execute single update statement + + @see executeUpdate:withErrorAndBindings: + + @warning **Deprecated**: Please use `` instead. + */ + +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... __attribute__ ((deprecated)); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + + @note This technique supports the use of `?` placeholders in the SQL, automatically binding any supplied value parameters to those placeholders. This approach is more robust than techniques that entail using `stringWithFormat` to manually build SQL statements, which can be problematic if the values happened to include any characters that needed to be quoted. + */ + +- (BOOL)executeUpdate:(NSString*)sql, ...; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. Do not use `?` placeholders in the SQL if you use this method. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeUpdate: + @see lastError + @see lastErrorCode + @see lastErrorMessage + + @warning This should be used with great care. Generally, instead of this method, you should use `` (with `?` placeholders in the SQL), which properly escapes quotation marks encountered inside the values (minimizing errors and protecting against SQL injection attack) and handles a wider variety of data types. See `` for more information. + */ + +- (BOOL)executeUpdateWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) binding any `?` placeholders in the SQL with the optional list of parameters. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage +*/ + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments; + + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param args A `va_list` of arguments. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withVAList: (va_list)args; + +/** Execute multiple SQL statements + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeStatements:withResultBlock: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql; + +/** Execute multiple SQL statements with callback handler + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed. + @param block A block that will be called for any result sets returned by any SQL statements. + Note, if you supply this block, it must return integer value, zero upon success (this would be a good opportunity to use SQLITE_OK), + non-zero value upon failure (which will stop the bulk execution of the SQL). If a statement returns values, the block will be called with the results from the query in NSDictionary *resultsDictionary. + This may be `nil` if you don't care to receive any results. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, + ``, or `` for diagnostic information regarding the failure. + + @see executeStatements: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block; + +/** Last insert rowid + + Each entry in an SQLite table has a unique 64-bit signed integer key called the "rowid". The rowid is always available as an undeclared column named `ROWID`, `OID`, or `_ROWID_` as long as those names are not also used by explicitly declared columns. If the table has a column of type `INTEGER PRIMARY KEY` then that column is another alias for the rowid. + + This routine returns the rowid of the most recent successful `INSERT` into the database from the database connection in the first argument. As of SQLite version 3.7.7, this routines records the last insert rowid of both ordinary tables and virtual tables. If no successful `INSERT`s have ever occurred on that database connection, zero is returned. + + @return The rowid of the last inserted row. + + @see [sqlite3_last_insert_rowid()](http://sqlite.org/c3ref/last_insert_rowid.html) + + */ + +- (sqlite_int64)lastInsertRowId; + +/** The number of rows changed by prior SQL statement. + + This function returns the number of database rows that were changed or inserted or deleted by the most recently completed SQL statement on the database connection specified by the first parameter. Only changes that are directly specified by the INSERT, UPDATE, or DELETE statement are counted. + + @return The number of rows changed by prior SQL statement. + + @see [sqlite3_changes()](http://sqlite.org/c3ref/changes.html) + + */ + +- (int)changes; + + +///------------------------- +/// @name Retrieving results +///------------------------- + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + This method employs [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) for any optional value parameters. This properly escapes any characters that need escape sequences (e.g. quotation marks), which eliminates simple SQL errors as well as protects against SQL injection attacks. This method natively handles `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects. All other object types will be interpreted as text values using the object's `description` method. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + */ + +- (FMResultSet *)executeQuery:(NSString*)sql, ...; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeQuery: + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + + @warning This should be used with great care. Generally, instead of this method, you should use `` (with `?` placeholders in the SQL), which properly escapes quotation marks encountered inside the values (minimizing errors and protecting against SQL injection attack) and handles a wider variety of data types. See `` for more information. + + */ + +- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (FMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments; + + +// Documentation forthcoming. +- (FMResultSet *)executeQuery:(NSString*)sql withVAList: (va_list)args; + +///------------------- +/// @name Transactions +///------------------- + +/** Begin a transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginDeferredTransaction + @see inTransaction + */ + +- (BOOL)beginTransaction; + +/** Begin a deferred transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginTransaction + @see inTransaction + */ + +- (BOOL)beginDeferredTransaction; + +/** Commit a transaction + + Commit a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see rollback + @see inTransaction + */ + +- (BOOL)commit; + +/** Rollback a transaction + + Rollback a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see inTransaction + */ + +- (BOOL)rollback; + +/** Identify whether currently in a transaction or not + + @return `YES` if currently within transaction; `NO` if not. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see rollback + */ + +- (BOOL)inTransaction; + + +///---------------------------------------- +/// @name Cached statements and result sets +///---------------------------------------- + +/** Clear cached statements */ + +- (void)clearCachedStatements; + +/** Close all open result sets */ + +- (void)closeOpenResultSets; + +/** Whether database has any open result sets + + @return `YES` if there are open result sets; `NO` if not. + */ + +- (BOOL)hasOpenResultSets; + +/** Return whether should cache statements or not + + @return `YES` if should cache statements; `NO` if not. + */ + +- (BOOL)shouldCacheStatements; + +/** Set whether should cache statements or not + + @param value `YES` if should cache statements; `NO` if not. + */ + +- (void)setShouldCacheStatements:(BOOL)value; + + +///------------------------- +/// @name Encryption methods +///------------------------- + +/** Set encryption key. + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKey:(NSString*)key; + +/** Reset encryption key + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekey:(NSString*)key; + +/** Set encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKeyWithData:(NSData *)keyData; + +/** Reset encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekeyWithData:(NSData *)keyData; + + +///------------------------------ +/// @name General inquiry methods +///------------------------------ + +/** The path of the database file + + @return path of database. + + */ + +- (NSString *)databasePath; + +/** The underlying SQLite handle + + @return The `sqlite3` pointer. + + */ + +- (sqlite3*)sqliteHandle; + + +///----------------------------- +/// @name Retrieving error codes +///----------------------------- + +/** Last error message + + Returns the English-language text that describes the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return `NSString` of the last error message. + + @see [sqlite3_errmsg()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorCode + @see lastError + + */ + +- (NSString*)lastErrorMessage; + +/** Last error code + + Returns the numeric result code or extended result code for the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return Integer value of the last error code. + + @see [sqlite3_errcode()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorMessage + @see lastError + + */ + +- (int)lastErrorCode; + +/** Had error + + @return `YES` if there was an error, `NO` if no error. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + + */ + +- (BOOL)hadError; + +/** Last error + + @return `NSError` representing the last error. + + @see lastErrorCode + @see lastErrorMessage + + */ + +- (NSError*)lastError; + + +// description forthcoming +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeoutInSeconds; +- (NSTimeInterval)maxBusyRetryTimeInterval; + + +#if SQLITE_VERSION_NUMBER >= 3007000 + +///------------------ +/// @name Save points +///------------------ + +/** Start save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + */ + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Release save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Roll back to save point + + @param name Name of save point. + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + + */ + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Start save point + + @param block Block of code to perform from within save point. + + @return The NSError corresponding to the error, if any. If no error, returns `nil`. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block; + +#endif + +///---------------------------- +/// @name SQLite library status +///---------------------------- + +/** Test to see if the library is threadsafe + + @return `NO` if and only if SQLite was compiled with mutexing code omitted due to the SQLITE_THREADSAFE compile-time option being set to 0. + + @see [sqlite3_threadsafe()](http://sqlite.org/c3ref/threadsafe.html) + */ + ++ (BOOL)isSQLiteThreadSafe; + +/** Run-time library version numbers + + @return The sqlite library version string. + + @see [sqlite3_libversion()](http://sqlite.org/c3ref/libversion.html) + */ + ++ (NSString*)sqliteLibVersion; + + ++ (NSString*)FMDBUserVersion; + ++ (SInt32)FMDBVersion; + + +///------------------------ +/// @name Make SQL function +///------------------------ + +/** Adds SQL functions or aggregates or to redefine the behavior of existing SQL functions or aggregates. + + For example: + + [queue inDatabase:^(FMDatabase *adb) { + + [adb executeUpdate:@"create table ftest (foo text)"]; + [adb executeUpdate:@"insert into ftest values ('hello')"]; + [adb executeUpdate:@"insert into ftest values ('hi')"]; + [adb executeUpdate:@"insert into ftest values ('not h!')"]; + [adb executeUpdate:@"insert into ftest values ('definitely not h!')"]; + + [adb makeFunctionNamed:@"StringStartsWithH" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) { + if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) { + @autoreleasepool { + const char *c = (const char *)sqlite3_value_text(aargv[0]); + NSString *s = [NSString stringWithUTF8String:c]; + sqlite3_result_int(context, [s hasPrefix:@"h"]); + } + } + else { + NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__); + sqlite3_result_null(context); + } + }]; + + int rowCount = 0; + FMResultSet *ars = [adb executeQuery:@"select * from ftest where StringStartsWithH(foo)"]; + while ([ars next]) { + rowCount++; + NSLog(@"Does %@ start with 'h'?", [rs stringForColumnIndex:0]); + } + FMDBQuickCheck(rowCount == 2); + }]; + + @param name Name of function + + @param count Maximum number of parameters + + @param block The block of code for the function + + @see [sqlite3_create_function()](http://sqlite.org/c3ref/create_function.html) + */ + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(sqlite3_context *context, int argc, sqlite3_value **argv))block; + + +///--------------------- +/// @name Date formatter +///--------------------- + +/** Generate an `NSDateFormatter` that won't be broken by permutations of timezones or locales. + + Use this method to generate values to set the dateFormat property. + + Example: + + myDB.dateFormat = [FMDatabase storeableDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + + @param format A valid NSDateFormatter format string. + + @return A `NSDateFormatter` that can be used for converting dates to strings and vice versa. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note that `NSDateFormatter` is not thread-safe, so the formatter generated by this method should be assigned to only one FMDB instance and should not be used for other purposes. + + */ + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format; + +/** Test whether the database has a date formatter assigned. + + @return `YES` if there is a date formatter; `NO` if not. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (BOOL)hasDateFormatter; + +/** Set to a date formatter to use string dates with sqlite instead of the default UNIX timestamps. + + @param format Set to nil to use UNIX timestamps. Defaults to nil. Should be set using a formatter generated using FMDatabase::storeableDateFormat. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note there is no direct getter for the `NSDateFormatter`, and you should not use the formatter you pass to FMDB for other purposes, as `NSDateFormatter` is not thread-safe. + */ + +- (void)setDateFormat:(NSDateFormatter *)format; + +/** Convert the supplied NSString to NSDate, using the current database formatter. + + @param s `NSString` to convert to `NSDate`. + + @return The `NSDate` object; or `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSDate *)dateFromString:(NSString *)s; + +/** Convert the supplied NSDate to NSString, using the current database formatter. + + @param date `NSDate` of date to convert to `NSString`. + + @return The `NSString` representation of the date; `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSString *)stringFromDate:(NSDate *)date; + +@end + + +/** Objective-C wrapper for `sqlite3_stmt` + + This is a wrapper for a SQLite `sqlite3_stmt`. Generally when using FMDB you will not need to interact directly with `FMStatement`, but rather with `` and `` only. + + ### See also + + - `` + - `` + - [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@interface FMStatement : NSObject { + sqlite3_stmt *_statement; + NSString *_query; + long _useCount; + BOOL _inUse; +} + +///----------------- +/// @name Properties +///----------------- + +/** Usage count */ + +@property (atomic, assign) long useCount; + +/** SQL statement */ + +@property (atomic, retain) NSString *query; + +/** SQLite sqlite3_stmt + + @see [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@property (atomic, assign) sqlite3_stmt *statement; + +/** Indication of whether the statement is in use */ + +@property (atomic, assign) BOOL inUse; + +///---------------------------- +/// @name Closing and Resetting +///---------------------------- + +/** Close statement */ + +- (void)close; + +/** Reset statement */ + +- (void)reset; + +@end + diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.m b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.m new file mode 100644 index 0000000..f94c86d --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabase.m @@ -0,0 +1,1413 @@ +#import "FMDatabase.h" +#import "unistd.h" +#import + +@interface FMDatabase () + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; + +@end + +@implementation FMDatabase +@synthesize cachedStatements=_cachedStatements; +@synthesize logsErrors=_logsErrors; +@synthesize crashOnErrors=_crashOnErrors; +@synthesize checkedOut=_checkedOut; +@synthesize traceExecution=_traceExecution; + +#pragma mark FMDatabase instantiation and deallocation + ++ (instancetype)databaseWithPath:(NSString*)aPath { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + assert(sqlite3_threadsafe()); // whoa there big boy- gotta make sure sqlite it happy with what we're going to do. + + self = [super init]; + + if (self) { + _databasePath = [aPath copy]; + _openResultSets = [[NSMutableSet alloc] init]; + _db = nil; + _logsErrors = YES; + _crashOnErrors = NO; + _maxBusyRetryTimeInterval = 2; + } + + return self; +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + FMDBRelease(_openResultSets); + FMDBRelease(_cachedStatements); + FMDBRelease(_dateFormat); + FMDBRelease(_databasePath); + FMDBRelease(_openFunctions); + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (NSString *)databasePath { + return _databasePath; +} + ++ (NSString*)FMDBUserVersion { + return @"2.3"; +} + +// returns 0x0230 for version 2.3. This makes it super easy to do things like: +// /* need to make sure to do X with FMDB version 2.3 or later */ +// if ([FMDatabase FMDBVersion] >= 0x0230) { … } + ++ (SInt32)FMDBVersion { + + // we go through these hoops so that we only have to change the version number in a single spot. + static dispatch_once_t once; + static SInt32 FMDBVersionVal = 0; + + dispatch_once(&once, ^{ + NSString *prodVersion = [self FMDBUserVersion]; + + if ([[prodVersion componentsSeparatedByString:@"."] count] < 3) { + prodVersion = [prodVersion stringByAppendingString:@".0"]; + } + + NSString *junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; + + char *e = nil; + FMDBVersionVal = (int) strtoul([junk UTF8String], &e, 16); + + }); + + + return FMDBVersionVal; +} + +#pragma mark SQLite information + ++ (NSString*)sqliteLibVersion { + return [NSString stringWithFormat:@"%s", sqlite3_libversion()]; +} + ++ (BOOL)isSQLiteThreadSafe { + // make sure to read the sqlite headers on this guy! + return sqlite3_threadsafe() != 0; +} + +- (sqlite3*)sqliteHandle { + return _db; +} + +- (const char*)sqlitePath { + + if (!_databasePath) { + return ":memory:"; + } + + if ([_databasePath length] == 0) { + return ""; // this creates a temporary database (it's an sqlite thing). + } + + return [_databasePath fileSystemRepresentation]; + +} + +#pragma mark Open and close database + +- (BOOL)open { + if (_db) { + return YES; + } + + int err = sqlite3_open([self sqlitePath], &_db ); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + + return YES; +} + +#if SQLITE_VERSION_NUMBER >= 3005000 +- (BOOL)openWithFlags:(int)flags { + if (_db) { + return YES; + } + + int err = sqlite3_open_v2([self sqlitePath], &_db, flags, NULL /* Name of VFS module to use */); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + return YES; +} +#endif + + +- (BOOL)close { + + [self clearCachedStatements]; + [self closeOpenResultSets]; + + if (!_db) { + return YES; + } + + int rc; + BOOL retry; + BOOL triedFinalizingOpenStatements = NO; + + do { + retry = NO; + rc = sqlite3_close(_db); + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + if (!triedFinalizingOpenStatements) { + triedFinalizingOpenStatements = YES; + sqlite3_stmt *pStmt; + while ((pStmt = sqlite3_next_stmt(_db, nil)) !=0) { + NSLog(@"Closing leaked statement"); + sqlite3_finalize(pStmt); + retry = YES; + } + } + } + else if (SQLITE_OK != rc) { + NSLog(@"error closing!: %d", rc); + } + } + while (retry); + + _db = nil; + return YES; +} + +#pragma mark Busy handler routines + +// NOTE: appledoc seems to choke on this function for some reason; +// so when generating documentation, you might want to ignore the +// .m files so that it only documents the public interfaces outlined +// in the .h files. +// +// This is a known appledoc bug that it has problems with C functions +// within a class implementation, but for some reason, only this +// C function causes problems; the rest don't. Anyway, ignoring the .m +// files with appledoc will prevent this problem from occurring. + +static int FMDBDatabaseBusyHandler(void *f, int count) { + FMDatabase *self = (__bridge FMDatabase*)f; + + if (count == 0) { + self->_startBusyRetryTime = [NSDate timeIntervalSinceReferenceDate]; + return 1; + } + + NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - (self->_startBusyRetryTime); + + if (delta < [self maxBusyRetryTimeInterval]) { + sqlite3_sleep(50); // milliseconds + return 1; + } + + return 0; +} + +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout { + + _maxBusyRetryTimeInterval = timeout; + + if (!_db) { + return; + } + + if (timeout > 0) { + sqlite3_busy_handler(_db, &FMDBDatabaseBusyHandler, (__bridge void *)(self)); + } + else { + // turn it off otherwise + sqlite3_busy_handler(_db, nil, nil); + } +} + +- (NSTimeInterval)maxBusyRetryTimeInterval { + return _maxBusyRetryTimeInterval; +} + + +// we no longer make busyRetryTimeout public +// but for folks who don't bother noticing that the interface to FMDatabase changed, +// we'll still implement the method so they don't get suprise crashes +- (int)busyRetryTimeout { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"FMDB: busyRetryTimeout no longer works, please use maxBusyRetryTimeInterval"); + return -1; +} + +- (void)setBusyRetryTimeout:(int)i { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"FMDB: setBusyRetryTimeout does nothing, please use setMaxBusyRetryTimeInterval:"); +} + +#pragma mark Result set functions + +- (BOOL)hasOpenResultSets { + return [_openResultSets count] > 0; +} + +- (void)closeOpenResultSets { + + //Copy the set so we don't get mutation errors + NSSet *openSetCopy = FMDBReturnAutoreleased([_openResultSets copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + + [rs setParentDB:nil]; + [rs close]; + + [_openResultSets removeObject:rsInWrappedInATastyValueMeal]; + } +} + +- (void)resultSetDidClose:(FMResultSet *)resultSet { + NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet]; + + [_openResultSets removeObject:setValue]; +} + +#pragma mark Cached statements + +- (void)clearCachedStatements { + + for (NSMutableSet *statements in [_cachedStatements objectEnumerator]) { + [statements makeObjectsPerformSelector:@selector(close)]; + } + + [_cachedStatements removeAllObjects]; +} + +- (FMStatement*)cachedStatementForQuery:(NSString*)query { + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + + return [[statements objectsPassingTest:^BOOL(FMStatement* statement, BOOL *stop) { + + *stop = ![statement inUse]; + return *stop; + + }] anyObject]; +} + + +- (void)setCachedStatement:(FMStatement*)statement forQuery:(NSString*)query { + + query = [query copy]; // in case we got handed in a mutable string... + [statement setQuery:query]; + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + if (!statements) { + statements = [NSMutableSet set]; + } + + [statements addObject:statement]; + + [_cachedStatements setObject:statements forKey:query]; + + FMDBRelease(query); +} + +#pragma mark Key routines + +- (BOOL)rekey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self rekeyWithData:keyData]; +} + +- (BOOL)rekeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_rekey(_db, [keyData bytes], (int)[keyData length]); + + if (rc != SQLITE_OK) { + NSLog(@"error on rekey: %d", rc); + NSLog(@"%@", [self lastErrorMessage]); + } + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +- (BOOL)setKey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self setKeyWithData:keyData]; +} + +- (BOOL)setKeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_key(_db, [keyData bytes], (int)[keyData length]); + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +#pragma mark Date routines + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format { + + NSDateFormatter *result = FMDBReturnAutoreleased([[NSDateFormatter alloc] init]); + result.dateFormat = format; + result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + result.locale = FMDBReturnAutoreleased([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); + return result; +} + + +- (BOOL)hasDateFormatter { + return _dateFormat != nil; +} + +- (void)setDateFormat:(NSDateFormatter *)format { + FMDBAutorelease(_dateFormat); + _dateFormat = FMDBReturnRetained(format); +} + +- (NSDate *)dateFromString:(NSString *)s { + return [_dateFormat dateFromString:s]; +} + +- (NSString *)stringFromDate:(NSDate *)date { + return [_dateFormat stringFromDate:date]; +} + +#pragma mark State of database + +- (BOOL)goodConnection { + + if (!_db) { + return NO; + } + + FMResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"]; + + if (rs) { + [rs close]; + return YES; + } + + return NO; +} + +- (void)warnInUse { + NSLog(@"The FMDatabase %@ is currently in use.", self); + +#ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is currently in use.", self); + abort(); + } +#endif +} + +- (BOOL)databaseExists { + + if (!_db) { + + NSLog(@"The FMDatabase %@ is not open.", self); + + #ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is not open.", self); + abort(); + } + #endif + + return NO; + } + + return YES; +} + +#pragma mark Error routines + +- (NSString*)lastErrorMessage { + return [NSString stringWithUTF8String:sqlite3_errmsg(_db)]; +} + +- (BOOL)hadError { + int lastErrCode = [self lastErrorCode]; + + return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW); +} + +- (int)lastErrorCode { + return sqlite3_errcode(_db); +} + +- (NSError*)errorWithMessage:(NSString*)message { + NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:@"FMDatabase" code:sqlite3_errcode(_db) userInfo:errorMessage]; +} + +- (NSError*)lastError { + return [self errorWithMessage:[self lastErrorMessage]]; +} + +#pragma mark Update information routines + +- (sqlite_int64)lastInsertRowId { + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + sqlite_int64 ret = sqlite3_last_insert_rowid(_db); + + _isExecutingStatement = NO; + + return ret; +} + +- (int)changes { + if (_isExecutingStatement) { + [self warnInUse]; + return 0; + } + + _isExecutingStatement = YES; + + int ret = sqlite3_changes(_db); + + _isExecutingStatement = NO; + + return ret; +} + +#pragma mark SQL manipulation + +- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt { + + if ((!obj) || ((NSNull *)obj == [NSNull null])) { + sqlite3_bind_null(pStmt, idx); + } + + // FIXME - someday check the return codes on these binds. + else if ([obj isKindOfClass:[NSData class]]) { + const void *bytes = [obj bytes]; + if (!bytes) { + // it's an empty NSData object, aka [NSData data]. + // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob. + bytes = ""; + } + sqlite3_bind_blob(pStmt, idx, bytes, (int)[obj length], SQLITE_STATIC); + } + else if ([obj isKindOfClass:[NSDate class]]) { + if (self.hasDateFormatter) + sqlite3_bind_text(pStmt, idx, [[self stringFromDate:obj] UTF8String], -1, SQLITE_STATIC); + else + sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]); + } + else if ([obj isKindOfClass:[NSNumber class]]) { + + if (strcmp([obj objCType], @encode(BOOL)) == 0) { + sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0)); + } + else if (strcmp([obj objCType], @encode(char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj charValue]); + } + else if (strcmp([obj objCType], @encode(unsigned char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedCharValue]); + } + else if (strcmp([obj objCType], @encode(short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj shortValue]); + } + else if (strcmp([obj objCType], @encode(unsigned short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedShortValue]); + } + else if (strcmp([obj objCType], @encode(int)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj intValue]); + } + else if (strcmp([obj objCType], @encode(unsigned int)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedIntValue]); + } + else if (strcmp([obj objCType], @encode(long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongValue]); + } + else if (strcmp([obj objCType], @encode(long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longLongValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongLongValue]); + } + else if (strcmp([obj objCType], @encode(float)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj floatValue]); + } + else if (strcmp([obj objCType], @encode(double)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj doubleValue]); + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } +} + +- (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments { + + NSUInteger length = [sql length]; + unichar last = '\0'; + for (NSUInteger i = 0; i < length; ++i) { + id arg = nil; + unichar current = [sql characterAtIndex:i]; + unichar add = current; + if (last == '%') { + switch (current) { + case '@': + arg = va_arg(args, id); + break; + case 'c': + // warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSString stringWithFormat:@"%c", va_arg(args, int)]; + break; + case 's': + arg = [NSString stringWithUTF8String:va_arg(args, char*)]; + break; + case 'd': + case 'D': + case 'i': + arg = [NSNumber numberWithInt:va_arg(args, int)]; + break; + case 'u': + case 'U': + arg = [NSNumber numberWithUnsignedInt:va_arg(args, unsigned int)]; + break; + case 'h': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + // warning: second argument to 'va_arg' is of promotable type 'short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithShort:(short)(va_arg(args, int))]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + // warning: second argument to 'va_arg' is of promotable type 'unsigned short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithUnsignedShort:(unsigned short)(va_arg(args, uint))]; + } + else { + i--; + } + break; + case 'q': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + break; + case 'f': + arg = [NSNumber numberWithDouble:va_arg(args, double)]; + break; + case 'g': + // warning: second argument to 'va_arg' is of promotable type 'float'; this va_arg has undefined behavior because arguments will be promoted to 'double' + arg = [NSNumber numberWithFloat:(float)(va_arg(args, double))]; + break; + case 'l': + i++; + if (i < length) { + unichar next = [sql characterAtIndex:i]; + if (next == 'l') { + i++; + if (i < length && [sql characterAtIndex:i] == 'd') { + //%lld + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + //%llu + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + } + else if (next == 'd') { + //%ld + arg = [NSNumber numberWithLong:va_arg(args, long)]; + } + else if (next == 'u') { + //%lu + arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)]; + } + else { + i--; + } + } + else { + i--; + } + break; + default: + // something else that we can't interpret. just pass it on through like normal + break; + } + } + else if (current == '%') { + // percent sign; skip this character + add = '\0'; + } + + if (arg != nil) { + [cleanedSQL appendString:@"?"]; + [arguments addObject:arg]; + } + else if (add == (unichar)'@' && last == (unichar) '%') { + [cleanedSQL appendFormat:@"NULL"]; + } + else if (add != '\0') { + [cleanedSQL appendFormat:@"%C", add]; + } + last = current; + } +} + +#pragma mark Execute queries + +- (FMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return 0x00; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return 0x00; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + FMStatement *statement = 0x00; + FMResultSet *rs = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeQuery: %@", self, sql); + } + + if (_shouldCacheStatements) { + statement = [self cachedStatementForQuery:sql]; + pStmt = statement ? [statement statement] : 0x00; + [statement reset]; + } + + if (!pStmt) { + + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!) + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + FMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + if (idx != queryCount) { + NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)"); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + + FMDBRetain(statement); // to balance the release below + + if (!statement) { + statement = [[FMStatement alloc] init]; + [statement setStatement:pStmt]; + + if (_shouldCacheStatements && sql) { + [self setCachedStatement:statement forQuery:sql]; + } + } + + // the statement gets closed in rs's dealloc or [rs close]; + rs = [FMResultSet resultSetWithStatement:statement usingParentDatabase:self]; + [rs setQuery:sql]; + + NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs]; + [_openResultSets addObject:openResultSet]; + + [statement setUseCount:[statement useCount] + 1]; + + FMDBRelease(statement); + + _isExecutingStatement = NO; + + return rs; +} + +- (FMResultSet *)executeQuery:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeQuery:sql withArgumentsInArray:arguments]; +} + +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeQuery:sql withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (FMResultSet *)executeQuery:(NSString*)sql withVAList:(va_list)args { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +#pragma mark Execute updates + +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return NO; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + FMStatement *cachedStmt = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeUpdate: %@", self, sql); + } + + if (_shouldCacheStatements) { + cachedStmt = [self cachedStatementForQuery:sql]; + pStmt = cachedStmt ? [cachedStmt statement] : 0x00; + [cachedStmt reset]; + } + + if (!pStmt) { + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + + if (outErr) { + *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; + } + + _isExecutingStatement = NO; + return NO; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + FMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + + if (idx != queryCount) { + NSLog(@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return NO; + } + + /* Call sqlite3_step() to run the virtual machine. Since the SQL being + ** executed is not a SELECT statement, we assume no data will be returned. + */ + + rc = sqlite3_step(pStmt); + + if (SQLITE_DONE == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else { + // wtf? + if (_logsErrors) { + NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + if (rc == SQLITE_ROW) { + NSAssert(NO, @"A executeUpdate is being called with a query string '%@'", sql); + } + + if (_shouldCacheStatements && !cachedStmt) { + cachedStmt = [[FMStatement alloc] init]; + + [cachedStmt setStatement:pStmt]; + + [self setCachedStatement:cachedStmt forQuery:sql]; + + FMDBRelease(cachedStmt); + } + + int closeErrorCode; + + if (cachedStmt) { + [cachedStmt setUseCount:[cachedStmt useCount] + 1]; + closeErrorCode = sqlite3_reset(pStmt); + } + else { + /* Finalize the virtual machine. This releases all memory and other + ** resources allocated by the sqlite3_prepare() call above. + */ + closeErrorCode = sqlite3_finalize(pStmt); + } + + if (closeErrorCode != SQLITE_OK) { + if (_logsErrors) { + NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + _isExecutingStatement = NO; + return (rc == SQLITE_DONE || rc == SQLITE_OK); +} + + +- (BOOL)executeUpdate:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withVAList:(va_list)args { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +- (BOOL)executeUpdateWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeUpdate:sql withArgumentsInArray:arguments]; +} + + +int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names); // shhh clang. +int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names) { + + if (!theBlockAsVoid) { + return SQLITE_OK; + } + + int (^execCallbackBlock)(NSDictionary *resultsDictionary) = (__bridge int (^)(NSDictionary *__strong))(theBlockAsVoid); + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns]; + + for (NSInteger i = 0; i < columns; i++) { + NSString *key = [NSString stringWithUTF8String:names[i]]; + id value = values[i] ? [NSString stringWithUTF8String:values[i]] : [NSNull null]; + [dictionary setObject:value forKey:key]; + } + + return execCallbackBlock(dictionary); +} + +- (BOOL)executeStatements:(NSString *)sql { + return [self executeStatements:sql withResultBlock:nil]; +} + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block { + + int rc; + char *errmsg = nil; + + rc = sqlite3_exec([self sqliteHandle], [sql UTF8String], block ? FMDBExecuteBulkSQLCallback : nil, (__bridge void *)(block), &errmsg); + + if (errmsg && [self logsErrors]) { + NSLog(@"Error inserting batch: %s", errmsg); + sqlite3_free(errmsg); + } + + return (rc == SQLITE_OK); +} + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +#pragma clang diagnostic pop + +#pragma mark Transactions + +- (BOOL)rollback { + BOOL b = [self executeUpdate:@"rollback transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)commit { + BOOL b = [self executeUpdate:@"commit transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)beginDeferredTransaction { + + BOOL b = [self executeUpdate:@"begin deferred transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)beginTransaction { + + BOOL b = [self executeUpdate:@"begin exclusive transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)inTransaction { + return _inTransaction; +} + +#if SQLITE_VERSION_NUMBER >= 3007000 + +static NSString *FMDBEscapeSavePointName(NSString *savepointName) { + return [savepointName stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; +} + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"savepoint '%@';", FMDBEscapeSavePointName(name)]; + + if (![self executeUpdate:sql]) { + + if (outErr) { + *outErr = [self lastError]; + } + + return NO; + } + + return YES; +} + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"release savepoint '%@';", FMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", FMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block { + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + NSError *err = 0x00; + + if (![self startSavePointWithName:name error:&err]) { + return err; + } + + block(&shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [self rollbackToSavePointWithName:name error:&err]; + } + [self releaseSavePointWithName:name error:&err]; + + return err; +} + +#endif + +#pragma mark Cache statements + +- (BOOL)shouldCacheStatements { + return _shouldCacheStatements; +} + +- (void)setShouldCacheStatements:(BOOL)value { + + _shouldCacheStatements = value; + + if (_shouldCacheStatements && !_cachedStatements) { + [self setCachedStatements:[NSMutableDictionary dictionary]]; + } + + if (!_shouldCacheStatements) { + [self setCachedStatements:nil]; + } +} + +#pragma mark Callback function + +void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv); // -Wmissing-prototypes +void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv) { +#if ! __has_feature(objc_arc) + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (id)sqlite3_user_data(context); +#else + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (__bridge id)sqlite3_user_data(context); +#endif + block(context, argc, argv); +} + + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(sqlite3_context *context, int argc, sqlite3_value **argv))block { + + if (!_openFunctions) { + _openFunctions = [NSMutableSet new]; + } + + id b = FMDBReturnAutoreleased([block copy]); + + [_openFunctions addObject:b]; + + /* I tried adding custom functions to release the block when the connection is destroyed- but they seemed to never be called, so we use _openFunctions to store the values instead. */ +#if ! __has_feature(objc_arc) + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#else + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (__bridge void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#endif +} + +@end + + + +@implementation FMStatement +@synthesize statement=_statement; +@synthesize query=_query; +@synthesize useCount=_useCount; +@synthesize inUse=_inUse; + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + FMDBRelease(_query); +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + if (_statement) { + sqlite3_finalize(_statement); + _statement = 0x00; + } + + _inUse = NO; +} + +- (void)reset { + if (_statement) { + sqlite3_reset(_statement); + } + + _inUse = NO; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"%@ %ld hit(s) for query %@", [super description], _useCount, _query]; +} + + +@end + diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h new file mode 100644 index 0000000..e35df93 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.h @@ -0,0 +1,267 @@ +// +// FMDatabaseAdditions.h +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import +#import "FMDatabase.h" + + +/** Category of additions for `` class. + + ### See also + + - `` + */ + +@interface FMDatabase (FMDatabaseAdditions) + +///---------------------------------------- +/// @name Return results of SQL to variable +///---------------------------------------- + +/** Return `int` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `int` value. + */ + +- (int)intForQuery:(NSString*)query, ...; + +/** Return `long` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `long` value. + */ + +- (long)longForQuery:(NSString*)query, ...; + +/** Return `BOOL` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `BOOL` value. + */ + +- (BOOL)boolForQuery:(NSString*)query, ...; + +/** Return `double` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `double` value. + */ + +- (double)doubleForQuery:(NSString*)query, ...; + +/** Return `NSString` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSString` value. + */ + +- (NSString*)stringForQuery:(NSString*)query, ...; + +/** Return `NSData` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSData` value. + */ + +- (NSData*)dataForQuery:(NSString*)query, ...; + +/** Return `NSDate` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSDate` value. + */ + +- (NSDate*)dateForQuery:(NSString*)query, ...; + + +// Notice that there's no dataNoCopyForQuery:. +// That would be a bad idea, because we close out the result set, and then what +// happens to the data that we just didn't copy? Who knows, not I. + + +///-------------------------------- +/// @name Schema related operations +///-------------------------------- + +/** Does table exist in database? + + @param tableName The name of the table being looked for. + + @return `YES` if table found; `NO` if not found. + */ + +- (BOOL)tableExists:(NSString*)tableName; + +/** The schema of the database. + + This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: + + - `type` - The type of entity (e.g. table, index, view, or trigger) + - `name` - The name of the object + - `tbl_name` - The name of the table to which the object references + - `rootpage` - The page number of the root b-tree page for tables and indices + - `sql` - The SQL that created the entity + + @return `FMResultSet` of schema; `nil` on error. + + @see [SQLite File Format](http://www.sqlite.org/fileformat.html) + */ + +- (FMResultSet*)getSchema; + +/** The schema of the database. + + This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: + + PRAGMA table_info('employees') + + This will report: + + - `cid` - The column ID number + - `name` - The name of the column + - `type` - The data type specified for the column + - `notnull` - whether the field is defined as NOT NULL (i.e. values required) + - `dflt_value` - The default value for the column + - `pk` - Whether the field is part of the primary key of the table + + @param tableName The name of the table for whom the schema will be returned. + + @return `FMResultSet` of schema; `nil` on error. + + @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) + */ + +- (FMResultSet*)getTableSchema:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + */ + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + + @see columnExists:inTableWithName: + + @warning Deprecated - use `` instead. + */ + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); + + +/** Validate SQL statement + + This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. + + @param sql The SQL statement being validated. + + @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. + + @return `YES` if validation succeeded without incident; `NO` otherwise. + + */ + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; + + +#if SQLITE_VERSION_NUMBER >= 3007017 + +///----------------------------------- +/// @name Application identifier tasks +///----------------------------------- + +/** Retrieve application ID + + @return The `uint32_t` numeric value of the application ID. + + @see setApplicationID: + */ + +- (uint32_t)applicationID; + +/** Set the application ID + + @param appID The `uint32_t` numeric value of the application ID. + + @see applicationID + */ + +- (void)setApplicationID:(uint32_t)appID; + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +/** Retrieve application ID string + + @return The `NSString` value of the application ID. + + @see setApplicationIDString: + */ + + +- (NSString*)applicationIDString; + +/** Set the application ID string + + @param string The `NSString` value of the application ID. + + @see applicationIDString + */ + +- (void)setApplicationIDString:(NSString*)string; +#endif + +#endif + +///----------------------------------- +/// @name user version identifier tasks +///----------------------------------- + +/** Retrieve user version + + @return The `uint32_t` numeric value of the user version. + + @see setUserVersion: + */ + +- (uint32_t)userVersion; + +/** Set the user-version + + @param version The `uint32_t` numeric value of the user version. + + @see userVersion + */ + +- (void)setUserVersion:(uint32_t)version; + +@end diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m new file mode 100644 index 0000000..4ab35fa --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseAdditions.m @@ -0,0 +1,224 @@ +// +// FMDatabaseAdditions.m +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import "FMDatabase.h" +#import "FMDatabaseAdditions.h" +#import "TargetConditionals.h" + +@interface FMDatabase (PrivateStuff) +- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +@end + +@implementation FMDatabase (FMDatabaseAdditions) + +#define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ +va_list args; \ +va_start(args, query); \ +FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ +va_end(args); \ +if (![resultSet next]) { return (type)0; } \ +type ret = [resultSet sel:0]; \ +[resultSet close]; \ +[resultSet setParentDB:nil]; \ +return ret; + + +- (NSString*)stringForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); +} + +- (int)intForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); +} + +- (long)longForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); +} + +- (BOOL)boolForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); +} + +- (double)doubleForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); +} + +- (NSData*)dataForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); +} + +- (NSDate*)dateForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); +} + + +- (BOOL)tableExists:(NSString*)tableName { + + tableName = [tableName lowercaseString]; + + FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; + + //if at least one next exists, table exists + BOOL returnBool = [rs next]; + + //close and free object + [rs close]; + + return returnBool; +} + +/* + get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + check if table exist in database (patch from OZLB) +*/ +- (FMResultSet*)getSchema { + + //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; + + return rs; +} + +/* + get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] +*/ +- (FMResultSet*)getTableSchema:(NSString*)tableName { + + //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] + FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; + + return rs; +} + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { + + BOOL returnBool = NO; + + tableName = [tableName lowercaseString]; + columnName = [columnName lowercaseString]; + + FMResultSet *rs = [self getTableSchema:tableName]; + + //check if column is present in table schema + while ([rs next]) { + if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { + returnBool = YES; + break; + } + } + + //If this is not done FMDatabase instance stays out of pool + [rs close]; + + return returnBool; +} + + +#if SQLITE_VERSION_NUMBER >= 3007017 + +- (uint32_t)applicationID { + + uint32_t r = 0; + + FMResultSet *rs = [self executeQuery:@"pragma application_id"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; + + return r; +} + +- (void)setApplicationID:(uint32_t)appID { + NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; + FMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +} + + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +- (NSString*)applicationIDString { + NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); + + assert([s length] == 6); + + s = [s substringWithRange:NSMakeRange(1, 4)]; + + + return s; + +} + +- (void)setApplicationIDString:(NSString*)s { + + if ([s length] != 4) { + NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); + } + + [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; +} + + +#endif + +#endif + +- (uint32_t)userVersion { + uint32_t r = 0; + + FMResultSet *rs = [self executeQuery:@"pragma user_version"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; + return r; +} + +- (void)setUserVersion:(uint32_t)version { + NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; + FMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { + return [self columnExists:columnName inTableWithName:tableName]; +} + +#pragma clang diagnostic pop + + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { + sqlite3_stmt *pStmt = NULL; + BOOL validationSucceeded = YES; + + int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + if (rc != SQLITE_OK) { + validationSucceeded = NO; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:[self lastErrorCode] + userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] + forKey:NSLocalizedDescriptionKey]]; + } + } + + sqlite3_finalize(pStmt); + + return validationSucceeded; +} + +@end diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.h new file mode 100644 index 0000000..692b8ae --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.h @@ -0,0 +1,204 @@ +// +// FMDatabasePool.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import +#import "sqlite3.h" + +@class FMDatabase; + +/** Pool of `` objects. + + ### See also + + - `` + - `` + + @warning Before using `FMDatabasePool`, please consider using `` instead. + + If you really really really know what you're doing and `FMDatabasePool` is what + you really really need (ie, you're using a read only database), OK you can use + it. But just be careful not to deadlock! + + For an example on deadlocking, search for: + `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` + in the main.m file. + */ + +@interface FMDatabasePool : NSObject { + NSString *_path; + + dispatch_queue_t _lockQueue; + + NSMutableArray *_databaseInPool; + NSMutableArray *_databaseOutPool; + + __unsafe_unretained id _delegate; + + NSUInteger _maximumNumberOfDatabasesToCreate; + int _openFlags; +} + +/** Database path */ + +@property (atomic, retain) NSString *path; + +/** Delegate object */ + +@property (atomic, assign) id delegate; + +/** Maximum number of databases to create */ + +@property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +///------------------------------------------------ +/// @name Keeping track of checked in/out databases +///------------------------------------------------ + +/** Number of checked-in databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedInDatabases; + +/** Number of checked-out databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedOutDatabases; + +/** Total number of databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfOpenDatabases; + +/** Release all databases in pool */ + +- (void)releaseAllDatabases; + +///------------------------------------------ +/// @name Perform database operations in pool +///------------------------------------------ + +/** Synchronously perform database operations in pool. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDatabase:(void (^)(FMDatabase *db))block; + +/** Synchronously perform database operations in pool using transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations in pool using deferred transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +#if SQLITE_VERSION_NUMBER >= 3007000 + +/** Synchronously perform database operations in pool using save point. + + @param block The code to be run on the `FMDatabasePool` pool. + + @return `NSError` object if error; `nil` if successful. + + @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. +*/ + +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; +#endif + +@end + + +/** FMDatabasePool delegate category + + This is a category that defines the protocol for the FMDatabasePool delegate + */ + +@interface NSObject (FMDatabasePoolDelegate) + +/** Asks the delegate whether database should be added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + @return `YES` if it should add database to pool; `NO` if not. + + */ + +- (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; + +/** Tells the delegate that database was added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + */ + +- (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; + +@end + diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.m b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.m new file mode 100644 index 0000000..38114a9 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabasePool.m @@ -0,0 +1,273 @@ +// +// FMDatabasePool.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "FMDatabasePool.h" +#import "FMDatabase.h" + +@interface FMDatabasePool() + +- (void)pushDatabaseBackInPool:(FMDatabase*)db; +- (FMDatabase*)db; + +@end + + +@implementation FMDatabasePool +@synthesize path=_path; +@synthesize delegate=_delegate; +@synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; +@synthesize openFlags=_openFlags; + + ++ (instancetype)databasePoolWithPath:(NSString*)aPath { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { + return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + + self = [super init]; + + if (self != nil) { + _path = [aPath copy]; + _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + _databaseInPool = FMDBReturnRetained([NSMutableArray array]); + _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath +{ + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + _delegate = 0x00; + FMDBRelease(_path); + FMDBRelease(_databaseInPool); + FMDBRelease(_databaseOutPool); + + if (_lockQueue) { + FMDBDispatchQueueRelease(_lockQueue); + _lockQueue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + + +- (void)executeLocked:(void (^)(void))aBlock { + dispatch_sync(_lockQueue, aBlock); +} + +- (void)pushDatabaseBackInPool:(FMDatabase*)db { + + if (!db) { // db can be null if we set an upper bound on the # of databases to create. + return; + } + + [self executeLocked:^() { + + if ([_databaseInPool containsObject:db]) { + [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; + } + + [_databaseInPool addObject:db]; + [_databaseOutPool removeObject:db]; + + }]; +} + +- (FMDatabase*)db { + + __block FMDatabase *db; + + + [self executeLocked:^() { + db = [_databaseInPool lastObject]; + + BOOL shouldNotifyDelegate = NO; + + if (db) { + [_databaseOutPool addObject:db]; + [_databaseInPool removeLastObject]; + } + else { + + if (_maximumNumberOfDatabasesToCreate) { + NSUInteger currentCount = [_databaseOutPool count] + [_databaseInPool count]; + + if (currentCount >= _maximumNumberOfDatabasesToCreate) { + NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); + return; + } + } + + db = [FMDatabase databaseWithPath:_path]; + shouldNotifyDelegate = YES; + } + + //This ensures that the db is opened before returning +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [db openWithFlags:_openFlags]; +#else + BOOL success = [db open]; +#endif + if (success) { + if ([_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![_delegate databasePool:self shouldAddDatabaseToPool:db]) { + [db close]; + db = 0x00; + } + else { + //It should not get added in the pool twice if lastObject was found + if (![_databaseOutPool containsObject:db]) { + [_databaseOutPool addObject:db]; + + if (shouldNotifyDelegate && [_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { + [_delegate databasePool:self didAddDatabase:db]; + } + } + } + } + else { + NSLog(@"Could not open up the database at path %@", _path); + db = 0x00; + } + }]; + + return db; +} + +- (NSUInteger)countOfCheckedInDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [_databaseInPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfCheckedOutDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [_databaseOutPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfOpenDatabases { + __block NSUInteger count; + + [self executeLocked:^() { + count = [_databaseOutPool count] + [_databaseInPool count]; + }]; + + return count; +} + +- (void)releaseAllDatabases { + [self executeLocked:^() { + [_databaseOutPool removeAllObjects]; + [_databaseInPool removeAllObjects]; + }]; +} + +- (void)inDatabase:(void (^)(FMDatabase *db))block { + + FMDatabase *db = [self db]; + + block(db); + + [self pushDatabaseBackInPool:db]; +} + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { + + BOOL shouldRollback = NO; + + FMDatabase *db = [self db]; + + if (useDeferred) { + [db beginDeferredTransaction]; + } + else { + [db beginTransaction]; + } + + + block(db, &shouldRollback); + + if (shouldRollback) { + [db rollback]; + } + else { + [db commit]; + } + + [self pushDatabaseBackInPool:db]; +} + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} +#if SQLITE_VERSION_NUMBER >= 3007000 +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { + + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + FMDatabase *db = [self db]; + + NSError *err = 0x00; + + if (![db startSavePointWithName:name error:&err]) { + [self pushDatabaseBackInPool:db]; + return err; + } + + block(db, &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [db rollbackToSavePointWithName:name error:&err]; + } + [db releaseSavePointWithName:name error:&err]; + + [self pushDatabaseBackInPool:db]; + + return err; +} +#endif + +@end diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.h new file mode 100644 index 0000000..34c0750 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.h @@ -0,0 +1,174 @@ +// +// FMDatabaseQueue.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import +#import "sqlite3.h" + +@class FMDatabase; + +/** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. + + Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. + + Instead, use `FMDatabaseQueue`. Here's how to use it: + + First, make your queue. + + FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; + + Then use it like so: + + [queue inDatabase:^(FMDatabase *db) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + FMResultSet *rs = [db executeQuery:@"select * from foo"]; + while ([rs next]) { + //… + } + }]; + + An easy way to wrap things up in a transaction can be done like this: + + [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + if (whoopsSomethingWrongHappened) { + *rollback = YES; + return; + } + // etc… + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; + }]; + + `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. + + ### See also + + - `` + + @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. + + @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. + + */ + +@interface FMDatabaseQueue : NSObject { + NSString *_path; + dispatch_queue_t _queue; + FMDatabase *_db; + int _openFlags; +} + +/** Path of database */ + +@property (atomic, retain) NSString *path; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + +///---------------------------------------------------- +/// @name Initialization, opening, and closing of queue +///---------------------------------------------------- + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. + + Subclasses can override this method to return specified Class of 'FMDatabase' subclass. + + @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. + */ + ++ (Class)databaseClass; + +/** Close database used by queue. */ + +- (void)close; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations on queue. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDatabase:(void (^)(FMDatabase *db))block; + +/** Synchronously perform database operations on queue, using transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations on queue, using deferred transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations using save point. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +#if SQLITE_VERSION_NUMBER >= 3007000 +// NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. +// If you need to nest, use FMDatabase's startSavePointWithName:error: instead. +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; +#endif + +@end + diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.m b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.m new file mode 100644 index 0000000..46a84ea --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMDatabaseQueue.m @@ -0,0 +1,232 @@ +// +// FMDatabaseQueue.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "FMDatabaseQueue.h" +#import "FMDatabase.h" + +/* + + Note: we call [self retain]; before using dispatch_sync, just incase + FMDatabaseQueue is released on another thread and we're in the middle of doing + something in dispatch_sync + + */ + +/* + * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. + * This in turn is used for deadlock detection by seeing if inDatabase: is called on + * the queue's dispatch queue, which should not happen and causes a deadlock. + */ +static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; + +@implementation FMDatabaseQueue + +@synthesize path = _path; +@synthesize openFlags = _openFlags; + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath { + + FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; + + FMDBAutorelease(q); + + return q; +} + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { + + FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; + + FMDBAutorelease(q); + + return q; +} + ++ (Class)databaseClass { + return [FMDatabase class]; +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + + self = [super init]; + + if (self != nil) { + + _db = [[[self class] databaseClass] databaseWithPath:aPath]; + FMDBRetain(_db); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:openFlags]; +#else + BOOL success = [_db open]; +#endif + if (!success) { + NSLog(@"Could not create database queue for path %@", aPath); + FMDBRelease(self); + return 0x00; + } + + _path = FMDBReturnRetained(aPath); + + _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + FMDBRelease(_db); + FMDBRelease(_path); + + if (_queue) { + FMDBDispatchQueueRelease(_queue); + _queue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + FMDBRetain(self); + dispatch_sync(_queue, ^() { + [_db close]; + FMDBRelease(_db); + _db = 0x00; + }); + FMDBRelease(self); +} + +- (FMDatabase*)database { + if (!_db) { + _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:_openFlags]; +#else + BOOL success = [db open]; +#endif + if (!success) { + NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); + FMDBRelease(_db); + _db = 0x00; + return 0x00; + } + } + + return _db; +} + +- (void)inDatabase:(void (^)(FMDatabase *db))block { + /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue + * and then check it against self to make sure we're not about to deadlock. */ + FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); + assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); + + FMDBRetain(self); + + dispatch_sync(_queue, ^() { + + FMDatabase *db = [self database]; + block(db); + + if ([db hasOpenResultSets]) { + NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); + +#ifdef DEBUG + NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + NSLog(@"query: '%@'", [rs query]); + } +#endif + } + }); + + FMDBRelease(self); +} + + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { + FMDBRetain(self); + dispatch_sync(_queue, ^() { + + BOOL shouldRollback = NO; + + if (useDeferred) { + [[self database] beginDeferredTransaction]; + } + else { + [[self database] beginTransaction]; + } + + block([self database], &shouldRollback); + + if (shouldRollback) { + [[self database] rollback]; + } + else { + [[self database] commit]; + } + }); + + FMDBRelease(self); +} + +- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} + +#if SQLITE_VERSION_NUMBER >= 3007000 +- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { + + static unsigned long savePointIdx = 0; + __block NSError *err = 0x00; + FMDBRetain(self); + dispatch_sync(_queue, ^() { + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + if ([[self database] startSavePointWithName:name error:&err]) { + + block([self database], &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [[self database] rollbackToSavePointWithName:name error:&err]; + } + [[self database] releaseSavePointWithName:name error:&err]; + + } + }); + FMDBRelease(self); + return err; +} +#endif + +@end diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.h b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.h new file mode 100644 index 0000000..8585a69 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.h @@ -0,0 +1,456 @@ +#import +#import "sqlite3.h" + +#ifndef __has_feature // Optional. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_NOT_RETAINED +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#else +#define NS_RETURNS_NOT_RETAINED +#endif +#endif + +@class FMDatabase; +@class FMStatement; + +/** Represents the results of executing a query on an ``. + + ### See also + + - `` + */ + +@interface FMResultSet : NSObject { + FMDatabase *_parentDB; + FMStatement *_statement; + + NSString *_query; + NSMutableDictionary *_columnNameToIndexMap; +} + +///----------------- +/// @name Properties +///----------------- + +/** Executed query */ + +@property (atomic, retain) NSString *query; + +/** `NSMutableDictionary` mapping column names to numeric index */ + +@property (readonly) NSMutableDictionary *columnNameToIndexMap; + +/** `FMStatement` used by result set. */ + +@property (atomic, retain) FMStatement *statement; + +///------------------------------------ +/// @name Creating and closing database +///------------------------------------ + +/** Create result set from `` + + @param statement A `` to be performed + + @param aDB A `` to be used + + @return A `FMResultSet` on success; `nil` on failure + */ + ++ (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; + +/** Close result set */ + +- (void)close; + +- (void)setParentDB:(FMDatabase *)newDb; + +///--------------------------------------- +/// @name Iterating through the result set +///--------------------------------------- + +/** Retrieve next row for result set. + + You must always invoke `next` before attempting to access the values returned in a query, even if you're only expecting one. + + @return `YES` if row successfully retrieved; `NO` if end of result set reached + + @see hasAnotherRow + */ + +- (BOOL)next; + +/** Did the last call to `` succeed in retrieving another row? + + @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. + + @see next + + @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. + */ + +- (BOOL)hasAnotherRow; + +///--------------------------------------------- +/// @name Retrieving information from result set +///--------------------------------------------- + +/** How many columns in result set + + @return Integer value of the number of columns. + */ + +- (int)columnCount; + +/** Column index for column name + + @param columnName `NSString` value of the name of the column. + + @return Zero-based index for column. + */ + +- (int)columnIndexForName:(NSString*)columnName; + +/** Column name for column index + + @param columnIdx Zero-based index for column. + + @return columnName `NSString` value of the name of the column. + */ + +- (NSString*)columnNameForIndex:(int)columnIdx; + +/** Result set integer value for column. + + @param columnName `NSString` value of the name of the column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumn:(NSString*)columnName; + +/** Result set integer value for column. + + @param columnIdx Zero-based index for column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumnIndex:(int)columnIdx; + +/** Result set `long` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumn:(NSString*)columnName; + +/** Result set long value for column. + + @param columnIdx Zero-based index for column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumnIndex:(int)columnIdx; + +/** Result set `long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumn:(NSString*)columnName; + +/** Result set `long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumnIndex:(int)columnIdx; + +/** Result set `unsigned long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; + +/** Result set `unsigned long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; + +/** Result set `BOOL` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumn:(NSString*)columnName; + +/** Result set `BOOL` value for column. + + @param columnIdx Zero-based index for column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumnIndex:(int)columnIdx; + +/** Result set `double` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumn:(NSString*)columnName; + +/** Result set `double` value for column. + + @param columnIdx Zero-based index for column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumnIndex:(int)columnIdx; + +/** Result set `NSString` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSString` value of the result set's column. + + */ + +- (NSString*)stringForColumn:(NSString*)columnName; + +/** Result set `NSString` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSString` value of the result set's column. + */ + +- (NSString*)stringForColumnIndex:(int)columnIdx; + +/** Result set `NSDate` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSDate` value of the result set's column. + */ + +- (NSDate*)dateForColumn:(NSString*)columnName; + +/** Result set `NSDate` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSDate` value of the result set's column. + + */ + +- (NSDate*)dateForColumnIndex:(int)columnIdx; + +/** Result set `NSData` value for column. + + This is useful when storing binary data in table (such as image or the like). + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + */ + +- (NSData*)dataForColumn:(NSString*)columnName; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + */ + +- (NSData*)dataForColumnIndex:(int)columnIdx; + +/** Result set `(const unsigned char *)` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; + +/** Result set `(const unsigned char *)` value for column. + + @param columnIdx Zero-based index for column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectForKeyedSubscript: + */ + +- (id)objectForColumnName:(NSString*)columnName; + +/** Result set object for column. + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectAtIndexedSubscript: + */ + +- (id)objectForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[@"employee_name"]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:@"employee_name"]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:@"employee_name"]; + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectForKeyedSubscript:(NSString *)columnName; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[0]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:0]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:0]; + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectAtIndexedSubscript:(int)columnIdx; + +/** Result set `NSData` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the +result set, make sure to make a copy of the data first (or just use ``/``) +If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the + result set, make sure to make a copy of the data first (or just use ``/``) + If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; + +/** Is the column `NULL`? + + @param columnIdx Zero-based index for column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIndexIsNull:(int)columnIdx; + +/** Is the column `NULL`? + + @param columnName `NSString` value of the name of the column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIsNull:(NSString*)columnName; + + +/** Returns a dictionary of the row results mapped to case sensitive keys of the column names. + + @returns `NSDictionary` of the row results. + + @warning The keys to the dictionary are case sensitive of the column names. + */ + +- (NSDictionary*)resultDictionary; + +/** Returns a dictionary of the row results + + @see resultDictionary + + @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! + */ + +- (NSDictionary*)resultDict __attribute__ ((deprecated)); + +///----------------------------- +/// @name Key value coding magic +///----------------------------- + +/** Performs `setValue` to yield support for key value observing. + + @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. + + */ + +- (void)kvcMagic:(id)object; + + +@end + diff --git a/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.m b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.m new file mode 100644 index 0000000..6d52f68 --- /dev/null +++ b/LFHeatMapDemo/Pods/FMDB/src/fmdb/FMResultSet.m @@ -0,0 +1,389 @@ +#import "FMResultSet.h" +#import "FMDatabase.h" +#import "unistd.h" + +@interface FMDatabase () +- (void)resultSetDidClose:(FMResultSet *)resultSet; +@end + + +@implementation FMResultSet +@synthesize query=_query; +@synthesize statement=_statement; + ++ (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { + + FMResultSet *rs = [[FMResultSet alloc] init]; + + [rs setStatement:statement]; + [rs setParentDB:aDB]; + + NSParameterAssert(![statement inUse]); + [statement setInUse:YES]; // weak reference + + return FMDBReturnAutoreleased(rs); +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + + FMDBRelease(_query); + _query = nil; + + FMDBRelease(_columnNameToIndexMap); + _columnNameToIndexMap = nil; + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + [_statement reset]; + FMDBRelease(_statement); + _statement = nil; + + // we don't need this anymore... (i think) + //[_parentDB setInUse:NO]; + [_parentDB resultSetDidClose:self]; + _parentDB = nil; +} + +- (int)columnCount { + return sqlite3_column_count([_statement statement]); +} + +- (NSMutableDictionary *)columnNameToIndexMap { + if (!_columnNameToIndexMap) { + int columnCount = sqlite3_column_count([_statement statement]); + _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] + forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; + } + } + return _columnNameToIndexMap; +} + +- (void)kvcMagic:(id)object { + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + // check for a null row + if (c) { + NSString *s = [NSString stringWithUTF8String:c]; + + [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; + } + } +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (NSDictionary*)resultDict { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; + NSString *columnName = nil; + while ((columnName = [columnNames nextObject])) { + id objectValue = [self objectForColumnName:columnName]; + [dict setObject:objectValue forKey:columnName]; + } + + return FMDBReturnAutoreleased([dict copy]); + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + +#pragma clang diagnostic pop + +- (NSDictionary*)resultDictionary { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; + id objectValue = [self objectForColumnIndex:columnIdx]; + [dict setObject:objectValue forKey:columnName]; + } + + return dict; + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + + + + +- (BOOL)next { + + int rc = sqlite3_step([_statement statement]); + + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); + NSLog(@"Database busy"); + } + else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + else { + // wtf? + NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + } + + + if (rc != SQLITE_ROW) { + [self close]; + } + + return (rc == SQLITE_ROW); +} + +- (BOOL)hasAnotherRow { + return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; +} + +- (int)columnIndexForName:(NSString*)columnName { + columnName = [columnName lowercaseString]; + + NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; + + if (n) { + return [n intValue]; + } + + NSLog(@"Warning: I could not find the column named '%@'.", columnName); + + return -1; +} + + + +- (int)intForColumn:(NSString*)columnName { + return [self intForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (int)intForColumnIndex:(int)columnIdx { + return sqlite3_column_int([_statement statement], columnIdx); +} + +- (long)longForColumn:(NSString*)columnName { + return [self longForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long)longForColumnIndex:(int)columnIdx { + return (long)sqlite3_column_int64([_statement statement], columnIdx); +} + +- (long long int)longLongIntForColumn:(NSString*)columnName { + return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long long int)longLongIntForColumnIndex:(int)columnIdx { + return sqlite3_column_int64([_statement statement], columnIdx); +} + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { + return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { + return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; +} + +- (BOOL)boolForColumn:(NSString*)columnName { + return [self boolForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (BOOL)boolForColumnIndex:(int)columnIdx { + return ([self intForColumnIndex:columnIdx] != 0); +} + +- (double)doubleForColumn:(NSString*)columnName { + return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (double)doubleForColumnIndex:(int)columnIdx { + return sqlite3_column_double([_statement statement], columnIdx); +} + +- (NSString*)stringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + if (!c) { + // null row. + return nil; + } + + return [NSString stringWithUTF8String:c]; +} + +- (NSString*)stringForColumn:(NSString*)columnName { + return [self stringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumn:(NSString*)columnName { + return [self dateForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; +} + + +- (NSData*)dataForColumn:(NSString*)columnName { + return [self dataForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + + NSMutableData *data = [NSMutableData dataWithLength:(NSUInteger)dataSize]; + + memcpy([data mutableBytes], sqlite3_column_blob([_statement statement], columnIdx), dataSize); + + return data; +} + + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName { + return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + + NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob([_statement statement], columnIdx) length:(NSUInteger)dataSize freeWhenDone:NO]; + + return data; +} + + +- (BOOL)columnIndexIsNull:(int)columnIdx { + return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; +} + +- (BOOL)columnIsNull:(NSString*)columnName { + return [self columnIndexIsNull:[self columnIndexForName:columnName]]; +} + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return sqlite3_column_text([_statement statement], columnIdx); +} + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { + return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (id)objectForColumnIndex:(int)columnIdx { + int columnType = sqlite3_column_type([_statement statement], columnIdx); + + id returnValue = nil; + + if (columnType == SQLITE_INTEGER) { + returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_FLOAT) { + returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_BLOB) { + returnValue = [self dataForColumnIndex:columnIdx]; + } + else { + //default to a string for everything else + returnValue = [self stringForColumnIndex:columnIdx]; + } + + if (returnValue == nil) { + returnValue = [NSNull null]; + } + + return returnValue; +} + +- (id)objectForColumnName:(NSString*)columnName { + return [self objectForColumnIndex:[self columnIndexForName:columnName]]; +} + +// returns autoreleased NSString containing the name of the column in the result set +- (NSString*)columnNameForIndex:(int)columnIdx { + return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; +} + +- (void)setParentDB:(FMDatabase *)newDb { + _parentDB = newDb; +} + +- (id)objectAtIndexedSubscript:(int)columnIdx { + return [self objectForColumnIndex:columnIdx]; +} + +- (id)objectForKeyedSubscript:(NSString *)columnName { + return [self objectForColumnName:columnName]; +} + + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/LICENSE b/LFHeatMapDemo/Pods/GRMustache/LICENSE new file mode 100644 index 0000000..b3da59e --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2014 Gwendal Roué + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LFHeatMapDemo/Pods/GRMustache/README.md b/LFHeatMapDemo/Pods/GRMustache/README.md new file mode 100644 index 0000000..178fc0f --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/README.md @@ -0,0 +1,72 @@ +GRMustache +========== + +GRMustache is an implementation of [Mustache templates](http://mustache.github.io/) for MacOS Cocoa and iOS. + +It ships with built-in goodies and extensibility hooks that let you avoid the strict minimalism of the genuine Mustache language when you need it. + +**System requirements**: GRMustache targets iOS down to version 4.3, MacOS down to 10.6 Snow Leopard (without garbage collection), and only depends on the Foundation framework. + +**September 13, 2014: GRMustache 7.3.0 is out.** [Release notes](RELEASE_NOTES.md) + + +Get release announcements and usage tips: follow [@GRMustache on Twitter](http://twitter.com/GRMustache). + + +How To +------ + +### 1. Setup your Xcode project + +You have three options, from the simplest to the hairiest: + +- [CocoaPods](Guides/installation.md#option-1-cocoapods) +- [Static Library](Guides/installation.md#option-2-static-library) +- [Compile the raw sources](Guides/installation.md#option-3-compiling-the-raw-sources) + + +### 2. Start rendering templates + +```objc +#import "GRMustache.h" +``` + +One-liners: + +```objc +// Renders "Hello Arthur!" +NSString *rendering = [GRMustacheTemplate renderObject:@{ @"name": @"Arthur" } fromString:@"Hello {{name}}!" error:NULL]; +``` + +```objc +// Renders the `Profile.mustache` resource of the main bundle +NSString *rendering = [GRMustacheTemplate renderObject:user fromResource:@"Profile" bundle:nil error:NULL]; +``` + +Reuse templates in order to avoid parsing the same template several times: + +```objc +GRMustacheTemplate *template = [GRMustacheTemplate templateFromResource:@"Profile" bundle:nil error:nil]; +rendering = [template renderObject:arthur error:NULL]; +rendering = [template renderObject:barbara error:NULL]; +rendering = ... +``` + +[GRMustachio](https://github.com/mugginsoft/GRMustachio) by Jonathan Mitchell is "A super simple, interactive GRMustache based application". It can help you design and test your templates. + + +Documentation +------------- + +If you don't know Mustache, start here: http://mustache.github.io/mustache.5.html + +- [Guides](Guides/README.md): a guided tour of GRMustache +- [Reference](http://groue.github.io/GRMustache/Reference/): all classes & protocols +- [Troubleshooting](Guides/troubleshooting.md) +- [FAQ](Guides/faq.md) + + +License +------- + +Released under the [MIT License](LICENSE). diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m new file mode 100644 index 0000000..67470d5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +@implementation GRMustacheExpression +@synthesize token=_token; + +- (void)dealloc +{ + [_token release]; + [super dealloc]; +} + +- (BOOL)isEqual:(id)anObject +{ + return [super isEqual:anObject]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return YES; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h new file mode 100644 index 0000000..a50b8c5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h @@ -0,0 +1,39 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheFilteredExpression; +@class GRMustacheIdentifierExpression; +@class GRMustacheImplicitIteratorExpression; +@class GRMustacheScopedExpression; + +@protocol GRMustacheExpressionVisitor + +// Don't use these methods directly. Use -[GRMustacheExpression acceptVisitor:error:] instead +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h new file mode 100644 index 0000000..b10ddb9 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h @@ -0,0 +1,66 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheToken; +@protocol GRMustacheExpressionVisitor; + +/** + * The GRMustacheExpression is the base class for objects that represent + * Mustache expression such as `name`, `uppercase(name)`, or `user.name`. + */ +@interface GRMustacheExpression : NSObject { +@private + GRMustacheToken *_token; +} + +/** + * This property stores a token whose sole purpose is to help the library user + * debugging his templates, using the token's ability to output its location + * (`{{ foo }}` at line 23 of /path/to/template). + */ +@property (nonatomic, retain) GRMustacheToken *token GRMUSTACHE_API_INTERNAL; + +/** + * Returns a Boolean value that indicates whether the receiver and a given + * object are equal. + * + * Expressions are equal if and only if the result of their + * `hasValue:withContext:protected:error:` implementation would return the same + * value in a given rendering context. + * + * Default implementation is NSObject's one: subclasses must override. + * + * @param anObject The object to be compared to the receiver. + * + * @return YES if the receiver and anObject are equal, otherwise NO. + */ +- (BOOL)isEqual:(id)anObject; // no availability macro for Foundation method declaration + +/** + * Has the visitor visit the expression. + */ +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m new file mode 100644 index 0000000..abbbc62 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m @@ -0,0 +1,89 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +@implementation GRMustacheFilteredExpression +@synthesize filterExpression=_filterExpression; +@synthesize argumentExpression=_argumentExpression; +@synthesize curried=_curried; + ++ (instancetype)expressionWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried +{ + return [[[self alloc] initWithFilterExpression:filterExpression argumentExpression:argumentExpression curried:curried] autorelease]; +} + +- (void)dealloc +{ + [_filterExpression release]; + [_argumentExpression release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (void)setToken:(GRMustacheToken *)token +{ + [super setToken:token]; + _filterExpression.token = token; + _argumentExpression.token = token; +} + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheFilteredExpression class]]) { + return NO; + } + if (![_filterExpression isEqual:((GRMustacheFilteredExpression *)expression).filterExpression]) { + return NO; + } + return [_argumentExpression isEqual:((GRMustacheFilteredExpression *)expression).argumentExpression]; +} + +- (NSUInteger)hash +{ + return [_filterExpression hash] ^ [_argumentExpression hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitFilteredExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried +{ + self = [super init]; + if (self) { + _filterExpression = [filterExpression retain]; + _argumentExpression = [argumentExpression retain]; + _curried = curried; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h new file mode 100644 index 0000000..1b2f8e5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h @@ -0,0 +1,58 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheFilteredExpression represents expressions such as + * `()`. + */ +@interface GRMustacheFilteredExpression : GRMustacheExpression { +@private + GRMustacheExpression *_filterExpression; + GRMustacheExpression *_argumentExpression; + BOOL _curried; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *filterExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) GRMustacheExpression *argumentExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, getter=isCurried, readonly) BOOL curried GRMUSTACHE_API_INTERNAL; + +/** + * Returns a filtered expression, given an expression that returns a filter, and + * an expression that return the filter argument. + * + * For example, the Mustache tag `{{ f(x) }}` contains a filtered expression, + * whose filterExpression is a GRMustacheIdentifierExpression (for the + * identifier `f`), and whose argumentExpression is a + * GRMustacheIdentifierExpression (for the identifier `x`). + * + * @param filterExpression An expression whose value is an object conforming + * to the protocol. + * @param argumentExpression An expression whose value is the argument of the + * filter. + * @param curried If YES, this expression must evaluate to a filter. + * + * @return A GRMustacheFilteredExpression. + */ ++ (instancetype)expressionWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m new file mode 100644 index 0000000..43055b6 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m @@ -0,0 +1,73 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +@implementation GRMustacheIdentifierExpression +@synthesize identifier=_identifier; + ++ (instancetype)expressionWithIdentifier:(NSString *)identifier +{ + return [[[self alloc] initWithIdentifier:identifier] autorelease]; +} + +- (void)dealloc +{ + [_identifier release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheIdentifierExpression class]]) { + return NO; + } + return [_identifier isEqual:((GRMustacheIdentifierExpression *)expression).identifier]; +} + +- (NSUInteger)hash +{ + return [_identifier hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitIdentifierExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithIdentifier:(NSString *)identifier +{ + self = [super init]; + if (self) { + _identifier = [identifier retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h new file mode 100644 index 0000000..a72831c --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h @@ -0,0 +1,47 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheIdentifierExpression represents expressions such as + * `identifier`. + */ +@interface GRMustacheIdentifierExpression : GRMustacheExpression { +@private + NSString *_identifier; +} + +@property (nonatomic, retain, readonly) NSString *identifier GRMUSTACHE_API_INTERNAL; + +/** + * Returns an identifier expression, given an identifier. + * + * For example, the Mustache tag `{{ name }}` contains an identifier + * expression, whose identifier is `name`. + * + * @param identifier An identifier + * + * @return A GRMustacheIdentifierExpression. + */ ++ (instancetype)expressionWithIdentifier:(NSString *)identifier GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m new file mode 100644 index 0000000..b28fc78 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +static GRMustacheImplicitIteratorExpression *instance; + +@implementation GRMustacheImplicitIteratorExpression + ++ (void)initialize +{ + instance = [[self alloc] init]; +} + ++ (instancetype)expression +{ + return instance; +} + + +#pragma mark - GRMustacheExpression + +- (BOOL)isEqual:(id)expression +{ + return expression == instance; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitImplicitIteratorExpression:self error:error]; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h new file mode 100644 index 0000000..cd1bd6d --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h @@ -0,0 +1,39 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheImplicitIteratorExpression represents the `.` expression. + */ +@interface GRMustacheImplicitIteratorExpression : GRMustacheExpression + +/** + * Returns an "implicit iterator" expression. + * + * For example, the Mustache tag `{{ . }}` contains an implicit iterator + * expression. + * + * @return A GRMustacheImplicitIteratorExpression. + */ ++ (instancetype)expression GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m new file mode 100644 index 0000000..204d415 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m @@ -0,0 +1,86 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + + +@implementation GRMustacheScopedExpression +@synthesize baseExpression=_baseExpression; +@synthesize identifier=_identifier; + ++ (instancetype)expressionWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier +{ + return [[[self alloc] initWithBaseExpression:baseExpression identifier:identifier] autorelease]; +} + +- (void)dealloc +{ + [_baseExpression release]; + [_identifier release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (void)setToken:(GRMustacheToken *)token +{ + [super setToken:token]; + _baseExpression.token = token; +} + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheScopedExpression class]]) { + return NO; + } + if (![_baseExpression isEqual:((GRMustacheScopedExpression *)expression).baseExpression]) { + return NO; + } + return [_identifier isEqual:((GRMustacheScopedExpression *)expression).identifier]; +} + +- (NSUInteger)hash +{ + return [_baseExpression hash] ^ [_identifier hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitScopedExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier +{ + self = [super init]; + if (self) { + _baseExpression = [baseExpression retain]; + _identifier = [identifier retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h new file mode 100644 index 0000000..282c556 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h @@ -0,0 +1,52 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheScopedExpression represents expressions such as + * `.identifier`. + */ +@interface GRMustacheScopedExpression : GRMustacheExpression { +@private + GRMustacheExpression *_baseExpression; + NSString *_identifier; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *baseExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) NSString *identifier GRMUSTACHE_API_INTERNAL; + +/** + * Returns a scoped expression, given an expression that returns a value, and + * an identifier. + * + * For example, the Mustache tag `{{ person.name }}` contains a scoped + * expression, whose baseExpression is a GRMustacheIdentifierExpression (for the + * identifier `person`), and whose identifier is `name`. + * + * @param baseExpression An expression. + * @param identifier An identifier. + * + * @return A GRMustacheScopedExpression. + */ ++ (instancetype)expressionWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m new file mode 100644 index 0000000..54fb10d --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m @@ -0,0 +1,643 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheCompiler_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheTextNode_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheCompiler() + +/** + * The fatal error that should be returned by the public method + * ASTNodesReturningError:. + * + * @see currentASTNodes + */ +@property (nonatomic, retain) NSError *fatalError; + +/** + * After an opening token has been found such as {{#A}}, {{^B}}, or {{ 0, @"WTF empty GRMustacheTokenTypeContent"); + + // Success: append GRMustacheTextASTNode + [_currentASTNodes addObject:[GRMustacheTextNode textNodeWithText:token.templateSubstring]]; + break; + + + case GRMustacheTokenTypeEscapedVariable: { + // Expression validation + NSError *error; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:NULL error:&error]; + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Success: append GRMustacheVariableTag + expression.token = token; + [_currentASTNodes addObject:[GRMustacheVariableTag variableTagWithExpression:expression escapesHTML:YES contentType:_contentType]]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeUnescapedVariable: { + // Expression validation + NSError *error; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:NULL error:&error]; + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Success: append GRMustacheVariableTag + expression.token = token; + [_currentASTNodes addObject:[GRMustacheVariableTag variableTagWithExpression:expression escapesHTML:NO contentType:_contentType]]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeSectionOpening: { + // Expression validation + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + + if (_currentOpeningToken && + _currentOpeningToken.type == GRMustacheTokenTypeInvertedSectionOpening && + ((expression == nil && empty) || (expression != nil && [expression isEqual:_currentTagValue]))) + { + // We found the "else" close of an inverted section: + // {{^foo}}...{{#}}... + // {{^foo}}...{{#foo}}... + + // Insert a new inverted section and prepare a regular one + + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + GRMustacheSectionTag *sectionTag = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:YES + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + [_ASTNodesStack removeLastObject]; + [[_ASTNodesStack lastObject] addObject:sectionTag]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + } else { + // This is a new regular section + + // Validate expression + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Prepare a new section + + expression.token = token; + self.currentTagValue = expression; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } + } break; + + + case GRMustacheTokenTypeInvertedSectionOpening: { + // Expression validation + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + + if (_currentOpeningToken && + _currentOpeningToken.type == GRMustacheTokenTypeSectionOpening && + ((expression == nil && empty) || (expression != nil && [expression isEqual:_currentTagValue]))) + { + // We found the "else" close of a regular or inheritable section: + // {{#foo}}...{{^}}...{{/foo}} + // {{#foo}}...{{^foo}}...{{/foo}} + + // Insert a new section and prepare an inverted one + + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + GRMustacheSectionTag *sectionTag = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:NO + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + [_ASTNodesStack removeLastObject]; + [[_ASTNodesStack lastObject] addObject:sectionTag]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + } else { + // This is a new inverted section + + // Validate expression + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Prepare a new section + + expression.token = token; + self.currentTagValue = expression; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } + } break; + + + case GRMustacheTokenTypeInheritableSectionOpening: { + // Inheritable section name validation + NSError *inheritableSectionError; + NSString *name = [parser parseInheritableSectionName:token.tagInnerContent empty:NULL error:&inheritableSectionError]; + if (name == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in inheritable section tag", inheritableSectionError.localizedDescription]]]; + return NO; + } + + // Expand stacks + self.currentTagValue = name; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeInheritablePartial: { + // Partial name validation + NSError *partialError; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:NULL error:&partialError]; + if (partialName == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial tag", partialError.localizedDescription]]]; + return NO; + } + + // Expand stacks + self.currentTagValue = partialName; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeClosing: { + if (_currentOpeningToken == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // What are we closing? + + id wrapperASTNode = nil; + switch (_currentOpeningToken.type) { + case GRMustacheTokenTypeSectionOpening: + case GRMustacheTokenTypeInvertedSectionOpening: { + // Expression validation + // We need a valid expression that matches section opening, + // or an empty `{{/}}` closing tags. + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + if (expression == nil && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + NSAssert(_currentTagValue, @"WTF expected _currentTagValue"); + if (expression && ![expression isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // Nothing prevents tokens to come from different template strings. + // We, however, do not support this case, because GRMustacheSectionTag + // builds from a single template string and a single innerRange. + if (_currentOpeningToken.templateString != token.templateString) { + [NSException raise:NSInternalInconsistencyException format:@"Support for tokens coming from different strings is not implemented."]; + } + + // Success: create new GRMustacheSectionTag + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:(_currentOpeningToken.type == GRMustacheTokenTypeInvertedSectionOpening) + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + } break; + + case GRMustacheTokenTypeInheritableSectionOpening: { + // Inheritable section name validation + // We need a valid name that matches section opening, + // or an empty `{{/}}` closing tags. + NSError *error; + BOOL empty; + NSString *name = [parser parseInheritableSectionName:token.tagInnerContent empty:&empty error:&error]; + if (name && ![name isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } else if (!name && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial closing tag", error.localizedDescription]]]; + return NO; + } + + if (name && ![name isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // Success: create new GRMustacheInheritableSection + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheInheritableSectionNode inheritableSectionNodeWithName:(NSString *)_currentTagValue templateAST:templateAST]; + } break; + + case GRMustacheTokenTypeInheritablePartial: { + // Validate token: inheritable template ending should be missing, or match inheritable template opening + NSError *error; + BOOL empty; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:&empty error:&error]; + if (partialName && ![partialName isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } else if (!partialName && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial closing tag", error.localizedDescription]]]; + return NO; + } + + // Ask templateRepository for inheritable template + partialName = (NSString *)_currentTagValue; + GRMustacheTemplateAST *templateAST = [_templateRepository templateASTNamed:partialName relativeToTemplateID:_baseTemplateID error:&error]; + if (templateAST == nil) { + [self failWithFatalError:error]; + return NO; + } + + // Check for consistency of HTML safety + // + // If templateAST.isPlaceholder, this means that we are actually + // compiling it, and that template simply recursively refers to itself. + // Consistency of HTML safety is thus guaranteed. + // + // However, if templateAST.isPlaceholder is false, then we must ensure + // content type compatibility: an HTML template can not override a + // text one, and vice versa. + // + // See test "HTML template can not override TEXT template" in GRMustacheSuites/text_rendering.json + if (!templateAST.isPlaceholder && templateAST.contentType != _contentType) { + [self failWithFatalError:[self parseErrorAtToken:_currentOpeningToken description:@"HTML safety mismatch"]]; + return NO; + } + + // Success: create new GRMustacheInheritablePartialNode + GRMustachePartialNode *partialNode = [GRMustachePartialNode partialNodeWithTemplateAST:templateAST name:partialName]; + GRMustacheTemplateAST *overridingTemplateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheInheritablePartialNode inheritablePartialNodeWithPartialNode:partialNode overridingTemplateAST:overridingTemplateAST]; + } break; + + default: + NSAssert(NO, @"WTF unexpected _currentOpeningToken.type"); + break; + } + + NSAssert(wrapperASTNode, @"WTF expected wrapperASTNode"); + + [_tagValueStack removeLastObject]; + self.currentTagValue = [_tagValueStack lastObject]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = [_openingTokenStack lastObject]; + + [_ASTNodesStack removeLastObject]; + self.currentASTNodes = [_ASTNodesStack lastObject]; + + [_currentASTNodes addObject:wrapperASTNode]; + } break; + + + case GRMustacheTokenTypePartial: { + // Partial name validation + NSError *partialError; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:NULL error:&partialError]; + if (partialName == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial tag", partialError.localizedDescription]]]; + return NO; + } + + // Ask templateRepository for partial template + GRMustacheTemplateAST *templateAST = [_templateRepository templateASTNamed:partialName relativeToTemplateID:_baseTemplateID error:&partialError]; + if (templateAST == nil) { + [self failWithFatalError:partialError]; + return NO; + } + + // Success: append ASTNode + GRMustachePartialNode *partialNode = [GRMustachePartialNode partialNodeWithTemplateAST:templateAST name:partialName]; + [_currentASTNodes addObject:partialNode]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + } + return YES; +} + +- (void)templateParser:(GRMustacheTemplateParser *)parser didFailWithError:(NSError *)error +{ + [self failWithFatalError:error]; +} + +#pragma mark Private + +/** + * This method is called whenever an error has occurred beyond any repair hope. + * + * @param fatalError The fatal error + */ +- (void)failWithFatalError:(NSError *)fatalError +{ + // Make sure ASTNodesReturningError: returns correct results: + self.fatalError = fatalError; + self.currentASTNodes = nil; + + // All those objects are useless, now + self.currentOpeningToken = nil; + self.currentTagValue = nil; + self.ASTNodesStack = nil; + self.openingTokenStack = nil; +} + +/** + * Builds and returns an NSError of domain GRMustacheErrorDomain, code + * GRMustacheErrorCodeParseError, related to a specific location in a template, + * represented by the token argument. + * + * @param token The GRMustacheToken where the parse error has been + * found. + * @param description A NSString that fills the NSLocalizedDescriptionKey key + * of the error's userInfo. + * + * @return An NSError + */ +- (NSError *)parseErrorAtToken:(GRMustacheToken *)token description:(NSString *)description +{ + NSString *localizedDescription; + if (token.templateID) { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu of template %@: %@", (unsigned long)token.line, token.templateID, description]; + } else { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu: %@", (unsigned long)token.line, description]; + } + return [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:localizedDescription forKey:NSLocalizedDescriptionKey]]; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h new file mode 100644 index 0000000..60133c3 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h @@ -0,0 +1,115 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateParser_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheTemplateRepository; +@class GRMustacheTemplateAST; + +/** + * The GRMustacheCompiler interprets GRMustacheTokens provided by a + * GRMustacheTemplateParser, and outputs a syntax tree of objects conforming to + * the GRMustacheTemplateASTNode protocol. + * + * @see GRMustacheTemplateASTNode + * @see GRMustacheToken + * @see GRMustacheTemplateParser + */ +@interface GRMustacheCompiler : NSObject { +@private + NSError *_fatalError; + + NSMutableArray *_currentASTNodes; + NSMutableArray *_ASTNodesStack; + + GRMustacheToken *_currentOpeningToken; + NSMutableArray *_openingTokenStack; + + NSObject *_currentTagValue; + NSMutableArray *_tagValueStack; + + GRMustacheTemplateRepository *_templateRepository; + id _baseTemplateID; + GRMustacheContentType _contentType; + BOOL _contentTypeLocked; +} + +/** + * The template repository that provides partial templates to the compiler. + */ +@property (nonatomic, assign) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_INTERNAL; + +/** + * ID of the currently compiled template + */ +@property (nonatomic, retain) id baseTemplateID GRMUSTACHE_API_INTERNAL; + +/** + * Returns an initialized compiler. + * + * @param contentType The contentType that affects the compilation phase. + * + * @return a compiler + */ +- (instancetype)initWithContentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +/** + * Returns a Mustache Abstract Syntax Tree. + * + * The AST will contain something if a GRMustacheTemplateParser has provided + * GRMustacheToken instances to the compiler. + * + * For example: + * + * ``` + * // Create a Mustache compiler + * GRMustacheCompiler *compiler = [[[GRMustacheCompiler alloc] initWithContentType:...] autorelease]; + * + * // Some GRMustacheCompilerDataSource tells the compiler where are the + * // partials. + * compiler.dataSource = ...; + * + * // Create a Mustache parser + * GRMustacheTemplateParser *parser = [[[GRMustacheTemplateParser alloc] initWithContentType:...] autorelease]; + * + * // The parser feeds the compiler + * parser.delegate = compiler; + * + * // Parse some string + * [parser parseTemplateString:... templateID:...]; + * + * // Extract template ASTNodes from the compiler + * GRMustacheTemplateAST *templateAST = [compiler templateASTReturningError:...]; + * ``` + * + * @param error If there is an error building the abstract syntax tree, upon + * return contains an NSError object that describes the problem. + * + * @return A GRMustacheTemplateAST instance + * + * @see GRMustacheTemplateAST + */ +- (GRMustacheTemplateAST *)templateASTReturningError:(NSError **)error GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m new file mode 100644 index 0000000..7ba077a --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m @@ -0,0 +1,74 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheInheritablePartialNode +@synthesize overridingTemplateAST=_overridingTemplateAST; +@synthesize partialNode=_partialNode; + ++ (instancetype)inheritablePartialNodeWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST +{ + return [[[self alloc] initWithPartialNode:partialNode overridingTemplateAST:overridingTemplateAST] autorelease]; +} + +- (void)dealloc +{ + [_partialNode release]; + [_overridingTemplateAST release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheTemplateASTNode + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitInheritablePartialNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // look for the last inheritable ASTNode in inner templateAST + for (id innerASTNode in _overridingTemplateAST.templateASTNodes) { + templateASTNode = [innerASTNode resolveTemplateASTNode:templateASTNode]; + } + return templateASTNode; +} + + +#pragma mark - Private + +- (instancetype)initWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST +{ + self = [super init]; + if (self) { + _partialNode = [partialNode retain]; + _overridingTemplateAST = [overridingTemplateAST retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h new file mode 100644 index 0000000..1dcc424 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustachePartialNode; +@class GRMustacheTemplateAST; + +/** + * A GRMustacheInheritablePartialNode is an AST node that represents inheritable + * partials as `{{ { +@private + GRMustachePartialNode *_partialNode; + GRMustacheTemplateAST *_overridingTemplateAST; +} + +/** + * The overriding AST, built from the inner content of the inheritable partial + * node: + * + * {{< ... }} AST {{/ }} + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *overridingTemplateAST GRMUSTACHE_API_INTERNAL; + +/** + * The partial template that is inherited: + * + * {{< inherited_partial_template }}...{{/ }} + */ +@property (nonatomic, retain, readonly) GRMustachePartialNode *partialNode GRMUSTACHE_API_INTERNAL; + +/** + * Builds a GRMustacheInheritablePartialNode. + * + * @param partialNode The inherited partial. + * @param templateAST The AST that overrides the inherited partial template. + * + * @return A GRMustacheInheritablePartialNode + */ ++ (instancetype)inheritablePartialNodeWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m new file mode 100644 index 0000000..fbb7e26 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m @@ -0,0 +1,80 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheInheritableSectionNode +@synthesize name=_name; +@synthesize templateAST=_templateAST; + ++ (instancetype)inheritableSectionNodeWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST +{ + return [[[self alloc] initWithName:name templateAST:templateAST] autorelease]; +} + +- (void)dealloc +{ + [_name release]; + [_templateAST release]; + [super dealloc]; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitInheritableSectionNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // Inheritable section can only override inheritable section + if (![templateASTNode isKindOfClass:[GRMustacheInheritableSectionNode class]]) { + return templateASTNode; + } + GRMustacheInheritableSectionNode *otherSection = (GRMustacheInheritableSectionNode *)templateASTNode; + + // names must match + if (![otherSection.name isEqual:_name]) { + return otherSection; + } + + // OK, override with self + return self; +} + + +#pragma mark - Private + +- (instancetype)initWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST +{ + self = [self init]; + if (self) { + _name = [name retain]; + _templateAST = [templateAST retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h new file mode 100644 index 0000000..eb75fd4 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheTemplateAST; + +/** + * A GRMustacheInheritableSection is an AST node that represents inheritable + * sections as `{{$name}}...{{/name}}`. + */ +@interface GRMustacheInheritableSectionNode : NSObject { +@private + NSString *_name; + GRMustacheTemplateAST *_templateAST; +} + +/** + * The AST of the inner content of the section + * + * {{$ ... }} AST {{/ }} + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + +/** + * The name of the inheritable section: + * + * {{$ name }} ... {{/ }} + */ +@property (nonatomic, readonly) NSString *name GRMUSTACHE_API_INTERNAL; + +/** + * Returns a new inheritable section. + * + * @param name The name of the inheritable section + * @param templateAST The AST of the inner content of the section + * + * @return a new GRMustacheInheritableSection. + * + * @see GRMustacheTemplateASTNode + */ ++ (instancetype)inheritableSectionNodeWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m new file mode 100644 index 0000000..fe9963b --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m @@ -0,0 +1,85 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + + +@implementation GRMustachePartialNode +@synthesize templateAST=_templateAST; +@synthesize name=_name; + +- (void)dealloc +{ + [_templateAST release]; + [_name release]; + [super dealloc]; +} + ++ (instancetype)partialNodeWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name +{ + return [[[self alloc] initWithTemplateAST:templateAST name:name] autorelease]; +} + +#pragma mark + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitPartialNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // Look for the last inheritable node in inner nodes. + // + // This allows a partial do define an inheritable section: + // + // { + // data: { }, + // expected: "partial1", + // name: "Partials in inheritable partials can override inheritable sections", + // template: "{{partial1}}{{/partial2}}" + // partials: { + // partial1: "{{$inheritable}}partial1{{/inheritable}}"; + // partial2: "{{$inheritable}}ignored{{/inheritable}}"; + // }, + // } + for (id innerASTNode in _templateAST.templateASTNodes) { + templateASTNode = [innerASTNode resolveTemplateASTNode:templateASTNode]; + } + return templateASTNode; +} + +#pragma mark - Private + +- (instancetype)initWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name +{ + self = [self init]; + if (self) { + _templateAST = [templateAST retain]; + _name = [name retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h new file mode 100644 index 0000000..7cff6cb --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h @@ -0,0 +1,59 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheTemplateAST; + +/** + * A GRMustachePartialNode is an AST node that represents partial tags as + * `{{>name}}`. + */ +@interface GRMustachePartialNode : NSObject { +@private + NSString *_name; + GRMustacheTemplateAST *_templateAST; +} + +/** + * The name of the partial: + * + * {{> name }} + */ +@property (nonatomic, retain, readonly) NSString *name GRMUSTACHE_API_INTERNAL; + +/** + * The abstract syntax tree of the partial template. + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + +/** + * Returns a newly created partial node. + * + * @param templateAST The abstract syntax tree of the partial template. + * @param name The name of the partial template. + * + * @return a newly created partial node. + */ ++ (instancetype)partialNodeWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m new file mode 100644 index 0000000..082ac1f --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m @@ -0,0 +1,100 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheRenderingEngine_private.h" + +@implementation GRMustacheSectionTag +@synthesize expression=_expression; +@synthesize templateAST=_templateAST; +@synthesize inverted=_inverted; + +- (void)dealloc +{ + [_expression release]; + [_templateString release]; + [_templateAST release]; + [super dealloc]; +} + ++ (instancetype)sectionTagWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST +{ + return [[[self alloc] initWithExpression:expression inverted:inverted templateString:templateString innerRange:innerRange templateAST:templateAST] autorelease]; +} + + +#pragma mark - GRMustacheTag + +- (NSString *)description +{ + GRMustacheToken *token = _expression.token; + if (token.templateID) { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu of template %@>", [self class], token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu>", [self class], token.templateSubstring, (unsigned long)token.line]; + } +} + +- (NSString *)innerTemplateString +{ + return [_templateString substringWithRange:_innerRange]; +} + +- (GRMustacheTagType)type +{ + return GRMustacheTagTypeSection; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + GRMustacheRenderingEngine *renderingEngine = [GRMustacheRenderingEngine renderingEngineWithContentType:_templateAST.contentType context:context]; + return [renderingEngine renderTemplateAST:_templateAST HTMLSafe:HTMLSafe error:error]; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitSectionTag:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST +{ + self = [super init]; + if (self) { + _expression = [expression retain]; + _inverted = inverted; + _templateString = [templateString retain]; + _innerRange = innerRange; + _templateAST = [templateAST retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h new file mode 100644 index 0000000..094e1ce --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h @@ -0,0 +1,66 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheExpression; +@class GRMustacheTemplateAST; + +@interface GRMustacheSectionTag : GRMustacheTag { +@private + GRMustacheExpression *_expression; + BOOL _inverted; + NSString *_templateString; + NSRange _innerRange; + GRMustacheTemplateAST *_templateAST; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + + +/** + * Builds a GRMustacheSectionTag. + * + * The rendering of Mustache sections depend on the value they are attached to. + * The value is fetched by evaluating the _expression_ parameter against a + * rendering context. + * + * The templateAST describes the inner content of the section + * + * @param expression The expression that would evaluate against a + * rendering context. + * @param inverted NO for {{# section }}, YES for {{^ section }}. + * @param templateString A Mustache template string. + * @param innerRange The range of the inner template string of the + * section in _templateString_. + * @param templateAST The AST of the inner content of the section. + * + * @return A GRMustacheSectionTag + * + * @see GRMustacheExpression + */ ++ (instancetype)sectionTagWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h new file mode 100644 index 0000000..cc67aa0 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h @@ -0,0 +1,150 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheTemplateRepository; + +/** + * The types of Mustache tags + * + * @since v6.0 + */ +typedef NS_ENUM(NSUInteger, GRMustacheTagType) { + /** + * The type for variable tags such as `{{name}}`. + * + * @since v6.0 + */ + GRMustacheTagTypeVariable = 1 << 1 AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER, + + /** + * The type for regular and inverted section tags, such as + * `{{#name}}...{{/name}}` and `{{#name}}...{{/name}}`. + * + * @since v6.0 + */ + GRMustacheTagTypeSection = 1 << 2 AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER, + +} AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The type for inverted section tags such as {{^ name }}...{{/}} + * + * This value is deprecated. + * + * @since v6.0 + * @deprecated v7.2 + */ +AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED_IN_GRMUSTACHE_VERSION_7_2 static GRMustacheTagType const GRMustacheTagTypeInvertedSection = 1 << 3; + +/** + * GRMustacheTag instances represent Mustache tags that render values, such as + * a variable tag `{{ name }}`, or a section tag `{{# name }}...{{/ })`. + * + * **Companion guides:** + * + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + */ +@interface GRMustacheTag: NSObject + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Tag Information +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The type of the tag + */ +@property (nonatomic, readonly) GRMustacheTagType type AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the literal and unprocessed inner content of the tag. + * + * A section tag such as `{{# name }}inner content{{/}}` returns `inner content`. + * + * Variable tags such as `{{ name }}` have no inner content: their inner + * template string is the empty string. + */ +@property (nonatomic, readonly) NSString *innerTemplateString AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the description of the tag. + * + * For example: + * + * ``` + * + * ``` + */ +- (NSString *)description; + +//////////////////////////////////////////////////////////////////////////////// +/// @name Methods Dedicated to the GRMustacheRendering Protocol +//////////////////////////////////////////////////////////////////////////////// + +/** + * This method is deprecated. + * + * Replace `[tag.templateRepository templateFromString:... error:...]` with + * `[GRMustacheTemplate templateFromString:... error:...]`. + * + * Replace `[tag.templateRepository templateNamed:... error:...]` with explicit + * invocation of the targeted template repository. + * + * @since v6.0 + * @deprecated v7.0 + */ +@property (nonatomic, readonly) GRMustacheTemplateRepository *templateRepository AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +/** + * Returns the rendering of the tag's inner content, rendering all inner + * Mustache tags with the rendering context argument. + * + * This method is intended for objects conforming to the GRMustacheRendering + * protocol. The following Guides show some use cases for this method: + * + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * + * Note that variable tags such as `{{ name }}` have no inner content, and + * return the empty string. + * + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES or NO, depending on the content + * type of the tag's template, as set by the configuration of + * the source template repository. HTML templates yield YES, + * text templates yield NO. + * @param error If there is an error rendering the tag, upon return contains + * an NSError object that describes the problem. + * + * @see GRMustacheRendering + * @see GRMustacheContext + * + * @return The rendering of the tag's inner content. + */ +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m new file mode 100644 index 0000000..8491c88 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m @@ -0,0 +1,72 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheTag_private.h" +#import "GRMustacheRendering_private.h" + +@implementation GRMustacheTag + +- (GRMustacheTagType)type +{ + [self doesNotRecognizeSelector:_cmd]; + return 0; +} + +- (GRMustacheTemplateRepository *)templateRepository +{ + return [GRMustacheRendering currentTemplateRepository]; +} + +- (NSString *)innerTemplateString +{ + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (BOOL)isInverted +{ + [self doesNotRecognizeSelector:_cmd]; + return NO; +} + +#pragma mark - + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + [self doesNotRecognizeSelector:_cmd]; + return NO; +} + +@end + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h new file mode 100644 index 0000000..0485c73 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h @@ -0,0 +1,56 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheContext; +@class GRMustacheTemplateRepository; + +// Documented in GRMustacheTag.h +typedef NS_ENUM(NSUInteger, GRMustacheTagType) { + GRMustacheTagTypeVariable = 1 << 1 GRMUSTACHE_API_PUBLIC, + GRMustacheTagTypeSection = 1 << 2 GRMUSTACHE_API_PUBLIC, +} GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@interface GRMustacheTag: NSObject + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) GRMustacheTagType type GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) NSString *innerTemplateString GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +// Documented in GRMustacheTag.h +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +/** + * TODO + */ +@property (nonatomic, readonly, getter=isInverted) BOOL inverted GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m new file mode 100644 index 0000000..5904da4 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m @@ -0,0 +1,76 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheTemplateAST +@synthesize templateASTNodes=_templateASTNodes; +@synthesize contentType=_contentType; + +- (void)dealloc +{ + [_templateASTNodes release]; + [super dealloc]; +} + ++ (instancetype)placeholderAST +{ + return [[[self alloc] initWithASTNodes:nil contentType:GRMustacheContentTypeHTML] autorelease]; +} + ++ (instancetype)templateASTWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType +{ + NSAssert(templateASTNodes, @"nil templateASTNodes"); + return [[[self alloc] initWithASTNodes:templateASTNodes contentType:contentType] autorelease]; +} + +- (BOOL)isPlaceholder +{ + return (_templateASTNodes == nil); +} + +- (instancetype)initWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType +{ + self = [super init]; + if (self) { + _templateASTNodes = [templateASTNodes retain]; + _contentType = contentType; + } + return self; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitTemplateAST:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h new file mode 100644 index 0000000..b600cd0 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h @@ -0,0 +1,75 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@class GRMustacheExpression; + +/** + * The protocol for AST nodes. + * + * When parsing a Mustache template, GRMustacheCompiler builds an abstract + * tree of objects representing raw text and various mustache tags. + * + * This abstract tree is made of objects conforming to the + * GRMustacheTemplateASTNode protocol. + * + * For example, the template string "hello {{name}}!" would give four AST nodes: + * + * - a GRMustacheTextNode that renders "hello ". + * - a GRMustacheVariableTag that renders the value of the `name` key in the + * rendering context. + * - a GRMustacheTextNode that renders "!". + * - a GRMustachePartialNode that would contain the three previous nodes. + * + * @see GRMustacheCompiler + * @see GRMustacheContext + */ +@protocol GRMustacheTemplateASTNode +@required + +/** + * Has the visitor visit the receiver. + */ +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * In the context of template inheritance, return the AST node that should be + * rendered in lieu of the node argument. + * + * All classes conforming to the GRMustacheTemplateASTNode protocol return + * the node argument, but GRMustacheInheritableSectionNode and + * GRMustacheInheritablePartialNode. + * + * @param ASTNode A node + * + * @return The resolution of the node in the context of Mustache template + * inheritance. + * + * @see GRMustacheSectionTag + * @see GRMustacheTemplate + * @see GRMustacheInheritablePartialNode + */ +- (id)resolveTemplateASTNode:(id)templateASTNode GRMUSTACHE_API_INTERNAL; +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h new file mode 100644 index 0000000..13e7976 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h @@ -0,0 +1,45 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheTemplateAST; +@class GRMustacheInheritablePartialNode; +@class GRMustacheInheritableSectionNode; +@class GRMustachePartialNode; +@class GRMustacheVariableTag; +@class GRMustacheSectionTag; +@class GRMustacheTextNode; + +@protocol GRMustacheTemplateASTVisitor + +// Don't use these methods directly. Use -[ +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +/** + * The GRMustacheTemplateAST represents the abstract syntax tree of a template. + */ +@interface GRMustacheTemplateAST : NSObject { +@private + NSArray *_templateASTNodes; + GRMustacheContentType _contentType; +} + +/** + * An NSArray containing instances + * + * @see GRMustacheTemplateASTNode + */ +@property (nonatomic, retain) NSArray *templateASTNodes GRMUSTACHE_API_INTERNAL; + +/** + * The content type of the AST + */ +@property (nonatomic) GRMustacheContentType contentType GRMUSTACHE_API_INTERNAL; + +/** + * Used by GRMustacheTemplateRepository, which uses placeholder ASTs when + * building recursive templates. + */ +@property (nonatomic, readonly, getter = isPlaceholder) BOOL placeholder GRMUSTACHE_API_INTERNAL; + +/** + * Returns a new allocated AST. + * + * @param templateASTNodes An array of instances. + * @param contentType A content type + * + * @return A new GRMustacheTemplateAST + * + * @see GRMustacheTemplateASTNode + */ ++ (instancetype)templateASTWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +/** + * Returns a placeholder AST + * @see placeholder + */ ++ (instancetype)placeholderAST GRMUSTACHE_API_INTERNAL; + +@end + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m new file mode 100644 index 0000000..52a0a36 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m @@ -0,0 +1,70 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTextNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheTextNode + ++ (instancetype)textNodeWithText:(NSString *)text +{ + return [[[self alloc] initWithText:text] autorelease]; +} + +- (void)dealloc +{ + [_text release]; + [super dealloc]; +} + +- (NSString *)text +{ + return _text; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitTextNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + + +#pragma mark - Private + +- (instancetype)initWithText:(NSString *)text +{ + NSAssert(text, @"WTF"); + self = [self init]; + if (self) { + _text = [text retain]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h new file mode 100644 index 0000000..7b226a5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h @@ -0,0 +1,50 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +/** + * A GRMustacheTextNode is an AST node that represents raw text. + */ +@interface GRMustacheTextNode: NSObject { +@private + NSString *_text; +} + +/** + * The text of the text node. + */ +@property (nonatomic, retain, readonly) NSString *text GRMUSTACHE_API_INTERNAL; + +/** + * Builds and returns a GRMustacheTextNode. + * + * @param string The string that should be rendered. + * @return a GRMustacheTextNode + */ ++ (instancetype)textNodeWithText:(NSString *)string GRMUSTACHE_API_INTERNAL; + +@end + + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m new file mode 100644 index 0000000..bbe6ae1 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m @@ -0,0 +1,100 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" + +@implementation GRMustacheVariableTag +@synthesize expression=_expression; +@synthesize escapesHTML=_escapesHTML; + +- (void)dealloc +{ + [_expression release]; + [super dealloc]; +} + ++ (instancetype)variableTagWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType +{ + return [[[self alloc] initWithExpression:expression escapesHTML:escapesHTML contentType:contentType] autorelease]; +} + + +#pragma mark - GRMustacheTag + +- (NSString *)description +{ + GRMustacheToken *token = _expression.token; + if (token.templateID) { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu of template %@>", [self class], token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu>", [self class], token.templateSubstring, (unsigned long)token.line]; + } +} + +- (GRMustacheTagType)type +{ + return GRMustacheTagTypeVariable; +} + +- (BOOL)isInverted +{ + return NO; +} + +- (NSString *)innerTemplateString +{ + return @""; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + if (HTMLSafe) { + *HTMLSafe = (_contentType == GRMustacheContentTypeHTML); + } + return @""; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitVariableTag:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType +{ + self = [super init]; + if (self) { + _expression = [expression retain]; + _escapesHTML = escapesHTML; + _contentType = contentType; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h new file mode 100644 index 0000000..8d78038 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheExpression; + +@interface GRMustacheVariableTag : GRMustacheTag { +@private + GRMustacheExpression *_expression; + BOOL _escapesHTML; + GRMustacheContentType _contentType; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, readonly) BOOL escapesHTML GRMUSTACHE_API_INTERNAL; + +/** + * Builds and returns a GRMustacheVariableTag. + * + * @param expression The expression that would evaluate against a rendering + * contex. + * @param escapesHTML YES if the value should be escaped. + * @param contentType The content type of the tag rendering. + * + * @return a GRMustacheVariableTag + * + * @see GRMustacheExpression + */ ++ (instancetype)variableTagWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h new file mode 100644 index 0000000..2d061ae --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h @@ -0,0 +1,296 @@ +// The MIT License +// +// Copyright (c) 2013 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheContentType.h" + +@class GRMustacheContext; +@protocol GRMustacheTagDelegate; + +/** + * A GRMustacheConfiguration instance configures GRMustache rendering. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/configuration.md + * + * The default configuration [GRMustacheConfiguration defaultConfiguration] + * applies to all GRMustache rendering by default: + * + * ``` + * // Have GRMustache templates render text by default, + * // and do not HTML-escape their input. + * [GRMustacheConfiguration defaultConfiguration].contentType = GRMustacheContentTypeText; + * ``` + * + * You can also alter the configuration of a specific template repository: its + * configuration only applies to the templates built by this very template + * repository: + * + * ``` + * // All templates loaded from _repo_ will use [[ and ]] as tag delimiters. + * GRMustacheTemplateRepository *repo = [GRMustacheTemplateRepository templateRepositoryWithBundle:nil]; + * repo.configuration.tagStartDelimiter = @"[["; + * repo.configuration.tagEndDelimiter = @"]]"; + * ``` + * + * A third option is to create a new configuration, and assign it to the template: + * + * ``` + * // Create a configuration + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration configuration]; + * configuration.... // setup + * + * GRMustacheTemplateRepository *repo = [GRMustacheTemplateRepository templateRepositoryWithBundle:nil]; + * repo.configuration = configuration; + * ``` + * + * The `contentType` option can be specified at the template level, so that your + * repositories can mix HTML and text templates: see the documentation of this + * property. + * + * The `tagStartDelimiter` and `tagEndDelimiter` options can also be specified + * at the template level, using a "Set Delimiters tag": see the documentation of + * these properties. + * + * @see GRMustacheTemplateRepository + * + * @since v6.2 + */ +@interface GRMustacheConfiguration : NSObject { +@private + GRMustacheContentType _contentType; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + GRMustacheContext *_baseContext; + BOOL _locked; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Default Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The default configuration. + * + * All templates and template repositories use the default configuration unless + * you specify otherwise by setting the configuration of a template repository. + * + * The "default" defaultConfiguration has GRMustacheContentTypeHTML contentType, + * and {{ and }} as tag delimiters. + * + * @returns The default configuration. + * + * @since v6.2 + */ ++ (GRMustacheConfiguration *)defaultConfiguration AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * @returns A new factory configuration. + * + * Its contentType is GRMustacheContentTypeHTML. + * Its tag delimiters are {{ and }}. + * + * @since v6.2 + */ ++ (GRMustacheConfiguration *)configuration AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Set Up Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The base context for templates rendering. The default base context contains + * the GRMustache standard Library. + * + * @see GRMustacheTemplate + * + * @since v6.4 + */ +@property (nonatomic, retain) GRMustacheContext *baseContext AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Extends the base context of the receiver with the provided object, making its + * keys available for all renderings. + * + * For example: + * + * ``` + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration defaultConfiguration]; + * + * // Have the `name` key defined for all template renderings: + * id object = @{ @"name": @"Arthur" }; + * [configuration extendBaseContextWithObject:object]; + * + * // Renders "Arthur" + * [GRMustacheTemplate renderObject:nil fromString:@"{{name}}" error:NULL]; + * ``` + * + * Keys defined by _object_ can be overriden by other objects that will + * eventually enter the context stack: + * + * ``` + * // Renders "Billy", not "Arthur" + * [GRMustacheTemplate renderObject:nil:@{ @"name": @"Billy" } fromString:@"{{name}}" error:NULL]; + * ``` + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingObject:object]; + * ``` + * + * @param object An object + * + * @see baseContext + * @see extendBaseContextWithProtectedObject: + * @see extendBaseContextWithTagDelegate: + * + * @since v6.8 + */ +- (void)extendBaseContextWithObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Extends the base context of the receiver with the provided object, making its + * keys available for all renderings. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * For example: + * + * ``` + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration defaultConfiguration]; + * + * // The `precious` key is given priority: + * [configuration extendBaseContextWithProtectedObject:@{ @"precious": @"gold" }]; + * + * // Renders "gold", not "lead". + * [GRMustacheTemplate renderObject:nil:@{ @"precious": @"lead" } fromString:@"{{precious}}" error:NULL]; + * ``` + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingProtectedObject:object]; + * ``` + * + * @param object An object + * + * @see baseContext + * @see extendBaseContextWithObject: + * @see extendBaseContextWithTagDelegate: + * + * @since v6.8 + */ +- (void)extendBaseContextWithProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER;; + +/** + * Extends the base context of the receiver with a tag delegate, making it aware + * of the rendering of all template tags. + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingTagDelegate:tagDelegate]; + * ``` + * + * @param tagDelegate A tag delegate + * + * @see baseContext + * @see extendBaseContextWithObject: + * @see extendBaseContextWithProtectedObject: + * + * @since v6.8 + */ +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER;; + +/** + * The content type of strings rendered by templates. + * + * This property affects the HTML-escaping of your data, and the inclusion + * of templates in other templates. + * + * The `GRMustacheContentTypeHTML` content type has templates render HTML. + * This is the default behavior. HTML template escape the input of variable tags + * such as `{{name}}`. Use triple mustache tags `{{{content}}}` in order to + * avoid the HTML-escaping. + * + * The `GRMustacheContentTypeText` content type has templates render text. + * They do not HTML-escape their input: `{{name}}` and `{{{name}}}` have + * identical renderings. + * + * GRMustache safely keeps track of the content type of templates: should a HTML + * template embed a text template, the content of the text template would be + * HTML-escaped. + * + * There is no API to specify the content type of individual templates. However, + * you can use pragma tags right in the content of your templates: + * + * - `{{% CONTENT_TYPE:TEXT }}` turns a template into a text template. + * - `{{% CONTENT_TYPE:HTML }}` turns a template into a HTML template. + * + * Insert those pragma tags early in your templates. For example: + * + * ``` + * {{! This template renders a bash script. }} + * {{% CONTENT_TYPE:TEXT }} + * export LANG={{ENV.LANG}} + * ... + * ``` + * + * Should two such pragmas be found in a template content, the last one wins. + * + * @since v6.2 + */ +@property (nonatomic) GRMustacheContentType contentType AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The opening delimiter for Mustache tags. Its default value is `{{`. + * + * You can also change the delimiters right in your templates using a "Set + * Delimiter tag": {{=[[ ]]=}} changes start and end delimiters to [[ and ]]. + * + * @since v6.4 + */ +@property (nonatomic, copy) NSString *tagStartDelimiter AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The closing delimiter for Mustache tags. Its default value is `}}`. + * + * You can also change the delimiters right in your templates using a "Set + * Delimiter tag": {{=[[ ]]=}} changes start and end delimiters to [[ and ]]. + * + * @since v6.4 + */ +@property (nonatomic, copy) NSString *tagEndDelimiter AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m new file mode 100644 index 0000000..0f09254 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m @@ -0,0 +1,165 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheConfiguration_private.h" +#import "GRMustache_private.h" +#import "GRMustacheContext_private.h" + +@implementation GRMustacheConfiguration +@synthesize contentType=_contentType; +@synthesize tagStartDelimiter=_tagStartDelimiter; +@synthesize tagEndDelimiter=_tagEndDelimiter; +@synthesize baseContext=_baseContext; +@synthesize locked=_locked; + ++ (GRMustacheConfiguration *)defaultConfiguration +{ + static GRMustacheConfiguration *defaultConfiguration; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultConfiguration = [[GRMustacheConfiguration alloc] init]; + }); + return defaultConfiguration; +} + ++ (GRMustacheConfiguration *)configuration +{ + return [[[GRMustacheConfiguration alloc] init] autorelease]; +} + +- (void)dealloc +{ + [_tagStartDelimiter release]; + [_tagEndDelimiter release]; + [_baseContext release]; + [super dealloc]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _contentType = GRMustacheContentTypeHTML; + _tagStartDelimiter = [@"{{" retain]; // useless retain that matches the release in dealloc + _tagEndDelimiter = [@"}}" retain]; // useless retain that matches the release in dealloc + _baseContext = [[GRMustacheContext contextWithObject:[GRMustache standardLibrary]] retain]; + } + return self; +} + +- (void)lock +{ + _locked = YES; +} + +- (void)setContentType:(GRMustacheContentType)contentType +{ + [self assertNotLocked]; + + _contentType = contentType; +} + +- (void)setTagStartDelimiter:(NSString *)tagStartDelimiter +{ + [self assertNotLocked]; + + if (tagStartDelimiter.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Invalid tagStartDelimiter:%@", tagStartDelimiter]; + return; + } + + if (_tagStartDelimiter != tagStartDelimiter) { + [_tagStartDelimiter release]; + _tagStartDelimiter = [tagStartDelimiter copy]; + } +} + +- (void)setTagEndDelimiter:(NSString *)tagEndDelimiter +{ + [self assertNotLocked]; + + if (tagEndDelimiter.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Invalid tagEndDelimiter:%@", tagEndDelimiter]; + return; + } + + if (_tagEndDelimiter != tagEndDelimiter) { + [_tagEndDelimiter release]; + _tagEndDelimiter = [tagEndDelimiter copy]; + } +} + +- (void)setBaseContext:(GRMustacheContext *)baseContext +{ + [self assertNotLocked]; + + if (!baseContext) { + [NSException raise:NSInvalidArgumentException format:@"Invalid baseContext:nil"]; + return; + } + + if (_baseContext != baseContext) { + [_baseContext release]; + _baseContext = [baseContext retain]; + } +} + +- (void)extendBaseContextWithObject:(id)object +{ + self.baseContext = [self.baseContext contextByAddingObject:object]; +} + +- (void)extendBaseContextWithProtectedObject:(id)object +{ + self.baseContext = [self.baseContext contextByAddingProtectedObject:object]; +} + +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate +{ + self.baseContext = [self.baseContext contextByAddingTagDelegate:tagDelegate]; +} + + +#pragma mark - + +- (id)copyWithZone:(NSZone *)zone +{ + GRMustacheConfiguration *configuration = [[GRMustacheConfiguration alloc] init]; + configuration.contentType = _contentType; + configuration.tagStartDelimiter = _tagStartDelimiter; + configuration.tagEndDelimiter = _tagEndDelimiter; + configuration.baseContext = _baseContext; + // Do not copy the _locked flag, so that the copy is mutable. + return configuration; +} + + +#pragma mark - Private + +- (void)assertNotLocked +{ + if (_locked) { + [NSException raise:NSGenericException format:@"%@ was mutated after template compilation", self]; + } +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h new file mode 100644 index 0000000..e2c155b --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h @@ -0,0 +1,88 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheContext; +@protocol GRMustacheTagDelegate; + +// Documented in GRMustacheConfiguration.h +@interface GRMustacheConfiguration : NSObject { +@private + GRMustacheContentType _contentType; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + GRMustacheContext *_baseContext; + BOOL _locked; +} + + +// Documented in GRMustacheConfiguration.h ++ (GRMustacheConfiguration *)defaultConfiguration GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h ++ (GRMustacheConfiguration *)configuration GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic) GRMustacheContentType contentType GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, copy) NSString *tagStartDelimiter GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, copy) NSString *tagEndDelimiter GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, retain) GRMustacheContext *baseContext GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +/** + * Whether the receiver is locked or not. + * + * @see lock + */ +@property (nonatomic, getter = isLocked, readonly) BOOL locked GRMUSTACHE_API_INTERNAL; + +/** + * Locks the receiver. + * + * A locked configuration raises an exception when the user attempts to mutate + * it. It is in effect an immutable object. + * + * The goal is to prevent the user to build template and alter the configuration + * afterwards. + * + * @see locked + */ +- (void)lock GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.h new file mode 100644 index 0000000..df385a1 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.h @@ -0,0 +1,174 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@protocol GRMustacheRendering; +@class GRMustacheTag; +@class GRMustacheContext; + +/** + * A C struct that hold GRMustache version information + * + * @since v1.0 + */ +typedef struct { + int major; /**< The major component of the version. */ + int minor; /**< The minor component of the version. */ + int patch; /**< The patch-level component of the version. */ +} GRMustacheVersion; + + +/** + * The GRMustache class provides with global-level information and configuration + * of the GRMustache library. + * + * @since v1.0 + */ +@interface GRMustache: NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Getting the GRMustache version +//////////////////////////////////////////////////////////////////////////////// + +/** + * @return The version of GRMustache as a GRMustacheVersion struct. + * + * @since v7.0 + */ ++ (GRMustacheVersion)libraryVersion AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Preventing NSUndefinedKeyException in Development configuration +//////////////////////////////////////////////////////////////////////////////// + +/** + * Have GRMustache avoid most `NSUndefinedKeyExceptions` when rendering + * templates. + * + * The rendering of a GRMustache template can lead to `NSUndefinedKeyExceptions` + * to be raised, because of the usage of the `valueForKey:` method. Those + * exceptions are nicely handled by GRMustache, and are part of the regular + * rendering of a template. + * + * Unfortunately, Objective-C exceptions have several drawbacks, particularly: + * + * 1. they play badly with autorelease pools, and are reputed to leak memory. + * 2. they usually stop your debugger when you are developping your application. + * + * The first point is indeed a matter of worry: Apple does not guarantee that + * exceptions raised by `valueForKey:` do not leak memory. However, I never had + * any evidence of such a leak from NSObject's implementation. + * + * Should you still worry, we recommend that you avoid the `valueForKey:` method + * altogether. Instead, implement the [keyed subscripting](http://clang.llvm.org/docs/ObjectiveCLiterals.html#dictionary-style-subscripting) + * `objectForKeyedSubscript:` method on objects that you provide to GRMustache. + * + * The second point is valid also: NSUndefinedKeyException raised by template + * rendering may become a real annoyance when you are debugging your project, + * because it's likely you've told your debugger to stop on every Objective-C + * exceptions. + * + * You can avoid them as well: make sure you invoke once, early in your + * application, the `preventNSUndefinedKeyExceptionAttack` method. + * + * Depending on the number of NSUndefinedKeyException that get prevented, you + * will experience a slight performance hit, or a performance improvement. + * + * Since the main use case for this method is to avoid Xcode breaks on rendering + * exceptions, the best practice is to conditionally invoke this method, using + * the [NS_BLOCK_ASSERTIONS](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html) + * that helps identifying the Debug configuration of your targets: + * + * ``` + * #if !defined(NS_BLOCK_ASSERTIONS) + * // Debug configuration: keep GRMustache quiet + * [GRMustache preventNSUndefinedKeyExceptionAttack]; + * #endif + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/runtime.md + * + * @since v1.7 + */ ++ (void)preventNSUndefinedKeyExceptionAttack AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Standard Library +//////////////////////////////////////////////////////////////////////////////// + +/** + * @return The GRMustache standard library. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/standard_library.md + * + * @since v6.4 + */ ++ (NSObject *)standardLibrary AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Building rendering objects +//////////////////////////////////////////////////////////////////////////////// + +/** + * This method is deprecated. Use + * `+[GRMustacheRendering renderingObjectForObject:]` instead. + * + * @see GRMustacheRendering class + * + * @since v6.0 + * @deprecated v7.0 + */ ++ (id)renderingObjectForObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +/** + * This method is deprecated. Use + * `+[GRMustacheRendering renderingObjectWithBlock:]` instead. + * + * @see GRMustacheRendering class + * + * @since v6.0 + * @deprecated v7.0 + */ ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +@end + +#import "GRMustacheTemplate.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheTemplateRepository.h" +#import "GRMustacheFilter.h" +#import "GRMustacheError.h" +#import "GRMustacheVersion.h" +#import "GRMustacheContentType.h" +#import "GRMustacheContext.h" +#import "GRMustacheRendering.h" +#import "GRMustacheTag.h" +#import "GRMustacheConfiguration.h" +#import "GRMustacheLocalizer.h" +#import "GRMustacheSafeKeyAccess.h" +#import "NSValueTransformer+GRMustache.h" +#import "NSFormatter+GRMustache.h" diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.m new file mode 100644 index 0000000..6e6ed18 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache.m @@ -0,0 +1,120 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustache_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheVersion.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheStandardLibrary_private.h" +#import "GRMustacheJavascriptLibrary_private.h" +#import "GRMustacheHTMLLibrary_private.h" +#import "GRMustacheURLLibrary_private.h" +#import "GRMustacheEachFilter_private.h" +#import "GRMustacheLocalizer.h" + + +// ============================================================================= +#pragma mark - GRMustache + +@implementation GRMustache + +// ============================================================================= +#pragma mark - Global services + ++ (void)preventNSUndefinedKeyExceptionAttack +{ + [GRMustacheKeyAccess preventNSUndefinedKeyExceptionAttack]; +} + ++ (GRMustacheVersion)libraryVersion +{ + return (GRMustacheVersion){ + .major = GRMUSTACHE_MAJOR_VERSION, + .minor = GRMUSTACHE_MINOR_VERSION, + .patch = GRMUSTACHE_PATCH_VERSION }; +} + ++ (NSObject *)standardLibrary +{ + static NSObject *standardLibrary = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + standardLibrary = [[NSDictionary dictionaryWithObjectsAndKeys: + // {{ capitalized(value) }} + [[[GRMustacheCapitalizedFilter alloc] init] autorelease], @"capitalized", + + // {{ lowercase(value) }} + [[[GRMustacheLowercaseFilter alloc] init] autorelease], @"lowercase", + + // {{ uppercase(value) }} + [[[GRMustacheUppercaseFilter alloc] init] autorelease], @"uppercase", + + // {{# isBlank(value) }}...{{/}} + [[[GRMustacheBlankFilter alloc] init] autorelease], @"isBlank", + + // {{# isEmpty(value) }}...{{/}} + [[[GRMustacheEmptyFilter alloc] init] autorelease], @"isEmpty", + + // {{ localize(value) }} + // {{# localize }}...{{/}} + [[[GRMustacheLocalizer alloc] initWithBundle:nil tableName:nil] autorelease], @"localize", + + // {{# each(collection) }}...{{/}} + [[[GRMustacheEachFilter alloc] init] autorelease], @"each", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ HTML.escape(value) }} + // {{# HTML.escape }}...{{/}} + [[[GRMustacheHTMLEscapeFilter alloc] init] autorelease], @"escape", + nil], @"HTML", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ javascript.escape(value) }} + // {{# javascript.escape }}...{{/}} + [[[GRMustacheJavascriptEscaper alloc] init] autorelease], @"escape", + nil], @"javascript", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ URL.escape(value) }} + // {{# URL.escape }}...{{/}} + [[[GRMustacheURLEscapeFilter alloc] init] autorelease], @"escape", + nil], @"URL", + nil] retain]; + }); + + return standardLibrary; +} + ++ (id)renderingObjectForObject:(id)object +{ + return [GRMustacheRendering renderingObjectForObject:object]; +} + ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block +{ + return [GRMustacheRendering renderingObjectWithBlock:block]; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustacheVersion.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustacheVersion.h new file mode 100644 index 0000000..c711cea --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustacheVersion.h @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +/** + * The major component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_MAJOR_VERSION 7 + +/** + * The minor component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_MINOR_VERSION 3 + +/** + * The patch-level component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_PATCH_VERSION 0 + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache_private.h new file mode 100644 index 0000000..051e417 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/GRMustache_private.h @@ -0,0 +1,54 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@protocol GRMustacheRendering; +@class GRMustacheTag; +@class GRMustacheContext; + +// Documented in GRMustache.h +typedef struct { + int major; + int minor; + int patch; +} GRMustacheVersion; + +@interface GRMustache: NSObject + +// Documented in GRMustache.h ++ (GRMustacheVersion)libraryVersion GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (void)preventNSUndefinedKeyExceptionAttack GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (NSObject *)standardLibrary GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (id)renderingObjectForObject:(id)object GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +// Documented in GRMustache.h ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m new file mode 100644 index 0000000..0a8d0e1 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m @@ -0,0 +1,561 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheError.h" + +@implementation GRMustacheExpressionParser + +- (GRMustacheExpression *)parseExpression:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + // -> ;;sm_parenLevel=0 -> stateInitial + // stateInitial -> ' ' -> stateInitial + // stateInitial -> '.' -> stateLeadingDot + // stateInitial -> 'a' -> stateIdentifier + // stateInitial -> sm_parenLevel==0;EOF; -> stateEmpty + // stateLeadingDot -> 'a' -> stateIdentifier + // stateLeadingDot -> ' ' -> stateIdentifierDone + // stateIdentifier -> '(';++sm_parenLevel -> stateInitial + // stateLeadingDot -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + // stateLeadingDot -> sm_parenLevel==0;EOF; -> stateValid + // stateIdentifier -> 'a' -> stateIdentifier + // stateIdentifier -> '.' -> stateWaitingForIdentifier + // stateIdentifier -> ' ' -> stateIdentifierDone + // stateIdentifier -> '(';++sm_parenLevel -> stateInitial + // stateIdentifier -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + // stateIdentifier -> sm_parenLevel==0;EOF; -> stateValid + // stateWaitingForIdentifier -> 'a' -> stateIdentifier + // stateIdentifierDone -> ' ' -> stateIdentifierDone + // stateIdentifierDone -> sm_parenLevel==0;EOF; -> stateValid + // stateIdentifierDone -> '(';++sm_parenLevel -> stateInitial + // stateFilterDone -> ' ' -> stateFilterDone + // stateFilterDone -> '.' -> stateWaitingForIdentifier + // stateFilterDone -> '(';++sm_parenLevel -> stateInitial + // stateFilterDone -> sm_parenLevel==0;EOF; -> stateValid + // stateFilterDone -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + + // state machine internal states + enum { + stateInitial, + stateLeadingDot, + stateIdentifier, + stateWaitingForIdentifier, + stateIdentifierDone, + stateFilterDone, + stateEmpty, + stateError, + stateValid + } state = stateInitial; + NSUInteger identifierStart = NSNotFound; + NSMutableArray *filterExpressionStack = [NSMutableArray array]; + GRMustacheExpression *currentExpression=nil; + GRMustacheExpression *validExpression=nil; + + NSUInteger length = string.length; + for (NSUInteger i = 0; i < length; ++i) { + + // shortcut + if (state == stateError) { + break; + } + + unichar c = [string characterAtIndex:i]; + switch (state) { + case stateInitial: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + NSAssert(currentExpression == nil, @"WTF expected nil currentExpression"); + state = stateLeadingDot; + currentExpression = [GRMustacheImplicitIteratorExpression expression]; + break; + + case '(': + state = stateError; + break; + + case ')': + state = stateError; + break; + + case ',': + state = stateError; + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateLeadingDot: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + state = stateIdentifierDone; + break; + + case '.': + state = stateError; + break; + + case '(': { + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + } break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateIdentifier: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + state = stateIdentifierDone; + } break; + + case '.': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + state = stateWaitingForIdentifier; + } break; + + case '(': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + } break; + + case ')': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + } break; + + case ',': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + } break; + + + default: + break; + } + break; + + case stateWaitingForIdentifier: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + state = stateError; + break; + + case '.': + state = stateError; + break; + + case '(': + state = stateError; + break; + + case ')': + state = stateError; + break; + + case ',': + state = stateError; + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateIdentifierDone: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + state = stateError; + break; + + case '(': + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + default: + state = stateError; + break; + } + break; + + case stateFilterDone: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + state = stateWaitingForIdentifier; + break; + + case '(': + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + default: + state = stateError; + break; + } + break; + default: + NSAssert(NO, @"WTF unexpected state"); + break; + } + } + + + // EOF + + switch (state) { + case stateInitial: + if (filterExpressionStack.count == 0) { + state = stateEmpty; + } else { + state = stateError; + } + break; + + case stateLeadingDot: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateIdentifier: { + // leave stateIdentifier + NSString *identifier = [string substringFromIndex:identifierStart]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + } break; + + case stateWaitingForIdentifier: + state = stateError; + break; + + case stateIdentifierDone: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateFilterDone: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateError: + break; + + default: + NSAssert(NO, @"WTF unexpected state"); + break; + } + + + // End + + switch (state) { + case stateEmpty: + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeParseError userInfo:[NSDictionary dictionaryWithObject:@"Missing expression" forKey:NSLocalizedDescriptionKey]]; + } + return nil; + + case stateError: + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeParseError userInfo:[NSDictionary dictionaryWithObject:@"Invalid expression" forKey:NSLocalizedDescriptionKey]]; + } + return nil; + + case stateValid: + NSAssert(validExpression, @"WTF expected validExpression"); + return validExpression; + + default: + NSAssert(NO, @"WTF unespected state"); + break; + } + + return nil; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h new file mode 100644 index 0000000..98abd17 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheExpression; + +@interface GRMustacheExpressionParser : NSObject + +/** + * Returns an expression from a string. + * + * @param string A string. + * @param empty If there is an error parsing the expression, upon return + * contains YES if the string contains no expression. + * @param error If there is an error parsing the expression, upon return + * contains an NSError object that describes the problem. + * + * @return An expression, or nil if the parsing fails or if the expression is + * empty. + */ +- (GRMustacheExpression *)parseExpression:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m new file mode 100644 index 0000000..4aa283e --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m @@ -0,0 +1,528 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateParser_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheTemplateParser() + +/** + * The Mustache tag opening delimiter. + */ +@property (nonatomic, copy) NSString *tagStartDelimiter; + +/** + * The Mustache tag opening delimiter. + */ +@property (nonatomic, copy) NSString *tagEndDelimiter; + +// Documented in GRMustacheTemplateParser_private.h +@property (nonatomic, strong) NSMutableSet *pragmas; + +@end + +@implementation GRMustacheTemplateParser +@synthesize delegate=_delegate; +@synthesize tagStartDelimiter=_tagStartDelimiter; +@synthesize tagEndDelimiter=_tagEndDelimiter; +@synthesize pragmas=_pragmas; + +- (instancetype)initWithConfiguration:(GRMustacheConfiguration *)configuration +{ + self = [super init]; + if (self) { + self.tagStartDelimiter = configuration.tagStartDelimiter; + self.tagEndDelimiter = configuration.tagEndDelimiter; + } + return self; +} + +- (void)dealloc +{ + [_tagStartDelimiter release]; + [_tagEndDelimiter release]; + [_pragmas release]; + [super dealloc]; +} + +- (void)parseTemplateString:(NSString *)templateString templateID:(id)templateID +{ + if (templateString == nil) { + if ([_delegate respondsToSelector:@selector(templateParser:didFailWithError:)]) { + [_delegate templateParser:self didFailWithError:[NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeTemplateNotFound + userInfo:[NSDictionary dictionaryWithObject:@"Nil template string can not be parsed." + forKey:NSLocalizedDescriptionKey]]]; + } + return; + } + + // Extract characters + + NSUInteger length = [templateString length]; + const UniChar *characters = CFStringGetCharactersPtr((CFStringRef)templateString); + if (!characters) { + NSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)]; + [templateString getCharacters:[data mutableBytes] range:(NSRange){ .location = 0, .length = length }]; + characters = [data bytes]; + } + + NSCharacterSet *whitespaceCharacterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + + // state machine internal states + enum { + stateStart, // Something is going to happen. We don't know what yet. Next character will tell. + stateText, // Currently enumerating other characters + stateTag, // Currently enumerating characters of a {{tag}} + stateUnescapedTag, // Currently enumerating characters of a {{{tag}}} + stateSetDelimitersTag, // Currently enumerating characters of a {{=tag=}} + } state = stateStart; + + // Some cached value for "efficient" lookup of {{ and }} + NSString *tagStartDelimiter = self.tagStartDelimiter; + NSString *tagEndDelimiter = self.tagEndDelimiter; + UniChar tagStartDelimiterInitial = [tagStartDelimiter characterAtIndex:0]; + NSUInteger tagStartDelimiterLength = tagStartDelimiter.length; + UniChar tagEndDelimiterInitial = [tagEndDelimiter characterAtIndex:0]; + NSUInteger tagEndDelimiterLength = tagEndDelimiter.length; + + // Some cached value for "efficient" lookup of {{{ and }}} + // + // Mustache spec does not say that what happens to triple mustache tags when + // delimiters are not {{ and }}. It just says to use the & tag prefix: + // {{{ a }}} <=> {{& a }}. + // + // We interpret this as a complete removal of triple mustache tags when + // delimiters are not {{ and }}: unescapedTagStartDelimiterInitial will be 0 + // and we will never enter the stateUnescapedTag state. + BOOL standardDelimiters = [tagStartDelimiter isEqualToString:@"{{"] && [tagEndDelimiter isEqualToString:@"}}"]; + NSString *unescapedTagStartDelimiter = standardDelimiters ? @"{{{" : nil; + NSString *unescapedTagEndDelimiter = standardDelimiters ? @"}}}" : nil; + UniChar unescapedTagStartDelimiterInitial = [unescapedTagStartDelimiter characterAtIndex:0]; + NSUInteger unescapedTagStartDelimiterLength = unescapedTagStartDelimiter.length; + UniChar unescapedTagEndDelimiterInitial = [unescapedTagEndDelimiter characterAtIndex:0]; + NSUInteger unescapedTagEndDelimiterLength = unescapedTagEndDelimiter.length; + + // Some cached value for "efficient" lookup of {{= and =}} + // + // Set delimiters tags {{=<% %>=}} have a dedicated lookup and state, so that + // we support setting to the current delimiters: {{={{ }}=}}. We achieve this + // by exiting the stateSetDelimitersTag state on =}}, not on }}. + NSString *setDelimitersTagStartDelimiter = [NSString stringWithFormat:@"%@=", tagStartDelimiter]; + NSString *setDelimitersTagEndDelimiter = [NSString stringWithFormat:@"=%@", tagEndDelimiter]; + UniChar setDelimitersTagStartDelimiterInitial = [setDelimitersTagStartDelimiter characterAtIndex:0]; + NSUInteger setDelimitersTagStartDelimiterLength = setDelimitersTagStartDelimiter.length; + UniChar setDelimitersTagEndDelimiterInitial = [setDelimitersTagEndDelimiter characterAtIndex:0]; + NSUInteger setDelimitersTagEndDelimiterLength = setDelimitersTagEndDelimiter.length; + + NSUInteger i = 0; // index of current character + NSUInteger start = 0; // index of character at the beginning of the current state + NSUInteger lineNumber = 1; // 1-based index of the current line + NSUInteger tagStartLineNumber = 1; // 1-based index of the beginning of the current tag + for (; i': + type = GRMustacheTokenTypePartial; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '<': + type = GRMustacheTokenTypeInheritablePartial; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '{': + type = GRMustacheTokenTypeUnescapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '&': + type = GRMustacheTokenTypeUnescapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '%': + type = GRMustacheTokenTypePragma; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + default: + type = GRMustacheTokenTypeEscapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength, .length = i-(start+tagStartDelimiterLength) }; + break; + } + GRMustacheToken *token = [GRMustacheToken tokenWithType:type + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+tagEndDelimiterLength)-start}]; + token.tagInnerRange = tagInnerRange; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + tagEndDelimiterLength; + state = stateStart; + i += tagEndDelimiterLength - 1; + } + } break; + + case stateUnescapedTag: { + if (c == '\n') + { + ++lineNumber; + } + else if (CHARACTER_STARTS(unescapedTagEndDelimiter)) + { + // Tag + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeUnescapedVariable + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+unescapedTagEndDelimiterLength)-start}]; + token.tagInnerRange = (NSRange){ .location = start+unescapedTagStartDelimiterLength, .length = i-(start+unescapedTagStartDelimiterLength) }; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + unescapedTagEndDelimiterLength; + state = stateStart; + i += unescapedTagEndDelimiterLength - 1; + } + } break; + + case stateSetDelimitersTag: { + if (c == '\n') + { + ++lineNumber; + } + else if (CHARACTER_STARTS(setDelimitersTagEndDelimiter)) + { + // Set Delimiters Tag + NSString *innerContent = [templateString substringWithRange:(NSRange){ .location = start+setDelimitersTagStartDelimiterLength, .length = i-(start+setDelimitersTagStartDelimiterLength) }]; + NSArray *newTags = [innerContent componentsSeparatedByCharactersInSet:whitespaceCharacterSet]; + NSMutableArray *nonBlankNewTags = [NSMutableArray array]; + for (NSString *newTag in newTags) { + if (newTag.length > 0) { + [nonBlankNewTags addObject:newTag]; + } + } + if (nonBlankNewTags.count != 2) { + [self failWithParseErrorAtLine:lineNumber description:@"Invalid set delimiters tag" templateID:templateID]; + return; + } + + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeSetDelimiter + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+setDelimitersTagEndDelimiterLength)-start}]; + token.tagInnerRange = (NSRange){ .location = start+setDelimitersTagStartDelimiterLength, .length = i-(start+setDelimitersTagStartDelimiterLength) }; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + setDelimitersTagEndDelimiterLength; + state = stateStart; + i += setDelimitersTagEndDelimiterLength - 1; + + // Update tag delimiters, and cached values for "efficient" + // lookup of them (see character loop initialization) + + tagStartDelimiter = [nonBlankNewTags objectAtIndex:0]; + tagEndDelimiter = [nonBlankNewTags objectAtIndex:1]; + tagStartDelimiterInitial = [tagStartDelimiter characterAtIndex:0]; + tagStartDelimiterLength = tagStartDelimiter.length; + tagEndDelimiterInitial = [tagEndDelimiter characterAtIndex:0]; + tagEndDelimiterLength = tagEndDelimiter.length; + + BOOL standardDelimiters = [tagStartDelimiter isEqualToString:@"{{"] && [tagEndDelimiter isEqualToString:@"}}"]; + unescapedTagStartDelimiter = standardDelimiters ? @"{{{" : nil; + unescapedTagEndDelimiter = standardDelimiters ? @"}}}" : nil; + unescapedTagStartDelimiterInitial = [unescapedTagStartDelimiter characterAtIndex:0]; + unescapedTagStartDelimiterLength = unescapedTagStartDelimiter.length; + unescapedTagEndDelimiterInitial = [unescapedTagEndDelimiter characterAtIndex:0]; + unescapedTagEndDelimiterLength = unescapedTagEndDelimiter.length; + + setDelimitersTagStartDelimiter = [NSString stringWithFormat:@"%@=", tagStartDelimiter]; + setDelimitersTagEndDelimiter = [NSString stringWithFormat:@"=%@", tagEndDelimiter]; + setDelimitersTagStartDelimiterInitial = [setDelimitersTagStartDelimiter characterAtIndex:0]; + setDelimitersTagStartDelimiterLength = setDelimitersTagStartDelimiter.length; + setDelimitersTagEndDelimiterInitial = [setDelimitersTagEndDelimiter characterAtIndex:0]; + setDelimitersTagEndDelimiterLength = setDelimitersTagEndDelimiter.length; + } + } break; + } + } + + // EOF + switch (state) { + case stateStart: + break; + + case stateText: { + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeText + templateString:templateString + templateID:templateID + line:lineNumber + range:(NSRange){ .location = start, .length = i-start}]; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + } break; + + case stateTag: + case stateUnescapedTag: + case stateSetDelimitersTag: { + [self failWithParseErrorAtLine:tagStartLineNumber description:@"Unclosed Mustache tag" templateID:templateID]; + return; + } break; + } +} + +- (NSString *)parseInheritableSectionName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *inheritableSectionName = [string stringByTrimmingCharactersInSet:whiteSpace]; + if (inheritableSectionName.length == 0) { + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Missing inheritable section name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + if ([inheritableSectionName rangeOfCharacterFromSet:whiteSpace].location != NSNotFound) { + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Invalid inheritable section name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + return inheritableSectionName; +} + +- (NSString *)parseTemplateName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *templateName = [string stringByTrimmingCharactersInSet:whiteSpace]; + if (templateName.length == 0) { + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Missing template name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + if ([templateName rangeOfCharacterFromSet:whiteSpace].location != NSNotFound) { + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Invalid template name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + return templateName; +} + +- (NSString *)parsePragma:(NSString *)string +{ + NSString *pragma = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (pragma.length == 0) { + return nil; + } + return pragma; +} + + +#pragma mark - Private + +/** + * Wrapper around the delegate's `templateParser:shouldContinueAfterParsingToken:` + * method. + */ +- (BOOL)shouldContinueAfterParsingToken:(GRMustacheToken *)token +{ + if ([_delegate respondsToSelector:@selector(templateParser:shouldContinueAfterParsingToken:)]) { + return [_delegate templateParser:self shouldContinueAfterParsingToken:token]; + } + return YES; +} + +/** + * Wrapper around the delegate's `templateParser:didFailWithError:` method. + * + * @param line The line at which the error occurred. + * @param description A human-readable error message + * @param templateID A template ID (see GRMustacheTemplateRepository) + */ +- (void)failWithParseErrorAtLine:(NSInteger)line description:(NSString *)description templateID:(id)templateID +{ + if ([_delegate respondsToSelector:@selector(templateParser:didFailWithError:)]) { + NSString *localizedDescription; + if (templateID) { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu of template %@: %@", (unsigned long)line, templateID, description]; + } else { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu: %@", (unsigned long)line, description]; + } + [_delegate templateParser:self didFailWithError:[NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:localizedDescription + forKey:NSLocalizedDescriptionKey]]]; + } +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h new file mode 100644 index 0000000..b292e1c --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h @@ -0,0 +1,156 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheToken; +@class GRMustacheTemplateParser; +@class GRMustacheConfiguration; + + +// ============================================================================= +#pragma mark - + +/** + * The protocol for the delegate of a GRMustacheTemplateParser. + * + * The delegate's responsability is to consume tokens and handle parser + * errors. + * + * @see GRMustacheCompiler + */ +@protocol GRMustacheTemplateParserDelegate +@optional + +/** + * Sent after the parser has parsed a token. + * + * @param parser The parser that did find a token. + * @param token The token + * + * @return YES if the parser should continue producing tokens; otherwise, NO. + * + * @see GRMustacheToken + */ +- (BOOL)templateParser:(GRMustacheTemplateParser *)parser shouldContinueAfterParsingToken:(GRMustacheToken *)token GRMUSTACHE_API_INTERNAL; + +/** + * Sent after the token has failed. + * + * @param parser The parser that failed to producing tokens. + * @param error The error that occurred. + */ +- (void)templateParser:(GRMustacheTemplateParser *)parser didFailWithError:(NSError *)error GRMUSTACHE_API_INTERNAL; +@end + + +// ============================================================================= +#pragma mark - GRMustacheTemplateParser + +/** + * The GRMustacheTemplateParser consumes a Mustache template string, and + * produces tokens. + * + * Those tokens are consumed by the parser's delegate. + * + * @see GRMustacheToken + * @see GRMustacheTemplateParserDelegate + */ +@interface GRMustacheTemplateParser : NSObject { +@private + id _delegate; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + NSMutableSet *_pragmas; +} + +/** + * The parser's delegate. + * + * The delegate is sent messages as the parser interprets a Mustache template + * string. + * + * @see GRMustacheTemplateParserDelegate + */ +@property (nonatomic, assign) id delegate GRMUSTACHE_API_INTERNAL; + +/** + * A set of all pragmas found while parsing. Pragmas are defined via pragma tags + * such as `{{% FILTERS }}`. + */ +@property (nonatomic, strong, readonly) NSMutableSet *pragmas GRMUSTACHE_API_INTERNAL; + +/** + * Returns an initialized parser. + * + * @param configuration The GRMustacheConfiguration that affects the + * parsing phase. + * @return a compiler + */ +- (instancetype)initWithConfiguration:(GRMustacheConfiguration *)configuration GRMUSTACHE_API_INTERNAL; + +/** + * The parser will invoke its delegate as it builds tokens from the template + * string. + * + * @param templateString A Mustache template string + * @param templateID A template ID (see GRMustacheTemplateRepository) + */ +- (void)parseTemplateString:(NSString *)templateString templateID:(id)templateID GRMUSTACHE_API_INTERNAL; + +/** + * Returns a template name from a string. + * + * @param string A string. + * @param empty If there is an error parsing a template name, upon return + * contains YES if the string contains no information. + * @param error If there is an error parsing a template name, upon return + * contains an NSError object that describes the problem. + * + * @return a template name, or nil if the string is not a partial name. + */ +- (NSString *)parseTemplateName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * Returns an inheritable section name from a string. + * + * @param string A string. + * @param empty If there is an error parsing an identifier, upon return + * contains YES if the string contains no information. + * @param error If there is an error parsing an identifier, upon return + * contains an NSError object that describes the problem. + * + * @return a template name, or nil if the string is not a partial name. + */ +- (NSString *)parseInheritableSectionName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * Returns a pragma from a string + * + * @param string A string + * + * @return a pragma, or nil if the string is not a pragma. + */ +- (NSString *)parsePragma:(NSString *)string GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m new file mode 100644 index 0000000..e53f355 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m @@ -0,0 +1,63 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheToken_private.h" + + +@implementation GRMustacheToken +@synthesize type=_type; +@synthesize templateString=_templateString; +@synthesize templateID=_templateID; +@synthesize line=_line; +@synthesize range=_range; +@synthesize tagInnerRange=_tagInnerRange; + +- (void)dealloc +{ + [_templateString release]; + [_templateID release]; + [super dealloc]; +} + ++ (instancetype)tokenWithType:(GRMustacheTokenType)type templateString:(NSString *)templateString templateID:(id)templateID line:(NSUInteger)line range:(NSRange)range +{ + GRMustacheToken *token = [[[self alloc] init] autorelease]; + token.type = type; + token.templateString = templateString; + token.templateID = templateID; + token.line = line; + token.range = range; + return token; +} + +- (NSString *)templateSubstring +{ + return [_templateString substringWithRange:_range]; +} + +- (NSString *)tagInnerContent +{ + return [_templateString substringWithRange:_tagInnerRange]; +} + +@end + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h new file mode 100644 index 0000000..26f0852 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h @@ -0,0 +1,183 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +/** + * The kinds of tokens + */ +typedef NS_ENUM(NSInteger, GRMustacheTokenType) { + + /** + * The kind of tokens representing raw template text. + */ + GRMustacheTokenTypeText, + + /** + * The kind of tokens representing escaped variable tags such as `{{name}}`. + */ + GRMustacheTokenTypeEscapedVariable, + + /** + * The kind of tokens representing a comment tag such as `{{! comment }}`. + */ + GRMustacheTokenTypeComment, + + /** + * The kind of tokens representing unescaped variable tag such as + * `{{{name}}}` and `{{&name}}`. + */ + GRMustacheTokenTypeUnescapedVariable, + + /** + * The kind of tokens representing section opening tags such as `{{#name}}`. + */ + GRMustacheTokenTypeSectionOpening, + + /** + * The kind of tokens representing inverted section opening tags such as + * `{{^name}}`. + */ + GRMustacheTokenTypeInvertedSectionOpening, + + /** + * The kind of tokens representing closing tags such as `{{/name}}`. + */ + GRMustacheTokenTypeClosing, + + /** + * The kind of tokens representing partial tags such as `{{>name}}`. + */ + GRMustacheTokenTypePartial, + + /** + * The kind of tokens representing delimiters tags such as `{{=< >=}}`. + */ + GRMustacheTokenTypeSetDelimiter, + + /** + * The kind of tokens representing pragma tags such as `{{%FILTERS}}`. + */ + GRMustacheTokenTypePragma, + + /** + * The kind of tokens representing inheritable partial tags such as + * `{{ +#import "GRMustacheAvailabilityMacros.h" + +@protocol GRMustacheTagDelegate; + +/** + * The GRMustacheContext represents a Mustache rendering context: it internally + * maintains three stacks: + * + * - a *context stack*, that makes it able to provide the current context + * object, and to perform key lookup. + * + * - a *priority context stack*, whose objects define important keys that + * should not be overriden. + * + * - a *tag delegate stack*, so that tag delegates are notified when a Mustache + * tag is rendered. + * + * **Companion guides:** + * + * - https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * - https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @warning GRMustacheContext is not suitable for subclassing. + * + * @see GRMustacheRendering protocol + */ +@interface GRMustacheContext : NSObject { +@private +#define GRMUSTACHE_STACK_TOP_IVAR(stackName) _ ## stackName ## Object +#define GRMUSTACHE_STACK_PARENT_IVAR(stackName) _ ## stackName ## Parent +#define GRMUSTACHE_STACK_DECLARE_IVARS(stackName, type) \ + GRMustacheContext *GRMUSTACHE_STACK_PARENT_IVAR(stackName); \ + type GRMUSTACHE_STACK_TOP_IVAR(stackName) + + GRMUSTACHE_STACK_DECLARE_IVARS(contextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(protectedContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(hiddenContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(tagDelegateStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(inheritablePartialNodeStack, id); + + BOOL _unsafeKeyAccess; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Rendering Contexts +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns an initialized empty rendering context. + * + * Empty contexts do not provide any value for any key. + * + * If you wish to use the services provided by the GRMustache standard library, + * you should create a context with the +[GRMustacheContext contextWithObject:] + * method, like this: + * + * ``` + * [GRMustacheContext contextWithObject:[GRMustache standardLibrary]] + * ``` + * + * @return A rendering context. + * + * @see +[GRMustache standardLibrary] + */ +- (instancetype)init; + +/** + * Returns an empty rendering context. + * + * Empty contexts do not provide any value for any key. + * + * If you wish to use the services provided by the GRMustache standard library, + * you should create a context with the +[GRMustacheContext contextWithObject:] + * method, like this: + * + * ``` + * [GRMustacheContext contextWithObject:[GRMustache standardLibrary]] + * ``` + * + * @return A rendering context. + * + * @see contextWithObject: + * @see +[GRMustache standardLibrary] + * + * @since v6.4 + */ ++ (instancetype)context AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a rendering context containing a single object. + * + * Keys defined by _object_ gets available for template rendering. + * + * ``` + * context = [GRMustacheContext contextWithObject:@{ @"name": @"Arthur" }]; + * [context valueForMustacheKey:@"name"]; // @"Arthur" + * ``` + * + * If _object_ conforms to the GRMustacheTemplateDelegate protocol, it is also + * made the top of the tag delegate stack. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param object An object + * + * @return A rendering context. + * + * @see contextByAddingObject: + * + * @see GRMustacheTemplateDelegate + * + * @since v6.4 + */ ++ (instancetype)contextWithObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a context containing a single priority object. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * ``` + * // Create a context with a priority `precious` key + * context = [GRMustacheContext contextWithProtectedObject:@{ @"precious": @"gold" }]; + * + * // Derive a new context by attempting to override the `precious` key: + * context = [context contextByAddingObject:@{ @"precious": @"lead" }]; + * + * // Priority keys can't be overriden + * [context valueForMustacheKey:@"precious"]; // @"gold" + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md#priority-keys + * + * @param object An object + * + * @return A rendering context. + * + * @see contextByAddingProtectedObject: + * + * @since v6.4 + */ ++ (instancetype)contextWithProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a context containing a single tag delegate. + * + * _tagDelegate_ will be notified of the rendering of all tags rendered from the + * receiver or from contexts derived from the receiver. + * + * Unlike contextWithObject: and contextWithProtectedObject:, _tagDelegate_ will + * not provide any key to the templates. It will only be notified of the + * rendering of tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param tagDelegate A tag delegate + * + * @return A rendering context. + * + * @see GRMustacheTagDelegate + * + * @since v6.4 + */ ++ (instancetype)contextWithTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Deriving New Contexts +//////////////////////////////////////////////////////////////////////////////// + + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the context stack. + * + * Keys defined by _object_ gets available for template rendering, and override + * the values defined by objects already contained in the context stack. Keys + * unknown to _object_ will be looked up deeper in the context stack. + * + * ``` + * context = [GRMustacheContext contextWithObject:@{ @"a": @"ignored", @"b": @"foo" }]; + * context = [context contextByAddingObject:@{ @"a": @"bar" }]; + * + * // `a` is overriden + * [context valueForMustacheKey:@"a"]; // @"bar" + * + * // `b` is inherited + * [context valueForMustacheKey:@"b"]; // @"foo" + * ``` + * + * _object_ can not override keys defined by the objects of the priority + * context stack, though. See contextWithProtectedObject: and + * contextByAddingProtectedObject:. + * + * If _object_ conforms to the GRMustacheTemplateDelegate protocol, it is also + * added at the top of the tag delegate stack. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param object An object + * + * @return A new rendering context. + * + * @see GRMustacheTemplateDelegate + * + * @since v6.0 + */ +- (instancetype)contextByAddingObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the priority context stack. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * ``` + * // Derive a context with a priority `precious` key + * context = [context contextByAddingProtectedObject:@{ @"precious": @"gold" }]; + * + * // Derive a new context by attempting to override the `precious` key: + * context = [context contextByAddingObject:@{ @"precious": @"lead" }]; + * + * // Priority keys can't be overriden + * [context valueForMustacheKey:@"precious"]; // @"gold" + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md#priority-keys + * + * @param object An object + * + * @return A new rendering context. + * + * @since v6.0 + */ +- (instancetype)contextByAddingProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the tag delegate stack. + * + * _tagDelegate_ will be notified of the rendering of all tags rendered from the + * receiver or from contexts derived from the receiver. + * + * Unlike contextByAddingObject: and contextByAddingProtectedObject:, + * _tagDelegate_ will not provide any key to the templates. It will only be + * notified of the rendering of tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param tagDelegate A tag delegate + * + * @return A new rendering context. + * + * @see GRMustacheTagDelegate + * + * @since v6.0 + */ +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Fetching Values from the Context Stack +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns the object at the top of the receiver's context stack. + * + * The returned object is the same as the one that would be rendered by a + * `{{ . }}` tag. + * + * ``` + * user = ...; + * context = [GRMustacheContext contextWithObject:user]; + * context.topMustacheObject; // user + * ``` + * + * @return The object at the top of the receiver's context stack. + * + * @see contextWithObject: + * @see contextByAddingObject: + * + * @since v6.7 + */ +@property (nonatomic, readonly) id topMustacheObject AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the value stored in the context stack for the given key. + * + * If you want the value for an full expression such as `user.name` or + * `uppercase(user.name)`, use the hasValue:forMustacheExpression:error: + * method. + * + * ### Search Pattern for valueForMustacheKey + * + * The Mustache value of any object for a given key is defined as: + * + * 1. If the object responds to the `objectForKeyedSubscript:` instance method, + * return the result of this method. + * + * 2. Otherwise, build the list of safe keys: + * a. If the object responds to the `safeMustacheKeys` class method defined + * by the `GRMustacheSafeKeyAccess` protocol, use this method. + * b. Otherwise, use the list of Objective-C properties declared with + * `@property`. + * c. If object is an instance of NSManagedObject, add all the attributes of + * its Core Data entity. + * + * 3. If the key belongs to the list of safe keys, return the result of the + * `valueForKey:` method, unless this method throws NSUndefinedKeyException. + * + * 4. Otherwise, return nil. + * + * Contexts with unsafe key access skip the key validation step. + * + * In this method, the following search pattern is used: + * + * 1. Searches the priority context stack for an object that has a non-nil + * Mustache value for the key. + * + * 2. Otherwise (irrelevant priority context stack), search the context stack + * for an object that has a non-nil Mustache value for the key. + * + * 3. If none of the above situations occurs, returns nil. + * + * **Companion guides:** https://github.com/groue/GRMustache/blob/master/Guides/runtime.md, + * https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * + * @param key a key such as @"name" + * + * @return The value found in the context stack for the given key. + * + * @see contextWithUnsafeKeyAccess + * @see hasValue:forMustacheExpression:error: + * + * @since v6.6 + */ +- (id)valueForMustacheKey:(NSString *)key AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Evaluates an expression such as `name`, or `uppercase(user.name)`. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * + * @param value Upon return contains the value of the expression. + * @param expression An expression. + * @param error If there is an error computing the value, upon return + * contains an NSError object that describes the problem. + * + * @return YES if the value could be computed. + * + * @see valueForMustacheKey: + * + * @since v6.8 + */ +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)expression error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Unsafe Key Access +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns whether this context allows unsafe key access or not. + * + * @since v7.0 + */ +@property (nonatomic, readonly) BOOL unsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new context with unsafe key access. + * + * Unsafe key access allows this context, and all contexts derived from it, to + * access keys that are normally forbidden: keys that are not declared as + * Objective-C properties, or keys that do not belong to the result of the + * `safeMustacheKeys` method. + * + * Compare: + * + * ``` + * @interface DBRecord : NSObject + * - (void)deleteRecord; + * @end + * + * @implementation DBRecord + * - (void)deleteRecord + * { + *     NSLog(@"Oooops, your record was just deleted!"); + * } + * @end + * + * DBRecord *record = ...; + * NSString *templateString = @"{{ deleteRecord }}"; + * GRMustacheTemplate * template = [GRMustacheTemplate templateWithString:templateString error:NULL]; + * + * // Safe rendering of the dangerous template: record is not deleted. + * [template renderObject:record error:NULL]; + * + * // Unsafe rendering of the dangerous template: record is deleted. + * template.baseContext = [GRMustacheContext contextWithUnsafeKeyAccess]; + * [template renderObject:record error:NULL]; + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @see GRMustacheSafeKeyAccess + * + * @since v7.0 + */ ++ (instancetype)contextWithUnsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, with unsafe + * key access. + * + * Unsafe key access allows this context, and all contexts derived from it, to + * access keys that are normally forbidden: keys that are not declared as + * Objective-C properties, or keys that do not belong to the result of the + * `safeMustacheKeys` method. + * + * Compare: + * + * ``` + * @interface DBRecord : NSObject + * - (void)deleteRecord; + * @end + * + * @implementation DBRecord + * - (void)deleteRecord + * { + *     NSLog(@"Oooops, your record was just deleted!"); + * } + * @end + * + * DBRecord *record = ...; + * NSString *templateString = @"{{ deleteRecord }}"; + * GRMustacheTemplate * template = [GRMustacheTemplate templateWithString:templateString error:NULL]; + * + * // Safe rendering of the dangerous template: record is not deleted. + * [template renderObject:record error:NULL]; + * + * // Unsafe rendering of the dangerous template: record is deleted. + * template.baseContext = [template.baseContext contextWithUnsafeKeyAccess]; + * [template renderObject:record error:NULL]; + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @see GRMustacheSafeKeyAccess + * + * @since v7.0 + */ +- (instancetype)contextWithUnsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m new file mode 100644 index 0000000..5eecc66 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m @@ -0,0 +1,458 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheContext_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheExpressionInvocation_private.h" + +#define GRMUSTACHE_STACK_RELEASE(stackName) \ + [GRMUSTACHE_STACK_TOP_IVAR(stackName) release]; \ + [GRMUSTACHE_STACK_PARENT_IVAR(stackName) release] + +#define GRMUSTACHE_STACK_INIT(stackName, context, object) \ + GRMUSTACHE_STACK_TOP(stackName, context) = [object retain] + +#define GRMUSTACHE_STACK_COPY(stackName, sourceContext, targetContext) \ + GRMUSTACHE_STACK_TOP(stackName, targetContext) = [GRMUSTACHE_STACK_TOP(stackName, sourceContext) retain]; \ + GRMUSTACHE_STACK_PARENT(stackName, targetContext) = [GRMUSTACHE_STACK_PARENT(stackName, sourceContext) retain] + +#define GRMUSTACHE_STACK_PUSH(stackName, sourceContext, targetContext, object) \ + NSAssert(object, @"WTF"); \ + if (GRMUSTACHE_STACK_TOP(stackName, sourceContext)) { \ + GRMUSTACHE_STACK_PARENT(stackName, targetContext) = [sourceContext retain]; \ + } \ + GRMUSTACHE_STACK_TOP(stackName, targetContext) = [object retain]; + +#define GRMUSTACHE_STACK_TOP(stackName, context) context->GRMUSTACHE_STACK_TOP_IVAR(stackName) + +#define GRMUSTACHE_STACK_PARENT(stackName, context) context->GRMUSTACHE_STACK_PARENT_IVAR(stackName) + +#define GRMUSTACHE_STACK_ENUMERATE(stackName, sourceContext, context) \ + if (GRMUSTACHE_STACK_TOP(stackName, sourceContext)) \ + for (GRMustacheContext *context = sourceContext; context; context = GRMUSTACHE_STACK_PARENT(stackName, context)) + +// ============================================================================= +#pragma mark - GRMustacheTagDelegate conformance + +static pthread_key_t GRTagDelegateClassesKey; +void freeTagDelegateClasses(void *objects) { + CFRelease((CFMutableDictionaryRef)objects); +} +#define setupTagDelegateClasses() pthread_key_create(&GRTagDelegateClassesKey, freeTagDelegateClasses) +#define getCurrentThreadTagDelegateClasses() (CFMutableDictionaryRef)pthread_getspecific(GRTagDelegateClassesKey) +#define setCurrentThreadTagDelegateClasses(classes) pthread_setspecific(GRTagDelegateClassesKey, classes) + +static BOOL objectConformsToTagDelegateProtocol(id object) +{ + if (object == nil) { + return NO; + } + + CFMutableDictionaryRef classes = getCurrentThreadTagDelegateClasses(); + if (!classes) { + classes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + setCurrentThreadTagDelegateClasses(classes); + } + + Class klass = [object class]; + intptr_t conform = (intptr_t)CFDictionaryGetValue(classes, klass); + if (conform == 0) { + conform = [klass conformsToProtocol:@protocol(GRMustacheTagDelegate)] ? 1 : 2; + CFDictionarySetValue(classes, klass, (void *)conform); + } + return (conform == 1); +} + + +// ============================================================================= +#pragma mark - GRMustacheContext + +@implementation GRMustacheContext + ++ (void)initialize +{ + setupTagDelegateClasses(); +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + if (!GRMUSTACHE_STACK_TOP(inheritablePartialNodeStack, self)) { + return templateASTNode; + } + + NSMutableSet *usedTemplateASTs = [[NSMutableSet alloc] init]; + GRMUSTACHE_STACK_ENUMERATE(inheritablePartialNodeStack, self, context) { + GRMustacheInheritablePartialNode *inheritablePartialNode = GRMUSTACHE_STACK_TOP(inheritablePartialNodeStack, context); + GRMustacheTemplateAST *templateAST = inheritablePartialNode.partialNode.templateAST; + if ([usedTemplateASTs containsObject:templateAST]) { + continue; + } + id resolvedASTNode = [inheritablePartialNode resolveTemplateASTNode:templateASTNode]; + if (resolvedASTNode != templateASTNode) { + [usedTemplateASTs addObject:templateAST]; + } + templateASTNode = resolvedASTNode; + } + [usedTemplateASTs release]; + + return templateASTNode; +} + +- (BOOL)unsafeKeyAccess +{ + return _unsafeKeyAccess; +} + + +// ============================================================================= +#pragma mark - Creating Contexts + ++ (instancetype)context +{ + return [[[self alloc] init] autorelease]; +} + ++ (instancetype)contextWithUnsafeKeyAccess +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + context->_unsafeKeyAccess = YES; + return context; +} + ++ (instancetype)contextWithObject:(id)object +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(contextStack, context, object); + if (objectConformsToTagDelegateProtocol(object)) { + GRMUSTACHE_STACK_INIT(tagDelegateStack, context, object); + } + return context; +} + ++ (instancetype)contextWithProtectedObject:(id)object +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(protectedContextStack, context, object); + return context; +} + ++ (instancetype)contextWithTagDelegate:(id)tagDelegate +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(tagDelegateStack, context, tagDelegate); + return context; +} + +- (void)dealloc +{ + GRMUSTACHE_STACK_RELEASE(contextStack); + GRMUSTACHE_STACK_RELEASE(protectedContextStack); + GRMUSTACHE_STACK_RELEASE(hiddenContextStack); + GRMUSTACHE_STACK_RELEASE(tagDelegateStack); + GRMUSTACHE_STACK_RELEASE(inheritablePartialNodeStack); + [super dealloc]; +} + + +// ============================================================================= +#pragma mark - Deriving Contexts + +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate +{ + if (tagDelegate == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + + GRMUSTACHE_STACK_PUSH(tagDelegateStack, self, context, tagDelegate); + + return context; +} + +- (instancetype)newContextByAddingObject:(id)object +{ + if (object == nil) { + return [self retain]; + } + + GRMustacheContext *context = [[GRMustacheContext alloc] init]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(contextStack, self, context, object); + + if (objectConformsToTagDelegateProtocol(object)) { + GRMUSTACHE_STACK_PUSH(tagDelegateStack, self, context, object); + } else { + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + } + + return context; +} + +- (instancetype)contextByAddingObject:(id)object +{ + return [[self newContextByAddingObject:object] autorelease]; +} + +- (instancetype)contextByAddingProtectedObject:(id)object +{ + if (object == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(protectedContextStack, self, context, object); + + return context; +} + +- (instancetype)contextByAddingHiddenObject:(id)object +{ + if (object == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(hiddenContextStack, self, context, object); + + return context; +} + +- (instancetype)contextByAddingInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode +{ + if (inheritablePartialNode == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(inheritablePartialNodeStack, self, context, inheritablePartialNode); + + return context; +} + +- (instancetype)contextWithUnsafeKeyAccess +{ +#define GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(stackName) \ + GRMUSTACHE_STACK_ENUMERATE(stackName, self, __context) { \ + GRMustacheContext *__unsafeContext = CFDictionaryGetValue(unsafeContextForContext, __context); \ + if (!__unsafeContext) { \ + __unsafeContext = [GRMustacheContext contextWithUnsafeKeyAccess]; \ + GRMUSTACHE_STACK_COPY(contextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(protectedContextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(hiddenContextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(tagDelegateStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, __context, __unsafeContext); \ + CFDictionarySetValue(unsafeContextForContext, __context, __unsafeContext); \ + } \ + } + +#define GRMUSTACHE_UPDATE_UNSAFE_PARENT(stackName, context) { \ + GRMustacheContext *__safeParent = GRMUSTACHE_STACK_PARENT(stackName, context); \ + if (__safeParent) { \ + GRMustacheContext *__unsafeParent = CFDictionaryGetValue(unsafeContextForContext, __safeParent); \ + [__safeParent release]; \ + GRMUSTACHE_STACK_PARENT(stackName, context) = [__unsafeParent retain]; \ + } \ +} + + // Duplicate contexts of all stacks into unsafe contexts. + // The parents of unsafe contexts are still the safe ones, that we'll update later. + + CFMutableDictionaryRef unsafeContextForContext = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(contextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(protectedContextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(hiddenContextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(tagDelegateStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(inheritablePartialNodeStack); + + + // Update safe parents of unsafe contexts with unsafe ones + + CFIndex count = CFDictionaryGetCount(unsafeContextForContext); + GRMustacheContext **unsafeContexts = malloc(count * sizeof(GRMustacheContext *)); + if (unsafeContexts == NULL) { + // Allocation failed. + // + // This method is supposed to return a newly created object, so we can + // behave like failing allocating methods and return nil. + // + // And make sure we cleanup allocated memory before. + CFRelease(unsafeContextForContext); + return nil; + } + CFDictionaryGetKeysAndValues(unsafeContextForContext, NULL, (const void **)unsafeContexts); + for (CFIndex i = 0; i < count; ++i) { + GRMustacheContext *unsafeContext = unsafeContexts[i]; + GRMUSTACHE_UPDATE_UNSAFE_PARENT(contextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(protectedContextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(hiddenContextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(tagDelegateStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(inheritablePartialNodeStack, unsafeContext); + } + free(unsafeContexts); + + + // Done + + GRMustacheContext *unsafeContext = CFDictionaryGetValue(unsafeContextForContext, self); + CFRelease(unsafeContextForContext); + return unsafeContext; +} + +// ============================================================================= +#pragma mark - Context Stack + +- (id)topMustacheObject +{ + return [[GRMUSTACHE_STACK_TOP(contextStack, self) retain] autorelease]; +} + +- (id)valueForMustacheKey:(NSString *)key +{ + return [self valueForMustacheKey:key protected:NULL]; +} + +- (id)valueForMustacheKey:(NSString *)key protected:(BOOL *)protected +{ + // First look for in the protected context stack + + GRMUSTACHE_STACK_ENUMERATE(protectedContextStack, self, context) { + id value = [GRMustacheKeyAccess valueForMustacheKey:key inObject:GRMUSTACHE_STACK_TOP(protectedContextStack, context) unsafeKeyAccess:context->_unsafeKeyAccess]; + if (value != nil) { + if (protected != NULL) { + *protected = YES; + } + return value; + } + } + + + // Then look for in the regular context stack + + GRMUSTACHE_STACK_ENUMERATE(contextStack, self, context) { + // First check for contextObject: + // + // context = [GRMustacheContext contextWithObject:@{key:value}]; + // assert([context valueForKey:key] == value); + id contextObject = GRMUSTACHE_STACK_TOP(contextStack, context); + BOOL hidden = NO; + GRMUSTACHE_STACK_ENUMERATE(hiddenContextStack, self, hiddenContext) { + if (contextObject == GRMUSTACHE_STACK_TOP(hiddenContextStack, hiddenContext)) { + hidden = YES; + break; + } + } + if (hidden) { continue; } + id value = [GRMustacheKeyAccess valueForMustacheKey:key inObject:contextObject unsafeKeyAccess:context->_unsafeKeyAccess]; + if (value != nil) { + if (protected != NULL) { + *protected = NO; + } + return value; + } + } + + + // OK give up now + + return nil; +} + +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)string error:(NSError **)error +{ + GRMustacheExpressionParser *parser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [parser parseExpression:string empty:NULL error:error]; + + GRMustacheExpressionInvocation *invocation = [[[GRMustacheExpressionInvocation alloc] init] autorelease]; + invocation.context = self; + invocation.expression = expression; + if (![invocation invokeReturningError:error]) { + return NO; + } + + if (value) { + *value = invocation.value; + } + return YES; +} + + +// ============================================================================= +#pragma mark - Tag Delegates Stack + +- (NSArray *)tagDelegateStack +{ + NSMutableArray *tagDelegateStack = nil; + + GRMUSTACHE_STACK_ENUMERATE(tagDelegateStack, self, context) { + if (!tagDelegateStack) { + tagDelegateStack = [NSMutableArray array]; + } + [tagDelegateStack insertObject:GRMUSTACHE_STACK_TOP(tagDelegateStack, context) atIndex:0]; + } + + return tagDelegateStack; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h new file mode 100644 index 0000000..f1836ea --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h @@ -0,0 +1,183 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@protocol GRMustacheTagDelegate; +@protocol GRMustacheTemplateASTNode; +@class GRMustacheInheritablePartialNode; + +/** + * The GRMustacheContext maintains the following stacks: + * + * - a context stack, + * - a protected context stack, + * - a hidden context stack, + * - a tag delegate stack, + * - an inheritable partial stack. + * + * As such, it is able to: + * + * - Provide the current context object (the top of the context stack). + * + * - Perform a key lookup, starting with the protected context stack, then + * looking in the context stack, avoiding objects in the hidden context stack. + * + * For a full discussion of the interaction between the protected and the + * hidden stacks, see the implementation of + * [GRMustacheTag renderContentType:inBuffer:withContext:error:]. + * + * - Let tag delegates interpret rendered values. + * + * - Let inheritable partial templates override AST nodes. + */ +@interface GRMustacheContext : NSObject { +@private + +#define GRMUSTACHE_STACK_TOP_IVAR(stackName) _ ## stackName ## Object +#define GRMUSTACHE_STACK_PARENT_IVAR(stackName) _ ## stackName ## Parent +#define GRMUSTACHE_STACK_DECLARE_IVARS(stackName, type) \ + GRMustacheContext *GRMUSTACHE_STACK_PARENT_IVAR(stackName); \ + type GRMUSTACHE_STACK_TOP_IVAR(stackName) + + GRMUSTACHE_STACK_DECLARE_IVARS(contextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(protectedContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(hiddenContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(tagDelegateStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(inheritablePartialNodeStack, GRMustacheInheritablePartialNode *); + + BOOL _unsafeKeyAccess; +} + +// Documented in GRMustacheContext.h ++ (instancetype)context GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithUnsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextWithUnsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)expression error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (id)valueForMustacheKey:(NSString *)key GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +// @see -[GRMustacheImplicitIteratorExpression hasValue:withContext:protected:error:] +@property (nonatomic, readonly) id topMustacheObject GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +@property (nonatomic, readonly) BOOL unsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +/** + * Same as [contextByAddingObject:object], but returns a retained object. + * This method helps efficiently managing memory, and targeting slow methods. + */ +- (instancetype)newContextByAddingObject:(id)object GRMUSTACHE_API_INTERNAL; + +/** + * Returns a GRMustacheContext object identical to the receiver, but for the + * hidden object stack that is extended with _object_. + * + * Hidden objects can not be queried by the valueForMustacheKey:protected: + * method. + * + * For a full discussion of the interaction between the protected and the hidden + * stacks, see the implementation of + * [GRMustacheTag renderContentType:inBuffer:withContext:error:]. + * + * @param object An object that should be hidden. + * + * @return A GRMustacheContext object. + * + * @see [GRMustacheContext valueForMustacheKey:protected:] + */ +- (instancetype)contextByAddingHiddenObject:(id)object GRMUSTACHE_API_INTERNAL; + +/** + * Returns a GRMustacheContext object identical to the receiver, but for the + * inheritable partial stack that is extended with _inheritablePartial_. + * + * @param inheritablePartialNode An inheritable partial + * + * @return A GRMustacheContext object. + * + * @see GRMustacheInheritablePartialNode + * @see [GRMustacheInheritablePartialNode renderWithContext:inBuffer:error:] + */ +- (instancetype)contextByAddingInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode GRMUSTACHE_API_INTERNAL; + +/** + * Performs a key lookup in the receiver's context stack, and returns the found + * value. + * + * @param key The searched key. + * @param protected Upon return, is YES if the value comes from the protected + * context stack. + * + * @return The value found in the context stack. + * + * @see -[GRMustacheIdentifierExpression hasValue:withContext:protected:error:] + */ +- (id)valueForMustacheKey:(NSString *)key protected:(BOOL *)protected GRMUSTACHE_API_INTERNAL; + +/** + * In the context of template inheritance, return the node that should be + * rendered in lieu of the node argument. + * + * @param ASTNode A node + * + * @return The resolution of the node in the context of Mustache template + * inheritance. + */ +- (id)resolveTemplateASTNode:(id)templateASTNode GRMUSTACHE_API_INTERNAL; + +/** + * Returns an array containing all tag delegates in the delegate stack. + * Array may be null (meaning there is no tag delegate in the stack). + * + * Last object is the top object in the delegate stack. + */ +- (NSArray *)tagDelegateStack GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m new file mode 100644 index 0000000..435242e --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m @@ -0,0 +1,135 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionInvocation_private.h" +#import "GRMustacheExpressionVisitor_private.h" +#import "GRMustacheFilter_private.h" +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheExpressionInvocation() +@end + +@implementation GRMustacheExpressionInvocation +@synthesize context=_context; +@synthesize expression=_expression; +@synthesize value=_value; +@synthesize valueIsProtected=_valueIsProtected; + +- (BOOL)invokeReturningError:(NSError **)error +{ + return [_expression acceptVisitor:self error:error]; +} + + +#pragma mark - + +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error +{ + if (![expression.filterExpression acceptVisitor:self error:error]) { + return NO; + } + id filter = _value; + + if (![expression.argumentExpression acceptVisitor:self error:error]) { + return NO; + } + id argument = _value; + + if (filter == nil) { + GRMustacheToken *token = expression.token; + NSString *renderingErrorDescription = nil; + if (token) { + if (token.templateID) { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter in tag `%@` at line %lu of template %@", token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter in tag `%@` at line %lu", token.templateSubstring, (unsigned long)token.line]; + } + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter"]; + } + NSError *renderingError = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:[NSDictionary dictionaryWithObject:renderingErrorDescription forKey:NSLocalizedDescriptionKey]]; + if (error != NULL) { + *error = renderingError; + } + return NO; + } + + if (![filter respondsToSelector:@selector(transformedValue:)]) { + GRMustacheToken *token = expression.token; + NSString *renderingErrorDescription = nil; + if (token) { + if (token.templateID) { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol in tag `%@` at line %lu of template %@: %@", token.templateSubstring, (unsigned long)token.line, token.templateID, filter]; + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol in tag `%@` at line %lu: %@", token.templateSubstring, (unsigned long)token.line, filter]; + } + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol: %@", filter]; + } + NSError *renderingError = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:[NSDictionary dictionaryWithObject:renderingErrorDescription forKey:NSLocalizedDescriptionKey]]; + if (error != NULL) { + *error = renderingError; + } + return NO; + } + + if (expression.isCurried && [filter respondsToSelector:@selector(filterByCurryingArgument:)]) { + _value = [(id)filter filterByCurryingArgument:argument]; + } else { + _value = [(id)filter transformedValue:argument]; + } + + _valueIsProtected = NO; + return YES; +} + +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error +{ + _value = [_context valueForMustacheKey:expression.identifier protected:&_valueIsProtected]; + return YES; +} + +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error +{ + if (![expression.baseExpression acceptVisitor:self error:error]) { + return NO; + } + + _value = [GRMustacheKeyAccess valueForMustacheKey:expression.identifier inObject:_value unsafeKeyAccess:_context.unsafeKeyAccess]; + _valueIsProtected = NO; + return YES; +} + +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error +{ + _value = [_context topMustacheObject]; + _valueIsProtected = NO; + return YES; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h new file mode 100644 index 0000000..316fd53 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheContext; +@class GRMustacheExpression; + +/** + * TODO + */ +@interface GRMustacheExpressionInvocation : NSObject { +@private + GRMustacheContext *_context; + GRMustacheExpression *_expression; + id _value; + BOOL _valueIsProtected; +} + +/** + * TODO + */ +@property (nonatomic, assign) GRMustacheContext *context GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, assign) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, assign, readonly) id value GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, readonly) BOOL valueIsProtected GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +- (BOOL)invokeReturningError:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h new file mode 100644 index 0000000..b89e2ec --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h @@ -0,0 +1,125 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GRMUSTACHE_FILTER +#define GRMUSTACHE_FILTER + +#import +#import "GRMustacheAvailabilityMacros.h" + + +// ============================================================================= +#pragma mark - + + +/** + * The protocol for implementing GRMustache filters. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/filters.md + * + * The responsability of a GRMustacheFilter is to transform a value into + * another. + * + * For example, the tag `{{ uppercase(name) }}` uses a filter object that + * returns the uppercase version of its input. + * + * @since v4.3 + */ +@protocol GRMustacheFilter +@required + +//////////////////////////////////////////////////////////////////////////////// +/// @name Transforming Values +//////////////////////////////////////////////////////////////////////////////// + +/** + * Applies some transformation to its input, and returns the transformed value. + * + * @param object An object to be processed by the filter. + * + * @return A transformed value. + * + * @since v4.3 + */ +- (id)transformedValue:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + + + +// ============================================================================= +#pragma mark - GRMustacheFilter + +/** + * The GRMustacheFilter class helps building mustache filters without writing a + * custom class that conforms to the GRMustacheFilter protocol. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/filters.md + * + * @see GRMustacheFilter protocol + * + * @since v4.3 + */ +@interface GRMustacheFilter : NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Filters +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns a GRMustacheFilter object that executes the provided block when + * tranforming a value. + * + * @param block The block that transforms its input. + * + * @return a GRMustacheFilter object. + * + * @since v4.3 + * + * @see variadicFilterWithBlock: + */ ++ (id)filterWithBlock:(id(^)(id value))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a GRMustacheFilter object that executes the provided block, given an + * array of arguments. + * + * Those filters can evaluate expressions like `{{ f(a,b) }}`. + * + * GRMustache will invoke the filter regardless of the number of arguments in + * the template: `{{ f(a) }}`, `{{ f(a,b) }}` and `{{ f(a,b,c) }}` will provide + * arrays of 1, 2, and 3 arguments respectively. It is your responsability to + * check that you are provided with as many arguments as you expect. + * + * @param block The block that transforms its input. + * + * @return a GRMustacheFilter object. + * + * @since v5.5 + * + * @see filterWithBlock: + */ ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + +#endif diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m new file mode 100644 index 0000000..bbbc549 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m @@ -0,0 +1,155 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheFilter_private.h" + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockFilter + +/** + * Private subclass of GRMustacheFilter that filters a single argument by + * calling a block. + */ +@interface GRMustacheBlockFilter: GRMustacheFilter { +@private + id(^_block)(id value); +} +- (instancetype)initWithBlock:(id(^)(id value))block; +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockVariadicFilter + +/** + * Private subclass of GRMustacheFilter that filters an array of arguments by + * calling a block. + */ +@interface GRMustacheBlockVariadicFilter: GRMustacheFilter { +@private + NSArray *_arguments; + id(^_block)(NSArray *arguments); +} +- (instancetype)initWithBlock:(id(^)(NSArray *arguments))block arguments:(NSArray *)arguments; +@end + + +// ============================================================================= +#pragma mark - GRMustacheFilter + +@implementation GRMustacheFilter + ++ (id)filterWithBlock:(id(^)(id value))block +{ + return [[[GRMustacheBlockFilter alloc] initWithBlock:block] autorelease]; +} + ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block +{ + return [[[GRMustacheBlockVariadicFilter alloc] initWithBlock:block arguments:[NSArray array]] autorelease]; +} + +- (id)transformedValue:(id)object +{ + return object; +} + +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockFilter + +@implementation GRMustacheBlockFilter + +- (instancetype)initWithBlock:(id(^)(id value))block +{ + if (block == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a filter with a nil block."]; + } + + self = [self init]; + if (self) { + _block = [block copy]; + } + return self; +} + + +- (void)dealloc +{ + [_block release]; + [super dealloc]; +} + +#pragma mark + +- (id)transformedValue:(id)object +{ + return _block(object); +} + +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockVariadicFilter + +@implementation GRMustacheBlockVariadicFilter + +- (instancetype)initWithBlock:(id(^)(NSArray *arguments))block arguments:(NSArray *)arguments +{ + if (block == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a filter with a nil block."]; + } + + self = [self init]; + if (self) { + _block = [block copy]; + _arguments = [arguments retain]; + } + return self; +} + +- (void)dealloc +{ + [_block release]; + [_arguments release]; + [super dealloc]; +} + + +#pragma mark + +- (id)transformedValue:(id)object +{ + NSArray *arguments = [_arguments arrayByAddingObject:(object ?: [NSNull null])]; + return _block(arguments); +} + +- (id)filterByCurryingArgument:(id)object +{ + NSArray *arguments = [_arguments arrayByAddingObject:(object ?: [NSNull null])]; + return [[[GRMustacheBlockVariadicFilter alloc] initWithBlock:_block arguments:arguments] autorelease]; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h new file mode 100644 index 0000000..df688c5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h @@ -0,0 +1,64 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +// prevent GRMustacheFilter.h to load +#define GRMUSTACHE_FILTER + +// Documented in GRMustacheFilter.h +@protocol GRMustacheFilter +@required + +// Documented in GRMustacheFilter.h +- (id)transformedValue:(id)object GRMUSTACHE_API_PUBLIC; + +@optional + +/** + * Returns a new filter that uses the _object_ parameter. + * + * Filter currying is involved in `f(a,...)` expressions, filters with more than + * one argument. + * + * The evaluation of `f(a,b)` is implemented as `f(a)(b)`: the filter `f` is + * asked for a curried filter using argument `a`. This curried filter `g` is + * then applied to `b`: + * + * g = f(a) + * f(a,b) = g(b) + */ +- (id)filterByCurryingArgument:(id)object GRMUSTACHE_API_INTERNAL; +@end + + +// Documented in GRMustacheFilter.h +@interface GRMustacheFilter : NSObject + +// Documented in GRMustacheFilter.h ++ (id)filterWithBlock:(id(^)(id value))block GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheFilter.h ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block GRMUSTACHE_API_PUBLIC; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m new file mode 100644 index 0000000..c0f7fb2 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m @@ -0,0 +1,693 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheSafeKeyAccess.h" +#import "JRSwizzle.h" + + +#if !defined(NS_BLOCK_ASSERTIONS) +// For testing purpose +BOOL GRMustacheKeyAccessDidCatchNSUndefinedKeyException; +#endif + + +// ============================================================================= +#pragma mark - Safe key access + +static pthread_key_t GRSafeKeysForClassKey; +void freeSafeKeysForClass(void *objects) { + CFRelease((CFMutableDictionaryRef)objects); +} +#define setupSafeKeysForClass() pthread_key_create(&GRSafeKeysForClassKey, freeSafeKeysForClass) +#define getCurrentThreadSafeKeysForClass() (CFMutableDictionaryRef)pthread_getspecific(GRSafeKeysForClassKey) +#define setCurrentThreadSafeKeysForClass(classes) pthread_setspecific(GRSafeKeysForClassKey, classes) + + +// ============================================================================= +#pragma mark - Foundation declarations + +static NSMutableSet *safeMustacheKeysForNSArray; +static NSMutableSet *safeMustacheKeysForNSAttributedString; +static NSMutableSet *safeMustacheKeysForNSData; +static NSMutableSet *safeMustacheKeysForNSDate; +static NSMutableSet *safeMustacheKeysForNSDateComponents; +static NSMutableSet *safeMustacheKeysForNSDecimalNumber; +static NSMutableSet *safeMustacheKeysForNSError; +static NSMutableSet *safeMustacheKeysForNSHashTable; +static NSMutableSet *safeMustacheKeysForNSIndexPath; +static NSMutableSet *safeMustacheKeysForNSIndexSet; +static NSMutableSet *safeMustacheKeysForNSMapTable; +static NSMutableSet *safeMustacheKeysForNSNotification; +static NSMutableSet *safeMustacheKeysForNSException; +static NSMutableSet *safeMustacheKeysForNSNumber; +static NSMutableSet *safeMustacheKeysForNSOrderedSet; +static NSMutableSet *safeMustacheKeysForNSPointerArray; +static NSMutableSet *safeMustacheKeysForNSSet; +static NSMutableSet *safeMustacheKeysForNSString; +static NSMutableSet *safeMustacheKeysForNSURL; +static NSMutableSet *safeMustacheKeysForNSValue; + +static NSSet *safeMustacheKeys_NSArray(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSAttributedString(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSData(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDate(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDateComponents(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDecimalNumber(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSError(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSHashTable(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSIndexPath(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSIndexSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSMapTable(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSNotification(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSException(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSNumber(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSOrderedSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSPointerArray(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSString(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSURL(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSValue(id self, SEL _cmd); + + +// ============================================================================= +#pragma mark - NSUndefinedKeyException prevention declarations + +@interface NSObject(GRMustacheKeyAccessPreventionOfNSUndefinedKeyException) +- (id)GRMustacheKeyAccessValueForUndefinedKey_NSObject:(NSString *)key; +- (id)GRMustacheKeyAccessValueForUndefinedKey_NSManagedObject:(NSString *)key; +@end; + + +// ============================================================================= +#pragma mark - GRMustacheKeyAccess + +static Class NSOrderedSetClass; +static Class NSManagedObjectClass; + +@interface NSObject(GRMustacheCoreDataMethods) +- (NSDictionary *)propertiesByName; +- (id)entity; +@end + +@implementation GRMustacheKeyAccess + ++ (void)initialize +{ + NSOrderedSetClass = NSClassFromString(@"NSOrderedSet"); + NSManagedObjectClass = NSClassFromString(@"NSManagedObject"); + [self setupSafeKeyAccessForFoundationClasses]; + setupSafeKeysForClass(); +} + ++ (id)valueForMustacheKey:(NSString *)key inObject:(id)object unsafeKeyAccess:(BOOL)unsafeKeyAccess +{ + if (object == nil) { + return nil; + } + + + // Try objectForKeyedSubscript: first (see https://github.com/groue/GRMustache/issues/66:) + + if ([object respondsToSelector:@selector(objectForKeyedSubscript:)]) { + return [object objectForKeyedSubscript:key]; + } + + + // Then try valueForKey: for safe keys + + if (!unsafeKeyAccess && ![self isSafeMustacheKey:key forObject:object]) { + return nil; + } + + + @try { + + // valueForKey: may throw NSUndefinedKeyException, and user may want to + // prevent them. + + if (preventsNSUndefinedKeyException) { + [GRMustacheKeyAccess startPreventingNSUndefinedKeyExceptionFromObject:object]; + } + + // We don't want to use NSArray, NSSet and NSOrderedSet implementation + // of valueForKey:, because they return another collection: see issue + // #21 and "anchored key should not extract properties inside an array" + // test in src/tests/Public/v4.0/GRMustacheSuites/compound_keys.json + // + // Instead, we want the behavior of NSObject's implementation of valueForKey:. + + if ([self objectIsFoundationCollectionWhoseImplementationOfValueForKeyReturnsAnotherCollection:object]) { + return [self valueForMustacheKey:key inFoundationCollectionObject:object]; + } else { + return [object valueForKey:key]; + } + } + + @catch (NSException *exception) { + + // Swallow NSUndefinedKeyException only + + if (![[exception name] isEqualToString:NSUndefinedKeyException]) { + [exception raise]; + } +#if !defined(NS_BLOCK_ASSERTIONS) + else { + // For testing purpose + GRMustacheKeyAccessDidCatchNSUndefinedKeyException = YES; + } +#endif + } + + @finally { + if (preventsNSUndefinedKeyException) { + [GRMustacheKeyAccess stopPreventingNSUndefinedKeyExceptionFromObject:object]; + } + } + + return nil; +} + + +// ============================================================================= +#pragma mark - Foundation collections + ++ (BOOL)objectIsFoundationCollectionWhoseImplementationOfValueForKeyReturnsAnotherCollection:(id)object +{ + if ([object isKindOfClass:[NSArray class]]) { return YES; } + if ([object isKindOfClass:[NSSet class]]) { return YES; } + if (NSOrderedSetClass && [object isKindOfClass:NSOrderedSetClass]) { return YES; } + return NO; +} + ++ (id)valueForMustacheKey:(NSString *)key inFoundationCollectionObject:(id)object +{ + // Ideally, we would use NSObject's implementation for collections, so that + // we can access properties such as `count`, `anyObject`, etc. + // + // And so we did, until [issue #70](https://github.com/groue/GRMustache/issues/70) + // revealed that the direct use of NSObject's imp crashes on arm64: + // + // IMP imp = class_getMethodImplementation([NSObject class], @selector(valueForKey:)); + // return imp(object, @selector(valueForKey:), key); // crash on arm64 + // + // objc_msgSendSuper fails on arm64 as well: + // + // return objc_msgSendSuper( + // &(struct objc_super){ .receiver = object, .super_class = [NSObject class] }, + // @selector(valueForKey:), + // key); // crash on arm64 + // + // So we have to implement NSObject's valueForKey: ourselves. + // + // Quoting Apple documentation: + // https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/SearchImplementation.html + // + // > Default Search Pattern for valueForKey: + // > + // > 1. Searches the class of the receiver for an accessor method whose + // > name matches the pattern get, , or is, in that order. + // + // The remaining of the search pattern goes into aggregates and ivars. Let's + // ignore aggregates (until someone has a need for it), and ivars (since + // they are private). + + NSString *keyWithUppercaseInitial = [NSString stringWithFormat:@"%@%@", + [[key substringToIndex:1] uppercaseString], + [key substringFromIndex:1]]; + NSArray *accessors = [NSArray arrayWithObjects: + [NSString stringWithFormat:@"get%@", keyWithUppercaseInitial], + key, + [NSString stringWithFormat:@"is%@", keyWithUppercaseInitial], + nil]; + + for (NSString *accessor in accessors) { + SEL selector = NSSelectorFromString(accessor); + if ([object respondsToSelector:selector]) { + + // Extract the raw value into a buffer + + NSMethodSignature *methodSignature = [object methodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; + invocation.selector = selector; + [invocation invokeWithTarget:object]; + NSUInteger methodReturnLength = [methodSignature methodReturnLength]; + if (methodReturnLength == 0) { + // no value + return nil; + } else { + void *buffer = malloc(methodReturnLength); + if (buffer == NULL) { + // Allocation failed. + // + // This method is not supposed to allocate any object, so we + // can not behave like failing allocating methods and return + // nil. + // + // So let's raise an exception. + // + // NSMallocException is supposedly obsolete but there are + // evidences it is still used by Foundation: + // http://stackoverflow.com/search?q=NSMallocException + [NSException raise:NSMallocException format:@"Out of memory."]; + } + [invocation getReturnValue:buffer]; + + // Turn the raw value buffer into an object + + id result = nil; + const char *objCType = [methodSignature methodReturnType]; + switch(objCType[0]) { + case 'c': + result = [NSNumber numberWithChar:*(char *)buffer]; + break; + case 'i': + result = [NSNumber numberWithInt:*(int *)buffer]; + break; + case 's': + result = [NSNumber numberWithShort:*(short *)buffer]; + break; + case 'l': + result = [NSNumber numberWithLong:*(long *)buffer]; + break; + case 'q': + result = [NSNumber numberWithLongLong:*(long long *)buffer]; + break; + case 'C': + result = [NSNumber numberWithUnsignedChar:*(unsigned char *)buffer]; + break; + case 'I': + result = [NSNumber numberWithUnsignedInt:*(unsigned int *)buffer]; + break; + case 'S': + result = [NSNumber numberWithUnsignedShort:*(unsigned short *)buffer]; + break; + case 'L': + result = [NSNumber numberWithUnsignedLong:*(unsigned long *)buffer]; + break; + case 'Q': + result = [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)buffer]; + break; + case 'B': + result = [NSNumber numberWithBool:*(_Bool *)buffer]; + break; + case 'f': + result = [NSNumber numberWithFloat:*(float *)buffer]; + break; + case 'd': + result = [NSNumber numberWithDouble:*(double *)buffer]; + break; + case '@': + case '#': + result = *(id *)buffer; + break; + default: + [NSException raise:NSInternalInconsistencyException format:@"Not implemented yet"]; + break; + } + + free(buffer); + return result; + } + } + } + + return nil; +} + + +// ============================================================================= +#pragma mark - Foundation + ++ (void)setupSafeKeyAccessForFoundationClasses +{ + // Safe key access prevents dangerous methods from being accessed by bad + // templates through `valueForKey:`. + // + // By default, only declared properties can be accessed, unless classes + // conform to the GRMustacheSafeKeyAccess protocol. + // + // We want to let users have a liberal use of KVC on Foundation classes: + // `{{# array.count }}`, `{{ dateComponents.year }}`, etc. Those classes + // do not always declare properties for those accessors. + // + // So let's setup safe keys for common Foundation classes, by allowing + // all their non-mutating methods, plus a few safe NSObject methods, + // minus dangerous NSObject methods. + + NSSet *safeMustacheNSObjectKeys = [NSSet setWithObjects: + @"class", + @"superclass", + @"self", + @"description", + @"debugDescription", + nil]; + NSSet *unsafeMustacheNSObjectKeys = [NSSet setWithObjects: + @"init", + @"dealloc", + @"finalize", + @"copy", + @"mutableCopy", + @"retain", + @"release", + @"autorelease", + nil]; + + SEL selector = @selector(safeMustacheKeys); + Protocol *protocol = @protocol(GRMustacheSafeKeyAccess); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, NO); + +#define setupSafeKeyAccessForClass(klassName) do {\ +Class klass = NSClassFromString(@#klassName);\ +if (klass) {\ +Class metaKlass = object_getClass(klass);\ +safeMustacheKeysFor ## klassName = [[self allPublicKeysForClass:klass] retain];\ +[safeMustacheKeysFor ## klassName unionSet:safeMustacheNSObjectKeys];\ +[safeMustacheKeysFor ## klassName minusSet:unsafeMustacheNSObjectKeys];\ +class_addMethod(metaKlass, selector, (IMP)safeMustacheKeys_ ## klassName, methodDescription.types);\ +class_addProtocol(klass, protocol);\ +}\ +} while(0); + + setupSafeKeyAccessForClass(NSArray); + setupSafeKeyAccessForClass(NSAttributedString); + setupSafeKeyAccessForClass(NSData); + setupSafeKeyAccessForClass(NSDate); + setupSafeKeyAccessForClass(NSDateComponents); + setupSafeKeyAccessForClass(NSDecimalNumber); + setupSafeKeyAccessForClass(NSError); + setupSafeKeyAccessForClass(NSHashTable); + setupSafeKeyAccessForClass(NSIndexPath); + setupSafeKeyAccessForClass(NSIndexSet); + setupSafeKeyAccessForClass(NSMapTable); + setupSafeKeyAccessForClass(NSNotification); + setupSafeKeyAccessForClass(NSException); + setupSafeKeyAccessForClass(NSNumber); + setupSafeKeyAccessForClass(NSOrderedSet); + setupSafeKeyAccessForClass(NSPointerArray); + setupSafeKeyAccessForClass(NSSet); + setupSafeKeyAccessForClass(NSString); + setupSafeKeyAccessForClass(NSURL); + setupSafeKeyAccessForClass(NSValue); +} + +/** + * Return the set of methods without arguments, up to NSObject, non including NSObject. + */ ++ (NSMutableSet *)allPublicKeysForClass:(Class)klass +{ + NSMutableSet *keys = [NSMutableSet set]; + Class NSObjectClass = [NSObject class]; + while (klass && klass != NSObjectClass) { + unsigned int methodCount; + Method *methods = class_copyMethodList(klass, &methodCount); + for (unsigned int i = 0; i < methodCount; ++i) { + SEL selector = method_getName(methods[i]); + const char *selectorName = sel_getName(selector); + if (selectorName[0] != '_' && selectorName[strlen(selectorName) - 1] != '_' && strstr(selectorName, ":") == NULL) { + [keys addObject:NSStringFromSelector(selector)]; + } + } + free (methods); + klass = class_getSuperclass(klass); + } + + return keys; +} + + +// ============================================================================= +#pragma mark - Safe key access + ++ (BOOL)isSafeMustacheKey:(NSString *)key forObject:(id)object +{ + NSSet *safeKeys = nil; + { + CFMutableDictionaryRef safeKeysForClass = getCurrentThreadSafeKeysForClass(); + if (!safeKeysForClass) { + safeKeysForClass = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); + setCurrentThreadSafeKeysForClass(safeKeysForClass); + } + + Class klass = [object class]; + safeKeys = (NSSet *)CFDictionaryGetValue(safeKeysForClass, klass); + if (safeKeys == nil) { + if ([klass respondsToSelector:@selector(safeMustacheKeys)]) { + safeKeys = [klass safeMustacheKeys] ?: [NSSet set]; + } else { + NSMutableSet *keys = [self propertyGettersForClass:klass]; + if (NSManagedObjectClass && [object isKindOfClass:NSManagedObjectClass]) { + [keys unionSet:[NSSet setWithArray:[[[object entity] propertiesByName] allKeys]]]; + } + safeKeys = keys; + } + CFDictionarySetValue(safeKeysForClass, klass, safeKeys); + } + } + + return [safeKeys containsObject:key]; +} + ++ (NSMutableSet *)propertyGettersForClass:(Class)klass +{ + NSMutableSet *safeKeys = [NSMutableSet set]; + while (klass) { + // Iterate properties + + unsigned int count; + objc_property_t *properties = class_copyPropertyList(klass, &count); + + for (unsigned int i=0; i +#import "GRMustacheAvailabilityMacros_private.h" + +#if !defined(NS_BLOCK_ASSERTIONS) +/** + * This global variable is used by GRPreventNSUndefinedKeyExceptionAttackTest. + */ +extern BOOL GRMustacheKeyAccessDidCatchNSUndefinedKeyException; +#endif + +/** + * GRMustacheKeyAccess implements all the GRMustache key-fetching logic. + */ +@interface GRMustacheKeyAccess : NSObject + +/** + * Avoids most NSUndefinedException to be raised by the invocation of + * `valueForMustacheKey:inObject:`. + * + * @see valueForMustacheKey:inObject: + */ ++ (void)preventNSUndefinedKeyExceptionAttack GRMUSTACHE_API_INTERNAL; + +/** + * Sends the `objectForKeyedSubscript:` or `valueForKey:` message to object + * with the provided key, and returns the result. + * + * If object responds to `objectForKeyedSubscript:`, `valueForKey:` is not + * invoked. + * + * If `valueForKey:` raise an NSUndefinedKeyException, the method returns nil. + * + * @param key The searched key + * @param object The queried object + * @param unsafeKeyAccess If YES, the `valueForKey:` method will be used + * without any restriction. + * + * @return The value that should be handled by Mustache rendering for a given + * key. + */ ++ (id)valueForMustacheKey:(NSString *)key inObject:(id)object unsafeKeyAccess:(BOOL)unsafeKeyAccess GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h new file mode 100644 index 0000000..f1b526a --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h @@ -0,0 +1,130 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GRMUSTACHE_RENDERING +#define GRMUSTACHE_RENDERING + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheContext; +@class GRMustacheTag; + + +// ============================================================================= +#pragma mark - + + +/** + * The protocol for your own objects that perform custom rendering. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + */ +@protocol GRMustacheRendering + +/** + * This method is invoked when the receiver should be rendered by a Mustache + * tag. + * + * It returns three values: the rendering itself, a boolean that says whether + * the rendering is HTML-safe or not, and an eventual error. + * + * Input values are the tag that should be rendered, and the context object that + * represents the current context stack. + * + * Depending on the content type of the currently rendered template, an output + * parameter _HTMLSafe_ set to NO will have the returned string HTML-escaped. + * + * @param tag The tag to be rendered + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES if the result is HTML-safe. + * @param error If there is an error performing the rendering, upon return + * contains an NSError object that describes the problem. + * + * @return The rendering of the receiver for the given tag, in the given + * context. + * + * @see GRMustacheTag + * @see GRMustacheContext + * @see GRMustacheContentType + * + * @since v6.0 + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; +@end + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +/** + * The GRMustacheRendering class helps building rendering objects without + * writing a custom class that conforms to the GRMustacheRendering protocol. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ +@interface GRMustacheRendering : NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Rendering Objects +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns a rendering object that is able to render the argument _object_ for + * the various Mustache tags. + * + * @param object An object. + * + * @return A rendering object able to render the argument. + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ ++ (id)renderingObjectForObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a rendering object that renders with the provided block. + * + * @param renderingBlock A block that follows the semantics of the + * renderForMustacheTag:context:HTMLSafe:error: method + * defined by the GRMustacheRendering protocol. See the + * documentation of this method. + * + * @return A rendering object + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + +#endif diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m new file mode 100644 index 0000000..ed7a138 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m @@ -0,0 +1,608 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheRendering_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheError.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheBuffer_private.h" + + +// ============================================================================= +#pragma mark - Rendering declarations + + +// GRMustacheNilRendering renders for nil + +@interface GRMustacheNilRendering : NSObject +@end +static GRMustacheNilRendering *nilRendering; + + +// GRMustacheBlockRendering renders with a block + +@interface GRMustacheBlockRendering : NSObject { +@private + NSString *(^_renderingBlock)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +} +- (instancetype)initWithRenderingBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock; +@end + + +// NSNull, NSNumber, NSString, NSObject, NSFastEnumeration rendering + +typedef NSString *(*GRMustacheRenderIMP)(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderGeneric(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); + +typedef NSString *(*GRMustacheRenderWithIterationSupportIMP)(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportGeneric(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSNull(NSNull *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSNumber(NSNumber *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSString(NSString *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSObject(NSObject *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSFastEnumeration(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); + +typedef BOOL (*GRMustacheBoolValueIMP)(id self, SEL _cmd); +static BOOL GRMustacheBoolValueGeneric(id self, SEL _cmd); +static BOOL GRMustacheBoolValueNSNull(NSNull *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSNumber(NSNumber *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSString(NSString *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSObject(NSObject *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSFastEnumeration(id self, SEL _cmd); + + +// ============================================================================= +#pragma mark - Current Template Repository + +static pthread_key_t GRCurrentTemplateRepositoryStackKey; +void freeCurrentTemplateRepositoryStack(void *objects) { + [(NSMutableArray *)objects release]; +} +#define setupCurrentTemplateRepositoryStack() pthread_key_create(&GRCurrentTemplateRepositoryStackKey, freeCurrentTemplateRepositoryStack) +#define getCurrentThreadCurrentTemplateRepositoryStack() (NSMutableArray *)pthread_getspecific(GRCurrentTemplateRepositoryStackKey) +#define setCurrentThreadCurrentTemplateRepositoryStack(classes) pthread_setspecific(GRCurrentTemplateRepositoryStackKey, classes) + + +// ============================================================================= +#pragma mark - Current Content Type + +static pthread_key_t GRCurrentContentTypeStackKey; +void freeCurrentContentTypeStack(void *objects) { + [(NSMutableArray *)objects release]; +} +#define setupCurrentContentTypeStack() pthread_key_create(&GRCurrentContentTypeStackKey, freeCurrentContentTypeStack) +#define getCurrentThreadCurrentContentTypeStack() (NSMutableArray *)pthread_getspecific(GRCurrentContentTypeStackKey) +#define setCurrentThreadCurrentContentTypeStack(classes) pthread_setspecific(GRCurrentContentTypeStackKey, classes) + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +@implementation GRMustacheRendering + ++ (void)initialize +{ + setupCurrentTemplateRepositoryStack(); + setupCurrentContentTypeStack(); + + nilRendering = [[GRMustacheNilRendering alloc] init]; + + // We could have declared categories on NSNull, NSNumber, NSString and + // NSDictionary. + // + // We do not, because many GRMustache users use the static library, and + // we don't want to force them adding the `-ObjC` option to their + // target's "Other Linker Flags" (which is required for code declared by + // categories to be loaded). + // + // Instead, dynamically alter the classes whose rendering implementation + // is already known. + // + // Other classes will be dynamically attached their rendering implementation + // in the GRMustacheRenderWithIterationSupportGeneric implementation + // attached to NSObject. + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSNull boolValueIMP:GRMustacheBoolValueNSNull forClass:[NSNull class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSNumber boolValueIMP:GRMustacheBoolValueNSNumber forClass:[NSNumber class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSString boolValueIMP:GRMustacheBoolValueNSString forClass:[NSString class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:[NSDictionary class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportGeneric boolValueIMP:GRMustacheBoolValueGeneric forClass:[NSObject class]]; + + // Besides, provide all objects the ability to render as an enumeration item + // or not through GRMustacheRenderGeneric: + [self registerRenderIMP:GRMustacheRenderGeneric forClass:[NSObject class]]; + +} + ++ (id)renderingObjectForObject:(id)object +{ + // All objects but nil know how to render (see setupRendering). + return object ?: nilRendering; +} + ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock +{ + return [[[GRMustacheBlockRendering alloc] initWithRenderingBlock:renderingBlock] autorelease]; +} + + +#pragma mark - Current Template Repository + ++ (void)pushCurrentTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + if (!stack) { + stack = [[NSMutableArray alloc] init]; + setCurrentThreadCurrentTemplateRepositoryStack(stack); + } + [stack addObject:templateRepository]; +} + ++ (void)popCurrentTemplateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + NSAssert(stack, @"Missing currentTemplateRepositoryStack"); + NSAssert(stack.count > 0, @"Empty currentTemplateRepositoryStack"); + [stack removeLastObject]; +} + ++ (GRMustacheTemplateRepository *)currentTemplateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + return [stack lastObject]; +} + + +#pragma mark - Current Content Type + ++ (void)pushCurrentContentType:(GRMustacheContentType)contentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + if (!stack) { + stack = [[NSMutableArray alloc] init]; + setCurrentThreadCurrentContentTypeStack(stack); + } + [stack addObject:[NSNumber numberWithUnsignedInteger:contentType]]; +} + ++ (void)popCurrentContentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + NSAssert(stack, @"Missing currentContentTypeStack"); + NSAssert(stack.count > 0, @"Empty currentContentTypeStack"); + [stack removeLastObject]; +} + ++ (GRMustacheContentType)currentContentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + if (stack.count > 0) { + return [(NSNumber *)[stack lastObject] unsignedIntegerValue]; + } + return ([self currentTemplateRepository].configuration ?: [GRMustacheConfiguration defaultConfiguration]).contentType; +} + + +#pragma mark - Private + +/** + * Have the class _aClass_ conform to the + * GRMustacheRenderingWithIterationSupport protocol. + * + * @param renderIMP the implementation of the + * renderForMustacheTag:asEnumerationItem:context:HTMLSafe:error: + * method. + * @param boolValueIMP the implementation of the mustacheBoolValue method. + * @param aClass the class to modify. + */ ++ (void)registerRenderWithIterationSupportIMP:(GRMustacheRenderWithIterationSupportIMP)renderIMP boolValueIMP:(GRMustacheBoolValueIMP)boolValueIMP forClass:(Class)klass +{ + Protocol *protocol = @protocol(GRMustacheRenderingWithIterationSupport); + + // Add method implementations + + { + SEL selector = @selector(renderForMustacheTag:asEnumerationItem:context:HTMLSafe:error:); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)renderIMP, methodDescription.types); + } + + { + SEL selector = @selector(mustacheBoolValue); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)boolValueIMP, methodDescription.types); + } + + // Add protocol conformance + class_addProtocol(klass, protocol); +} + +/** + * Have the class _aClass_ conform to the GRMustacheRendering protocol. + * + * @param renderIMP the implementation of the + * renderForMustacheTag:context:HTMLSafe:error: method. + * @param aClass the class to modify. + */ ++ (void)registerRenderIMP:(GRMustacheRenderIMP)renderIMP forClass:(Class)klass +{ + Protocol *protocol = @protocol(GRMustacheRendering); + + // Add method implementations + + { + SEL selector = @selector(renderForMustacheTag:context:HTMLSafe:error:); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)renderIMP, methodDescription.types); + } + + // Add protocol conformance + class_addProtocol(klass, protocol); +} + +@end + + +// ============================================================================= +#pragma mark - Rendering Implementations + +@implementation GRMustacheNilRendering + +- (BOOL)mustacheBoolValue +{ + return NO; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return [self renderForMustacheTag:tag asEnumerationItem:NO context:context HTMLSafe:HTMLSafe error:error]; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag asEnumerationItem:(BOOL)enumerationItem context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ nil }} + return @""; + + case GRMustacheTagTypeSection: + // {{# nil }}...{{/}} + // {{^ nil }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + +@end + + +@implementation GRMustacheBlockRendering + +- (void)dealloc +{ + [_renderingBlock release]; + [super dealloc]; +} + +- (instancetype)initWithRenderingBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock +{ + if (renderingBlock == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a rendering object with a nil rendering block."]; + } + + self = [super init]; + if (self) { + _renderingBlock = [renderingBlock copy]; + } + return self; +} + +- (BOOL)mustacheBoolValue +{ + return YES; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return _renderingBlock(tag, context, HTMLSafe, error); +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag asEnumerationItem:(BOOL)enumerationItem context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return _renderingBlock(tag, context, HTMLSafe, error); +} + +@end + + +static BOOL GRMustacheBoolValueGeneric(id self, SEL _cmd) +{ + // Self doesn't know (yet) its mustache boolean value + + Class klass = object_getClass(self); + if ([self respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) + { + // Future invocations will use GRMustacheBoolValueNSFastEnumeration + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSFastEnumeration boolValueIMP:GRMustacheBoolValueNSFastEnumeration forClass:klass]; + return GRMustacheBoolValueNSFastEnumeration(self, _cmd); + } + + if (klass != [NSObject class]) + { + // Future invocations will use GRMustacheRenderNSObject + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:klass]; + } + + return GRMustacheBoolValueNSObject(self, _cmd); +} + +static NSString *GRMustacheRenderGeneric(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + return [self renderForMustacheTag:tag asEnumerationItem:NO context:context HTMLSafe:HTMLSafe error:error]; +} + +static NSString *GRMustacheRenderWithIterationSupportGeneric(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + // Self doesn't know (yet) how to render as an enumeration item + + Class klass = object_getClass(self); + if ([self respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) + { + // Future invocations will use GRMustacheRenderNSFastEnumeration + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSFastEnumeration boolValueIMP:GRMustacheBoolValueNSFastEnumeration forClass:klass]; + return GRMustacheRenderWithIterationSupportNSFastEnumeration(self, _cmd, tag, enumerationItem, context, HTMLSafe, error); + } + + if (klass != [NSObject class]) + { + // Future invocations will use GRMustacheRenderWithIterationSupportNSObject + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:klass]; + } + + return GRMustacheRenderWithIterationSupportNSObject(self, _cmd, tag, enumerationItem, context, HTMLSafe, error); +} + +static BOOL GRMustacheBoolValueNSNull(NSNull *self, SEL _cmd) +{ + return NO; +} + +static NSString *GRMustacheRenderWithIterationSupportNSNull(NSNull *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ null }} + return @""; + + case GRMustacheTagTypeSection: + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } else { + // {{^ null }}...{{/}} + // {{# null }}...{{/}} + + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} + +static BOOL GRMustacheBoolValueNSNumber(NSNumber *self, SEL _cmd) +{ + return [self boolValue]; +} + +static NSString *GRMustacheRenderWithIterationSupportNSNumber(NSNumber *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ number }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return [self description]; + + case GRMustacheTagTypeSection: + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } else { + // {{^ number }}...{{/}} + // {{# number }}...{{/}} + // + // janl/mustache.js and defunkt/mustache don't push bools in the + // context stack. Follow their path, and avoid the creation of a + // useless context nobody cares about. + // + // GRMustache 7.2.0 broke this behavior (see issue + // https://github.com/groue/GRMustache/issues/83). This behavior + // must stay! + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} + +static BOOL GRMustacheBoolValueNSString(NSString *self, SEL _cmd) +{ + return (self.length > 0); +} + +static NSString *GRMustacheRenderWithIterationSupportNSString(NSString *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ string }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return self; + + case GRMustacheTagTypeSection: + if (tag.isInverted) { + // {{^ number }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } else { + // {{# string }}...{{/}} + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } + } +} + +static BOOL GRMustacheBoolValueNSObject(NSObject *self, SEL _cmd) +{ + return YES; +} + +static NSString *GRMustacheRenderWithIterationSupportNSObject(NSObject *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ object }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# object }}...{{/}} + // {{^ object }}...{{/}} + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } +} + +static BOOL GRMustacheBoolValueNSFastEnumeration(id self, SEL _cmd) +{ + for (id _ __attribute__((unused)) in self) { + return YES; + } + return NO; +} + +static NSString *GRMustacheRenderWithIterationSupportNSFastEnumeration(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } + + // {{ list }} + // {{# list }}...{{/}} + // {{^ list }}...{{/}} + + BOOL success = YES; + BOOL bufferCreated = NO; + GRMustacheBuffer buffer; + BOOL anyItemHTMLSafe = NO; + BOOL anyItemHTMLUnsafe = NO; + + for (id item in self) { + if (!bufferCreated) { + buffer = GRMustacheBufferCreate(1024); + bufferCreated = YES; + } + @autoreleasepool { + // Render item + + BOOL itemHTMLSafe = NO; // always assume unsafe rendering + NSError *renderingError = nil; + NSString *rendering = [[GRMustacheRendering renderingObjectForObject:item] renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:&itemHTMLSafe error:&renderingError]; + + if (!rendering) { + if (!renderingError) { + // Rendering is nil, but rendering error is not set. + // + // Assume a rendering object coded by a lazy programmer, + // whose intention is to render nothing. + + rendering = @""; + } else { + if (error != NULL) { + // make sure error is not released by autoreleasepool + *error = renderingError; + [*error retain]; + } + success = NO; + break; + } + } + + // check consistency of HTML escaping + + if (itemHTMLSafe) { + anyItemHTMLSafe = YES; + if (anyItemHTMLUnsafe) { + [NSException raise:GRMustacheRenderingException format:@"Inconsistant HTML escaping of items in enumeration"]; + } + } else { + anyItemHTMLUnsafe = YES; + if (anyItemHTMLSafe) { + [NSException raise:GRMustacheRenderingException format:@"Inconsistant HTML escaping of items in enumeration"]; + } + } + + // appending the rendering to the buffer + + GRMustacheBufferAppendString(&buffer, rendering); + } + } + + if (!success) { + if (error != NULL) [*error autorelease]; + GRMustacheBufferRelease(&buffer); + return nil; + } + + if (bufferCreated) { + // Non-empty list + + if (HTMLSafe != NULL) { + *HTMLSafe = !anyItemHTMLUnsafe; + } + return GRMustacheBufferGetStringAndRelease(&buffer); + } else { + // Empty list + + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ emptyList }} + return @""; + + case GRMustacheTagTypeSection: + // {{^ emptyList }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m new file mode 100644 index 0000000..df7e4f2 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m @@ -0,0 +1,352 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheRenderingEngine_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheTranslateCharacters_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTextNode_private.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheExpressionInvocation_private.h" + +@interface GRMustacheRenderingEngine() +@end + +static pthread_key_t GRCurrentExpressionInvocationKey; +void freeCurrentExpressionInvocation(void *object) { + [(GRMustacheExpressionInvocation *)object release]; +} +#define setupCurrentExpressionInvocation() pthread_key_create(&GRCurrentExpressionInvocationKey, freeCurrentExpressionInvocation) +#define getCurrentThreadCurrentExpressionInvocation() (GRMustacheExpressionInvocation *)pthread_getspecific(GRCurrentExpressionInvocationKey) +#define setCurrentThreadCurrentExpressionInvocation(object) pthread_setspecific(GRCurrentExpressionInvocationKey, object) +static inline GRMustacheExpressionInvocation *currentThreadCurrentExpressionInvocation() { + GRMustacheExpressionInvocation *expressionInvocation = getCurrentThreadCurrentExpressionInvocation(); + if (!expressionInvocation) { + expressionInvocation = [[GRMustacheExpressionInvocation alloc] init]; + setCurrentThreadCurrentExpressionInvocation(expressionInvocation); + } + return expressionInvocation; +} + + +@implementation GRMustacheRenderingEngine + ++ (void)initialize +{ + setupCurrentExpressionInvocation(); +} + ++ (instancetype)renderingEngineWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context +{ + return [[[self alloc] initWithContentType:contentType context:context] autorelease]; +} + +- (NSString *)renderTemplateAST:(GRMustacheTemplateAST *)templateAST HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + _buffer = GRMustacheBufferCreate(1024); + + NSString *result = nil; + if ([self visitTemplateAST:templateAST error:error]) { + if (HTMLSafe) { + *HTMLSafe = (_contentType == GRMustacheContentTypeHTML); + } + result = GRMustacheBufferGetString(&_buffer); + } + + GRMustacheBufferRelease(&_buffer); + + return result; +} + + +#pragma mark - AST Nodes + +- (BOOL)visitTemplateAST:(GRMustacheTemplateAST *)templateAST error:(NSError **)error +{ + GRMustacheContentType ASTContentType = templateAST.contentType; + + if (_contentType != ASTContentType) + { + // Render separately... + + GRMustacheRenderingEngine *renderingEngine = [[[GRMustacheRenderingEngine alloc] initWithContentType:ASTContentType context:_context] autorelease]; + BOOL HTMLSafe; + NSString *rendering = [renderingEngine renderTemplateAST:templateAST HTMLSafe:&HTMLSafe error:error]; + if (!rendering) { + return NO; + } + + // ... and escape if needed + + if (_contentType == GRMustacheContentTypeHTML && !HTMLSafe) { + rendering = GRMustacheTranslateHTMLCharacters(rendering); + } + GRMustacheBufferAppendString(&_buffer, rendering); + return YES; + } + else + { + [GRMustacheRendering pushCurrentContentType:ASTContentType]; + BOOL success = [self visitTemplateASTNodes:templateAST.templateASTNodes error:error]; + [GRMustacheRendering popCurrentContentType]; + return success; + } +} + +- (BOOL)visitInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode error:(NSError **)error +{ + GRMustacheContext *context = _context; + _context = [_context contextByAddingInheritablePartialNode:inheritablePartialNode]; + BOOL success = [self visitPartialNode:inheritablePartialNode.partialNode error:error]; + _context = context; + return success; +} + +- (BOOL)visitInheritableSectionNode:(GRMustacheInheritableSectionNode *)inheritableSectionNode error:(NSError **)error +{ + return [self visitTemplateAST:inheritableSectionNode.templateAST error:error]; +} + +- (BOOL)visitPartialNode:(GRMustachePartialNode *)partialNode error:(NSError **)error +{ + return [self visitTemplateAST:partialNode.templateAST error:error]; +} + +- (BOOL)visitVariableTag:(GRMustacheVariableTag *)variableTag error:(NSError **)error +{ + return [self visitTag:variableTag expression:variableTag.expression escapesHTML:variableTag.escapesHTML error:error]; +} + +- (BOOL)visitSectionTag:(GRMustacheSectionTag *)sectionTag error:(NSError **)error +{ + return [self visitTag:sectionTag expression:sectionTag.expression escapesHTML:YES error:error]; +} + +- (BOOL)visitTextNode:(GRMustacheTextNode *)textNode error:(NSError **)error +{ + GRMustacheBufferAppendString(&_buffer, textNode.text); + return YES; +} + + +#pragma mark - Private + +- (instancetype)initWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context +{ + NSAssert(context, @"Invalid context:nil"); + + self = [super init]; + if (self) { + _contentType = contentType; + _context = context; + } + return self; +} + +- (BOOL)visitTag:(GRMustacheTag *)tag expression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML error:(NSError **)error +{ + BOOL success = YES; + + @autoreleasepool { + + GRMustacheContext *context = _context; + + // Evaluate expression + + GRMustacheExpressionInvocation *expressionInvocation = currentThreadCurrentExpressionInvocation(); + expressionInvocation.expression = expression; + expressionInvocation.context = context; + if (![expressionInvocation invokeReturningError:error]) { + + // Error + + if (error != NULL) { + [*error retain]; // retain error so that it survives the @autoreleasepool block + } + + success = NO; + + } else { + + id value = expressionInvocation.value; + BOOL valueIsProtected = expressionInvocation.valueIsProtected; + + // Hide value if it is protected + if (valueIsProtected) { + // Object is protected: it may enter the context stack, and provide + // value for `.` and `.name`. However, it must not expose its keys. + // + // The goal is to have `{{ safe.name }}` and `{{#safe}}{{.name}}{{/safe}}` + // work, but not `{{#safe}}{{name}}{{/safe}}`. + // + // Rationale: + // + // Let's look at `{{#safe}}{{#hacker}}{{name}}{{/hacker}}{{/safe}}`: + // + // The protected context stack contains the "protected root": + // { safe : { name: "important } }. + // + // Since the user has used the key `safe`, he expects `name` to be + // safe as well, even if `hacker` has defined its own `name`. + // + // So we need to have `name` come from `safe`, not from `hacker`. + // We should thus start looking in `safe` first. But `safe` was + // not initially in the protected context stack. Only the protected + // root was. Hence somebody had `safe` in the protected context + // stack. + // + // Who has objects enter the context stack? Rendering objects do. So + // rendering objects have to know that values are protected or not, + // and choose the correct bucket accordingly. + // + // Who can write his own rendering objects? The end user does. So + // the end user must carefully read a documentation about safety, + // and then carefully code his rendering objects so that they + // conform to this safety notice. + // + // Of course this is not what we want. So `name` can not be + // protected. Since we don't want to let the user think he is data + // is given protected when it is not, we prevent this whole pattern, and + // forbid `{{#safe}}{{name}}{{/safe}}`. + context = [context contextByAddingHiddenObject:value]; + } + + + // Rendered value hooks + + NSArray *tagDelegateStack = [context tagDelegateStack]; + for (id tagDelegate in [tagDelegateStack reverseObjectEnumerator]) { // willRenderObject: from top to bottom + if ([tagDelegate respondsToSelector:@selector(mustacheTag:willRenderObject:)]) { + value = [tagDelegate mustacheTag:tag willRenderObject:value]; + } + } + + + // Render value + + id renderingObject = [GRMustacheRendering renderingObjectForObject:value]; + NSString *rendering = nil; + NSError *renderingError = nil; // Default nil, so that we can help lazy coders who return nil as a valid rendering. + BOOL HTMLSafe = NO; // Default NO, so that we assume unsafe rendering from lazy coders who do not explicitly set it. + switch (tag.type) { + case GRMustacheTagTypeVariable: + rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:&HTMLSafe error:&renderingError]; + break; + + case GRMustacheTagTypeSection: { + // Section rendering depends on the boolean value of the + // rendering object. + // + // Despite the mustacheBoolValue method being declared + // optional by the GRMustacheRendering protocol (for API + // compatibility with GRMustache <= 7.1), the method is + // always implemented, with YES as a default value. + // + // See +[GRMustacheRendering initialize] + BOOL boolValue = [renderingObject mustacheBoolValue]; + if (!tag.isInverted != !boolValue) { + rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:&HTMLSafe error:&renderingError]; + } else { + rendering = @""; + } + } break; + } + + if (!rendering && !renderingError) + { + // Rendering is nil, but rendering error is not set. + // + // Assume a rendering object coded by a lazy programmer, whose + // intention is to render nothing. + + rendering = @""; + } + + + // Finish + + if (rendering) + { + // Render + + if ((_contentType == GRMustacheContentTypeHTML) && !HTMLSafe && escapesHTML) { + rendering = GRMustacheTranslateHTMLCharacters(rendering); + } + GRMustacheBufferAppendString(&_buffer, rendering); + + + // Post-rendering hooks + + for (id tagDelegate in tagDelegateStack) { // didRenderObject: from bottom to top + if ([tagDelegate respondsToSelector:@selector(mustacheTag:didRenderObject:as:)]) { + [tagDelegate mustacheTag:tag didRenderObject:value as:rendering]; + } + } + } + else + { + // Error + + if (error != NULL) { + *error = [renderingError retain]; // retain error so that it survives the @autoreleasepool block + } + success = NO; + + + // Post-error hooks + + for (id tagDelegate in tagDelegateStack) { // didFailRenderingObject: from bottom to top + if ([tagDelegate respondsToSelector:@selector(mustacheTag:didFailRenderingObject:withError:)]) { + [tagDelegate mustacheTag:tag didFailRenderingObject:value withError:renderingError]; + } + } + } + } + } + + if (!success && error) [*error autorelease]; // the error has been retained inside the @autoreleasepool block + return success; +} + +- (BOOL)visitTemplateASTNodes:(NSArray *)templateASTNodes error:(NSError **)error +{ + for (id ASTNode in templateASTNodes) { + ASTNode = [_context resolveTemplateASTNode:ASTNode]; + if (![ASTNode acceptTemplateASTVisitor:self error:error]) { + return NO; + } + } + + return YES; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h new file mode 100644 index 0000000..1b326c5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" +#import "GRMustacheBuffer_private.h" + +@class GRMustacheContext; +@class GRMustacheSectionTag; +@class GRMustacheExpressionInvocation; +@class GRMustacheTemplateAST; + +/** + * TODO + */ +@interface GRMustacheRenderingEngine : NSObject { +@private + GRMustacheBuffer _buffer; + GRMustacheContentType _contentType; + GRMustacheContext *_context; +} + +/** + * TODO + */ +- (NSString *)renderTemplateAST:(GRMustacheTemplateAST *)templateAST HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ ++ (instancetype)renderingEngineWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h new file mode 100644 index 0000000..9ff0b29 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h @@ -0,0 +1,157 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" + +// prevent GRMustacheFilter.h to load +#define GRMUSTACHE_RENDERING + + +@class GRMustacheContext; +@class GRMustacheTag; +@class GRMustacheTemplateRepository; + + +// ============================================================================= +#pragma mark - + + +// Documented in GRMustacheRendering.h +@protocol GRMustacheRendering +@required + +// Documented in GRMustacheRendering.h +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +@optional + +/** + * The boolean value of the rendering object. + * + * A YES boolean value triggers the rendering of {{#section}}...{{/section}} + * tags, and avoids the rendering of inverted {{^section}}...{{/section}} tags. + * + * A NO boolean value avoids the rendering of {{#section}}...{{/section}} + * tags, and triggers the rendering of inverted {{^section}}...{{/section}} tags. + * + * When this method is not provided, the rendering object is assumed to be + * true. + */ +@property (nonatomic, readonly) BOOL mustacheBoolValue GRMUSTACHE_API_INTERNAL; + +@end + + +// ============================================================================= +#pragma mark - + +/** + * The GRMustacheRenderingWithIterationSupport protocol is a private extension + * to the public GRMustacheRendering protocol. + * + * Objects conforming to this protocol can have a different rendering when + * they render as an enumeration item. + * + * Use cases are: + * + * - An NSNumber does not enter the context stack when it renders a + * section, as in {{# 1 }}...{{/}}. + * + * - An NSNumber does enter the context stack when it renders as an enumeration + * item, as in {{# [0,1,2] }}...{{/}}. + * + * - An enumerable object renders all of its items when it renders a + * section, as in {{# [a,b,c] }}...{{/}}. + * + * - An enumerable object have itself enter the context stack when it renders as + * an enumeration item, as in {{# [[a,b,c],[d,e,f]] }}...{{/}}. + */ +@protocol GRMustacheRenderingWithIterationSupport +@required + +/** + * This method is invoked when the receiver should be rendered by a Mustache + * tag. + * + * It returns three values: the rendering itself, a boolean that says whether + * the rendering is HTML-safe or not, and an eventual error. + * + * Input values are the tag that should be rendered, the context object that + * represents the current context stack, and whether the object renders as an + * enumeratiom item or not. + * + * Depending on the content type of the currently rendered template, an output + * parameter _HTMLSafe_ set to NO will have the returned string HTML-escaped. + * + * @param tag The tag to be rendered + * @param enumerationItem YES if the receiver renders as an enumeration item. + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES if the result is HTML-safe. + * @param error If there is an error performing the rendering, upon + * return contains an NSError object that describes the + * problem. + * + * @return The rendering of the receiver. + * + * @see GRMustacheTag + * @see GRMustacheContext + * @see GRMustacheContentType + * + * @since v6.0 + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + asEnumerationItem:(BOOL)enumerationItem + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end + + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +// Documented in GRMustacheRendering.h +@interface GRMustacheRendering : NSObject + +// Documented in GRMustacheRendering.h ++ (id)renderingObjectForObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheRendering.h ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock GRMUSTACHE_API_PUBLIC; + ++ (void)pushCurrentTemplateRepository:(GRMustacheTemplateRepository *)templateRepository GRMUSTACHE_API_INTERNAL; ++ (void)popCurrentTemplateRepository GRMUSTACHE_API_INTERNAL; ++ (GRMustacheTemplateRepository *)currentTemplateRepository GRMUSTACHE_API_INTERNAL; + ++ (void)pushCurrentContentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; ++ (void)popCurrentContentType GRMUSTACHE_API_INTERNAL; ++ (GRMustacheContentType)currentContentType GRMUSTACHE_API_INTERNAL; + +@end + diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h new file mode 100644 index 0000000..caca227 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h @@ -0,0 +1,54 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + + +/** + * Your data classes should conform to the GRMustacheSafeKeyAccess protocol + * to filter the keys that can be accessed by GRMustache templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/runtime/security.md + */ +@protocol GRMustacheSafeKeyAccess + +/** + * List the name of the keys GRMustache can access on this class using the + * `valueForKey:` method. + * + * When objects do not respond to this method, only declared properties can be + * accessed. All properties of Core Data NSManagedObjects are also accessible, + * even without property declaration. + * + * This method is not used for objects responding to `objectForKeyedSubscript:`. + * For those objects, all keys are accessible from templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @return The set of accessible keys on the class. + * + * @since v7.0 + */ ++ (NSSet *)safeMustacheKeys AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h new file mode 100644 index 0000000..573410f --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h @@ -0,0 +1,84 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheTag; + +/** + * Objects conforming to the GRMustacheTagDelegate protocol can observe and + * alter, the rendering of Mustache tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @since v6.0 + */ +@protocol GRMustacheTagDelegate +@optional + +/** + * Sent before a Mustache tag renders. + * + * This method gives an opportunity to alter objects that are rendered. + * + * For example, it is implemented by the NSFormatter class, in templates like + * `{{# dateFormatter }}...{{ value }}...{{ value }}... {{/}}`. + * + * @param tag The Mustache tag about to render. + * @param object The object about to be rendered. + * + * @return The object that should be rendered. + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Sent after a Mustache tag has rendered. + * + * @param tag The Mustache tag that has just rendered. + * @param object The rendered object. + * @param rendering The actual rendering + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (void)mustacheTag:(GRMustacheTag *)tag didRenderObject:(id)object as:(NSString *)rendering AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Sent right after a Mustache tag has failed rendering. + * + * @param tag The Mustache tag that has just failed rendering. + * @param object The rendered object. + * @param error The error. + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (void)mustacheTag:(GRMustacheTag *)tag didFailRenderingObject:(id)object withError:(NSError *)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m new file mode 100644 index 0000000..6be0ca4 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m @@ -0,0 +1,69 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionGenerator_private.h" +#import "GRMustacheExpressionVisitor_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheScopedExpression_private.h" + + +@interface GRMustacheExpressionGenerator() +@end + +@implementation GRMustacheExpressionGenerator + +- (NSString *)stringWithExpression:(GRMustacheExpression *)expression +{ + [expression acceptVisitor:self error:NULL]; + return _expressionString; +} + + +#pragma mark - + +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error +{ + _expressionString = [NSString stringWithFormat:@"%@(%@)", [self stringWithExpression:expression.filterExpression], [self stringWithExpression:expression.argumentExpression]]; + return YES; +} + +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error +{ + _expressionString = expression.identifier; + return YES; +} + +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error +{ + _expressionString = @"."; + return YES; +} + +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error +{ + _expressionString = [NSString stringWithFormat:@"%@.%@", [self stringWithExpression:expression.baseExpression], expression.identifier]; + return YES; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h new file mode 100644 index 0000000..355e378 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h @@ -0,0 +1,35 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheExpression; + +@interface GRMustacheExpressionGenerator : NSObject { +@private + NSString *_expressionString; +} + +- (NSString *)stringWithExpression:(GRMustacheExpression *)expression GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m new file mode 100644 index 0000000..c9b5e2d --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m @@ -0,0 +1,163 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateGenerator_private.h" +#import "GRMustacheExpressionGenerator_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheTemplate_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheTextNode_private.h" + + +@interface GRMustacheTemplateGenerator() +@end + +@implementation GRMustacheTemplateGenerator +@synthesize templateRepository=_templateRepository; + +- (void)dealloc +{ + [_templateRepository release]; + [_expressionGenerator release]; + [super dealloc]; +} + ++ (instancetype)templateGeneratorWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + return [[[self alloc] initWithTemplateRepository:templateRepository] autorelease]; +} + +- (NSString *)stringWithTemplate:(GRMustacheTemplate *)template +{ + _templateString = [NSMutableString string]; + [self visitTemplateAST:template.templateAST error:NULL]; + return _templateString; +} + + +#pragma mark - + +- (BOOL)visitTemplateAST:(GRMustacheTemplateAST *)templateAST error:(NSError **)error +{ + for (id ASTNode in templateAST.templateASTNodes) { + [ASTNode acceptTemplateASTVisitor:self error:error]; + } + + return YES; +} + +- (BOOL)visitInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *partialName = inheritablePartialNode.partialNode.name; + NSString *tagStartString = [NSString stringWithFormat:@"%@<%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:inheritablePartialNode.overridingTemplateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitInheritableSectionNode:(GRMustacheInheritableSectionNode *)inheritableSectionNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *tagStartString = [NSString stringWithFormat:@"%@$%@%@", tagStartDelimiter, inheritableSectionNode.name, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, inheritableSectionNode.name, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:inheritableSectionNode.templateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitPartialNode:(GRMustachePartialNode *)partialNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *partialName = partialNode.name; + NSString *tagString = [NSString stringWithFormat:@"%@>%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + [_templateString appendString:tagString]; + return YES; +} + +- (BOOL)visitVariableTag:(GRMustacheVariableTag *)variableTag error:(NSError **)error +{ + NSString *tagStartDelimiter = nil; + NSString *tagEndDelimiter = nil; + if (variableTag.escapesHTML) { + tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + } else { + tagStartDelimiter = [NSString stringWithFormat:@"%@&", _templateRepository.configuration.tagStartDelimiter]; + tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + } + NSString *expressionString = [_expressionGenerator stringWithExpression:variableTag.expression]; + NSString *tagString = [NSString stringWithFormat:@"%@%@%@", tagStartDelimiter, expressionString, tagEndDelimiter]; + [_templateString appendString:tagString]; + return YES; +} + +- (BOOL)visitSectionTag:(GRMustacheSectionTag *)sectionTag error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *expressionString = [_expressionGenerator stringWithExpression:sectionTag.expression]; + NSString *sectionPrefix = sectionTag.isInverted ? @"^" : @"#"; + NSString *tagStartString = [NSString stringWithFormat:@"%@%@%@%@", tagStartDelimiter, sectionPrefix, expressionString, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, expressionString, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:sectionTag.templateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitTextNode:(GRMustacheTextNode *)textNode error:(NSError **)error +{ + [_templateString appendString:textNode.text]; + return YES; +} + + +#pragma mark - Private + +- (instancetype)initWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + self = [super init]; + if (self) { + _templateRepository = [templateRepository retain]; + _expressionGenerator = [[GRMustacheExpressionGenerator alloc] init]; + } + return self; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h new file mode 100644 index 0000000..a9d0b0b --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h @@ -0,0 +1,42 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheTemplate; +@class GRMustacheTemplateRepository; +@class GRMustacheExpressionGenerator; + +@interface GRMustacheTemplateGenerator : NSObject { +@private + GRMustacheTemplateRepository *_templateRepository; + GRMustacheExpressionGenerator *_expressionGenerator; + NSMutableString *_templateString; +} + +@property (nonatomic, retain, readonly) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_INTERNAL; + ++ (instancetype)templateGeneratorWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository GRMUSTACHE_API_INTERNAL; +- (NSString *)stringWithTemplate:(GRMustacheTemplate *)template GRMUSTACHE_API_INTERNAL; + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h new file mode 100644 index 0000000..b3ba1d5 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h @@ -0,0 +1,70 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheRendering.h" +#import "GRMustacheFilter.h" +#import "GRMustacheTagDelegate.h" + +/** + * A category on NSFormatter that allows them to be directly used in GRMustache + * templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/NSFormatter.md + * + * All NSFormatter subclasses such as NSDateFormatter, NSNumberFormatter, and + * your custom subclasses are concerned. + * + * ## Filter facet + * + * A formatter can be used as a filter, as in `{{ percent(value) }}`. Just have + * your `percent` key evaluate to a formatter. + * + * ## Formatting all values in a section + * + * A formatter can be used to format all values in a section of a template: + * + * ``` + * {{# percent }}...{{ value1 }}...{{ value2 }}...{{/ percent }} + * ``` + * + * The formatting then applies to all inner variable tags that evaluate to a + * value that can be processed by the filter (see + * [NSFormatter stringForObjectValue:] documentation). + * + * Inner loops and boolean sections are unaffected. However their inner variable + * tags are: + * + * ``` + * {{# percent }} + *   {{ value1 }}      {{! format applies }} + *   {{# condition }}  {{! format does not apply }} + *     {{ value2 }}    {{! format applies }} + *   {{/ condition }} + * {{/ percent }} + * ``` + * + * @since v6.4 + */ +@interface NSFormatter (GRMustache) +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m new file mode 100644 index 0000000..a7e42f7 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m @@ -0,0 +1,108 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "NSFormatter+GRMustache.h" +#import "GRMustacheTag.h" +#import "GRMustacheContext.h" + +@implementation NSFormatter (GRMustache) + +#pragma mark - + +/** + * Support for {{ formatter(value) }} + */ +- (id)transformedValue:(id)object +{ + // [NSNumberFormatter stringForObjectValue:] and + // [NSDateFormatter stringForObjectValue:] return nil or an empty string for + // nil, [NSNull null], and other off-topic values. + // + // Since nil and empty strings do not render anything, and are false when + // controlling boolean sections, we can safely say that formatters do not + // have surprising behavior: just use the plain straight + // stringForObjectValue: without any special care. + return [self stringForObjectValue:object]; +} + +#pragma mark - + +/** + * Support for {{# formatter }}...{{ value }}...{{ value }}...{{/ formatter }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ formatter }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# formatter }}...{{/ formatter }} + // {{^ formatter }}...{{/ formatter }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + +#pragma mark - + +/** + * Support for {{# formatter }}...{{ value }}...{{ value }}...{{/ formatter }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: { + // {{ value }} + + NSString *formatted = [self stringForObjectValue:object]; + + if (formatted == nil) { + // NSFormatter documentation for stringForObjectValue: states: + // + // > First test the passed-in object to see if it’s of the correct + // > class. If it isn’t, return nil; but if it is of the right class, + // > return a properly formatted and, if necessary, localized string. + // + // So nil result means that object is not of the correct class. Leave + // it untouched. + + return object; + } + + return formatted; + } + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h new file mode 100644 index 0000000..1e7ff34 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h @@ -0,0 +1,34 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheFilter.h" + +/** + * A category on NSValueTransformer that allows them to be directly used as + * filters in GRMustache templates. + * + * @since v6.4 + */ +@interface NSValueTransformer (GRMustache) +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m new file mode 100644 index 0000000..e82afcc --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m @@ -0,0 +1,26 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "NSValueTransformer+GRMustache.h" + +@implementation NSValueTransformer (GRMustache) +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m new file mode 100644 index 0000000..3c5d5d7 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m @@ -0,0 +1,186 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheEachFilter_private.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheError.h" + +@implementation GRMustacheEachFilter + +/** + * The transformedValue: method is required by the GRMustacheFilter protocol. + */ + +- (id)transformedValue:(id)object +{ + /** + * Check that parameter can be iterated. + */ + + if (![object respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) { + + /** + * Filters have no way to directly return an error. + * + * So let's return a rendering object that will complain when it + * eventually gets rendered. + */ + + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + if (error) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"each filter in tag %@ expects its arguments to conform to the NSFastEnumeration protocol. %@ is not.", tag, object] }]; + } + return nil; + }]; + } + + + /** + * Index-based collections and key-based collections are not iterated in the + * same way. + */ + + if ([object isKindOfClass:[NSDictionary class]]) { + return [self transformedDictionary:object]; + } else { + return [self transformedArray:object]; + } +} + +- (id)transformedArray:(id)array +{ + /** + * Let's return an array containing as many objects as in the original + * collection. + * + * Returning an array is important: it allows the `each` filter to be + * chained with other collection-processing filters, as in + * {{# reverse(each(list)) }}...{{/}} for example. + * + * The new array contains objects that perform custom rendering by enqueuing + * in the context stack the positional keys before rendering just like the + * original objects. + * + * Those objects which perform custom rendering conform to the + * GRMustacheRendering protocol: + */ + + NSMutableArray *replacementRenderingObjects = [NSMutableArray array]; + __block NSUInteger indexOfLastObject = 0; + NSUInteger index = 0; + for (id object in array) { + + /** + * Build the replacement rendering object. + * + * It enqueues the positional keys, and then renders the same as the + * original object. + */ + + indexOfLastObject = index; + id replacementRenderingObject = [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + + /** + * Add our positional keys in the rendering context + */ + + context = [context contextByAddingObject:@{@"@index": @(index), + @"@indexPlusOne": @(index + 1), + @"@indexIsEven": @(index % 2 == 0), + @"@first": @(index == 0), + @"@last": @(index == indexOfLastObject), // When this is evaluated, on rendering, the filter will have been long executed. The __block variable indexOfLastObject will have the value of the last index. + }]; + + /** + * We want to render just like the original object. + */ + + id originalRenderingObject = [GRMustacheRendering renderingObjectForObject:object]; + return [originalRenderingObject renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:HTMLSafe error:error]; + }]; + + [replacementRenderingObjects addObject:replacementRenderingObject]; + ++index; + } + + return replacementRenderingObjects; +} + +- (id)transformedDictionary:(NSDictionary *)dictionary +{ + /** + * Let's return an array containing as many objects as in the original + * dictionary. + * + * The new array contains objects that perform custom rendering by enqueuing + * in the context stack the positional keys before rendering just like the + * original dictionary values. + * + * Those objects which perform custom rendering conform to the + * GRMustacheRendering protocol: + */ + + NSMutableArray *replacementRenderingObjects = [NSMutableArray array]; + NSUInteger indexOfLastObject = dictionary.count - 1; + NSUInteger index = 0; + for (id key in dictionary) { + + /** + * Build the replacement rendering object. + * + * It enqueues the positional keys, and then renders the same as the + * original object. + */ + + id object = [dictionary objectForKey:key]; + id replacementRenderingObject = [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + + /** + * Add our positional keys in the rendering context + */ + + context = [context contextByAddingObject:@{@"@key": key, + @"@index": @(index), + @"@indexPlusOne": @(index + 1), + @"@indexIsEven": @(index % 2 == 0), + @"@first": @(index == 0), + @"@last": @(index == indexOfLastObject), + }]; + + /** + * We want to render just like the original object. + */ + + id originalRenderingObject = [GRMustacheRendering renderingObjectForObject:object]; + return [originalRenderingObject renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:HTMLSafe error:error]; + }]; + + [replacementRenderingObjects addObject:replacementRenderingObject]; + ++index; + } + + return replacementRenderingObjects; +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h new file mode 100644 index 0000000..a0261a0 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h @@ -0,0 +1,27 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheFilter_private.h" + +@interface GRMustacheEachFilter : NSObject + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m new file mode 100644 index 0000000..cce13c1 --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m @@ -0,0 +1,107 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheHTMLLibrary_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheTranslateCharacters_private.h" + +// ============================================================================= +#pragma mark - GRMustacheHTMLEscapeFilter + +@implementation GRMustacheHTMLEscapeFilter + +#pragma mark + +/** + * Support for {{ HTML.escape(value) }} + */ +- (id)transformedValue:(id)object +{ + // Specific case for [NSNull null] + + if (object == [NSNull null]) { + return @""; + } + + // Turns other objects into strings, and escape + + NSString *string = [object description]; + return GRMustacheTranslateHTMLCharacters(string); +} + + +#pragma mark - + +/** + * Support for {{# HTML.escape }}...{{ value }}...{{ value }}...{{/ HTML.escape }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ HTML.escape }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# HTML.escape }}...{{/ HTML.escape }} + // {{^ HTML.escape }}...{{/ HTML.escape }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + + +#pragma mark - + +/** + * Support for {{# HTML.escape }}...{{ value }}...{{ value }}...{{/ HTML.escape }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ value }} + // + // We can not escape `object`, because it is not a string. + // We want to escape its rendering. + // So return a rendering object that will eventually render `object`, + // and escape its rendering. + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + id renderingObject = [GRMustacheRendering renderingObjectForObject:object]; + NSString *rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:HTMLSafe error:error]; + return GRMustacheTranslateHTMLCharacters(rendering); + }]; + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h new file mode 100644 index 0000000..2a973ff --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h @@ -0,0 +1,33 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheRendering_private.h" +#import "GRMustacheFilter_private.h" +#import "GRMustacheTagDelegate.h" + + +// ============================================================================= +#pragma mark - GRMustacheHTMLEscapeFilter + +@interface GRMustacheHTMLEscapeFilter: NSObject +@end diff --git a/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m new file mode 100644 index 0000000..0bf3ccc --- /dev/null +++ b/LFHeatMapDemo/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m @@ -0,0 +1,239 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheJavascriptLibrary_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContext_private.h" + + +// ============================================================================= +#pragma mark - GRMustacheJavascriptEscaper + +@implementation GRMustacheJavascriptEscaper + +#pragma mark + +/** + * Support for {{ javascript.escape(value) }} + */ +- (id)transformedValue:(id)object +{ + // Specific case for [NSNull null] + + if (object == [NSNull null]) { + return @""; + } + + // Turns other objects into strings, and escape + + NSString *string = [object description]; + return [self escape:string]; +} + + +#pragma mark - + +/** + * Support for {{# javascript.escape }}...{{ value }}...{{ value }}...{{/ javascript.escape }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ javascript.escape }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# javascript.escape }}...{{/ javascript.escape }} + // {{^ javascript.escape }}...{{/ javascript.escape }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + + +#pragma mark - + +/** + * Support for {{# javascript.escape }}...{{ value }}...{{ value }}...{{/ javascript.escape }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ value }} + // + // We can not escape `object`, because it is not a string. + // We want to escape its rendering. + // So return a rendering object that will eventually render `object`, + // and escape its rendering. + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + id renderingObject = [GRMustacheRendering renderingObjectForObject:object]; + NSString *rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:HTMLSafe error:error]; + return [self escape:rendering]; + }]; + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + + +#pragma mark - Private + +- (NSString *)escape:(NSString *)string +{ + NSUInteger length = [string length]; + if (length == 0) { + return string; + } + + + // Extract characters + + const UniChar *characters = CFStringGetCharactersPtr((CFStringRef)string); + if (!characters) { + NSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)]; + [string getCharacters:[data mutableBytes] range:(NSRange){ .location = 0, .length = length }]; + characters = [data bytes]; + } + + + // Set up the translation table + + static const NSString *escapeForCharacter[] = { + // This table comes from https://github.com/django/django/commit/8c4a525871df19163d5bfdf5939eff33b544c2e2#django/template/defaultfilters.py + // + // Quoting Malcolm Tredinnick: + // > Added extra robustness to the escapejs filter so that all invalid + // > characters are correctly escaped. This avoids any chance to inject + // > raw HTML inside