Full Code of ralcr/ConsentKit for AI

master e196c4c3b145 cached
31 files
66.2 KB
19.5k tokens
1 requests
Download .txt
Repository: ralcr/ConsentKit
Branch: master
Commit: e196c4c3b145
Files: 31
Total size: 66.2 KB

Directory structure:
gitextract_6bh629f5/

├── Consent.podspec
├── LICENSE
├── README.md
├── demo-ios/
│   ├── Gdpr/
│   │   ├── AppDelegate.swift
│   │   ├── Assets.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── Base.lproj/
│   │   │   ├── LaunchScreen.storyboard
│   │   │   └── Main.storyboard
│   │   ├── InMemoryDataSource.swift
│   │   ├── Info.plist
│   │   ├── NavigationViewController.swift
│   │   ├── SimpleViewController.swift
│   │   ├── TableViewController.swift
│   │   └── ViewController.swift
│   └── Gdpr.xcodeproj/
│       ├── project.pbxproj
│       ├── project.xcworkspace/
│       │   ├── contents.xcworkspacedata
│       │   ├── xcshareddata/
│       │   │   └── IDEWorkspaceChecks.plist
│       │   └── xcuserdata/
│       │       ├── cristi.xcuserdatad/
│       │       │   └── UserInterfaceState.xcuserstate
│       │       └── cristianbaluta.xcuserdatad/
│       │           └── UserInterfaceState.xcuserstate
│       └── xcuserdata/
│           ├── cristi.xcuserdatad/
│           │   ├── xcdebugger/
│           │   │   └── Breakpoints_v2.xcbkptlist
│           │   └── xcschemes/
│           │       └── xcschememanagement.plist
│           └── cristianbaluta.xcuserdatad/
│               └── xcschemes/
│                   └── xcschememanagement.plist
└── src/
    ├── CloudKitViewControllerHeader.swift
    ├── ConsentKit.swift
    ├── ConsentKitCell.swift
    ├── ConsentKitCell.xib
    ├── ConsentKitCellProtocol.swift
    ├── ConsentKitServices.swift
    ├── ConsentKitTableViewDataSource.swift
    ├── ConsentKitUserDefaultsDataSource.swift
    └── ConsentKitViewController.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: Consent.podspec
================================================
Pod::Spec.new do |s|
  s.name = 'ConsentKit'
  s.version = '0.9'
  s.summary = 'Keep track of GDPR consents in your app.'
  s.description = <<-DESC
   Keep track of GDPR consents in your app.
 DESC
  s.module_name = "ConsentKit"
  s.homepage = 'https://github.com/ralcr/Consent'
  s.license = 'MIT'
  s.authors = { 'Cristian Baluta' => 'cristi.baluta@gmail.com' }
  s.ios.deployment_target = '10.0'
  s.source = { :git => 'https://github.com/ralcr/Consent', :tag => s.version }
  s.source_files = 'src/*.{h,swift}'
end


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Cristian Baluta

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.


================================================
FILE: README.md
================================================
# ConsentKit
Note: This library only helps you collect consents for the services in your app, actually disabling those services is developer's job.

![Screenshot](https://image.ibb.co/iuASQy/Screen_Shot_2018_05_28_at_23_07_10.png)

## Usage
### Define the services in your app
Note: Some generic services can be found in ConsentKitServices

```swift
enum Services: String, ConsentKitItem {

        case icloud = "iCloud"
        case analytics = "analytics"

        func title() -> String {
            switch self {
                case .icloud: return "iCloud"
                case .analytics: return "Google analytics"
            }
        }
        func description() -> String {
            switch self {
                case .icloud: return "Wether to accept iCloud or not"
                case .analytics: return "Google analytics"
            }
        }
        func alertMessage() -> String? {
            switch self {
                case .icloud: return nil
                case .analytics: return "I accept this app to store anonymous analytics in Google Analytics!"
            }
        }
}
```

### Instantiate the lib, preferably once in the AppDelegate, but can be anywhere and as many times as you like.

```swift
let gdpr = ConsentKit()
```

### Check if you have missing consents
If yes, add the default ConsentKitViewController to handle all the switches for you.

```swift
if gdpr.needsReviewing([Services.icloud, Services.analytics]) {

    let vc = ConsentKitViewController()
    vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
    self.present(vc, animated: true)
}
```

### Custom storage
By default ConsentKit keeps values in UserDefaults, but you can change that with the gdpr.dataSource property. Just assign or pass through constructor a class implementing the ConsentKitDataSource

```swift
let gdpr = ConsentKit(dataSource: InMemoryDataSource())// InMemoryDataSource implements ConsentKitDataSource

protocol ConsentKitDataSource {
    func isAccepted (_ item: ConsentKitItem) -> Bool
    func isReviewed (_ item: ConsentKitItem) -> Bool
    func setAccepted (_ value: Bool, for item: ConsentKitItem)
    func reset (_ item: ConsentKitItem)// Optional
}
```

## Contribution
Help me create a complete list of services that the developers can use.
Thanks.


================================================
FILE: demo-ios/Gdpr/AppDelegate.swift
================================================
//
//  AppDelegate.swift
//  Gdpr
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Cristian Baluta. All rights reserved.
//

import UIKit

enum Services: String, ConsentKitItem {

    case icloud = "iCloud"
    case analytics = "analytics"

    func title() -> String {
        switch self {
        case .icloud: return "iCloud"
        case .analytics: return "Google analytics"
        }
    }

    func description() -> String {
        switch self {
        case .icloud: return "Store data to the Apple's iCloud. This will allow the data to by synced across all your devices."
        case .analytics: return "Help developer understand how the app is used by sharing usage with Google analytics."
        }
    }

    func alertMessage() -> String? {
        switch self {
        case .icloud: return nil
        case .analytics: return nil
        }
    }
}

let gdpr = ConsentKit()
//let gdpr = ConsentKit(dataSource: InMemoryDataSource())

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        // For testing purposes we reset all values from previous run
        gdpr.reset(Services.icloud)
        gdpr.reset(Services.analytics)
        gdpr.reset(ConsentKitServices.location)

        return true
    }
}



