├── images
├── 1.jpg
└── fritz_logo.png
├── BlindAssist
├── Assets.xcassets
│ ├── Contents.json
│ ├── car.imageset
│ │ ├── car.png
│ │ └── Contents.json
│ ├── camera.imageset
│ │ ├── camera.png
│ │ └── Contents.json
│ ├── smiley.imageset
│ │ ├── smiley.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── BlindAssist-Bridging-Header.h
├── AppDelegate.swift
├── blindassist.h
├── Extensions
│ └── UIDevice+Orientation.swift
├── Views
│ └── CameraPreviewView.swift
├── Inference
│ ├── Inference.h
│ ├── Inference.m
│ └── InferenceViewController.swift
├── Info.plist
├── Onboarding
│ ├── OnboardingViewController.swift
│ ├── PageView.swift
│ └── PagerView.swift
└── blindassist.c
├── Podfile
├── BlindAssist.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ └── BlindAssist.xcscheme
└── project.pbxproj
├── Podfile.lock
├── .travis.yml
├── download_model.sh
├── .gitignore
├── README.md
└── LICENSE
/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlindAssist/blindassist-ios/HEAD/images/1.jpg
--------------------------------------------------------------------------------
/images/fritz_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlindAssist/blindassist-ios/HEAD/images/fritz_logo.png
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '13.0'
2 |
3 | target 'BlindAssist' do
4 | use_frameworks!
5 |
6 | pod 'Anchors', '~> 2.4.0'
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/car.imageset/car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlindAssist/blindassist-ios/HEAD/BlindAssist/Assets.xcassets/car.imageset/car.png
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/camera.imageset/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlindAssist/blindassist-ios/HEAD/BlindAssist/Assets.xcassets/camera.imageset/camera.png
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/smiley.imageset/smiley.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlindAssist/blindassist-ios/HEAD/BlindAssist/Assets.xcassets/smiley.imageset/smiley.png
--------------------------------------------------------------------------------
/BlindAssist/BlindAssist-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "Inference.h"
6 |
--------------------------------------------------------------------------------
/BlindAssist.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Anchors (2.4.0)
3 |
4 | DEPENDENCIES:
5 | - Anchors (~> 2.4.0)
6 |
7 | SPEC REPOS:
8 | trunk:
9 | - Anchors
10 |
11 | SPEC CHECKSUMS:
12 | Anchors: 75614cac462e063b395386e31eb593a856d831a8
13 |
14 | PODFILE CHECKSUM: 2585a4014187823e7de3e4f2299b61254e6cdb20
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/BlindAssist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | xcode_project: BlindAssist.xcodeproj
3 | xcode_scheme: BlindAssist
4 | osx_image: xcode11.2
5 |
6 | before_install:
7 | - gem install cocoapods
8 | - pod --version
9 | install:
10 | - pod install --repo-update
11 | before_script:
12 | - ./download_model.sh
13 | script:
14 | - xcodebuild -workspace BlindAssist.xcworkspace -scheme BlindAssist -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO
15 |
--------------------------------------------------------------------------------
/download_model.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | OUTPUT_DIR="./BlindAssist/cityscapes.mlmodel"
4 | MODEL_URL="https://github.com/BlindAssist/blindassist-scripts/releases/download/v1.2/cityscapes.mlmodel"
5 |
6 | echo "Starting mlmodel download..."
7 |
8 | # Download the BlindAssist CoreML model
9 | # from the latest repos release and place
10 | # it in the correct location
11 | wget -O $OUTPUT_DIR $MODEL_URL
12 |
13 | echo "Done downloading"
14 |
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/car.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "car.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/camera.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "camera.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/smiley.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "smiley.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## User settings
2 | xcuserdata/
3 |
4 | # General
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | DerivedData
9 | Pods/
10 | *.xcworkspace
11 |
12 | # Icon must end with two \r
13 | Icon
14 |
15 | # Thumbnails
16 | ._*
17 |
18 | # Files that might appear in the root of a volume
19 | .DocumentRevisions-V100
20 | .fseventsd
21 | .Spotlight-V100
22 | .TemporaryItems
23 | .Trashes
24 | .VolumeIcon.icns
25 | .com.apple.timemachine.donotpresent
26 |
27 | # Directories potentially created on remote AFP share
28 | .AppleDB
29 | .AppleDesktop
30 | Network Trash Folder
31 | Temporary Items
32 | .apdisk
33 |
34 | # Don't upload models
35 | *.mlmodel
36 |
--------------------------------------------------------------------------------
/BlindAssist/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 21/10/2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
17 | // Override point for customization after application launch.
18 |
19 | window = UIWindow(frame: UIScreen.main.bounds)
20 | let controller = OnboardingViewController()
21 | window!.rootViewController = controller
22 | window!.makeKeyAndVisible()
23 |
24 | controller.onDone = {
25 | self.switchToMain()
26 | }
27 |
28 | return true
29 | }
30 |
31 | func switchToMain() {
32 | window!.rootViewController = InferenceViewController()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/BlindAssist/blindassist.h:
--------------------------------------------------------------------------------
1 | //
2 | // blindassist.h
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 31-07-18.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | #ifndef blindassist_h
10 | #define blindassist_h
11 |
12 | #include
13 |
14 | #define SUCCESS 0
15 |
16 | enum walk_positions {
17 | LEFT,
18 | RIGHT,
19 | FRONT,
20 | NONE
21 | };
22 |
23 | struct scene_information {
24 |
25 | /**
26 | * Defines the position where a user can walk.
27 | */
28 | enum walk_positions walk_position;
29 |
30 | /**
31 | * Defines wether there were poles detected in the environment.
32 | */
33 | int poles_detected;
34 |
35 | /**
36 | * Defines if there are obstacles in front.
37 | */
38 | int vehicle_detected;
39 | int bikes_detected;
40 | };
41 |
42 | typedef struct scene_information scene_information;
43 |
44 | int analyse_frame(uint8_t *classes, int height, int width);
45 |
46 | int poll_results(scene_information *information);
47 |
48 | #endif /* blindassist_h */
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlindAssist
2 | [](https://travis-ci.com/BlindAssist/blindassist-ios)
3 | [](LICENSE)
4 |
5 | BlindAssist is an iOS application which has the goal to support blind people
6 | on the road. Since I have a blind brother, I decided to create this open source
7 | project.
8 |
9 | 
10 |
11 | ## How does it work?
12 | The assisting process will be done using deep learning, image segmentation
13 | and translating the inference results to sentences which will be spoken out loud
14 | by tts (text to speech). The model used for this process is based on the
15 | [cityscapes](https://www.cityscapes-dataset.com) dataset.
16 |
17 | Currently BlindAssist uses CoreML. You can run the `download_model.sh` script to
18 | get the prebuilt model.
19 |
20 | The source of the model can be found here:
21 | https://github.com/BlindAssist/blindassist-scripts
22 |
23 | ## Sponsors
24 | [](https://fritz.ai)
25 |
--------------------------------------------------------------------------------
/BlindAssist/Extensions/UIDevice+Orientation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIDevice+Orientation.swift
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 22/10/2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | // Uses code from https://github.com/vfa-tranhv/MobileAILab-HairColor-iOS
10 |
11 | import UIKit
12 | import AVFoundation
13 |
14 | extension UIDevice {
15 |
16 | // Video orientation for current device orientation
17 | var videoOrientation: AVCaptureVideoOrientation {
18 | let orientation: AVCaptureVideoOrientation
19 |
20 | switch self.orientation {
21 | case .portrait:
22 | orientation = .portrait
23 | case .portraitUpsideDown:
24 | orientation = .portraitUpsideDown
25 | case .landscapeLeft:
26 | orientation = .landscapeLeft
27 | case .landscapeRight:
28 | orientation = .landscapeRight
29 | default:
30 | orientation = .portrait
31 | }
32 |
33 | return orientation
34 | }
35 |
36 | // Subscribes target to default NotificationCenter .UIDeviceOrientationDidChange
37 | class func subscribeToDeviceOrientationNotifications(_ target: AnyObject, selector: Selector) {
38 | let center = NotificationCenter.default
39 | let name = UIDevice.orientationDidChangeNotification
40 | let selector = selector
41 | center.addObserver(target, selector: selector, name: name, object: nil)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/BlindAssist/Views/CameraPreviewView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CameraPreviewView.swift
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 22/10/2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | // Uses code from https://github.com/vfa-tranhv/MobileAILab-HairColor-iOS
10 |
11 | import UIKit
12 | import AVFoundation
13 |
14 | final class CameraPreviewView: UIView {
15 |
16 | private weak var previewLayer: AVCaptureVideoPreviewLayer?
17 |
18 | override func awakeFromNib() {
19 | super.awakeFromNib()
20 |
21 | // Observe device rotation
22 | let selector = #selector(deviceOrientationDidChange(_:))
23 | UIDevice.subscribeToDeviceOrientationNotifications(self, selector: selector)
24 | }
25 |
26 | // Insert layer at index 0
27 | func addCaptureVideoPreviewLayer(_ previewLayer: AVCaptureVideoPreviewLayer) {
28 | self.previewLayer?.removeFromSuperlayer()
29 | self.layer.insertSublayer(previewLayer, at: 0)
30 | self.previewLayer = previewLayer
31 | self.previewLayer?.videoGravity = .resizeAspectFill
32 | }
33 |
34 | override func layoutSubviews() {
35 | super.layoutSubviews()
36 | previewLayer?.frame = bounds
37 | }
38 |
39 | // Change video orientation to always display video in correct orientation
40 | @objc private func deviceOrientationDidChange(_ notification: Notification) {
41 | previewLayer?.connection?.videoOrientation = UIDevice.current.videoOrientation
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/BlindAssist/Inference/Inference.h:
--------------------------------------------------------------------------------
1 | //
2 | // Inference.h
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 22/10/2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "blindassist.h"
13 |
14 | struct Color {
15 | uint8_t r;
16 | uint8_t g;
17 | uint8_t b;
18 | };
19 |
20 | static struct Color colors[] = {
21 | {.r = 128, .g = 64, .b = 128}, // road
22 | {.r = 244, .g = 35, .b = 232}, // sidewalk
23 | {.r = 70, .g = 70, .b = 70 }, // building
24 | {.r = 102, .g = 102, .b = 156}, // wall
25 | {.r = 190, .g = 153, .b = 153}, // fence
26 | {.r = 153, .g = 153, .b = 153}, // pole
27 | {.r = 250, .g = 170, .b = 30 }, // traffic light
28 | {.r = 220, .g = 220, .b = 0 }, // traffic sign
29 | {.r = 107, .g = 142, .b = 35 }, // vegetation
30 | {.r = 152, .g = 251, .b = 152}, // terrain
31 | {.r = 70, .g = 130, .b = 180}, // sky
32 | {.r = 220, .g = 20, .b = 60 }, // person
33 | {.r = 255, .g = 0, .b = 0 }, // rider
34 | {.r = 0, .g = 0, .b = 142}, // car
35 | {.r = 0, .g = 0, .b = 70 }, // truck
36 | {.r = 0, .g = 60, .b = 100}, // bus
37 | {.r = 0, .g = 80, .b = 100}, // train
38 | {.r = 0, .g = 0, .b = 230}, // motorcycle
39 | {.r = 119, .g = 11, .b = 32 } // bycycle
40 | };
41 |
42 | @interface Inference : NSObject
43 |
44 | +(int) handlePrediction:(VNRequest*)request :(UIImageView*)predictionView :(scene_information*)information;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/BlindAssist/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | Camera access is needed for inference
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BlindAssist/Onboarding/OnboardingViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingViewController.swift
3 | // BlindAssist
4 | //
5 | // Created by khoa on 30.09.2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Anchors
11 |
12 | final class OnboardingViewController: UIViewController {
13 | private lazy var pagerView: PagerView = self.makePagerView()
14 | @objc var onDone: (() -> Void)?
15 |
16 | // MARK: - Life cycle
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | view.backgroundColor = .white
22 | view.addSubview(pagerView)
23 | activate(
24 | pagerView.anchor.edges
25 | )
26 | }
27 |
28 | // MARK: - Make
29 |
30 | private func makePagerView() -> PagerView {
31 | let contents: [Content] = [
32 | Content(title: "What", text: "An iOS app which will support the blind in traffic", image: "smiley"),
33 | Content(title: "Why", text: "To support blind people on the road", image: "car"),
34 | Content(title: "How", text: "Image segmentation to segment camera images in realtime", image: "camera")
35 | ]
36 |
37 | let pageViews: [PageView] = contents.enumerated().map({ i, content in
38 | let view = PageView()
39 | view.titleLabel.text = content.title
40 | view.textLabel.text = content.text
41 | view.imageView.image = UIImage(named: content.image)
42 | view.button.isHidden = i < contents.count - 1
43 | view.button.addTarget(self, action: #selector(onButtonTouch), for: .touchUpInside)
44 | return view
45 | })
46 |
47 | return PagerView(views: pageViews)
48 | }
49 |
50 | @objc func onButtonTouch() {
51 | onDone?()
52 | }
53 | }
54 |
55 | private struct Content {
56 | let title: String
57 | let text: String
58 | let image: String
59 | }
60 |
--------------------------------------------------------------------------------
/BlindAssist/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/BlindAssist/Onboarding/PageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageView.swift
3 | // BlindAssist
4 | //
5 | // Created by khoa on 30.09.2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Anchors
11 |
12 | final class PageView: UIView {
13 | private(set) lazy var backgroundImageView: UIImageView = {
14 | let view = UIImageView()
15 | view.contentMode = .scaleAspectFill
16 | view.clipsToBounds = true
17 |
18 | return view
19 | }()
20 |
21 | private(set) lazy var imageView: UIImageView = {
22 | let view = UIImageView()
23 | view.contentMode = .scaleAspectFit
24 |
25 | return view
26 | }()
27 |
28 | private(set) lazy var titleLabel: UILabel = {
29 | let label = UILabel()
30 | label.textAlignment = .center
31 | label.textColor = UIColor.black
32 | label.numberOfLines = 0
33 | label.font = UIFont.preferredFont(forTextStyle: .headline)
34 |
35 | return label
36 | }()
37 |
38 | private(set) lazy var textLabel: UILabel = {
39 | let label = UILabel()
40 | label.textAlignment = .center
41 | label.textColor = UIColor.black
42 | label.numberOfLines = 0
43 | label.font = UIFont.preferredFont(forTextStyle: .title3)
44 |
45 | return label
46 | }()
47 |
48 | private(set) lazy var button: UIButton = {
49 | let button = UIButton(type: .custom)
50 | button.setTitle("Done", for: .normal)
51 | button.setTitleColor(.black, for: .normal)
52 | button.setTitleColor(.gray, for: .highlighted)
53 |
54 | return button
55 | }()
56 |
57 | // MARK: - Init
58 |
59 | override init(frame: CGRect) {
60 | super.init(frame: frame)
61 |
62 | addSubview(backgroundImageView)
63 | addSubview(imageView)
64 | addSubview(titleLabel)
65 | addSubview(textLabel)
66 | addSubview(button)
67 |
68 | activate(
69 | backgroundImageView.anchor.edges,
70 | imageView.anchor.size.equal.to(150),
71 | imageView.anchor.centerX,
72 | imageView.anchor.top.equal.to(anchor.top).constant(150),
73 | titleLabel.anchor.top.equal.to(imageView.anchor.bottom).constant(50),
74 | titleLabel.anchor.paddingHorizontally(20),
75 | textLabel.anchor.top.equal.to(titleLabel.anchor.bottom).constant(20),
76 | textLabel.anchor.paddingHorizontally(20),
77 | button.anchor.centerX,
78 | button.anchor.bottom.constant(-70)
79 | )
80 | }
81 |
82 | required init?(coder aDecoder: NSCoder) {
83 | fatalError()
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/BlindAssist/Onboarding/PagerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PagerView.swift
3 | // BlindAssist
4 | //
5 | // Created by khoa on 30.09.2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Anchors
11 |
12 | /// Show many views in horizonal paging
13 | final class PagerView: UIView {
14 | private let views: [UIView]
15 | private let scrollView = UIScrollView()
16 | private let contentView = UIView()
17 | private let pageControl = UIPageControl()
18 |
19 | // MARK: - Init
20 |
21 | required init(views: [UIView]) {
22 | self.views = views
23 | super.init(frame: .zero)
24 |
25 | setup()
26 | setupConstraints()
27 | }
28 |
29 | required init?(coder aDecoder: NSCoder) {
30 | fatalError("init(coder:) has not been implemented")
31 | }
32 |
33 | // MARK: - Logic
34 |
35 | func goToPage(index: Int) {
36 | let offset = CGPoint(
37 | x: scrollView.frame.size.width * CGFloat(index),
38 | y: 0
39 | )
40 | scrollView.setContentOffset(offset, animated: true)
41 | }
42 |
43 | // MARK: - Setup
44 |
45 | private func setup() {
46 | addSubview(scrollView)
47 | addSubview(pageControl)
48 | scrollView.addSubview(contentView)
49 | views.forEach {
50 | contentView.addSubview($0)
51 | }
52 |
53 | scrollView.isPagingEnabled = true
54 | scrollView.showsHorizontalScrollIndicator = false
55 | scrollView.delegate = self
56 |
57 | pageControl.currentPageIndicatorTintColor = UIColor.green
58 | pageControl.pageIndicatorTintColor = .gray
59 | pageControl.numberOfPages = views.count
60 | pageControl.isHidden = views.count < 2
61 | }
62 |
63 | private func setupConstraints() {
64 | activate(
65 | scrollView.anchor.edges,
66 | contentView.anchor.edges,
67 | pageControl.anchor.centerX,
68 | pageControl.anchor.bottom.constant(-20)
69 | )
70 |
71 | views.enumerated().forEach { tuple in
72 | let view = tuple.element
73 |
74 | activate(
75 | view.anchor.top.bottom.width.height.equal.to(scrollView.anchor)
76 | )
77 |
78 | if tuple.offset == 0 {
79 | activate(
80 | view.anchor.left
81 | )
82 | } else {
83 | activate(
84 | view.anchor.left.equal.to(views[tuple.offset-1].anchor.right)
85 | )
86 | }
87 |
88 | if tuple.offset == views.count - 1 {
89 | activate(
90 | view.anchor.right
91 | )
92 | }
93 | }
94 | }
95 | }
96 |
97 | extension PagerView: UIScrollViewDelegate {
98 | func scrollViewDidScroll(_ scrollView: UIScrollView) {
99 | pageControl.currentPage = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
100 | }
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/BlindAssist.xcodeproj/xcshareddata/xcschemes/BlindAssist.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/BlindAssist/Inference/Inference.m:
--------------------------------------------------------------------------------
1 | //
2 | // Inference.m
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 22/10/2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | /**
10 | * We keep this class in Objective-C, since performance is critical,
11 | * the same exact code was tested on Swift and was significantly
12 | * slower compared to this implementation.
13 | */
14 |
15 | #import
16 |
17 | #import "Inference.h"
18 |
19 | @implementation Inference
20 |
21 | +(int) handlePrediction:(VNRequest*)request :(UIImageView*)predictionView :(scene_information*) information {
22 | NSArray *results = [request.results copy];
23 | MLMultiArray *multiArray = ((VNCoreMLFeatureValueObservation*)(results[0])).featureValue.multiArrayValue;
24 |
25 | // Shape of MLMultiArray is sequence: channels, height and width
26 | int channels = multiArray.shape[0].intValue;
27 | int height = multiArray.shape[1].intValue;
28 | int width = multiArray.shape[2].intValue;
29 |
30 | // Holds the temporary maxima, and its index (only works if less than 256 channels!)
31 | double *tmax = (double*) malloc(width * height * sizeof(double));
32 | uint8_t *tchan = (uint8_t*) malloc(width * height);
33 |
34 | double *pointer = (double*) multiArray.dataPointer;
35 |
36 | int cStride = multiArray.strides[0].intValue;
37 | int hStride = multiArray.strides[1].intValue;
38 | int wStride = multiArray.strides[2].intValue;
39 |
40 | // Just copy the first channel as starting point
41 | for (int h = 0; h < height; h++) {
42 | for (int w = 0; w < width; w++) {
43 | tmax[w + h * width] = pointer[h * hStride + w * wStride];
44 | tchan[w + h * width] = 0; // first channel
45 | }
46 | }
47 |
48 | // We skip first channel on purpose.
49 | for (int c = 1; c < channels; c++) {
50 | for (int h = 0; h < height; h++) {
51 | for (int w = 0; w < width; w++) {
52 | double sample = pointer[h * hStride + w * wStride + c * cStride];
53 | if (sample > tmax[w + h * width]) {
54 | tmax[w + h * width] = sample;
55 | tchan[w + h * width] = c;
56 | }
57 | }
58 | }
59 | }
60 |
61 | // Now free the maximum buffer, useless
62 | free(tmax);
63 |
64 | // Holds the segmented image
65 | uint8_t *bytes = (uint8_t*) malloc(width * height * 4);
66 |
67 | // Calculate image color
68 | for (int i = 0; i < height * width; i++) {
69 | struct Color rgba = colors[tchan[i]];
70 | bytes[i * 4 + 0] = (rgba.r);
71 | bytes[i * 4 + 1] = (rgba.g);
72 | bytes[i * 4 + 2] = (rgba.b);
73 | bytes[i * 4 + 3] = (255 / 2); // semi transparent
74 | }
75 |
76 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
77 | CGContextRef context = CGBitmapContextCreate(bytes, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast);
78 | CFRelease(colorSpace);
79 | CGImageRef cgImage = CGBitmapContextCreateImage(context);
80 | CGContextRelease(context);
81 |
82 | UIImage *image = [UIImage imageWithCGImage:cgImage scale:0 orientation:UIImageOrientationUp];
83 | CGImageRelease(cgImage);
84 |
85 | dispatch_async(dispatch_get_main_queue(), ^{
86 | [predictionView setImage:image];
87 | });
88 |
89 | free(bytes);
90 |
91 | // predict results for this frame
92 | analyse_frame(tchan, height, width);
93 |
94 | free(tchan);
95 |
96 | return poll_results(information);
97 | }
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/BlindAssist/Inference/InferenceViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainController.swift
3 | // BlindAssist
4 | //
5 | // Created by khoa on 10.10.2018.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Anchors
11 | import AVFoundation
12 | import Vision
13 | import CoreML
14 | import CoreMotion
15 |
16 | final class InferenceViewController: UIViewController {
17 |
18 | private lazy var cameraPreview = CameraPreviewView()
19 | private lazy var predictionView = UIImageView()
20 | private var session: AVCaptureSession?
21 | private var motionManager: CMMotionManager?
22 | private var isFacingHorzion: Bool = false
23 | private var tts: AVSpeechSynthesizer = AVSpeechSynthesizer()
24 | private var request: VNCoreMLRequest?
25 | private var lastPredictionTime: Double = 0
26 |
27 | private let GravityCheckInterval: TimeInterval = 1.0
28 | private let PredictionInterval: TimeInterval = 3.0
29 |
30 | required init() {
31 | super.init(nibName: nil, bundle: nil)
32 | }
33 |
34 | required init?(coder aDecoder: NSCoder) {
35 | fatalError()
36 | }
37 |
38 | override func viewDidLoad() {
39 | super.viewDidLoad()
40 | setup()
41 | setupConstraints()
42 | }
43 |
44 | private func setup() {
45 | view.backgroundColor = .white
46 | predictionView.contentMode = .scaleToFill
47 |
48 | speak("Initializing application")
49 |
50 | motionManager = CMMotionManager()
51 | motionManager?.deviceMotionUpdateInterval = TimeInterval(GravityCheckInterval)
52 |
53 | if let queue = OperationQueue.current {
54 | motionManager!.startDeviceMotionUpdates(to: queue, withHandler: { motionData, error in
55 | self.handleGravity(motionData!.gravity)
56 | })
57 | }
58 |
59 | do {
60 | let model = try VNCoreMLModel(for: cityscapes().model)
61 | request = VNCoreMLRequest(model: model, completionHandler: self.handlePrediction)
62 | request!.imageCropAndScaleOption = VNImageCropAndScaleOption.centerCrop
63 | } catch {
64 | fatalError("Can't load BlindAssist CoreML model: \(error)")
65 | }
66 |
67 | speak("Finished loading, detecting environment")
68 | }
69 |
70 | private func setupConstraints() {
71 | view.addSubview(cameraPreview)
72 | view.addSubview(predictionView)
73 |
74 | activate(
75 | cameraPreview.anchor.left.top.right,
76 | cameraPreview.anchor.width,
77 | cameraPreview.anchor.height.ratio(1.0),
78 | predictionView.anchor.edges.equal.to(cameraPreview.anchor)
79 | )
80 | }
81 |
82 | override func viewDidAppear(_ animated: Bool) {
83 | super.viewDidAppear(animated)
84 | AVCaptureDevice.requestAccess(for: .video) { granted in
85 | self.permissions(granted)
86 | }
87 | }
88 |
89 | override func viewDidDisappear(_ animated: Bool) {
90 | super.viewDidDisappear(animated)
91 | session?.stopRunning()
92 | }
93 |
94 | private func permissions(_ granted: Bool) {
95 | if granted && session == nil {
96 | setupSession()
97 | }
98 | }
99 |
100 | private func setupSession() {
101 | guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back) else {
102 | fatalError("Camera not available")
103 | }
104 | guard let input = try? AVCaptureDeviceInput(device: device) else {
105 | fatalError("Camera data not available")
106 | }
107 | let output = AVCaptureVideoDataOutput()
108 | output.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .userInteractive))
109 |
110 | let session = AVCaptureSession()
111 | session.addInput(input)
112 | session.addOutput(output)
113 |
114 | let previewLayer = AVCaptureVideoPreviewLayer(session: session)
115 | DispatchQueue.main.async(execute: {
116 | self.cameraPreview.addCaptureVideoPreviewLayer(previewLayer)
117 | })
118 |
119 | self.session = session
120 | session.startRunning()
121 | }
122 |
123 | private func deviceOrientationDidChange() {
124 | session?.outputs.forEach {
125 | $0.connections.forEach {
126 | $0.videoOrientation = UIDevice.current.videoOrientation
127 | }
128 | }
129 | }
130 |
131 | private func handlePrediction(request: VNRequest, error: Error?) {
132 | if (!isFacingHorzion) {
133 | return
134 | }
135 |
136 | var information = scene_information()
137 | let result = Inference.handlePrediction(request, self.predictionView, &information)
138 | if (result != SUCCESS) {
139 | return
140 | }
141 |
142 | let currentTime = Date().timeIntervalSince1970
143 |
144 | if (lastPredictionTime == 0 || (currentTime - lastPredictionTime) > PredictionInterval) {
145 | // Clear tts queue
146 | tts.stopSpeaking(at: .word)
147 |
148 | if information.poles_detected > 0 {
149 | speak("Poles detected.")
150 | }
151 | if information.vehicle_detected > 0 {
152 | speak("Parked car detected.")
153 | }
154 | if information.bikes_detected > 0 {
155 | speak("Bikes detected.")
156 | }
157 | if information.walk_position == FRONT {
158 | speak("You can walk in front of you.")
159 | } else if information.walk_position == LEFT {
160 | speak("You can walk left.")
161 | } else if information.walk_position == RIGHT {
162 | speak("You can walk right.")
163 | }
164 | lastPredictionTime = Date().timeIntervalSince1970
165 | }
166 | }
167 |
168 | func speak(_ string: String) {
169 | let utterance = AVSpeechUtterance(string: string)
170 | utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
171 | utterance.rate = AVSpeechUtteranceMaximumSpeechRate * 0.60
172 | tts.speak(utterance)
173 | }
174 |
175 | func handleGravity(_ gravity: CMAcceleration) {
176 | isFacingHorzion = gravity.y <= -0.97 && gravity.y <= 1.0
177 | if (!isFacingHorzion) {
178 | // TODO: Make some beep for this
179 | speak("Warning: camera is not facing the horizon.")
180 | }
181 | }
182 | }
183 |
184 | extension InferenceViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
185 |
186 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
187 | deviceOrientationDidChange()
188 |
189 | guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
190 | return
191 | }
192 |
193 | var requestOptions: [VNImageOption: Any] = [:]
194 | if let cameraIntrinsicData = CMGetAttachment(sampleBuffer, key: kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, attachmentModeOut: nil) {
195 | requestOptions = [.cameraIntrinsics: cameraIntrinsicData]
196 | }
197 |
198 | let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: requestOptions)
199 | do {
200 | try handler.perform([request!])
201 | } catch {
202 | fatalError("Error while requesting predicition")
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/BlindAssist/blindassist.c:
--------------------------------------------------------------------------------
1 | //
2 | // blindassist.c
3 | // BlindAssist
4 | //
5 | // Created by Giovanni Terlingen on 31-07-18.
6 | // Copyright © 2018 Giovanni Terlingen. All rights reserved.
7 | //
8 |
9 | #include
10 |
11 | #include "blindassist.h"
12 |
13 | /*
14 | * This code is responsible for analyzing predicted frames and generate a suitable
15 | * explaination of them for the blind user.
16 | *
17 | * This code will retrieve segmented images using analyse_frame,
18 | * everytime this method is called, a calculation will be done for the best walkable
19 | * position for the blind user.
20 | *
21 | * There are also checks performed to detect obstacles such as poles within the scene.
22 | *
23 | * Before a predicition is made, several frames are analysed to guarantee a better
24 | * understanding of scene.
25 | *
26 | * This code is using ratios. Each part of a frame needs to contain a certain
27 | * amount of class pixels to make sure it represents the actual object in real life.
28 | *
29 | * After calculation is done, a client can retrieve the results using poll_results.
30 | */
31 |
32 | /**
33 | * The name of classes ordered by their index
34 | */
35 | enum classes {
36 | ROAD,
37 | SIDEWALK,
38 | BUILDING,
39 | WALL,
40 | FENCE,
41 | POLE,
42 | TRAFFIC_LIGHT,
43 | TRAFFIC_SIGN,
44 | VEGETATION,
45 | TERRAIN,
46 | SKY,
47 | PERSON,
48 | RIDER,
49 | CAR,
50 | TRUCK,
51 | BUS,
52 | TRAIN,
53 | MOTORCYCLE,
54 | BICYCLE
55 | };
56 |
57 | /**
58 | * The minimal amount of sidewalk/terrain a frame needs to contain to
59 | * consider as 'safe' to walk
60 | **/
61 | static const float MINIMAL_WALKABLE_RATIO = 0.1f;
62 |
63 | /**
64 | * The minimal amount of poles a frame needs to contain to be considered as dangerous
65 | **/
66 | static const float MINIMAL_POLE_RATIO = 0.05f;
67 |
68 | /**
69 | * The minimal amount of a vehicle the frame needs to contain
70 | * to be considered as dangerous
71 | **/
72 | static const float MINIMAL_VEHICLE_RATIO = 0.4f;
73 |
74 | /**
75 | * The minimal amount of a bike the frame needs to contain to
76 | * be considered as dangerous
77 | **/
78 | static const float MINIMAL_BIKE_RATIO = 0.2f;
79 |
80 | /**
81 | * The amount of frames which needs to be analyzed before predicting a result
82 | **/
83 | static const int FRAMES_TO_ANALYZE = 5;
84 |
85 | /**
86 | * Defines scores for the best position to walk.
87 | */
88 | int left_walk_score = 0;
89 | int right_walk_score = 0;
90 | int center_walk_score = 0;
91 |
92 | /**
93 | * These values will increment once a car/bike is detected in the
94 | * a frame. They must cover a certain part of the frame
95 | * to consider it as dangerous.
96 | */
97 | int vehicles_score = 0;
98 | int bikes_score = 0;
99 |
100 | /**
101 | * Will increment if poles are detected in the environment.
102 | */
103 | int poles_score = 0;
104 |
105 | /**
106 | * The amount of frames which are currently analyzed.
107 | * Gets reset after a result has been predicted
108 | */
109 | int current_analyzed_frames = 0;
110 |
111 | /**
112 | * Analyses a frame and pushes it to the results.
113 | *
114 | * @param classes an array with size (h * w) of the segmented image, each pixel defines a class
115 | * @param height the height of the segmented image
116 | * @param width the width of the segmented image
117 | * @return 0 on success, or negative on failure
118 | */
119 | int analyse_frame(uint8_t *classes, int height, int width) {
120 |
121 | int local_left_walk_score = 0;
122 | int local_right_walk_score = 0;
123 | int local_center_walk_score = 0;
124 |
125 | int local_vehicle_score = 0;
126 | int local_bike_score = 0;
127 |
128 | int local_obstacle_score = 0;
129 |
130 | // Loop through each pixel and get the class
131 | for (int i = 0; i < height * width; i++) {
132 | int w = i % height;
133 | int isLeft = w <= width / 2;
134 | int isCenter = w >= width / 3 && w <= (width / 3) * 2;
135 |
136 | int class = classes[i];
137 | // sidewalk or terrain (safe to walk on)
138 | if (class == SIDEWALK || class == TERRAIN) {
139 | if (isCenter) {
140 | local_center_walk_score++;
141 | }
142 | isLeft ? local_left_walk_score++ : local_right_walk_score++;
143 | } else if (class == POLE) {
144 | local_obstacle_score++;
145 | } else if (class == CAR || class == TRUCK) {
146 | // TODO: WHAT TO DO WITH A BUS OR TRAIN?
147 | local_vehicle_score++;
148 | } else if (class == BICYCLE || class == MOTORCYCLE) {
149 | local_bike_score++;
150 | }
151 | }
152 |
153 | // We divide h * w by 2 in the following calculations.
154 | // This is due left/right/center detection.
155 |
156 | if (local_left_walk_score > local_right_walk_score) {
157 | float leftWalkRatio = (local_left_walk_score / ((height * width) / 2.0f));
158 | if (leftWalkRatio >= MINIMAL_WALKABLE_RATIO) {
159 | // It's safe to walk here
160 | left_walk_score++;
161 | }
162 | } else {
163 | float rightWalkRatio = (local_right_walk_score / ((height * width) / 2.0f));
164 | if (rightWalkRatio >= MINIMAL_WALKABLE_RATIO) {
165 | // It's safe to walk here
166 | right_walk_score++;
167 | }
168 | }
169 |
170 | float centerWalkRatio = (local_center_walk_score / ((height * width) / 2.0f));
171 | if (centerWalkRatio >= MINIMAL_WALKABLE_RATIO) {
172 | // It's safe to walk here
173 | center_walk_score++;
174 | }
175 |
176 | float poleRatio = (local_obstacle_score / ((float)(height * width)));
177 | if (poleRatio > MINIMAL_POLE_RATIO) {
178 | // There are clearly poles detected
179 | poles_score++;
180 | }
181 |
182 | float vehiclesRatio = (local_vehicle_score / ((float)(height * width)));
183 | if (vehiclesRatio > MINIMAL_VEHICLE_RATIO) {
184 | // There is clearly a car in the front detected
185 | vehicles_score++;
186 | }
187 |
188 | float bikeRatio = (local_bike_score / ((float)(height * width)));
189 | if (bikeRatio > MINIMAL_BIKE_RATIO) {
190 | // There are some bikes in front of the user
191 | bikes_score++;
192 | }
193 |
194 | current_analyzed_frames++;
195 |
196 | return SUCCESS;
197 | }
198 |
199 | /**
200 | * Generates a scene information of the analyzed frames
201 | */
202 | int poll_results(scene_information *information) {
203 |
204 | if (current_analyzed_frames >= FRAMES_TO_ANALYZE) {
205 | if (center_walk_score > 0) {
206 | information->walk_position = FRONT;
207 | } else if (left_walk_score > 0 || right_walk_score > 0) {
208 | if (left_walk_score > right_walk_score) {
209 | information->walk_position = LEFT;
210 | } else {
211 | information->walk_position = RIGHT;
212 | }
213 | } else {
214 | information->walk_position = NONE;
215 | }
216 | if (poles_score > 0) {
217 | information->poles_detected = 1;
218 | }
219 | if (vehicles_score > 0) {
220 | information->vehicle_detected = 1;
221 | }
222 | if (bikes_score > 0) {
223 | information->bikes_detected = 1;
224 | }
225 |
226 | // reset values
227 | current_analyzed_frames = 0;
228 | left_walk_score = 0;
229 | right_walk_score = 0;
230 | center_walk_score = 0;
231 |
232 | vehicles_score = 0;
233 | bikes_score = 0;
234 | poles_score = 0;
235 |
236 | return SUCCESS;
237 | }
238 |
239 | return -1;
240 | }
241 |
--------------------------------------------------------------------------------
/BlindAssist.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 24D1263B874E7BD5AD704DA7 /* Pods_BlindAssist.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C7508745D9FA74F266C9884 /* Pods_BlindAssist.framework */; };
11 | A10C11FC213ECED600372056 /* SceneKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A10C11FB213ECED600372056 /* SceneKit.framework */; };
12 | A10C11FE213ECF2B00372056 /* ARKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A10C11FD213ECF2B00372056 /* ARKit.framework */; };
13 | A10C1203213ECF8D00372056 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A10C1201213ECF3F00372056 /* Vision.framework */; };
14 | A1857D81217E0995004C31CC /* CameraPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1857D80217E0995004C31CC /* CameraPreviewView.swift */; };
15 | A1857D84217E0A18004C31CC /* UIDevice+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1857D83217E0A18004C31CC /* UIDevice+Orientation.swift */; };
16 | A1857D86217E0AAB004C31CC /* InferenceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1857D85217E0AAB004C31CC /* InferenceViewController.swift */; };
17 | A1857D88217E0B65004C31CC /* Inference.m in Sources */ = {isa = PBXBuildFile; fileRef = A1857D87217E0B65004C31CC /* Inference.m */; };
18 | A1B789532110C7D700FB6CF1 /* blindassist.c in Sources */ = {isa = PBXBuildFile; fileRef = A1B789522110C7D700FB6CF1 /* blindassist.c */; };
19 | A1BF43B02070D11E0030848D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A1BF43AF2070D11E0030848D /* Assets.xcassets */; };
20 | A1BF43BF2070D1540030848D /* cityscapes.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = A1BF43BC2070D1540030848D /* cityscapes.mlmodel */; };
21 | A1E6B04F217CBCF400CBD0BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1E6B04E217CBCF400CBD0BF /* AppDelegate.swift */; };
22 | D275709F2160F34800DF9C94 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D275709E2160F34800DF9C94 /* OnboardingViewController.swift */; };
23 | D27570A12160F35C00DF9C94 /* PagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27570A02160F35C00DF9C94 /* PagerView.swift */; };
24 | D27570A32160F3FF00DF9C94 /* PageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27570A22160F3FF00DF9C94 /* PageView.swift */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXFileReference section */
28 | 4C7508745D9FA74F266C9884 /* Pods_BlindAssist.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BlindAssist.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29 | 7512F8B822D398669DB64D9F /* Pods-BlindAssist.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlindAssist.debug.xcconfig"; path = "Target Support Files/Pods-BlindAssist/Pods-BlindAssist.debug.xcconfig"; sourceTree = ""; };
30 | A10C11FB213ECED600372056 /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = System/Library/Frameworks/SceneKit.framework; sourceTree = SDKROOT; };
31 | A10C11FD213ECF2B00372056 /* ARKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ARKit.framework; path = System/Library/Frameworks/ARKit.framework; sourceTree = SDKROOT; };
32 | A10C11FF213ECF3200372056 /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = System/Library/Frameworks/CoreML.framework; sourceTree = SDKROOT; };
33 | A10C1201213ECF3F00372056 /* Vision.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vision.framework; path = System/Library/Frameworks/Vision.framework; sourceTree = SDKROOT; };
34 | A1857D80217E0995004C31CC /* CameraPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewView.swift; sourceTree = ""; };
35 | A1857D83217E0A18004C31CC /* UIDevice+Orientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Orientation.swift"; sourceTree = ""; };
36 | A1857D85217E0AAB004C31CC /* InferenceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InferenceViewController.swift; sourceTree = ""; };
37 | A1857D87217E0B65004C31CC /* Inference.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Inference.m; sourceTree = ""; };
38 | A1857D89217E0B73004C31CC /* Inference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Inference.h; sourceTree = ""; };
39 | A1B789512110C7D700FB6CF1 /* blindassist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = blindassist.h; sourceTree = ""; };
40 | A1B789522110C7D700FB6CF1 /* blindassist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = blindassist.c; sourceTree = ""; };
41 | A1BF43A32070D11C0030848D /* BlindAssist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlindAssist.app; sourceTree = BUILT_PRODUCTS_DIR; };
42 | A1BF43AF2070D11E0030848D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | A1BF43B42070D11E0030848D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
44 | A1BF43BC2070D1540030848D /* cityscapes.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = cityscapes.mlmodel; sourceTree = ""; };
45 | A1E6B04E217CBCF400CBD0BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
46 | C08A13BFDC68439276507632 /* Pods-BlindAssist.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlindAssist.release.xcconfig"; path = "Target Support Files/Pods-BlindAssist/Pods-BlindAssist.release.xcconfig"; sourceTree = ""; };
47 | D27570992160F24800DF9C94 /* BlindAssist-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BlindAssist-Bridging-Header.h"; sourceTree = ""; };
48 | D275709E2160F34800DF9C94 /* OnboardingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; };
49 | D27570A02160F35C00DF9C94 /* PagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagerView.swift; sourceTree = ""; };
50 | D27570A22160F3FF00DF9C94 /* PageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageView.swift; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | A1BF43A02070D11C0030848D /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | A10C1203213ECF8D00372056 /* Vision.framework in Frameworks */,
59 | A10C11FE213ECF2B00372056 /* ARKit.framework in Frameworks */,
60 | A10C11FC213ECED600372056 /* SceneKit.framework in Frameworks */,
61 | 24D1263B874E7BD5AD704DA7 /* Pods_BlindAssist.framework in Frameworks */,
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | /* End PBXFrameworksBuildPhase section */
66 |
67 | /* Begin PBXGroup section */
68 | 7CB17FEFC5EDC7C90C550A34 /* Pods */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 7512F8B822D398669DB64D9F /* Pods-BlindAssist.debug.xcconfig */,
72 | C08A13BFDC68439276507632 /* Pods-BlindAssist.release.xcconfig */,
73 | );
74 | path = Pods;
75 | sourceTree = "";
76 | };
77 | A10C11FA213ECED600372056 /* Frameworks */ = {
78 | isa = PBXGroup;
79 | children = (
80 | A10C1201213ECF3F00372056 /* Vision.framework */,
81 | A10C11FF213ECF3200372056 /* CoreML.framework */,
82 | A10C11FD213ECF2B00372056 /* ARKit.framework */,
83 | A10C11FB213ECED600372056 /* SceneKit.framework */,
84 | 4C7508745D9FA74F266C9884 /* Pods_BlindAssist.framework */,
85 | );
86 | name = Frameworks;
87 | sourceTree = "";
88 | };
89 | A1857D7E217E08F5004C31CC /* Inference */ = {
90 | isa = PBXGroup;
91 | children = (
92 | A1857D85217E0AAB004C31CC /* InferenceViewController.swift */,
93 | A1857D89217E0B73004C31CC /* Inference.h */,
94 | A1857D87217E0B65004C31CC /* Inference.m */,
95 | );
96 | path = Inference;
97 | sourceTree = "";
98 | };
99 | A1857D7F217E0911004C31CC /* Views */ = {
100 | isa = PBXGroup;
101 | children = (
102 | A1857D80217E0995004C31CC /* CameraPreviewView.swift */,
103 | );
104 | path = Views;
105 | sourceTree = "";
106 | };
107 | A1857D82217E09DB004C31CC /* Extensions */ = {
108 | isa = PBXGroup;
109 | children = (
110 | A1857D83217E0A18004C31CC /* UIDevice+Orientation.swift */,
111 | );
112 | path = Extensions;
113 | sourceTree = "";
114 | };
115 | A1BF439A2070D11C0030848D = {
116 | isa = PBXGroup;
117 | children = (
118 | A1BF43A52070D11C0030848D /* BlindAssist */,
119 | A1BF43A42070D11C0030848D /* Products */,
120 | A10C11FA213ECED600372056 /* Frameworks */,
121 | 7CB17FEFC5EDC7C90C550A34 /* Pods */,
122 | );
123 | sourceTree = "";
124 | };
125 | A1BF43A42070D11C0030848D /* Products */ = {
126 | isa = PBXGroup;
127 | children = (
128 | A1BF43A32070D11C0030848D /* BlindAssist.app */,
129 | );
130 | name = Products;
131 | sourceTree = "";
132 | };
133 | A1BF43A52070D11C0030848D /* BlindAssist */ = {
134 | isa = PBXGroup;
135 | children = (
136 | A1857D7E217E08F5004C31CC /* Inference */,
137 | D275709D2160F34800DF9C94 /* Onboarding */,
138 | A1857D82217E09DB004C31CC /* Extensions */,
139 | A1857D7F217E0911004C31CC /* Views */,
140 | A1E6B04E217CBCF400CBD0BF /* AppDelegate.swift */,
141 | A1BF43BC2070D1540030848D /* cityscapes.mlmodel */,
142 | A1BF43AF2070D11E0030848D /* Assets.xcassets */,
143 | A1BF43B42070D11E0030848D /* Info.plist */,
144 | A1B789512110C7D700FB6CF1 /* blindassist.h */,
145 | A1B789522110C7D700FB6CF1 /* blindassist.c */,
146 | D27570992160F24800DF9C94 /* BlindAssist-Bridging-Header.h */,
147 | );
148 | path = BlindAssist;
149 | sourceTree = "";
150 | };
151 | D275709D2160F34800DF9C94 /* Onboarding */ = {
152 | isa = PBXGroup;
153 | children = (
154 | D275709E2160F34800DF9C94 /* OnboardingViewController.swift */,
155 | D27570A02160F35C00DF9C94 /* PagerView.swift */,
156 | D27570A22160F3FF00DF9C94 /* PageView.swift */,
157 | );
158 | path = Onboarding;
159 | sourceTree = "";
160 | };
161 | /* End PBXGroup section */
162 |
163 | /* Begin PBXNativeTarget section */
164 | A1BF43A22070D11C0030848D /* BlindAssist */ = {
165 | isa = PBXNativeTarget;
166 | buildConfigurationList = A1BF43B92070D11E0030848D /* Build configuration list for PBXNativeTarget "BlindAssist" */;
167 | buildPhases = (
168 | 1BF0718EBA51CCC920E8563A /* [CP] Check Pods Manifest.lock */,
169 | A1BF439F2070D11C0030848D /* Sources */,
170 | A1BF43A02070D11C0030848D /* Frameworks */,
171 | A1BF43A12070D11C0030848D /* Resources */,
172 | 9F9044373B6FF449C094FED5 /* [CP] Embed Pods Frameworks */,
173 | );
174 | buildRules = (
175 | );
176 | dependencies = (
177 | );
178 | name = BlindAssist;
179 | productName = BlindAssist;
180 | productReference = A1BF43A32070D11C0030848D /* BlindAssist.app */;
181 | productType = "com.apple.product-type.application";
182 | };
183 | /* End PBXNativeTarget section */
184 |
185 | /* Begin PBXProject section */
186 | A1BF439B2070D11C0030848D /* Project object */ = {
187 | isa = PBXProject;
188 | attributes = {
189 | LastUpgradeCheck = 1020;
190 | ORGANIZATIONNAME = "Giovanni Terlingen";
191 | TargetAttributes = {
192 | A1BF43A22070D11C0030848D = {
193 | CreatedOnToolsVersion = 9.3;
194 | LastSwiftMigration = 1020;
195 | };
196 | };
197 | };
198 | buildConfigurationList = A1BF439E2070D11C0030848D /* Build configuration list for PBXProject "BlindAssist" */;
199 | compatibilityVersion = "Xcode 9.3";
200 | developmentRegion = en;
201 | hasScannedForEncodings = 0;
202 | knownRegions = (
203 | en,
204 | Base,
205 | );
206 | mainGroup = A1BF439A2070D11C0030848D;
207 | productRefGroup = A1BF43A42070D11C0030848D /* Products */;
208 | projectDirPath = "";
209 | projectRoot = "";
210 | targets = (
211 | A1BF43A22070D11C0030848D /* BlindAssist */,
212 | );
213 | };
214 | /* End PBXProject section */
215 |
216 | /* Begin PBXResourcesBuildPhase section */
217 | A1BF43A12070D11C0030848D /* Resources */ = {
218 | isa = PBXResourcesBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | A1BF43B02070D11E0030848D /* Assets.xcassets in Resources */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | /* End PBXResourcesBuildPhase section */
226 |
227 | /* Begin PBXShellScriptBuildPhase section */
228 | 1BF0718EBA51CCC920E8563A /* [CP] Check Pods Manifest.lock */ = {
229 | isa = PBXShellScriptBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | );
233 | inputFileListPaths = (
234 | );
235 | inputPaths = (
236 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
237 | "${PODS_ROOT}/Manifest.lock",
238 | );
239 | name = "[CP] Check Pods Manifest.lock";
240 | outputFileListPaths = (
241 | );
242 | outputPaths = (
243 | "$(DERIVED_FILE_DIR)/Pods-BlindAssist-checkManifestLockResult.txt",
244 | );
245 | runOnlyForDeploymentPostprocessing = 0;
246 | shellPath = /bin/sh;
247 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
248 | showEnvVarsInLog = 0;
249 | };
250 | 9F9044373B6FF449C094FED5 /* [CP] Embed Pods Frameworks */ = {
251 | isa = PBXShellScriptBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | inputFileListPaths = (
256 | "${PODS_ROOT}/Target Support Files/Pods-BlindAssist/Pods-BlindAssist-frameworks-${CONFIGURATION}-input-files.xcfilelist",
257 | );
258 | name = "[CP] Embed Pods Frameworks";
259 | outputFileListPaths = (
260 | "${PODS_ROOT}/Target Support Files/Pods-BlindAssist/Pods-BlindAssist-frameworks-${CONFIGURATION}-output-files.xcfilelist",
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | shellPath = /bin/sh;
264 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BlindAssist/Pods-BlindAssist-frameworks.sh\"\n";
265 | showEnvVarsInLog = 0;
266 | };
267 | /* End PBXShellScriptBuildPhase section */
268 |
269 | /* Begin PBXSourcesBuildPhase section */
270 | A1BF439F2070D11C0030848D /* Sources */ = {
271 | isa = PBXSourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | A1E6B04F217CBCF400CBD0BF /* AppDelegate.swift in Sources */,
275 | A1857D84217E0A18004C31CC /* UIDevice+Orientation.swift in Sources */,
276 | A1B789532110C7D700FB6CF1 /* blindassist.c in Sources */,
277 | A1857D81217E0995004C31CC /* CameraPreviewView.swift in Sources */,
278 | A1857D88217E0B65004C31CC /* Inference.m in Sources */,
279 | D27570A12160F35C00DF9C94 /* PagerView.swift in Sources */,
280 | D27570A32160F3FF00DF9C94 /* PageView.swift in Sources */,
281 | D275709F2160F34800DF9C94 /* OnboardingViewController.swift in Sources */,
282 | A1BF43BF2070D1540030848D /* cityscapes.mlmodel in Sources */,
283 | A1857D86217E0AAB004C31CC /* InferenceViewController.swift in Sources */,
284 | );
285 | runOnlyForDeploymentPostprocessing = 0;
286 | };
287 | /* End PBXSourcesBuildPhase section */
288 |
289 | /* Begin XCBuildConfiguration section */
290 | A1BF43B72070D11E0030848D /* Debug */ = {
291 | isa = XCBuildConfiguration;
292 | buildSettings = {
293 | ALWAYS_SEARCH_USER_PATHS = NO;
294 | CLANG_ANALYZER_NONNULL = YES;
295 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
297 | CLANG_CXX_LIBRARY = "libc++";
298 | CLANG_ENABLE_MODULES = YES;
299 | CLANG_ENABLE_OBJC_ARC = YES;
300 | CLANG_ENABLE_OBJC_WEAK = YES;
301 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
302 | CLANG_WARN_BOOL_CONVERSION = YES;
303 | CLANG_WARN_COMMA = YES;
304 | CLANG_WARN_CONSTANT_CONVERSION = YES;
305 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
306 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
307 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
308 | CLANG_WARN_EMPTY_BODY = YES;
309 | CLANG_WARN_ENUM_CONVERSION = YES;
310 | CLANG_WARN_INFINITE_RECURSION = YES;
311 | CLANG_WARN_INT_CONVERSION = YES;
312 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
313 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
314 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
315 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
316 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
317 | CLANG_WARN_STRICT_PROTOTYPES = YES;
318 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
319 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
320 | CLANG_WARN_UNREACHABLE_CODE = YES;
321 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
322 | CODE_SIGN_IDENTITY = "iPhone Developer";
323 | COPY_PHASE_STRIP = NO;
324 | DEBUG_INFORMATION_FORMAT = dwarf;
325 | ENABLE_STRICT_OBJC_MSGSEND = YES;
326 | ENABLE_TESTABILITY = YES;
327 | GCC_C_LANGUAGE_STANDARD = gnu11;
328 | GCC_DYNAMIC_NO_PIC = NO;
329 | GCC_NO_COMMON_BLOCKS = YES;
330 | GCC_OPTIMIZATION_LEVEL = 0;
331 | GCC_PREPROCESSOR_DEFINITIONS = (
332 | "DEBUG=1",
333 | "$(inherited)",
334 | );
335 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
336 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
337 | GCC_WARN_UNDECLARED_SELECTOR = YES;
338 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
339 | GCC_WARN_UNUSED_FUNCTION = YES;
340 | GCC_WARN_UNUSED_VARIABLE = YES;
341 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
342 | MTL_ENABLE_DEBUG_INFO = YES;
343 | ONLY_ACTIVE_ARCH = YES;
344 | SDKROOT = iphoneos;
345 | SWIFT_VERSION = 5.0;
346 | };
347 | name = Debug;
348 | };
349 | A1BF43B82070D11E0030848D /* Release */ = {
350 | isa = XCBuildConfiguration;
351 | buildSettings = {
352 | ALWAYS_SEARCH_USER_PATHS = NO;
353 | CLANG_ANALYZER_NONNULL = YES;
354 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
356 | CLANG_CXX_LIBRARY = "libc++";
357 | CLANG_ENABLE_MODULES = YES;
358 | CLANG_ENABLE_OBJC_ARC = YES;
359 | CLANG_ENABLE_OBJC_WEAK = YES;
360 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
361 | CLANG_WARN_BOOL_CONVERSION = YES;
362 | CLANG_WARN_COMMA = YES;
363 | CLANG_WARN_CONSTANT_CONVERSION = YES;
364 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
365 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
366 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
367 | CLANG_WARN_EMPTY_BODY = YES;
368 | CLANG_WARN_ENUM_CONVERSION = YES;
369 | CLANG_WARN_INFINITE_RECURSION = YES;
370 | CLANG_WARN_INT_CONVERSION = YES;
371 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
372 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
373 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
374 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
375 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
376 | CLANG_WARN_STRICT_PROTOTYPES = YES;
377 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
378 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
379 | CLANG_WARN_UNREACHABLE_CODE = YES;
380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
381 | CODE_SIGN_IDENTITY = "iPhone Developer";
382 | COPY_PHASE_STRIP = NO;
383 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
384 | ENABLE_NS_ASSERTIONS = NO;
385 | ENABLE_STRICT_OBJC_MSGSEND = YES;
386 | GCC_C_LANGUAGE_STANDARD = gnu11;
387 | GCC_NO_COMMON_BLOCKS = YES;
388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
390 | GCC_WARN_UNDECLARED_SELECTOR = YES;
391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
392 | GCC_WARN_UNUSED_FUNCTION = YES;
393 | GCC_WARN_UNUSED_VARIABLE = YES;
394 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
395 | MTL_ENABLE_DEBUG_INFO = NO;
396 | SDKROOT = iphoneos;
397 | SWIFT_COMPILATION_MODE = wholemodule;
398 | SWIFT_VERSION = 5.0;
399 | VALIDATE_PRODUCT = YES;
400 | };
401 | name = Release;
402 | };
403 | A1BF43BA2070D11E0030848D /* Debug */ = {
404 | isa = XCBuildConfiguration;
405 | baseConfigurationReference = 7512F8B822D398669DB64D9F /* Pods-BlindAssist.debug.xcconfig */;
406 | buildSettings = {
407 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
408 | CLANG_ENABLE_MODULES = YES;
409 | CODE_SIGN_STYLE = Automatic;
410 | COREML_CODEGEN_LANGUAGE = Swift;
411 | DEVELOPMENT_TEAM = 6Q9K4M2G5A;
412 | GCC_OPTIMIZATION_LEVEL = 2;
413 | INFOPLIST_FILE = BlindAssist/Info.plist;
414 | LD_RUNPATH_SEARCH_PATHS = (
415 | "$(inherited)",
416 | "@executable_path/Frameworks",
417 | );
418 | PRODUCT_BUNDLE_IDENTIFIER = org.blindassist.1;
419 | PRODUCT_NAME = "$(TARGET_NAME)";
420 | SWIFT_OBJC_BRIDGING_HEADER = "BlindAssist/BlindAssist-Bridging-Header.h";
421 | SWIFT_VERSION = 5.0;
422 | TARGETED_DEVICE_FAMILY = "1,2";
423 | };
424 | name = Debug;
425 | };
426 | A1BF43BB2070D11E0030848D /* Release */ = {
427 | isa = XCBuildConfiguration;
428 | baseConfigurationReference = C08A13BFDC68439276507632 /* Pods-BlindAssist.release.xcconfig */;
429 | buildSettings = {
430 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
431 | CLANG_ENABLE_MODULES = YES;
432 | CODE_SIGN_STYLE = Automatic;
433 | COREML_CODEGEN_LANGUAGE = Swift;
434 | DEVELOPMENT_TEAM = 6Q9K4M2G5A;
435 | GCC_OPTIMIZATION_LEVEL = 2;
436 | INFOPLIST_FILE = BlindAssist/Info.plist;
437 | LD_RUNPATH_SEARCH_PATHS = (
438 | "$(inherited)",
439 | "@executable_path/Frameworks",
440 | );
441 | PRODUCT_BUNDLE_IDENTIFIER = org.blindassist.1;
442 | PRODUCT_NAME = "$(TARGET_NAME)";
443 | SWIFT_OBJC_BRIDGING_HEADER = "BlindAssist/BlindAssist-Bridging-Header.h";
444 | SWIFT_VERSION = 5.0;
445 | TARGETED_DEVICE_FAMILY = "1,2";
446 | };
447 | name = Release;
448 | };
449 | /* End XCBuildConfiguration section */
450 |
451 | /* Begin XCConfigurationList section */
452 | A1BF439E2070D11C0030848D /* Build configuration list for PBXProject "BlindAssist" */ = {
453 | isa = XCConfigurationList;
454 | buildConfigurations = (
455 | A1BF43B72070D11E0030848D /* Debug */,
456 | A1BF43B82070D11E0030848D /* Release */,
457 | );
458 | defaultConfigurationIsVisible = 0;
459 | defaultConfigurationName = Release;
460 | };
461 | A1BF43B92070D11E0030848D /* Build configuration list for PBXNativeTarget "BlindAssist" */ = {
462 | isa = XCConfigurationList;
463 | buildConfigurations = (
464 | A1BF43BA2070D11E0030848D /* Debug */,
465 | A1BF43BB2070D11E0030848D /* Release */,
466 | );
467 | defaultConfigurationIsVisible = 0;
468 | defaultConfigurationName = Release;
469 | };
470 | /* End XCConfigurationList section */
471 | };
472 | rootObject = A1BF439B2070D11C0030848D /* Project object */;
473 | }
474 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------