================================================
FILE: demo-ios/Gdpr/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "76x76",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "83.5x83.5",
      "scale" : "2x"
    },
    {
      "idiom" : "ios-marketing",
      "size" : "1024x1024",
      "scale" : "1x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: demo-ios/Gdpr/Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: demo-ios/Gdpr/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>


================================================
FILE: demo-ios/Gdpr/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="LAz-b6-3ca">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Navigation bar view-->
        <scene sceneID="ikM-cg-FSJ">
            <objects>
                <navigationController id="rAn-8a-pj6" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Navigation bar view" id="VpN-hb-qYi"/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="kZn-n3-9ci">
                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <connections>
                        <segue destination="AAu-ag-sAO" kind="relationship" relationship="rootViewController" id="xuh-MY-TNU"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="rgg-IP-jt5" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-458" y="257"/>
        </scene>
        <!--Inline-->
        <scene sceneID="9tQ-UH-Y3J">
            <objects>
                <tableViewController id="JRJ-aa-STA" customClass="TableViewController" customModule="Gdpr" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="RvO-n1-z4v">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="2Oy-CL-TyF">
                                <rect key="frame" x="0.0" y="28" width="375" height="44"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2Oy-CL-TyF" id="WJn-vx-ATr">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                </tableViewCellContentView>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="JRJ-aa-STA" id="NWO-A1-6To"/>
                            <outlet property="delegate" destination="JRJ-aa-STA" id="dhr-6T-vtr"/>
                        </connections>
                    </tableView>
                    <tabBarItem key="tabBarItem" title="Inline" id="mrh-Qw-N7V"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="CEM-0b-zLB" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-458" y="998"/>
        </scene>
        <!--My App-->
        <scene sceneID="x2z-WN-oMX">
            <objects>
                <viewController id="AAu-ag-sAO" customClass="NavigationViewController" customModule="Gdpr" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="4gr-jN-rc1">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8R6-qB-LUu">
                                <rect key="frame" x="0.0" y="199" width="375" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gQa-IJ-dUC">
                                <rect key="frame" x="0.0" y="260" width="375" height="30"/>
                                <state key="normal" title="Review"/>
                                <connections>
                                    <action selector="handleGdpr" destination="AAu-ag-sAO" eventType="touchUpInside" id="N1t-g0-jhT"/>
                                    <action selector="handleGdpr" destination="HQu-Jw-AKg" eventType="touchUpInside" id="xcP-K3-yzK"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                        <constraints>
                            <constraint firstItem="gQa-IJ-dUC" firstAttribute="trailing" secondItem="1lc-T6-JBk" secondAttribute="trailing" id="DTv-Kd-Vbx"/>
                            <constraint firstItem="gQa-IJ-dUC" firstAttribute="top" secondItem="8R6-qB-LUu" secondAttribute="bottom" constant="40" id="GNx-wR-URw"/>
                            <constraint firstItem="8R6-qB-LUu" firstAttribute="leading" secondItem="1lc-T6-JBk" secondAttribute="leading" id="WAh-Ho-VES"/>
                            <constraint firstItem="8R6-qB-LUu" firstAttribute="trailing" secondItem="1lc-T6-JBk" secondAttribute="trailing" id="YvS-CQ-m5R"/>
                            <constraint firstItem="8R6-qB-LUu" firstAttribute="top" secondItem="1lc-T6-JBk" secondAttribute="top" constant="135" id="j8z-Tb-glp"/>
                            <constraint firstItem="gQa-IJ-dUC" firstAttribute="leading" secondItem="1lc-T6-JBk" secondAttribute="leading" id="sFJ-W0-ybL"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="1lc-T6-JBk"/>
                    </view>
                    <navigationItem key="navigationItem" title="My App" id="qGR-cq-uTG"/>
                    <connections>
                        <outlet property="label" destination="8R6-qB-LUu" id="dW7-fx-Oz0"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Kaq-Zs-eDZ" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="271" y="257"/>
        </scene>
        <!--Single view-->
        <scene sceneID="eMF-ug-gER">
            <objects>
                <viewController id="HQu-Jw-AKg" customClass="SimpleViewController" customModule="Gdpr" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="8Cf-6l-0No">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m98-s8-VAw">
                                <rect key="frame" x="0.0" y="155" width="375" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UGX-v4-tK6">
                                <rect key="frame" x="0.0" y="216" width="375" height="30"/>
                                <state key="normal" title="Review"/>
                                <connections>
                                    <action selector="handleGdpr" destination="HQu-Jw-AKg" eventType="touchUpInside" id="ewQ-MA-v7x"/>
                                </connections>
                            </button>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                        <constraints>
                            <constraint firstItem="cmY-2c-3J0" firstAttribute="trailing" secondItem="m98-s8-VAw" secondAttribute="trailing" id="IZH-aU-7uG"/>
                            <constraint firstItem="m98-s8-VAw" firstAttribute="leading" secondItem="cmY-2c-3J0" secondAttribute="leading" id="OWd-zY-LL2"/>
                            <constraint firstItem="UGX-v4-tK6" firstAttribute="leading" secondItem="cmY-2c-3J0" secondAttribute="leading" id="Z5l-mL-i9m"/>
                            <constraint firstItem="UGX-v4-tK6" firstAttribute="top" secondItem="m98-s8-VAw" secondAttribute="bottom" constant="40" id="n5g-9B-XWb"/>
                            <constraint firstItem="cmY-2c-3J0" firstAttribute="trailing" secondItem="UGX-v4-tK6" secondAttribute="trailing" id="tq6-17-psV"/>
                            <constraint firstItem="m98-s8-VAw" firstAttribute="top" secondItem="cmY-2c-3J0" secondAttribute="top" constant="135" id="y94-oO-nsR"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="cmY-2c-3J0"/>
                    </view>
                    <tabBarItem key="tabBarItem" title="Single view" id="3ed-bw-ctx"/>
                    <connections>
                        <outlet property="label" destination="m98-s8-VAw" id="eY8-2R-cfd"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="wXt-eb-dav" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-458" y="-410"/>
        </scene>
        <!--View Controller-->
        <scene sceneID="tpU-XK-cGH">
            <objects>
                <tabBarController id="LAz-b6-3ca" customClass="ViewController" customModule="Gdpr" customModuleProvider="target" sceneMemberID="viewController">
                    <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="FMm-YJ-ZLV">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
                        <autoresizingMask key="autoresizingMask"/>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    </tabBar>
                    <connections>
                        <segue destination="HQu-Jw-AKg" kind="relationship" relationship="viewControllers" id="nkn-KP-7mk"/>
                        <segue destination="rAn-8a-pj6" kind="relationship" relationship="viewControllers" id="CjP-F1-Rny"/>
                        <segue destination="JRJ-aa-STA" kind="relationship" relationship="viewControllers" id="5QK-tI-hkk"/>
                    </connections>
                </tabBarController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="i27-h4-yUr" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-1411" y="-77"/>
        </scene>
    </scenes>
</document>


================================================
FILE: demo-ios/Gdpr/InMemoryDataSource.swift
================================================
//
//  InMemorydataSource.swift
//  Gdpr
//
//  Created by Cristian Baluta on 23/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import Foundation

class InMemoryDataSource: ConsentKitDataSource {
    
    private var dict = [String: Bool?]()
    
    func isAccepted (_ item: ConsentKitItem) -> Bool {
        return dict[item.rawValue] == true
    }
    
    func isReviewed (_ item: ConsentKitItem) -> Bool {
        return dict[item.rawValue] != nil
    }
    
    func setAccepted (_ value: Bool, for item: ConsentKitItem) {
        dict[item.rawValue] = value
    }
}


================================================
FILE: demo-ios/Gdpr/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>


================================================
FILE: demo-ios/Gdpr/NavigationViewController.swift
================================================
//
//  NavigationViewController.swift
//  Gdpr
//
//  Created by Cristian Baluta on 23/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import UIKit

class NavigationViewController: UIViewController {
    
    @IBOutlet var label: UILabel!
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if gdpr.needsReviewing([Services.icloud, Services.analytics, ConsentKitServices.location]) {
            label.text = "Gdpr needs reviewing!"
        } else {
            label.text = "All gdpr items already reviewed"
        }
    }
    
    @IBAction func handleGdpr() {
        
        let vc = ConsentKitViewController()
        vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
        vc.didFinishReview = {
            self.navigationController?.popViewController(animated: true)
        }
        self.navigationController?.pushViewController(vc, animated: true)
    }
}


================================================
FILE: demo-ios/Gdpr/SimpleViewController.swift
================================================
//
//  SimpleViewController.swift
//  Gdpr
//
//  Created by Cristian Baluta on 22/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import UIKit

class SimpleViewController: UIViewController {
    
    @IBOutlet var label: UILabel!
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if gdpr.needsReviewing([Services.icloud, Services.analytics, ConsentKitServices.location]) {
            label.text = "Gdpr needs reviewing!"
        } else {
            label.text = "All gdpr items already reviewed"
        }
    }
    
    @IBAction func handleGdpr() {
        
        let vc = ConsentKitViewController()
        vc.items = [Services.icloud, Services.analytics, ConsentKitServices.location]
        self.present(vc, animated: true)
    }
}


================================================
FILE: demo-ios/Gdpr/TableViewController.swift
================================================
//
//  TableViewController.swift
//  Gdpr
//
//  Created by Cristian Baluta on 04/06/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return section == 1 ? 1 : 2
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if indexPath.section == 1 {
            let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
            return cell
        } else {
            let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
            cell.textLabel?.text = "IndePath \(indexPath)"
            return cell
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "Section 1"
        case 1:
            return "GDPR section"
        default:
            return "Section 3"
        }
    }
}


================================================
FILE: demo-ios/Gdpr/ViewController.swift
================================================
//
//  ViewController.swift
//  Gdpr
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Cristian Baluta. All rights reserved.
//

import UIKit

class ViewController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}


================================================
FILE: demo-ios/Gdpr.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 50;
	objects = {

/* Begin PBXBuildFile section */
		283DB05C20BADECD00A8BC14 /* ConsentKitCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */; };
		283DB05E20BC77D200A8BC14 /* ConsentKitCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */; };
		2845157D20B3528B009F3EE1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845157C20B3528B009F3EE1 /* AppDelegate.swift */; };
		2845157F20B3528B009F3EE1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845157E20B3528B009F3EE1 /* ViewController.swift */; };
		2845158220B3528B009F3EE1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2845158020B3528B009F3EE1 /* Main.storyboard */; };
		2845158420B3528F009F3EE1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2845158320B3528F009F3EE1 /* Assets.xcassets */; };
		2845158720B3528F009F3EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */; };
		2845159320B352F4009F3EE1 /* CloudKitViewControllerHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */; };
		2845159420B352F4009F3EE1 /* ConsentKitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159020B352F4009F3EE1 /* ConsentKitCell.swift */; };
		2845159520B352F4009F3EE1 /* ConsentKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159120B352F4009F3EE1 /* ConsentKit.swift */; };
		2845159620B352F4009F3EE1 /* ConsentKitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */; };
		2845159820B4BB95009F3EE1 /* SimpleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159720B4BB95009F3EE1 /* SimpleViewController.swift */; };
		2845159A20B4BDBC009F3EE1 /* NavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */; };
		2845159C20B5EA1C009F3EE1 /* InMemoryDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */; };
		2845159E20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */; };
		284515A020B5F738009F3EE1 /* ConsentKitServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */; };
		5684412C20C5A4DB00D9A471 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5684412B20C5A4DB00D9A471 /* TableViewController.swift */; };
		5684413220C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
		283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConsentKitCell.xib; sourceTree = "<group>"; };
		283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitCellProtocol.swift; sourceTree = "<group>"; };
		2845157920B3528B009F3EE1 /* Gdpr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gdpr.app; sourceTree = BUILT_PRODUCTS_DIR; };
		2845157C20B3528B009F3EE1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
		2845157E20B3528B009F3EE1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
		2845158120B3528B009F3EE1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		2845158320B3528F009F3EE1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		2845158620B3528F009F3EE1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
		2845158820B3528F009F3EE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitViewControllerHeader.swift; sourceTree = "<group>"; };
		2845159020B352F4009F3EE1 /* ConsentKitCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKitCell.swift; sourceTree = "<group>"; };
		2845159120B352F4009F3EE1 /* ConsentKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKit.swift; sourceTree = "<group>"; };
		2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsentKitViewController.swift; sourceTree = "<group>"; };
		2845159720B4BB95009F3EE1 /* SimpleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleViewController.swift; sourceTree = "<group>"; };
		2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = "<group>"; };
		2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryDataSource.swift; sourceTree = "<group>"; };
		2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitUserDefaultsDataSource.swift; sourceTree = "<group>"; };
		2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitServices.swift; sourceTree = "<group>"; };
		5684412B20C5A4DB00D9A471 /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = "<group>"; };
		5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentKitTableViewDataSource.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		2845157620B3528B009F3EE1 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		2845157020B3528B009F3EE1 = {
			isa = PBXGroup;
			children = (
				2845157B20B3528B009F3EE1 /* Gdpr */,
				2845157A20B3528B009F3EE1 /* Products */,
			);
			sourceTree = "<group>";
		};
		2845157A20B3528B009F3EE1 /* Products */ = {
			isa = PBXGroup;
			children = (
				2845157920B3528B009F3EE1 /* Gdpr.app */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		2845157B20B3528B009F3EE1 /* Gdpr */ = {
			isa = PBXGroup;
			children = (
				2845157C20B3528B009F3EE1 /* AppDelegate.swift */,
				2845157E20B3528B009F3EE1 /* ViewController.swift */,
				2845159720B4BB95009F3EE1 /* SimpleViewController.swift */,
				2845159920B4BDBC009F3EE1 /* NavigationViewController.swift */,
				5684412B20C5A4DB00D9A471 /* TableViewController.swift */,
				2845159B20B5EA1C009F3EE1 /* InMemoryDataSource.swift */,
				2845158020B3528B009F3EE1 /* Main.storyboard */,
				2845158320B3528F009F3EE1 /* Assets.xcassets */,
				2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */,
				2845158820B3528F009F3EE1 /* Info.plist */,
				2845158E20B352F4009F3EE1 /* src */,
			);
			path = Gdpr;
			sourceTree = "<group>";
		};
		2845158E20B352F4009F3EE1 /* src */ = {
			isa = PBXGroup;
			children = (
				2845159120B352F4009F3EE1 /* ConsentKit.swift */,
				2845159F20B5F738009F3EE1 /* ConsentKitServices.swift */,
				2845159D20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift */,
				2845159220B352F4009F3EE1 /* ConsentKitViewController.swift */,
				5684413120C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift */,
				283DB05D20BC77D200A8BC14 /* ConsentKitCellProtocol.swift */,
				2845159020B352F4009F3EE1 /* ConsentKitCell.swift */,
				283DB05B20BADECD00A8BC14 /* ConsentKitCell.xib */,
				2845158F20B352F4009F3EE1 /* CloudKitViewControllerHeader.swift */,
			);
			name = src;
			path = ../../src;
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		2845157820B3528B009F3EE1 /* Gdpr */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 2845158B20B3528F009F3EE1 /* Build configuration list for PBXNativeTarget "Gdpr" */;
			buildPhases = (
				2845157520B3528B009F3EE1 /* Sources */,
				2845157620B3528B009F3EE1 /* Frameworks */,
				2845157720B3528B009F3EE1 /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = Gdpr;
			productName = Gdpr;
			productReference = 2845157920B3528B009F3EE1 /* Gdpr.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		2845157120B3528B009F3EE1 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastSwiftUpdateCheck = 0930;
				LastUpgradeCheck = 0930;
				ORGANIZATIONNAME = "Imagin soft";
				TargetAttributes = {
					2845157820B3528B009F3EE1 = {
						CreatedOnToolsVersion = 9.3;
					};
				};
			};
			buildConfigurationList = 2845157420B3528B009F3EE1 /* Build configuration list for PBXProject "Gdpr" */;
			compatibilityVersion = "Xcode 9.3";
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 2845157020B3528B009F3EE1;
			productRefGroup = 2845157A20B3528B009F3EE1 /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				2845157820B3528B009F3EE1 /* Gdpr */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		2845157720B3528B009F3EE1 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				2845158720B3528F009F3EE1 /* LaunchScreen.storyboard in Resources */,
				283DB05C20BADECD00A8BC14 /* ConsentKitCell.xib in Resources */,
				2845158420B3528F009F3EE1 /* Assets.xcassets in Resources */,
				2845158220B3528B009F3EE1 /* Main.storyboard in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		2845157520B3528B009F3EE1 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				2845159A20B4BDBC009F3EE1 /* NavigationViewController.swift in Sources */,
				2845159E20B5EDD6009F3EE1 /* ConsentKitUserDefaultsDataSource.swift in Sources */,
				5684412C20C5A4DB00D9A471 /* TableViewController.swift in Sources */,
				284515A020B5F738009F3EE1 /* ConsentKitServices.swift in Sources */,
				2845157F20B3528B009F3EE1 /* ViewController.swift in Sources */,
				2845159C20B5EA1C009F3EE1 /* InMemoryDataSource.swift in Sources */,
				2845159420B352F4009F3EE1 /* ConsentKitCell.swift in Sources */,
				2845159620B352F4009F3EE1 /* ConsentKitViewController.swift in Sources */,
				5684413220C6D62E00D9A471 /* ConsentKitTableViewDataSource.swift in Sources */,
				283DB05E20BC77D200A8BC14 /* ConsentKitCellProtocol.swift in Sources */,
				2845157D20B3528B009F3EE1 /* AppDelegate.swift in Sources */,
				2845159320B352F4009F3EE1 /* CloudKitViewControllerHeader.swift in Sources */,
				2845159820B4BB95009F3EE1 /* SimpleViewController.swift in Sources */,
				2845159520B352F4009F3EE1 /* ConsentKit.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXVariantGroup section */
		2845158020B3528B009F3EE1 /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				2845158120B3528B009F3EE1 /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
		2845158520B3528F009F3EE1 /* LaunchScreen.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				2845158620B3528F009F3EE1 /* Base */,
			);
			name = LaunchScreen.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		2845158920B3528F009F3EE1 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				CODE_SIGN_IDENTITY = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_DYNAMIC_NO_PIC = NO;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 11.3;
				MTL_ENABLE_DEBUG_INFO = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = iphoneos;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
			};
			name = Debug;
		};
		2845158A20B3528F009F3EE1 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				CODE_SIGN_IDENTITY = "iPhone Developer";
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				IPHONEOS_DEPLOYMENT_TARGET = 11.3;
				MTL_ENABLE_DEBUG_INFO = NO;
				SDKROOT = iphoneos;
				SWIFT_COMPILATION_MODE = wholemodule;
				SWIFT_OPTIMIZATION_LEVEL = "-O";
				VALIDATE_PRODUCT = YES;
			};
			name = Release;
		};
		2845158C20B3528F009F3EE1 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = 5NHDC5EV44;
				INFOPLIST_FILE = Gdpr/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
				);
				PRODUCT_BUNDLE_IDENTIFIER = ro.imagin.Gdpr;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_VERSION = 4.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		2845158D20B3528F009F3EE1 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = 5NHDC5EV44;
				INFOPLIST_FILE = Gdpr/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
				);
				PRODUCT_BUNDLE_IDENTIFIER = ro.imagin.Gdpr;
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_VERSION = 4.0;
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		2845157420B3528B009F3EE1 /* Build configuration list for PBXProject "Gdpr" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				2845158920B3528F009F3EE1 /* Debug */,
				2845158A20B3528F009F3EE1 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		2845158B20B3528F009F3EE1 /* Build configuration list for PBXNativeTarget "Gdpr" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				2845158C20B3528F009F3EE1 /* Debug */,
				2845158D20B3528F009F3EE1 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */
	};
	rootObject = 2845157120B3528B009F3EE1 /* Project object */;
}


================================================
FILE: demo-ios/Gdpr.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:Gdpr.xcodeproj">
   </FileRef>
</Workspace>


================================================
FILE: demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>


================================================
FILE: demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   type = "1"
   version = "2.0">
</Bucket>


================================================
FILE: demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>SchemeUserState</key>
	<dict>
		<key>Gdpr.xcscheme</key>
		<dict>
			<key>orderHint</key>
			<integer>0</integer>
		</dict>
	</dict>
</dict>
</plist>


================================================
FILE: demo-ios/Gdpr.xcodeproj/xcuserdata/cristianbaluta.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>SchemeUserState</key>
	<dict>
		<key>Gdpr.xcscheme</key>
		<dict>
			<key>orderHint</key>
			<integer>0</integer>
		</dict>
	</dict>
</dict>
</plist>


================================================
FILE: src/CloudKitViewControllerHeader.swift
================================================
//
//  CloudKitViewControllerHeader.swift
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Cristian Baluta. All rights reserved.
//

import UIKit

class CloudKitViewControllerHeader: UIView {
    
    var didDone: (() -> Void)?
    private let padding = CGFloat(16)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
        
        let label = UILabel()
        label.text = "Review services!"
        label.font = UIFont.boldSystemFont(ofSize: 16)
        label.sizeToFit()
        label.center = CGPoint(x: label.frame.size.width/2 + padding, y: 30)
        self.addSubview(label)
        
        let button = UIButton()
        button.setTitle("Done", for: .normal)
        button.setTitleColor(UIColor.orange, for: .normal)
        button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
        button.sizeToFit()
        button.center = CGPoint(x: frame.size.width - button.frame.size.width/2 - padding, y: 30)
        self.addSubview(button)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func handleButton() {
        didDone?()
    }
}


================================================
FILE: src/ConsentKit.swift
================================================
//
//  ConsentKit.swift
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import Foundation

protocol ConsentKitItem {
    var rawValue: String {get}
    /// Title used in the cell and alert
    func title() -> String
    /// Description used in the cell
    func description() -> String
    /// Message displayed in an alert when the switch is turned on.
    func alertMessage() -> String?
}

protocol ConsentKitDataSource {
    /// Returns if the item has a value of true
    func isAccepted (_ item: ConsentKitItem) -> Bool
    /// Returns if the item's value is different than nil, which means it was reviewed
    func isReviewed (_ item: ConsentKitItem) -> Bool
    /// Set a value for the item
    func setAccepted (_ value: Bool, for item: ConsentKitItem)
    /// Resets the value of an item, which means that isReviewed will return false after that
    func reset (_ item: ConsentKitItem)
}

extension ConsentKitDataSource {
    func reset (_ item: ConsentKitItem) {
        // This is a empty implementation to allow this method to be optional
    }
}

class ConsentKit {
    
    /// Assign a custom dataSource. By default UserDefaults is used and each key is prefixed with "ConsentKit-"
    var dataSource: ConsentKitDataSource = ConsentKitUserDefaultsDataSource()
    
    convenience init (dataSource: ConsentKitDataSource) {
        self.init()
        self.dataSource = dataSource
    }
    
    /// Returns if there's any value that was not reviewed
    /// Used to check if the ConsentKitViewController should be presented or not
    /// This will also be useful to present the controller if any new service added later in the app needs reviewing
    func needsReviewing(_ items: [ConsentKitItem]) -> Bool {
        for item in items {
            if !isReviewed(item) {
                return true
            }
        }
        return false
    }
}

extension ConsentKit: ConsentKitDataSource {
    
    func isAccepted (_ item: ConsentKitItem) -> Bool {
        return dataSource.isAccepted(item)
    }

    func isReviewed (_ item: ConsentKitItem) -> Bool {
        return dataSource.isReviewed(item)
    }

    func setAccepted (_ value: Bool, for item: ConsentKitItem) {
        dataSource.setAccepted(value, for: item)
    }
    
    func reset (_ item: ConsentKitItem) {
        dataSource.reset(item)
    }
}


================================================
FILE: src/ConsentKitCell.swift
================================================
//
//  ConsentKitCell.swift
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Cristian Baluta. All rights reserved.
//

import UIKit

class ConsentKitCell: UITableViewCell, ConsentKitCellProtocol {

    @IBOutlet private var titleLabel: UILabel!
    @IBOutlet private var subtitleLabel: UILabel!
    @IBOutlet private var switchButton: UISwitch!
    
    var title: String = "" {
        didSet {
            titleLabel.text = title
        }
    }
    var subtitle: String = "" {
        didSet {
            subtitleLabel.text = subtitle
        }
    }
    var value: Bool = false {
        didSet {
            switchButton.isOn = value
        }
    }
    var valueDidChange: ((Bool) -> Void)?

    override func awakeFromNib() {
        super.awakeFromNib()
        switchButton.onTintColor = UIColor.orange
    }

    static func instantiateFromXib() -> ConsentKitCell {
        let arrNib: Array = Bundle.main.loadNibNamed("ConsentKitCell", owner: self, options: nil)!
        return arrNib.first as! ConsentKitCell
    }

    @IBAction func switchChanged(_ sender: UISwitch) {
        valueDidChange?(sender.isOn)
    }
}


================================================
FILE: src/ConsentKitCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="tYq-AS-pci" customClass="ConsentKitCell" customModule="Gdpr" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="375" height="132"/>
            <autoresizingMask key="autoresizingMask"/>
            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="tYq-AS-pci" id="S6h-hV-QJN">
                <rect key="frame" x="0.0" y="0.0" width="375" height="131.5"/>
                <autoresizingMask key="autoresizingMask"/>
                <subviews>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cxL-hF-Ajw">
                        <rect key="frame" x="30" y="30" width="243" height="20.5"/>
                        <constraints>
                            <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="mCd-Al-Lwa"/>
                        </constraints>
                        <fontDescription key="fontDescription" type="system" weight="black" pointSize="17"/>
                        <nil key="textColor"/>
                        <nil key="highlightedColor"/>
                    </label>
                    <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ipj-VB-gT8">
                        <rect key="frame" x="293" y="30" width="51" height="31"/>
                        <connections>
                            <action selector="switchChanged:" destination="tYq-AS-pci" eventType="valueChanged" id="B28-by-HrB"/>
                        </connections>
                    </switch>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6vU-wc-8bW">
                        <rect key="frame" x="30" y="70.5" width="243" height="20.5"/>
                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                        <nil key="textColor"/>
                        <nil key="highlightedColor"/>
                    </label>
                </subviews>
                <constraints>
                    <constraint firstAttribute="bottomMargin" secondItem="6vU-wc-8bW" secondAttribute="bottom" constant="30" id="3Vr-oc-nL4"/>
                    <constraint firstItem="cxL-hF-Ajw" firstAttribute="top" secondItem="S6h-hV-QJN" secondAttribute="top" constant="30" id="4Tb-ZF-9DJ"/>
                    <constraint firstItem="Ipj-VB-gT8" firstAttribute="leading" secondItem="cxL-hF-Ajw" secondAttribute="trailing" constant="20" id="8hV-Hy-gHv"/>
                    <constraint firstItem="Ipj-VB-gT8" firstAttribute="top" secondItem="S6h-hV-QJN" secondAttribute="top" constant="30" id="9Vi-6d-mDa"/>
                    <constraint firstAttribute="trailing" secondItem="Ipj-VB-gT8" secondAttribute="trailing" constant="33" id="Prx-29-rl3"/>
                    <constraint firstItem="6vU-wc-8bW" firstAttribute="top" secondItem="cxL-hF-Ajw" secondAttribute="bottom" constant="20" id="U94-iV-0Kt"/>
                    <constraint firstItem="6vU-wc-8bW" firstAttribute="trailing" secondItem="cxL-hF-Ajw" secondAttribute="trailing" id="dtP-Xq-YWf"/>
                    <constraint firstItem="cxL-hF-Ajw" firstAttribute="leading" secondItem="S6h-hV-QJN" secondAttribute="leading" constant="30" id="sjN-2V-Zsd"/>
                    <constraint firstItem="6vU-wc-8bW" firstAttribute="leading" secondItem="cxL-hF-Ajw" secondAttribute="leading" id="xU8-fk-wP4"/>
                </constraints>
            </tableViewCellContentView>
            <connections>
                <outlet property="subtitleLabel" destination="6vU-wc-8bW" id="Rdm-Lx-G6h"/>
                <outlet property="switchButton" destination="Ipj-VB-gT8" id="nHc-3r-shJ"/>
                <outlet property="titleLabel" destination="cxL-hF-Ajw" id="cNa-IU-8V6"/>
            </connections>
            <point key="canvasLocation" x="60.5" y="-547"/>
        </tableViewCell>
    </objects>
</document>


================================================
FILE: src/ConsentKitCellProtocol.swift
================================================
//
//  ConsentKitCellProtocol.swift
//
//  Created by Cristian Baluta on 28/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import Foundation

protocol ConsentKitCellProtocol {
    var title: String {get set}
    var subtitle: String {get set}
    var value: Bool {get set}
    var valueDidChange: ((Bool) -> Void)? {get set}
}


================================================
FILE: src/ConsentKitServices.swift
================================================
//
//  ConsentKitServices.swift
//
//  Created by Cristian Baluta on 23/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import Foundation

enum ConsentKitServices: String, ConsentKitItem {
    
    case icloud = "ck-icloud"
    case analytics = "ck-analytics"
    case location = "ck-location"
    
    func title() -> String {
        switch self {
        case .icloud: return "iCloud"
        case .analytics: return "Google analytics"
        case .location: return "Location"
        }
    }
    
    func description() -> String {
        switch self {
        case .icloud: return "Store data to the Apple's iCloud. This will allow the data to by synced across all your devices."
        case .analytics: return "Help developer understand how the app is used by sharing usage with Google analytics."
        case .location: return "Store location on server"
        }
    }
    
    func alertMessage() -> String? {
        switch self {
        case .icloud: return "I accept that this app will store my data in the Apple's iCloud for the purpose of syncing it across multiple devices and backup"
        case .analytics: return "I accept that this app will store anonymous usage data in Google analytics for the purpose of improving the app"
        case .location: return "I accept to store my location on the server"
        }
    }
}


================================================
FILE: src/ConsentKitTableViewDataSource.swift
================================================
//
//  ConsentKitTableViewDataSource.swift
//  Gdpr
//
//  Created by Cristian Baluta on 05/06/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import UIKit

class ConsentKitTableViewDataSource: NSObject, UITableViewDelegate, UITableViewDataSource {

    var items: [ConsentKitItem] = []

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let item = items[indexPath.row]
        var cell: ConsentKitCellProtocol = ConsentKitCell.instantiateFromXib()
        cell.title = item.title()
        cell.subtitle = item.description()
        cell.value = gdpr.isAccepted(item)
        cell.valueDidChange = { isOn in
            self.item(item, didChangeValue: isOn, in: cell)
        }

        return cell as! ConsentKitCell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    func item(_ item: ConsentKitItem, didChangeValue value: Bool, in cell: ConsentKitCellProtocol) {

        if value {
            guard let message = item.alertMessage() else {
                self.gdpr.setAccepted(true, for: item)
                self.didAccept?(item)
                return
            }
            let alert = UIAlertController(title: item.title(), message: message, preferredStyle: .alert)
            alert.addAction(
                UIAlertAction(title: "Accept", style: .default, handler: { _ in
                    self.gdpr.setAccepted(true, for: item)
                    self.didAccept?(item)
                })
            )
            alert.addAction(
                UIAlertAction(title: "Decline", style: .cancel, handler: { _ in
                    var cell = cell
                    cell.value = false
                    self.gdpr.setAccepted(false, for: item)
                    self.didReject?(item)
                })
            )
            self.present(alert, animated: true, completion: nil)
        } else {
            self.gdpr.setAccepted(false, for: item)
            didReject?(item)
        }
    }
}


================================================
FILE: src/ConsentKitUserDefaultsDataSource.swift
================================================
//
//  ConsentKitUserDefaultsDataSource.swift
//
//  Created by Cristian Baluta on 23/05/2018.
//  Copyright © 2018 Imagin soft. All rights reserved.
//

import Foundation

class ConsentKitUserDefaultsDataSource {
    
    fileprivate let prefix = "ConsentKit-"
    fileprivate let userDefaults = UserDefaults.standard
    
    
    fileprivate func get (_ key: String) -> Any? {
        return userDefaults.object(forKey: prefix + key)
    }
    
    fileprivate func set (_ value: Bool?, forKey key: String) {
        if let v = value {
            userDefaults.set(v, forKey: prefix + key)
        } else {
            userDefaults.removeObject(forKey: prefix + key)
        }
        userDefaults.synchronize()
    }
}

extension ConsentKitUserDefaultsDataSource: ConsentKitDataSource {
    
    func isAccepted (_ item: ConsentKitItem) -> Bool {
        return (get(item.rawValue) as? Bool) == true
    }
    
    func isReviewed (_ item: ConsentKitItem) -> Bool {
        return get(item.rawValue) != nil
    }
    
    func setAccepted (_ value: Bool, for item: ConsentKitItem) {
        set(value, forKey: item.rawValue)
    }
    
    func reset (_ item: ConsentKitItem) {
        set(nil, forKey: item.rawValue)
    }
}


================================================
FILE: src/ConsentKitViewController.swift
================================================
//
//  ConsentKitViewController.swift
//
//  Created by Cristian Baluta on 21/05/2018.
//  Copyright © 2018 Cristian Baluta. All rights reserved.
//

import UIKit

class ConsentKitViewController: UITableViewController {

    var didAccept: ((ConsentKitItem) -> Void)?
    var didReject: ((ConsentKitItem) -> Void)?
    var didFinishReview: (() -> Void)?
    var items: [ConsentKitItem] = [] {
        didSet {
            tableView.reloadData()
        }
    }
    fileprivate let gdpr = ConsentKit()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.tableFooterView = UIView()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if self.navigationController == nil {
            // Add a custom header only if the VC is not pushed into a navigationController
            let header = CloudKitViewControllerHeader(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 80))
            header.didDone = {
                self.handleDone()
                self.dismiss(animated: true, completion: nil)
            }
            tableView.tableHeaderView = header
        } else {
            self.title = "Review services!"
            self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(handleDone))
        }
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let item = items[indexPath.row]
        var cell: ConsentKitCellProtocol = ConsentKitCell.instantiateFromXib()
        cell.title = item.title()
        cell.subtitle = item.description()
        cell.value = gdpr.isAccepted(item)
        cell.valueDidChange = { isOn in
            self.item(item, didChangeValue: isOn, in: cell)
        }
        
        return cell as! ConsentKitCell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    // MARK: - Switch changed

    func item(_ item: ConsentKitItem, didChangeValue value: Bool, in cell: ConsentKitCellProtocol) {

        if value {
            guard let message = item.alertMessage() else {
                self.gdpr.setAccepted(true, for: item)
                self.didAccept?(item)
                return
            }
            let alert = UIAlertController(title: item.title(), message: message, preferredStyle: .alert)
            alert.addAction(
                UIAlertAction(title: "Accept", style: .default, handler: { _ in
                    self.gdpr.setAccepted(true, for: item)
                    self.didAccept?(item)
                })
            )
            alert.addAction(
                UIAlertAction(title: "Decline", style: .cancel, handler: { _ in
                    var cell = cell
                    cell.value = false
                    self.gdpr.setAccepted(false, for: item)
                    self.didReject?(item)
                })
            )
            self.present(alert, animated: true, completion: nil)
        } else {
            self.gdpr.setAccepted(false, for: item)
            didReject?(item)
        }
    }
    
    @objc func handleDone() {
        // Set to false the untouched switches, to prevent gdpr being called again
        for item in items {
            if !gdpr.isReviewed(item) {
                gdpr.setAccepted(false, for: item)
            }
        }
        didFinishReview?()
    }
}
Download .txt
gitextract_6bh629f5/

├── Consent.podspec
├── LICENSE
├── README.md
├── demo-ios/
│   ├── Gdpr/
│   │   ├── AppDelegate.swift
│   │   ├── Assets.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── Base.lproj/
│   │   │   ├── LaunchScreen.storyboard
│   │   │   └── Main.storyboard
│   │   ├── InMemoryDataSource.swift
│   │   ├── Info.plist
│   │   ├── NavigationViewController.swift
│   │   ├── SimpleViewController.swift
│   │   ├── TableViewController.swift
│   │   └── ViewController.swift
│   └── Gdpr.xcodeproj/
│       ├── project.pbxproj
│       ├── project.xcworkspace/
│       │   ├── contents.xcworkspacedata
│       │   ├── xcshareddata/
│       │   │   └── IDEWorkspaceChecks.plist
│       │   └── xcuserdata/
│       │       ├── cristi.xcuserdatad/
│       │       │   └── UserInterfaceState.xcuserstate
│       │       └── cristianbaluta.xcuserdatad/
│       │           └── UserInterfaceState.xcuserstate
│       └── xcuserdata/
│           ├── cristi.xcuserdatad/
│           │   ├── xcdebugger/
│           │   │   └── Breakpoints_v2.xcbkptlist
│           │   └── xcschemes/
│           │       └── xcschememanagement.plist
│           └── cristianbaluta.xcuserdatad/
│               └── xcschemes/
│                   └── xcschememanagement.plist
└── src/
    ├── CloudKitViewControllerHeader.swift
    ├── ConsentKit.swift
    ├── ConsentKitCell.swift
    ├── ConsentKitCell.xib
    ├── ConsentKitCellProtocol.swift
    ├── ConsentKitServices.swift
    ├── ConsentKitTableViewDataSource.swift
    ├── ConsentKitUserDefaultsDataSource.swift
    └── ConsentKitViewController.swift
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (75K chars).
[
  {
    "path": "Consent.podspec",
    "chars": 519,
    "preview": "Pod::Spec.new do |s|\n  s.name = 'ConsentKit'\n  s.version = '0.9'\n  s.summary = 'Keep track of GDPR consents in your app."
  },
  {
    "path": "LICENSE",
    "chars": 1072,
    "preview": "MIT License\n\nCopyright (c) 2018 Cristian Baluta\n\nPermission is hereby granted, free of charge, to any person obtaining a"
  },
  {
    "path": "README.md",
    "chars": 2322,
    "preview": "# ConsentKit\nNote: This library only helps you collect consents for the services in your app, actually disabling those s"
  },
  {
    "path": "demo-ios/Gdpr/AppDelegate.swift",
    "chars": 1512,
    "preview": "//\n//  AppDelegate.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Cristian Baluta."
  },
  {
    "path": "demo-ios/Gdpr/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1590,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "demo-ios/Gdpr/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "demo-ios/Gdpr/Base.lproj/LaunchScreen.storyboard",
    "chars": 1681,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "demo-ios/Gdpr/Base.lproj/Main.storyboard",
    "chars": 13556,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "demo-ios/Gdpr/InMemoryDataSource.swift",
    "chars": 594,
    "preview": "//\n//  InMemorydataSource.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 23/05/2018.\n//  Copyright © 2018 Imagin so"
  },
  {
    "path": "demo-ios/Gdpr/Info.plist",
    "chars": 1463,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo-ios/Gdpr/NavigationViewController.swift",
    "chars": 979,
    "preview": "//\n//  NavigationViewController.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 23/05/2018.\n//  Copyright © 2018 Ima"
  },
  {
    "path": "demo-ios/Gdpr/SimpleViewController.swift",
    "chars": 824,
    "preview": "//\n//  SimpleViewController.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 22/05/2018.\n//  Copyright © 2018 Imagin "
  },
  {
    "path": "demo-ios/Gdpr/TableViewController.swift",
    "chars": 1512,
    "preview": "//\n//  TableViewController.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 04/06/2018.\n//  Copyright © 2018 Imagin s"
  },
  {
    "path": "demo-ios/Gdpr/ViewController.swift",
    "chars": 277,
    "preview": "//\n//  ViewController.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Cristian Balu"
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/project.pbxproj",
    "chars": 18987,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 149,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Gdpr.xcodeproj\""
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "chars": 91,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   type = \"1\"\n   version = \"2.0\">\n</Bucket>\n"
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/xcuserdata/cristi.xcuserdatad/xcschemes/xcschememanagement.plist",
    "chars": 327,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo-ios/Gdpr.xcodeproj/xcuserdata/cristianbaluta.xcuserdatad/xcschemes/xcschememanagement.plist",
    "chars": 327,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "src/CloudKitViewControllerHeader.swift",
    "chars": 1275,
    "preview": "//\n//  CloudKitViewControllerHeader.swift\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Cristian"
  },
  {
    "path": "src/ConsentKit.swift",
    "chars": 2394,
    "preview": "//\n//  ConsentKit.swift\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Imagin soft. All rights re"
  },
  {
    "path": "src/ConsentKitCell.swift",
    "chars": 1151,
    "preview": "//\n//  ConsentKitCell.swift\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Cristian Baluta. All r"
  },
  {
    "path": "src/ConsentKitCell.xib",
    "chars": 5810,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "src/ConsentKitCellProtocol.swift",
    "chars": 348,
    "preview": "//\n//  ConsentKitCellProtocol.swift\n//\n//  Created by Cristian Baluta on 28/05/2018.\n//  Copyright © 2018 Imagin soft. A"
  },
  {
    "path": "src/ConsentKitServices.swift",
    "chars": 1366,
    "preview": "//\n//  ConsentKitServices.swift\n//\n//  Created by Cristian Baluta on 23/05/2018.\n//  Copyright © 2018 Imagin soft. All r"
  },
  {
    "path": "src/ConsentKitTableViewDataSource.swift",
    "chars": 2323,
    "preview": "//\n//  ConsentKitTableViewDataSource.swift\n//  Gdpr\n//\n//  Created by Cristian Baluta on 05/06/2018.\n//  Copyright © 201"
  },
  {
    "path": "src/ConsentKitUserDefaultsDataSource.swift",
    "chars": 1230,
    "preview": "//\n//  ConsentKitUserDefaultsDataSource.swift\n//\n//  Created by Cristian Baluta on 23/05/2018.\n//  Copyright © 2018 Imag"
  },
  {
    "path": "src/ConsentKitViewController.swift",
    "chars": 3831,
    "preview": "//\n//  ConsentKitViewController.swift\n//\n//  Created by Cristian Baluta on 21/05/2018.\n//  Copyright © 2018 Cristian Bal"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the ralcr/ConsentKit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (66.2 KB), approximately 19.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!