├── .gitignore ├── scheme@2x.png ├── Early Math Prototype Player ├── finger_demo.m4v ├── Images.xcassets │ └── AppIcon.appiconset │ │ ├── Bitmap.png │ │ ├── Bitmap@2x.png │ │ └── Contents.json ├── Early Math Prototype Player-Bridging-Header.h ├── Info.plist ├── InstructionsViewController.swift ├── LaunchScreen.storyboard ├── AppDelegate.swift ├── ReadmeViewController.swift ├── PlayerViewController.swift ├── PrototypeProvider.swift ├── Instructions.xib └── PrototypeListCollectionViewController.swift ├── Early Math Prototype Player.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── jason.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Early Math Prototype Player.xcscheme └── project.pbxproj ├── .gitmodules └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.xccheckout 3 | 4 | *.xcbkptlist 5 | -------------------------------------------------------------------------------- /scheme@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khan/Early-Math-Prototype-Player/HEAD/scheme@2x.png -------------------------------------------------------------------------------- /Early Math Prototype Player/finger_demo.m4v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khan/Early-Math-Prototype-Player/HEAD/Early Math Prototype Player/finger_demo.m4v -------------------------------------------------------------------------------- /Early Math Prototype Player/Images.xcassets/AppIcon.appiconset/Bitmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khan/Early-Math-Prototype-Player/HEAD/Early Math Prototype Player/Images.xcassets/AppIcon.appiconset/Bitmap.png -------------------------------------------------------------------------------- /Early Math Prototype Player/Images.xcassets/AppIcon.appiconset/Bitmap@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Khan/Early-Math-Prototype-Player/HEAD/Early Math Prototype Player/Images.xcassets/AppIcon.appiconset/Bitmap@2x.png -------------------------------------------------------------------------------- /Early Math Prototype Player.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Early Math Prototype Player/Early Math Prototype Player-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 6 | #import "FLAnimatedImage.h" 7 | #import "FLAnimatedImageView.h" -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Early Math Prototype Player/Early-Math-Prototypes"] 2 | path = Early Math Prototype Player/Early-Math-Prototypes 3 | url = git@github.com:Khan/Early-Math-Prototypes.git 4 | [submodule "Prototope"] 5 | path = Prototope 6 | url = git@github.com:Khan/Prototope.git 7 | [submodule "ThirdParty/MMMarkdown"] 8 | path = ThirdParty/MMMarkdown 9 | url = https://github.com/mdiep/MMMarkdown 10 | [submodule "ThirdParty/FLAnimatedImage"] 11 | path = ThirdParty/FLAnimatedImage 12 | url = https://github.com/Flipboard/FLAnimatedImage.git 13 | -------------------------------------------------------------------------------- /Early Math Prototype Player.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Early Math Prototype Player.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 962558F51B39AF1A005E4360 16 | 17 | primary 18 | 19 | 20 | 9625590A1B39AF1A005E4360 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Early Math Prototype Player/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "ipad", 5 | "size" : "29x29", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "ipad", 10 | "size" : "29x29", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "ipad", 15 | "size" : "40x40", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "40x40", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "size" : "76x76", 25 | "idiom" : "ipad", 26 | "filename" : "Bitmap.png", 27 | "scale" : "1x" 28 | }, 29 | { 30 | "size" : "76x76", 31 | "idiom" : "ipad", 32 | "filename" : "Bitmap@2x.png", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "idiom" : "ipad", 37 | "size" : "83.5x83.5", 38 | "scale" : "2x" 39 | } 40 | ], 41 | "info" : { 42 | "version" : 1, 43 | "author" : "xcode" 44 | } 45 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Early-Math-Prototype-Player 2 | Play the [Early Math Prototypes](https://github.com/Khan/Early-Math-Prototypes) embedded in an iPad app. 3 | 4 | Running the app on your iPad: 5 | 6 | - Get Xcode from the Mac App Store if you don't already have it 7 | - Clone this git repository to your computer. 8 | - If you're not familiar with git, you can use the Github app to do it. 9 | - Alternatively, you can do the following from the Terminal app 10 | 11 | git clone --recursive git@github.com:Khan/Early-Math-Prototype-Player.git 12 | - Open the project file (Early Math Prototype Player.xcodeproj) in Xcode 13 | - Make sure you pick the correct app to run and device in Xcode if it's not already chosen. 14 | 15 | 16 | 17 | - Build and run the app on your Simulator or iPad. 18 | 19 | ## Navigating 20 | 21 | To navigate back to the list of prototypes, swipe to the right with three fingers. If you're using the simulator, you can also press Escape. 22 | -------------------------------------------------------------------------------- /Early Math Prototype Player/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.khanacademy.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations~ipad 34 | 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | 38 | UIViewControllerBasedStatusBarAppearance 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Early Math Prototype Player/InstructionsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InstructionsViewController.swift 3 | // Early Math Prototype Player 4 | // 5 | // Created by Andy Matuschak on 7/5/15. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AVFoundation 11 | 12 | class InstructionsViewController: UIViewController { 13 | // This state shouldn't be entangled here, but this is throwaway... 14 | static var userHasSeenInstructions: Bool { 15 | return NSUserDefaults.standardUserDefaults().boolForKey(InstructionsViewController.userHasSeenInstructionsKey) 16 | } 17 | 18 | init() { 19 | super.init(nibName: "Instructions", bundle: nil) 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | private static let userHasSeenInstructionsKey = "UserHasSeenInstructions" 27 | @IBOutlet weak var videoPlayerView: AVPlayerView! 28 | @IBOutlet weak var simulatorNoteLabel: UILabel! 29 | 30 | override func viewWillAppear(animated: Bool) { 31 | NSUserDefaults.standardUserDefaults().setBool(true, forKey: InstructionsViewController.userHasSeenInstructionsKey) 32 | 33 | simulatorNoteLabel.hidden = TARGET_IPHONE_SIMULATOR == 0 34 | 35 | videoPlayerView.playerLayer.player = AVPlayer(URL: NSBundle.mainBundle().URLForResource("finger_demo", withExtension: "m4v")!) 36 | videoPlayerView.playerLayer.player!.play() 37 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.loopPlayer), name: AVPlayerItemDidPlayToEndTimeNotification, object: videoPlayerView.playerLayer.player!.currentItem) 38 | } 39 | 40 | override func viewDidDisappear(animated: Bool) { 41 | NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: videoPlayerView.playerLayer.player!.currentItem) 42 | } 43 | 44 | @objc private func loopPlayer() { 45 | videoPlayerView.playerLayer.player!.seekToTime(kCMTimeZero) 46 | videoPlayerView.playerLayer.player!.play() 47 | } 48 | 49 | @IBAction func handleContinue(sender: AnyObject) { 50 | self.dismissViewControllerAnimated(true, completion: nil) 51 | } 52 | } 53 | 54 | @objc(AVPlayerView) class AVPlayerView: UIView { 55 | override class func layerClass() -> AnyClass { return AVPlayerLayer.self } 56 | var playerLayer: AVPlayerLayer { return layer as! AVPlayerLayer } 57 | } 58 | -------------------------------------------------------------------------------- /Early Math Prototype Player/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Early Math Prototype Player/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Protomath 4 | // 5 | // Created by Jason Brennan on 2015-06-22. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDelegate, UIGestureRecognizerDelegate { 13 | 14 | var window: UIWindow? 15 | var prototypeListCollectionViewController: PrototypeListCollectionViewController! 16 | var navigationController: UINavigationController! 17 | 18 | 19 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 20 | 21 | application.idleTimerDisabled = true 22 | 23 | window = UIWindow(frame: UIScreen.mainScreen().bounds) 24 | 25 | prototypeListCollectionViewController = PrototypeListCollectionViewController() 26 | 27 | navigationController = UINavigationController(rootViewController: prototypeListCollectionViewController) 28 | navigationController.delegate = self 29 | 30 | window?.rootViewController = navigationController 31 | 32 | let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(self.handleSwipeBackGesture(_:))) 33 | swipeGestureRecognizer.numberOfTouchesRequired = 3 34 | swipeGestureRecognizer.direction = .Right 35 | swipeGestureRecognizer.delegate = self 36 | window?.addGestureRecognizer(swipeGestureRecognizer) 37 | window?.makeKeyAndVisible() 38 | 39 | return true 40 | } 41 | 42 | func handleSwipeBackGesture(gesture: UIGestureRecognizer!) { 43 | self.navigationController.popToRootViewControllerAnimated(true) 44 | } 45 | 46 | func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { 47 | return false 48 | } 49 | 50 | func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { 51 | return true 52 | } 53 | 54 | // Hacks to show/hide navigation bar in prototypes so hack wow 55 | func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) { 56 | if viewController is PlayerViewController { 57 | navigationController.setNavigationBarHidden(true, animated: true) 58 | UIApplication.sharedApplication().setStatusBarHidden(true, withAnimation: .None) // view controller based status bar APIs interacts poorly with hiding/showing the navigation bar 59 | } else { 60 | navigationController.setNavigationBarHidden(false, animated: true) 61 | UIApplication.sharedApplication().setStatusBarHidden(false, withAnimation: .None) 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Early Math Prototype Player/ReadmeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadmeViewController.swift 3 | // Early Math Prototype Player 4 | // 5 | // Created by Andy Matuschak on 6/24/15. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** This view controller shows readmes for prototypes. */ 12 | class ReadmeViewController: UIViewController { 13 | let prototype: Prototype 14 | 15 | lazy var startButton: UIButton = { 16 | let button = UIButton(type: .System) 17 | button.setTitle("Start", forState: .Normal) 18 | button.titleLabel!.font = UIFont.systemFontOfSize(24) 19 | return button 20 | }() 21 | 22 | lazy var webView: UIWebView = { 23 | let webView = UIWebView() 24 | webView.scrollView.alwaysBounceVertical = false 25 | webView.backgroundColor = UIColor.clearColor() 26 | return webView 27 | }() 28 | 29 | init(prototype: Prototype) { 30 | precondition(prototype.readmeURL != nil) 31 | self.prototype = prototype 32 | 33 | super.init(nibName: nil, bundle: nil) 34 | 35 | navigationItem.title = prototype.name 36 | } 37 | 38 | required init?(coder aDecoder: NSCoder) { 39 | fatalError("init(coder:) has not been implemented") 40 | } 41 | 42 | private var readmeHTMLRepresentation: String { 43 | let markdownSource = try! NSString(contentsOfURL: prototype.readmeURL!, encoding: NSUTF8StringEncoding) 44 | 45 | let body: NSString 46 | do { 47 | body = try MMMarkdown.HTMLStringWithMarkdown(String(markdownSource), extensions: .GitHubFlavored) 48 | } catch { 49 | body = "Couldn't parse README: \(error)" 50 | } 51 | let systemFontName = UIFont.systemFontOfSize(12).fontName 52 | return "\(body)" 53 | } 54 | 55 | override func loadView() { 56 | super.loadView() 57 | view.backgroundColor = UIColor.whiteColor() 58 | 59 | startButton.addTarget(self, action: #selector(self.startPrototype), forControlEvents: .TouchUpInside) 60 | view.addSubview(startButton) 61 | 62 | webView.loadHTMLString(readmeHTMLRepresentation, baseURL: NSURL(fileURLWithPath: "/")) 63 | view.addSubview(webView) 64 | 65 | view.setNeedsLayout() 66 | } 67 | 68 | override func viewWillLayoutSubviews() { 69 | // what is the difference between a view controller and a view anyways?!? 70 | startButton.sizeToFit() 71 | startButton.center.x = view.bounds.size.width / 2.0 72 | startButton.center.y = view.bounds.size.height - startButton.bounds.size.height / 2.0 - 50 73 | 74 | webView.frame.origin.y = topLayoutGuide.length + 40 75 | webView.frame.size.width = 500 76 | webView.frame.size.height = startButton.frame.origin.y - webView.frame.origin.y 77 | webView.center.x = startButton.center.x 78 | } 79 | 80 | @objc private func startPrototype() { 81 | let player = PlayerViewController(path: prototype.mainFileURL) 82 | navigationController!.pushViewController(player, animated: true) // what is a "control flow" anyway so lazy so prototype 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Early Math Prototype Player/PlayerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlayerViewController.swift 3 | // Prototope 4 | // 5 | // Created by Jason Brennan on 2015-06-22. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Prototope 11 | import PrototopeJSBridge 12 | 13 | 14 | /** This view controller hosts and plays Prototypes. */ 15 | class PlayerViewController: UIViewController { 16 | var context: Context! 17 | let jsPath: NSURL 18 | 19 | init(path: NSURL) { 20 | self.jsPath = path 21 | super.init(nibName: nil, bundle: nil) 22 | } 23 | 24 | required init?(coder aDecoder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | view.backgroundColor = UIColor.whiteColor() 32 | 33 | 34 | let prototypeDirectoryURL = self.jsPath.URLByDeletingLastPathComponent! 35 | 36 | let imageProvider = { 37 | (name: String) -> UIImage? in 38 | let scale = UIScreen.mainScreen().scale 39 | let filenameWithScale = (name.stringByAppendingString("@\(Int(scale))x") as NSString).stringByAppendingPathExtension("png")! 40 | let filename = (name as NSString).stringByAppendingPathExtension("png")! 41 | 42 | let scalePath = prototypeDirectoryURL.URLByAppendingPathComponent(filenameWithScale) 43 | let noScalePath = prototypeDirectoryURL.URLByAppendingPathComponent(filename) 44 | 45 | let loadImage: (String) -> UIImage? = { path in 46 | let image = UIImage(contentsOfFile: path) 47 | return image 48 | } 49 | 50 | return loadImage(scalePath.path!) ?? loadImage(noScalePath.path!) 51 | } 52 | 53 | let soundProvider = { 54 | (name: String) -> NSData? in 55 | let fileManager = NSFileManager.defaultManager() 56 | for fileExtension in Sound.supportedExtensions { 57 | let URL = prototypeDirectoryURL.URLByAppendingPathComponent(name).URLByAppendingPathExtension(fileExtension) 58 | if fileManager.fileExistsAtPath(URL.path!) { 59 | return try? NSData(contentsOfURL: URL, options: []) 60 | } 61 | } 62 | return nil 63 | } 64 | 65 | 66 | let defaultEnvironment = Environment.defaultEnvironmentWithRootView(self.view) 67 | Environment.currentEnvironment = Environment( 68 | rootView: view, 69 | imageProvider: imageProvider, 70 | soundProvider: soundProvider, 71 | fontProvider: defaultEnvironment.fontProvider, 72 | exceptionHandler: defaultEnvironment.exceptionHandler 73 | ) 74 | 75 | runJSPrototope() 76 | } 77 | 78 | override func viewWillAppear(animated: Bool) { 79 | if !InstructionsViewController.userHasSeenInstructions { 80 | self.presentViewController(InstructionsViewController(), animated: true, completion: nil) 81 | } 82 | } 83 | 84 | 85 | func runJSPrototope() { 86 | 87 | context = Context() 88 | context.exceptionHandler = { value in 89 | let lineNumber = value.objectForKeyedSubscript("line") 90 | print("Exception on line \(lineNumber): \(value)") 91 | } 92 | context.consoleLogHandler = { message in 93 | print(message) 94 | } 95 | 96 | let script = try! NSString(contentsOfURL: self.jsPath, encoding: NSUTF8StringEncoding) 97 | context.evaluateScript(script as String) 98 | } 99 | 100 | 101 | func handleKeyCommand(command: UIKeyCommand!) { 102 | switch command.input { 103 | case UIKeyInputEscape: 104 | self.navigationController?.popToRootViewControllerAnimated(true) 105 | default: 106 | return 107 | } 108 | } 109 | 110 | // needed to let vc handle keypresses 111 | override func canBecomeFirstResponder() -> Bool { 112 | return true 113 | } 114 | 115 | override var keyCommands: [UIKeyCommand]? { 116 | get { 117 | let escape = UIKeyCommand(input: UIKeyInputEscape, modifierFlags: [], action: #selector(self.handleKeyCommand(_:))) 118 | return [escape] 119 | } 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /Early Math Prototype Player/PrototypeProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrototypeProvider.swift 3 | // Prototope 4 | // 5 | // Created by Jason Brennan on 2015-06-22. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /** Provides Prototype objects loaded from the application's bundle. */ 13 | struct PrototypeProvider { 14 | 15 | private static let prototypeDirectory = "Early-Math-Prototypes" 16 | private static let prototypeHiddenMarker = "hideme" // If this file is present in a prototype directory, we skip it in the UI. 17 | let prototypes: [Prototype] 18 | 19 | init() { 20 | if let resourcePath = NSBundle.mainBundle().resourcePath { 21 | let earlyMathPath = (resourcePath as NSString).stringByAppendingPathComponent(PrototypeProvider.prototypeDirectory) 22 | let files = try! NSFileManager.defaultManager().contentsOfDirectoryAtPath(earlyMathPath) 23 | let validPrototypeDirectories = files.filter { prototypeDirectory in 24 | PrototypeProvider.prototypeIsValidAtPath((earlyMathPath as NSString).stringByAppendingPathComponent(prototypeDirectory)) 25 | } 26 | self.prototypes = validPrototypeDirectories.map { prototypeDirectory in 27 | let prototypeURL = NSURL(fileURLWithPath: (earlyMathPath as NSString).stringByAppendingPathComponent(prototypeDirectory), isDirectory: true) 28 | return Prototype(directoryURL: prototypeURL, name: prototypeDirectory)! 29 | } 30 | } else { 31 | self.prototypes = [] 32 | } 33 | 34 | } 35 | 36 | private static func prototypeIsValidAtPath(path: String) -> Bool { 37 | var isDirectory: ObjCBool = ObjCBool(false) 38 | let fileManager = NSFileManager.defaultManager() 39 | if fileManager.fileExistsAtPath(path, isDirectory: &isDirectory) { 40 | let prototypeIsMarkedAsHidden = fileManager.fileExistsAtPath((path as NSString).stringByAppendingPathComponent(PrototypeProvider.prototypeHiddenMarker)) 41 | return isDirectory.boolValue && !prototypeIsMarkedAsHidden 42 | } else { 43 | return false 44 | } 45 | } 46 | } 47 | 48 | 49 | /** Prototype..er, type. Represents a prototype directory on disk with reference to the main javascript file. Derived from Protorope.Prototype. */ 50 | struct Prototype { 51 | let mainFileURL: NSURL 52 | let readmeURL: NSURL? 53 | let previewImageURL: NSURL? 54 | let name: String 55 | } 56 | 57 | 58 | extension Prototype { 59 | init?(directoryURL: NSURL, name: String) { 60 | 61 | if !directoryURL.fileURL { return nil } 62 | 63 | let path = directoryURL.filePathURL!.path! 64 | 65 | var isDirectory: ObjCBool = ObjCBool(false) 66 | let exists = NSFileManager.defaultManager().fileExistsAtPath(path, isDirectory: &isDirectory) 67 | if !exists { 68 | print("File does not exist: \(path)") 69 | return nil 70 | } 71 | 72 | var mainScriptPath: String 73 | 74 | if isDirectory.boolValue { 75 | do { 76 | let contents = try NSFileManager.defaultManager().contentsOfDirectoryAtPath(path) as [String]? 77 | 78 | let javaScriptFiles = contents!.filter { ($0 as NSString).pathExtension == "js" } 79 | switch javaScriptFiles.count { 80 | case 0: 81 | print("No JavaScript files found in \(path)") 82 | return nil 83 | case 1: 84 | mainScriptPath = (path as NSString).stringByAppendingPathComponent(javaScriptFiles.first!) 85 | default: 86 | print("Multiple JavaScript files found in \(path): \(javaScriptFiles)") 87 | return nil 88 | } 89 | 90 | let readmeFiles = contents!.filter { $0.lowercaseString.hasPrefix("readme.md") } 91 | switch readmeFiles.count { 92 | case 0: 93 | readmeURL = nil 94 | case 1: 95 | readmeURL = NSURL(fileURLWithPath: (path as NSString).stringByAppendingPathComponent(readmeFiles[0])) 96 | default: 97 | print("Multiple README files found in \(path): \(readmeFiles)") 98 | return nil 99 | } 100 | 101 | let previewFiles = contents!.filter { 102 | let normalizedName = $0.lowercaseString 103 | return normalizedName.hasPrefix("preview") && 104 | ["png", "gif", "jpg"].contains((normalizedName as NSString).pathExtension) 105 | } 106 | switch previewFiles.count { 107 | case 0: 108 | previewImageURL = nil 109 | case 1: 110 | previewImageURL = NSURL(fileURLWithPath: (path as NSString).stringByAppendingPathComponent(previewFiles[0])) 111 | default: 112 | print("Multiple preview images found in \(path): \(previewFiles)") 113 | return nil 114 | } 115 | } catch { 116 | print("Couldn't read directory \(path): \(error)") 117 | return nil 118 | } 119 | } else { 120 | readmeURL = nil 121 | previewImageURL = nil 122 | mainScriptPath = path 123 | } 124 | 125 | self.name = name 126 | self.mainFileURL = NSURL(fileURLWithPath: mainScriptPath) 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /Early Math Prototype Player.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/Early Math Prototype Player.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Early Math Prototype Player/Instructions.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 32 | 41 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Early Math Prototype Player/PrototypeListCollectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrototypeListCollectionViewController.swift 3 | // Protomath 4 | // 5 | // Created by Jason Brennan on 2015-06-22. 6 | // Copyright (c) 2015 Khan Academy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | /** Shows a list of Prototypes loaded from the application's bundle and lets you tap to play. */ 13 | class PrototypeListCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { 14 | 15 | private let prototypeProvider = PrototypeProvider() 16 | private let layout: UICollectionViewFlowLayout = { 17 | let layout = UICollectionViewFlowLayout() 18 | layout.minimumInteritemSpacing = 0 19 | layout.minimumLineSpacing = 0 20 | return layout 21 | }() 22 | 23 | init() { 24 | super.init(collectionViewLayout: layout) 25 | } 26 | 27 | required init?(coder aDecoder: NSCoder) { 28 | fatalError("init(coder:) has intentionally not been implemented") 29 | } 30 | 31 | override func viewDidLoad() { 32 | super.viewDidLoad() 33 | collectionView!.registerClass(PrototypePreviewCell.self, forCellWithReuseIdentifier: PrototypePreviewCell.reuseIdentifier) 34 | collectionView!.backgroundColor = UIColor.whiteColor() 35 | navigationItem.title = "Prototypes" 36 | } 37 | 38 | override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 39 | return prototypeProvider.prototypes.count 40 | } 41 | 42 | override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 43 | return 1 44 | } 45 | 46 | override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 47 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PrototypePreviewCell.reuseIdentifier, forIndexPath: indexPath) as! PrototypePreviewCell 48 | cell.prototype = self.prototypeProvider.prototypes[indexPath.item] 49 | return cell 50 | } 51 | 52 | override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 53 | let prototype = self.prototypeProvider.prototypes[indexPath.item] 54 | 55 | if prototype.readmeURL != nil { 56 | navigationController?.pushViewController(ReadmeViewController(prototype: prototype), animated: true) 57 | } else { 58 | navigationController?.pushViewController(PlayerViewController(path: prototype.mainFileURL), animated: true) 59 | } 60 | } 61 | 62 | override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 63 | layout.invalidateLayout() 64 | } 65 | 66 | func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 67 | let width = collectionView.bounds.size.width / round(collectionView.bounds.size.width / PrototypePreviewCell.desiredSize.width) 68 | let height = width * PrototypePreviewCell.desiredSize.height / PrototypePreviewCell.desiredSize.width 69 | return CGSize(width: floor(width), height: floor(height)) 70 | } 71 | 72 | } 73 | 74 | 75 | private class PrototypePreviewCell: UICollectionViewCell { 76 | static let desiredSize = CGSize(width: 256, height: 192) 77 | static let labelPadding: CGFloat = 15 78 | 79 | var prototype: Prototype? { 80 | didSet { 81 | imageView.backgroundColor = prototype?.colorRepresentation 82 | 83 | if let previewImageURL = prototype?.previewImageURL { 84 | precondition(previewImageURL.fileURL) 85 | if previewImageURL.pathExtension! == "gif" { 86 | // ultra lazy async lol 87 | dispatch_async(dispatch_get_global_queue(0, 0)) { 88 | let gifData = NSData(contentsOfURL: previewImageURL) 89 | let image = FLAnimatedImage(animatedGIFData: gifData) 90 | dispatch_async(dispatch_get_main_queue()) { 91 | if self.prototype?.previewImageURL == .Some(previewImageURL) { 92 | self.imageView.animatedImage = image 93 | } 94 | } 95 | } 96 | } else { 97 | imageView.image = UIImage(contentsOfFile: previewImageURL.path!) 98 | } 99 | } else { 100 | imageView.image = nil 101 | imageView.animatedImage = nil 102 | } 103 | 104 | label.text = prototype?.name 105 | setNeedsLayout() 106 | } 107 | } 108 | 109 | let imageView: FLAnimatedImageView = { 110 | let imageView = FLAnimatedImageView() 111 | imageView.contentMode = .ScaleAspectFill 112 | return imageView 113 | }() 114 | 115 | let label: UILabel = { 116 | let label = UILabel() 117 | label.numberOfLines = 2 118 | return label 119 | }() 120 | 121 | let labelBar: UIVisualEffectView 122 | let labelVibrancyContainer: UIVisualEffectView 123 | 124 | override init(frame: CGRect) { 125 | let blurEffect = UIBlurEffect(style: .Dark) 126 | labelBar = UIVisualEffectView(effect: blurEffect) 127 | labelVibrancyContainer = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect)) 128 | 129 | super.init(frame: frame) 130 | 131 | contentView.addSubview(imageView) 132 | 133 | contentView.addSubview(labelBar) 134 | 135 | labelBar.contentView.addSubview(labelVibrancyContainer) 136 | labelVibrancyContainer.contentView.addSubview(label) 137 | 138 | } 139 | 140 | private override func layoutSubviews() { 141 | super.layoutSubviews() 142 | 143 | imageView.frame = contentView.bounds 144 | 145 | let labelSizeThatFits = label.sizeThatFits(CGSize(width: contentView.bounds.size.width, height: CGFloat.max)) 146 | let labelHeight = labelSizeThatFits.height + 2 * PrototypePreviewCell.labelPadding 147 | 148 | labelBar.frame = CGRect( 149 | x: 0, 150 | y: contentView.bounds.size.height - labelHeight, 151 | width: contentView.bounds.size.width, 152 | height: labelHeight 153 | ) 154 | labelVibrancyContainer.frame = labelBar.bounds 155 | label.frame = CGRectInset(labelVibrancyContainer.bounds, PrototypePreviewCell.labelPadding, 0) 156 | } 157 | 158 | required init?(coder aDecoder: NSCoder) { 159 | fatalError("init(coder:) has intentionally not been implemented") 160 | } 161 | } 162 | 163 | extension UICollectionViewCell { 164 | /** Provides a default reuse identifier for cells. */ 165 | class var reuseIdentifier: String { return NSStringFromClass(self.self) } 166 | } 167 | 168 | extension Prototype { 169 | private var colorRepresentation: UIColor { 170 | let hue = CGFloat(name.hash % Int(Int16.max)) / CGFloat(Int16.max) 171 | return UIColor(hue: hue, saturation: 0.8, brightness: 0.96, alpha: 1) 172 | } 173 | } -------------------------------------------------------------------------------- /Early Math Prototype Player.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 962558FC1B39AF1A005E4360 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962558FB1B39AF1A005E4360 /* AppDelegate.swift */; }; 11 | 962559031B39AF1A005E4360 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 962559021B39AF1A005E4360 /* Images.xcassets */; }; 12 | 9625591C1B39AF72005E4360 /* PrototypeListCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9625591B1B39AF72005E4360 /* PrototypeListCollectionViewController.swift */; }; 13 | 9625591E1B39AF80005E4360 /* PlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9625591D1B39AF80005E4360 /* PlayerViewController.swift */; }; 14 | 962559211B39AFA6005E4360 /* PrototypeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962559201B39AFA6005E4360 /* PrototypeProvider.swift */; }; 15 | 962559231B39AFB9005E4360 /* Early-Math-Prototypes in Resources */ = {isa = PBXBuildFile; fileRef = 962559221B39AFB9005E4360 /* Early-Math-Prototypes */; }; 16 | 96DBF37F1B3AF25A003E0D46 /* Prototope.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96DBF36E1B3AF243003E0D46 /* Prototope.framework */; }; 17 | 96DBF3801B3AF25A003E0D46 /* Prototope.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 96DBF36E1B3AF243003E0D46 /* Prototope.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 96DBF3831B3AF25A003E0D46 /* PrototopeJSBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96DBF3741B3AF243003E0D46 /* PrototopeJSBridge.framework */; }; 19 | 96DBF3841B3AF25A003E0D46 /* PrototopeJSBridge.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 96DBF3741B3AF243003E0D46 /* PrototopeJSBridge.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | 96DBF3901B3AFE68003E0D46 /* protoscope-bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = 96DBF38F1B3AFE68003E0D46 /* protoscope-bundle.js */; }; 21 | EB3CBCF61B3B2ADE0038AE64 /* ReadmeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3CBCF51B3B2ADE0038AE64 /* ReadmeViewController.swift */; }; 22 | EB7841D21B3BB121008E5160 /* libMMMarkdown-iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB7841C61B3BB114008E5160 /* libMMMarkdown-iOS.a */; }; 23 | EB9530441B47080800E4E5C8 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9530411B47080800E4E5C8 /* FLAnimatedImage.m */; }; 24 | EB9530451B47080800E4E5C8 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9530431B47080800E4E5C8 /* FLAnimatedImageView.m */; }; 25 | EB9530F31B498A4D00E4E5C8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB9530F21B498A4D00E4E5C8 /* LaunchScreen.storyboard */; }; 26 | EB95312B1B49D88700E4E5C8 /* finger_demo.m4v in Resources */ = {isa = PBXBuildFile; fileRef = EB95312A1B49D88700E4E5C8 /* finger_demo.m4v */; }; 27 | EB95313B1B49D8DB00E4E5C8 /* InstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB95313A1B49D8DB00E4E5C8 /* InstructionsViewController.swift */; }; 28 | EBB48F5D1B4AFDB500850DA5 /* Instructions.xib in Resources */ = {isa = PBXBuildFile; fileRef = EB9531371B49D8C300E4E5C8 /* Instructions.xib */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 96DBF36D1B3AF243003E0D46 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 35 | proxyType = 2; 36 | remoteGlobalIDString = EBE3A75619DF79C400A77736; 37 | remoteInfo = Prototope; 38 | }; 39 | 96DBF36F1B3AF243003E0D46 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 42 | proxyType = 2; 43 | remoteGlobalIDString = EB306C0919DF77CC00113FA3; 44 | remoteInfo = PrototopeTestApp; 45 | }; 46 | 96DBF3711B3AF243003E0D46 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 49 | proxyType = 2; 50 | remoteGlobalIDString = EB1C2A6C19E4D19B000DC2C1; 51 | remoteInfo = PrototopeTests; 52 | }; 53 | 96DBF3731B3AF243003E0D46 /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 56 | proxyType = 2; 57 | remoteGlobalIDString = EB453D8F1A7AB0B2006F2A72; 58 | remoteInfo = PrototopeJSBridge; 59 | }; 60 | 96DBF3751B3AF243003E0D46 /* PBXContainerItemProxy */ = { 61 | isa = PBXContainerItemProxy; 62 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 63 | proxyType = 2; 64 | remoteGlobalIDString = EB453D991A7AB0B2006F2A72; 65 | remoteInfo = PrototopeJSBridgeTests; 66 | }; 67 | 96DBF3771B3AF243003E0D46 /* PBXContainerItemProxy */ = { 68 | isa = PBXContainerItemProxy; 69 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 70 | proxyType = 2; 71 | remoteGlobalIDString = EB6BFB801A857326002B4E6A; 72 | remoteInfo = Protocaster; 73 | }; 74 | 96DBF3791B3AF243003E0D46 /* PBXContainerItemProxy */ = { 75 | isa = PBXContainerItemProxy; 76 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 77 | proxyType = 2; 78 | remoteGlobalIDString = EB6BFB911A857326002B4E6A; 79 | remoteInfo = ProtocasterTests; 80 | }; 81 | 96DBF37B1B3AF243003E0D46 /* PBXContainerItemProxy */ = { 82 | isa = PBXContainerItemProxy; 83 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 84 | proxyType = 2; 85 | remoteGlobalIDString = EB6BFBB51A857920002B4E6A; 86 | remoteInfo = Protoscope; 87 | }; 88 | 96DBF37D1B3AF243003E0D46 /* PBXContainerItemProxy */ = { 89 | isa = PBXContainerItemProxy; 90 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 91 | proxyType = 2; 92 | remoteGlobalIDString = EB6BFBC91A857921002B4E6A; 93 | remoteInfo = ProtoscopeTests; 94 | }; 95 | 96DBF3811B3AF25A003E0D46 /* PBXContainerItemProxy */ = { 96 | isa = PBXContainerItemProxy; 97 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 98 | proxyType = 1; 99 | remoteGlobalIDString = EBE3A75519DF79C400A77736; 100 | remoteInfo = Prototope; 101 | }; 102 | 96DBF3851B3AF25A003E0D46 /* PBXContainerItemProxy */ = { 103 | isa = PBXContainerItemProxy; 104 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 105 | proxyType = 1; 106 | remoteGlobalIDString = EB453D8E1A7AB0B2006F2A72; 107 | remoteInfo = PrototopeJSBridge; 108 | }; 109 | EB7841C31B3BB114008E5160 /* PBXContainerItemProxy */ = { 110 | isa = PBXContainerItemProxy; 111 | containerPortal = EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */; 112 | proxyType = 2; 113 | remoteGlobalIDString = BE813DD614F893EB00EC9469; 114 | remoteInfo = "MMMarkdown-Mac"; 115 | }; 116 | EB7841C51B3BB114008E5160 /* PBXContainerItemProxy */ = { 117 | isa = PBXContainerItemProxy; 118 | containerPortal = EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */; 119 | proxyType = 2; 120 | remoteGlobalIDString = BE813E0E14F8961D00EC9469; 121 | remoteInfo = "MMMarkdown-iOS"; 122 | }; 123 | EB7841C71B3BB114008E5160 /* PBXContainerItemProxy */ = { 124 | isa = PBXContainerItemProxy; 125 | containerPortal = EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */; 126 | proxyType = 2; 127 | remoteGlobalIDString = BE813DEA14F893EB00EC9469; 128 | remoteInfo = MMMarkdownTests; 129 | }; 130 | EB7841C91B3BB114008E5160 /* PBXContainerItemProxy */ = { 131 | isa = PBXContainerItemProxy; 132 | containerPortal = EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */; 133 | proxyType = 2; 134 | remoteGlobalIDString = BE813E1314F92B6100EC9469; 135 | remoteInfo = mmmarkdown; 136 | }; 137 | EBAAD2B21D19C36300BB2C0A /* PBXContainerItemProxy */ = { 138 | isa = PBXContainerItemProxy; 139 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 140 | proxyType = 2; 141 | remoteGlobalIDString = 96A192331B531B3200D73B07; 142 | remoteInfo = PrototopeOSX; 143 | }; 144 | EBAAD2B41D19C36300BB2C0A /* PBXContainerItemProxy */ = { 145 | isa = PBXContainerItemProxy; 146 | containerPortal = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 147 | proxyType = 2; 148 | remoteGlobalIDString = 96A1923D1B531B3300D73B07; 149 | remoteInfo = PrototopeOSXTests; 150 | }; 151 | /* End PBXContainerItemProxy section */ 152 | 153 | /* Begin PBXCopyFilesBuildPhase section */ 154 | 96DBF3871B3AF25A003E0D46 /* Embed Frameworks */ = { 155 | isa = PBXCopyFilesBuildPhase; 156 | buildActionMask = 2147483647; 157 | dstPath = ""; 158 | dstSubfolderSpec = 10; 159 | files = ( 160 | 96DBF3801B3AF25A003E0D46 /* Prototope.framework in Embed Frameworks */, 161 | 96DBF3841B3AF25A003E0D46 /* PrototopeJSBridge.framework in Embed Frameworks */, 162 | ); 163 | name = "Embed Frameworks"; 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXCopyFilesBuildPhase section */ 167 | 168 | /* Begin PBXFileReference section */ 169 | 962558F61B39AF1A005E4360 /* Early Math.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Early Math.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 170 | 962558FA1B39AF1A005E4360 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 171 | 962558FB1B39AF1A005E4360 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 172 | 962559021B39AF1A005E4360 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 173 | 9625591B1B39AF72005E4360 /* PrototypeListCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrototypeListCollectionViewController.swift; sourceTree = ""; }; 174 | 9625591D1B39AF80005E4360 /* PlayerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerViewController.swift; sourceTree = ""; }; 175 | 962559201B39AFA6005E4360 /* PrototypeProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrototypeProvider.swift; sourceTree = ""; }; 176 | 962559221B39AFB9005E4360 /* Early-Math-Prototypes */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Early-Math-Prototypes"; sourceTree = ""; }; 177 | 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Prototope.xcodeproj; path = Prototope/Prototope.xcodeproj; sourceTree = SOURCE_ROOT; }; 178 | 96DBF38F1B3AFE68003E0D46 /* protoscope-bundle.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "protoscope-bundle.js"; sourceTree = ""; }; 179 | EB3CBCF51B3B2ADE0038AE64 /* ReadmeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeViewController.swift; sourceTree = ""; }; 180 | EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MMMarkdown.xcodeproj; path = ThirdParty/MMMarkdown/MMMarkdown.xcodeproj; sourceTree = SOURCE_ROOT; }; 181 | EB7841D31B3BB13D008E5160 /* Early Math Prototype Player-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Early Math Prototype Player-Bridging-Header.h"; sourceTree = ""; }; 182 | EB9530401B47080800E4E5C8 /* FLAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLAnimatedImage.h; path = ThirdParty/FLAnimatedImage/FLAnimatedImageDemo/FLAnimatedImage/FLAnimatedImage.h; sourceTree = SOURCE_ROOT; }; 183 | EB9530411B47080800E4E5C8 /* FLAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLAnimatedImage.m; path = ThirdParty/FLAnimatedImage/FLAnimatedImageDemo/FLAnimatedImage/FLAnimatedImage.m; sourceTree = SOURCE_ROOT; }; 184 | EB9530421B47080800E4E5C8 /* FLAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FLAnimatedImageView.h; path = ThirdParty/FLAnimatedImage/FLAnimatedImageDemo/FLAnimatedImage/FLAnimatedImageView.h; sourceTree = SOURCE_ROOT; }; 185 | EB9530431B47080800E4E5C8 /* FLAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLAnimatedImageView.m; path = ThirdParty/FLAnimatedImage/FLAnimatedImageDemo/FLAnimatedImage/FLAnimatedImageView.m; sourceTree = SOURCE_ROOT; }; 186 | EB9530F21B498A4D00E4E5C8 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 187 | EB95312A1B49D88700E4E5C8 /* finger_demo.m4v */ = {isa = PBXFileReference; lastKnownFileType = file; path = finger_demo.m4v; sourceTree = ""; }; 188 | EB9531371B49D8C300E4E5C8 /* Instructions.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Instructions.xib; sourceTree = ""; }; 189 | EB95313A1B49D8DB00E4E5C8 /* InstructionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstructionsViewController.swift; sourceTree = ""; }; 190 | /* End PBXFileReference section */ 191 | 192 | /* Begin PBXFrameworksBuildPhase section */ 193 | 962558F31B39AF1A005E4360 /* Frameworks */ = { 194 | isa = PBXFrameworksBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | EB7841D21B3BB121008E5160 /* libMMMarkdown-iOS.a in Frameworks */, 198 | 96DBF37F1B3AF25A003E0D46 /* Prototope.framework in Frameworks */, 199 | 96DBF3831B3AF25A003E0D46 /* PrototopeJSBridge.framework in Frameworks */, 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXFrameworksBuildPhase section */ 204 | 205 | /* Begin PBXGroup section */ 206 | 962558ED1B39AF1A005E4360 = { 207 | isa = PBXGroup; 208 | children = ( 209 | 962558F81B39AF1A005E4360 /* Early Math Prototype Player */, 210 | 962558F71B39AF1A005E4360 /* Products */, 211 | ); 212 | sourceTree = ""; 213 | }; 214 | 962558F71B39AF1A005E4360 /* Products */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 962558F61B39AF1A005E4360 /* Early Math.app */, 218 | ); 219 | name = Products; 220 | sourceTree = ""; 221 | }; 222 | 962558F81B39AF1A005E4360 /* Early Math Prototype Player */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 9625591F1B39AF96005E4360 /* Model */, 226 | 962558FB1B39AF1A005E4360 /* AppDelegate.swift */, 227 | 9625591B1B39AF72005E4360 /* PrototypeListCollectionViewController.swift */, 228 | EB3CBCF51B3B2ADE0038AE64 /* ReadmeViewController.swift */, 229 | 9625591D1B39AF80005E4360 /* PlayerViewController.swift */, 230 | EB9531391B49D8CD00E4E5C8 /* Instructions UI */, 231 | EB9530F21B498A4D00E4E5C8 /* LaunchScreen.storyboard */, 232 | 962559021B39AF1A005E4360 /* Images.xcassets */, 233 | 962558F91B39AF1A005E4360 /* Supporting Files */, 234 | ); 235 | path = "Early Math Prototype Player"; 236 | sourceTree = ""; 237 | }; 238 | 962558F91B39AF1A005E4360 /* Supporting Files */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | EB7841D31B3BB13D008E5160 /* Early Math Prototype Player-Bridging-Header.h */, 242 | EB9530341B4707D900E4E5C8 /* Third Party */, 243 | 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */, 244 | 962559221B39AFB9005E4360 /* Early-Math-Prototypes */, 245 | 962558FA1B39AF1A005E4360 /* Info.plist */, 246 | 96DBF38F1B3AFE68003E0D46 /* protoscope-bundle.js */, 247 | ); 248 | name = "Supporting Files"; 249 | sourceTree = ""; 250 | }; 251 | 9625591F1B39AF96005E4360 /* Model */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 962559201B39AFA6005E4360 /* PrototypeProvider.swift */, 255 | ); 256 | name = Model; 257 | sourceTree = ""; 258 | }; 259 | 96DBF35E1B3AF243003E0D46 /* Products */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | 96DBF36E1B3AF243003E0D46 /* Prototope.framework */, 263 | 96DBF3701B3AF243003E0D46 /* PrototopeTestApp.app */, 264 | 96DBF3721B3AF243003E0D46 /* PrototopeTests.xctest */, 265 | 96DBF3741B3AF243003E0D46 /* PrototopeJSBridge.framework */, 266 | 96DBF3761B3AF243003E0D46 /* PrototopeJSBridgeTests.xctest */, 267 | 96DBF3781B3AF243003E0D46 /* Protocaster.app */, 268 | 96DBF37A1B3AF243003E0D46 /* ProtocasterTests.xctest */, 269 | 96DBF37C1B3AF243003E0D46 /* Protoscope.app */, 270 | 96DBF37E1B3AF243003E0D46 /* ProtoscopeTests.xctest */, 271 | EBAAD2B31D19C36300BB2C0A /* PrototopeOSX.framework */, 272 | EBAAD2B51D19C36300BB2C0A /* PrototopeOSXTests.xctest */, 273 | ); 274 | name = Products; 275 | sourceTree = ""; 276 | }; 277 | EB7841BD1B3BB114008E5160 /* Products */ = { 278 | isa = PBXGroup; 279 | children = ( 280 | EB7841C41B3BB114008E5160 /* libMMMarkdown-Mac.a */, 281 | EB7841C61B3BB114008E5160 /* libMMMarkdown-iOS.a */, 282 | EB7841C81B3BB114008E5160 /* MMMarkdownTests.xctest */, 283 | EB7841CA1B3BB114008E5160 /* mmmarkdown */, 284 | ); 285 | name = Products; 286 | sourceTree = ""; 287 | }; 288 | EB9530341B4707D900E4E5C8 /* Third Party */ = { 289 | isa = PBXGroup; 290 | children = ( 291 | EB9530461B47080C00E4E5C8 /* FLAnimatedImageView */, 292 | EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */, 293 | ); 294 | name = "Third Party"; 295 | sourceTree = ""; 296 | }; 297 | EB9530461B47080C00E4E5C8 /* FLAnimatedImageView */ = { 298 | isa = PBXGroup; 299 | children = ( 300 | EB9530401B47080800E4E5C8 /* FLAnimatedImage.h */, 301 | EB9530411B47080800E4E5C8 /* FLAnimatedImage.m */, 302 | EB9530421B47080800E4E5C8 /* FLAnimatedImageView.h */, 303 | EB9530431B47080800E4E5C8 /* FLAnimatedImageView.m */, 304 | ); 305 | name = FLAnimatedImageView; 306 | sourceTree = ""; 307 | }; 308 | EB9531391B49D8CD00E4E5C8 /* Instructions UI */ = { 309 | isa = PBXGroup; 310 | children = ( 311 | EB95313A1B49D8DB00E4E5C8 /* InstructionsViewController.swift */, 312 | EB9531371B49D8C300E4E5C8 /* Instructions.xib */, 313 | EB95312A1B49D88700E4E5C8 /* finger_demo.m4v */, 314 | ); 315 | name = "Instructions UI"; 316 | sourceTree = ""; 317 | }; 318 | /* End PBXGroup section */ 319 | 320 | /* Begin PBXNativeTarget section */ 321 | 962558F51B39AF1A005E4360 /* Early Math Prototype Player */ = { 322 | isa = PBXNativeTarget; 323 | buildConfigurationList = 962559151B39AF1A005E4360 /* Build configuration list for PBXNativeTarget "Early Math Prototype Player" */; 324 | buildPhases = ( 325 | 962558F21B39AF1A005E4360 /* Sources */, 326 | 962558F31B39AF1A005E4360 /* Frameworks */, 327 | 962558F41B39AF1A005E4360 /* Resources */, 328 | 96DBF3871B3AF25A003E0D46 /* Embed Frameworks */, 329 | ); 330 | buildRules = ( 331 | ); 332 | dependencies = ( 333 | 96DBF3821B3AF25A003E0D46 /* PBXTargetDependency */, 334 | 96DBF3861B3AF25A003E0D46 /* PBXTargetDependency */, 335 | ); 336 | name = "Early Math Prototype Player"; 337 | productName = "Early Math Prototype Player"; 338 | productReference = 962558F61B39AF1A005E4360 /* Early Math.app */; 339 | productType = "com.apple.product-type.application"; 340 | }; 341 | /* End PBXNativeTarget section */ 342 | 343 | /* Begin PBXProject section */ 344 | 962558EE1B39AF1A005E4360 /* Project object */ = { 345 | isa = PBXProject; 346 | attributes = { 347 | LastSwiftMigration = 0730; 348 | LastSwiftUpdateCheck = 0700; 349 | LastUpgradeCheck = 0630; 350 | ORGANIZATIONNAME = "Khan Academy"; 351 | TargetAttributes = { 352 | 962558F51B39AF1A005E4360 = { 353 | CreatedOnToolsVersion = 6.3.1; 354 | }; 355 | }; 356 | }; 357 | buildConfigurationList = 962558F11B39AF1A005E4360 /* Build configuration list for PBXProject "Early Math Prototype Player" */; 358 | compatibilityVersion = "Xcode 3.2"; 359 | developmentRegion = English; 360 | hasScannedForEncodings = 0; 361 | knownRegions = ( 362 | en, 363 | Base, 364 | ); 365 | mainGroup = 962558ED1B39AF1A005E4360; 366 | productRefGroup = 962558F71B39AF1A005E4360 /* Products */; 367 | projectDirPath = ""; 368 | projectReferences = ( 369 | { 370 | ProductGroup = EB7841BD1B3BB114008E5160 /* Products */; 371 | ProjectRef = EB7841BC1B3BB114008E5160 /* MMMarkdown.xcodeproj */; 372 | }, 373 | { 374 | ProductGroup = 96DBF35E1B3AF243003E0D46 /* Products */; 375 | ProjectRef = 96DBF35D1B3AF243003E0D46 /* Prototope.xcodeproj */; 376 | }, 377 | ); 378 | projectRoot = ""; 379 | targets = ( 380 | 962558F51B39AF1A005E4360 /* Early Math Prototype Player */, 381 | ); 382 | }; 383 | /* End PBXProject section */ 384 | 385 | /* Begin PBXReferenceProxy section */ 386 | 96DBF36E1B3AF243003E0D46 /* Prototope.framework */ = { 387 | isa = PBXReferenceProxy; 388 | fileType = wrapper.framework; 389 | path = Prototope.framework; 390 | remoteRef = 96DBF36D1B3AF243003E0D46 /* PBXContainerItemProxy */; 391 | sourceTree = BUILT_PRODUCTS_DIR; 392 | }; 393 | 96DBF3701B3AF243003E0D46 /* PrototopeTestApp.app */ = { 394 | isa = PBXReferenceProxy; 395 | fileType = wrapper.application; 396 | path = PrototopeTestApp.app; 397 | remoteRef = 96DBF36F1B3AF243003E0D46 /* PBXContainerItemProxy */; 398 | sourceTree = BUILT_PRODUCTS_DIR; 399 | }; 400 | 96DBF3721B3AF243003E0D46 /* PrototopeTests.xctest */ = { 401 | isa = PBXReferenceProxy; 402 | fileType = wrapper.cfbundle; 403 | path = PrototopeTests.xctest; 404 | remoteRef = 96DBF3711B3AF243003E0D46 /* PBXContainerItemProxy */; 405 | sourceTree = BUILT_PRODUCTS_DIR; 406 | }; 407 | 96DBF3741B3AF243003E0D46 /* PrototopeJSBridge.framework */ = { 408 | isa = PBXReferenceProxy; 409 | fileType = wrapper.framework; 410 | path = PrototopeJSBridge.framework; 411 | remoteRef = 96DBF3731B3AF243003E0D46 /* PBXContainerItemProxy */; 412 | sourceTree = BUILT_PRODUCTS_DIR; 413 | }; 414 | 96DBF3761B3AF243003E0D46 /* PrototopeJSBridgeTests.xctest */ = { 415 | isa = PBXReferenceProxy; 416 | fileType = wrapper.cfbundle; 417 | path = PrototopeJSBridgeTests.xctest; 418 | remoteRef = 96DBF3751B3AF243003E0D46 /* PBXContainerItemProxy */; 419 | sourceTree = BUILT_PRODUCTS_DIR; 420 | }; 421 | 96DBF3781B3AF243003E0D46 /* Protocaster.app */ = { 422 | isa = PBXReferenceProxy; 423 | fileType = wrapper.application; 424 | path = Protocaster.app; 425 | remoteRef = 96DBF3771B3AF243003E0D46 /* PBXContainerItemProxy */; 426 | sourceTree = BUILT_PRODUCTS_DIR; 427 | }; 428 | 96DBF37A1B3AF243003E0D46 /* ProtocasterTests.xctest */ = { 429 | isa = PBXReferenceProxy; 430 | fileType = wrapper.cfbundle; 431 | path = ProtocasterTests.xctest; 432 | remoteRef = 96DBF3791B3AF243003E0D46 /* PBXContainerItemProxy */; 433 | sourceTree = BUILT_PRODUCTS_DIR; 434 | }; 435 | 96DBF37C1B3AF243003E0D46 /* Protoscope.app */ = { 436 | isa = PBXReferenceProxy; 437 | fileType = wrapper.application; 438 | path = Protoscope.app; 439 | remoteRef = 96DBF37B1B3AF243003E0D46 /* PBXContainerItemProxy */; 440 | sourceTree = BUILT_PRODUCTS_DIR; 441 | }; 442 | 96DBF37E1B3AF243003E0D46 /* ProtoscopeTests.xctest */ = { 443 | isa = PBXReferenceProxy; 444 | fileType = wrapper.cfbundle; 445 | path = ProtoscopeTests.xctest; 446 | remoteRef = 96DBF37D1B3AF243003E0D46 /* PBXContainerItemProxy */; 447 | sourceTree = BUILT_PRODUCTS_DIR; 448 | }; 449 | EB7841C41B3BB114008E5160 /* libMMMarkdown-Mac.a */ = { 450 | isa = PBXReferenceProxy; 451 | fileType = archive.ar; 452 | path = "libMMMarkdown-Mac.a"; 453 | remoteRef = EB7841C31B3BB114008E5160 /* PBXContainerItemProxy */; 454 | sourceTree = BUILT_PRODUCTS_DIR; 455 | }; 456 | EB7841C61B3BB114008E5160 /* libMMMarkdown-iOS.a */ = { 457 | isa = PBXReferenceProxy; 458 | fileType = archive.ar; 459 | path = "libMMMarkdown-iOS.a"; 460 | remoteRef = EB7841C51B3BB114008E5160 /* PBXContainerItemProxy */; 461 | sourceTree = BUILT_PRODUCTS_DIR; 462 | }; 463 | EB7841C81B3BB114008E5160 /* MMMarkdownTests.xctest */ = { 464 | isa = PBXReferenceProxy; 465 | fileType = wrapper.cfbundle; 466 | path = MMMarkdownTests.xctest; 467 | remoteRef = EB7841C71B3BB114008E5160 /* PBXContainerItemProxy */; 468 | sourceTree = BUILT_PRODUCTS_DIR; 469 | }; 470 | EB7841CA1B3BB114008E5160 /* mmmarkdown */ = { 471 | isa = PBXReferenceProxy; 472 | fileType = "compiled.mach-o.executable"; 473 | path = mmmarkdown; 474 | remoteRef = EB7841C91B3BB114008E5160 /* PBXContainerItemProxy */; 475 | sourceTree = BUILT_PRODUCTS_DIR; 476 | }; 477 | EBAAD2B31D19C36300BB2C0A /* PrototopeOSX.framework */ = { 478 | isa = PBXReferenceProxy; 479 | fileType = wrapper.framework; 480 | path = PrototopeOSX.framework; 481 | remoteRef = EBAAD2B21D19C36300BB2C0A /* PBXContainerItemProxy */; 482 | sourceTree = BUILT_PRODUCTS_DIR; 483 | }; 484 | EBAAD2B51D19C36300BB2C0A /* PrototopeOSXTests.xctest */ = { 485 | isa = PBXReferenceProxy; 486 | fileType = wrapper.cfbundle; 487 | path = PrototopeOSXTests.xctest; 488 | remoteRef = EBAAD2B41D19C36300BB2C0A /* PBXContainerItemProxy */; 489 | sourceTree = BUILT_PRODUCTS_DIR; 490 | }; 491 | /* End PBXReferenceProxy section */ 492 | 493 | /* Begin PBXResourcesBuildPhase section */ 494 | 962558F41B39AF1A005E4360 /* Resources */ = { 495 | isa = PBXResourcesBuildPhase; 496 | buildActionMask = 2147483647; 497 | files = ( 498 | 96DBF3901B3AFE68003E0D46 /* protoscope-bundle.js in Resources */, 499 | EB95312B1B49D88700E4E5C8 /* finger_demo.m4v in Resources */, 500 | EB9530F31B498A4D00E4E5C8 /* LaunchScreen.storyboard in Resources */, 501 | 962559231B39AFB9005E4360 /* Early-Math-Prototypes in Resources */, 502 | EBB48F5D1B4AFDB500850DA5 /* Instructions.xib in Resources */, 503 | 962559031B39AF1A005E4360 /* Images.xcassets in Resources */, 504 | ); 505 | runOnlyForDeploymentPostprocessing = 0; 506 | }; 507 | /* End PBXResourcesBuildPhase section */ 508 | 509 | /* Begin PBXSourcesBuildPhase section */ 510 | 962558F21B39AF1A005E4360 /* Sources */ = { 511 | isa = PBXSourcesBuildPhase; 512 | buildActionMask = 2147483647; 513 | files = ( 514 | EB9530451B47080800E4E5C8 /* FLAnimatedImageView.m in Sources */, 515 | 9625591C1B39AF72005E4360 /* PrototypeListCollectionViewController.swift in Sources */, 516 | 962558FC1B39AF1A005E4360 /* AppDelegate.swift in Sources */, 517 | EB9530441B47080800E4E5C8 /* FLAnimatedImage.m in Sources */, 518 | 9625591E1B39AF80005E4360 /* PlayerViewController.swift in Sources */, 519 | 962559211B39AFA6005E4360 /* PrototypeProvider.swift in Sources */, 520 | EB95313B1B49D8DB00E4E5C8 /* InstructionsViewController.swift in Sources */, 521 | EB3CBCF61B3B2ADE0038AE64 /* ReadmeViewController.swift in Sources */, 522 | ); 523 | runOnlyForDeploymentPostprocessing = 0; 524 | }; 525 | /* End PBXSourcesBuildPhase section */ 526 | 527 | /* Begin PBXTargetDependency section */ 528 | 96DBF3821B3AF25A003E0D46 /* PBXTargetDependency */ = { 529 | isa = PBXTargetDependency; 530 | name = Prototope; 531 | targetProxy = 96DBF3811B3AF25A003E0D46 /* PBXContainerItemProxy */; 532 | }; 533 | 96DBF3861B3AF25A003E0D46 /* PBXTargetDependency */ = { 534 | isa = PBXTargetDependency; 535 | name = PrototopeJSBridge; 536 | targetProxy = 96DBF3851B3AF25A003E0D46 /* PBXContainerItemProxy */; 537 | }; 538 | /* End PBXTargetDependency section */ 539 | 540 | /* Begin XCBuildConfiguration section */ 541 | 962559131B39AF1A005E4360 /* Debug */ = { 542 | isa = XCBuildConfiguration; 543 | buildSettings = { 544 | ALWAYS_SEARCH_USER_PATHS = NO; 545 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 546 | CLANG_CXX_LIBRARY = "libc++"; 547 | CLANG_ENABLE_MODULES = YES; 548 | CLANG_ENABLE_OBJC_ARC = YES; 549 | CLANG_WARN_BOOL_CONVERSION = YES; 550 | CLANG_WARN_CONSTANT_CONVERSION = YES; 551 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 552 | CLANG_WARN_EMPTY_BODY = YES; 553 | CLANG_WARN_ENUM_CONVERSION = YES; 554 | CLANG_WARN_INT_CONVERSION = YES; 555 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 556 | CLANG_WARN_UNREACHABLE_CODE = YES; 557 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 558 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 559 | COPY_PHASE_STRIP = NO; 560 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 561 | ENABLE_STRICT_OBJC_MSGSEND = YES; 562 | GCC_C_LANGUAGE_STANDARD = gnu99; 563 | GCC_DYNAMIC_NO_PIC = NO; 564 | GCC_NO_COMMON_BLOCKS = YES; 565 | GCC_OPTIMIZATION_LEVEL = 0; 566 | GCC_PREPROCESSOR_DEFINITIONS = ( 567 | "DEBUG=1", 568 | "$(inherited)", 569 | ); 570 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 571 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 572 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 573 | GCC_WARN_UNDECLARED_SELECTOR = YES; 574 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 575 | GCC_WARN_UNUSED_FUNCTION = YES; 576 | GCC_WARN_UNUSED_VARIABLE = YES; 577 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 578 | MTL_ENABLE_DEBUG_INFO = YES; 579 | ONLY_ACTIVE_ARCH = YES; 580 | SDKROOT = iphoneos; 581 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 582 | TARGETED_DEVICE_FAMILY = 2; 583 | }; 584 | name = Debug; 585 | }; 586 | 962559141B39AF1A005E4360 /* Release */ = { 587 | isa = XCBuildConfiguration; 588 | buildSettings = { 589 | ALWAYS_SEARCH_USER_PATHS = NO; 590 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 591 | CLANG_CXX_LIBRARY = "libc++"; 592 | CLANG_ENABLE_MODULES = YES; 593 | CLANG_ENABLE_OBJC_ARC = YES; 594 | CLANG_WARN_BOOL_CONVERSION = YES; 595 | CLANG_WARN_CONSTANT_CONVERSION = YES; 596 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 597 | CLANG_WARN_EMPTY_BODY = YES; 598 | CLANG_WARN_ENUM_CONVERSION = YES; 599 | CLANG_WARN_INT_CONVERSION = YES; 600 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 601 | CLANG_WARN_UNREACHABLE_CODE = YES; 602 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 603 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 604 | COPY_PHASE_STRIP = NO; 605 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 606 | ENABLE_NS_ASSERTIONS = NO; 607 | ENABLE_STRICT_OBJC_MSGSEND = YES; 608 | GCC_C_LANGUAGE_STANDARD = gnu99; 609 | GCC_NO_COMMON_BLOCKS = YES; 610 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 611 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 612 | GCC_WARN_UNDECLARED_SELECTOR = YES; 613 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 614 | GCC_WARN_UNUSED_FUNCTION = YES; 615 | GCC_WARN_UNUSED_VARIABLE = YES; 616 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 617 | MTL_ENABLE_DEBUG_INFO = NO; 618 | SDKROOT = iphoneos; 619 | TARGETED_DEVICE_FAMILY = 2; 620 | VALIDATE_PRODUCT = YES; 621 | }; 622 | name = Release; 623 | }; 624 | 962559161B39AF1A005E4360 /* Debug */ = { 625 | isa = XCBuildConfiguration; 626 | buildSettings = { 627 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 628 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 629 | CLANG_ENABLE_MODULES = YES; 630 | FRAMEWORK_SEARCH_PATHS = ( 631 | "$(inherited)", 632 | "$(PROJECT_DIR)/Prototope/ThirdParty/pop/build/Debug-iphoneos", 633 | ); 634 | HEADER_SEARCH_PATHS = ( 635 | "$(inherited)", 636 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 637 | "$(SRCROOT)/prototope/Prototope", 638 | "$(SRCROOT)/prototope/ThirdParty/**", 639 | "$(CONFIGURATION_BUILD_DIR)/MMMarkdown-iOS/public/", 640 | ); 641 | INFOPLIST_FILE = "Early Math Prototype Player/Info.plist"; 642 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 643 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 644 | LIBRARY_SEARCH_PATHS = "$(SRCROOT)/prototope/ThirdParty/**"; 645 | PRODUCT_NAME = "Early Math"; 646 | SWIFT_OBJC_BRIDGING_HEADER = "Early Math Prototype Player/Early Math Prototype Player-Bridging-Header.h"; 647 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 648 | TARGETED_DEVICE_FAMILY = 2; 649 | USER_HEADER_SEARCH_PATHS = ""; 650 | }; 651 | name = Debug; 652 | }; 653 | 962559171B39AF1A005E4360 /* Release */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 657 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 658 | CLANG_ENABLE_MODULES = YES; 659 | FRAMEWORK_SEARCH_PATHS = ( 660 | "$(inherited)", 661 | "$(PROJECT_DIR)/Prototope/ThirdParty/pop/build/Debug-iphoneos", 662 | ); 663 | HEADER_SEARCH_PATHS = ( 664 | "$(inherited)", 665 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 666 | "$(SRCROOT)/prototope/Prototope", 667 | "$(SRCROOT)/prototope/ThirdParty/**", 668 | "$(CONFIGURATION_BUILD_DIR)/MMMarkdown-iOS/public/", 669 | ); 670 | INFOPLIST_FILE = "Early Math Prototype Player/Info.plist"; 671 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 672 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 673 | LIBRARY_SEARCH_PATHS = "$(SRCROOT)/prototope/ThirdParty/**"; 674 | PRODUCT_NAME = "Early Math"; 675 | SWIFT_OBJC_BRIDGING_HEADER = "Early Math Prototype Player/Early Math Prototype Player-Bridging-Header.h"; 676 | TARGETED_DEVICE_FAMILY = 2; 677 | USER_HEADER_SEARCH_PATHS = ""; 678 | }; 679 | name = Release; 680 | }; 681 | /* End XCBuildConfiguration section */ 682 | 683 | /* Begin XCConfigurationList section */ 684 | 962558F11B39AF1A005E4360 /* Build configuration list for PBXProject "Early Math Prototype Player" */ = { 685 | isa = XCConfigurationList; 686 | buildConfigurations = ( 687 | 962559131B39AF1A005E4360 /* Debug */, 688 | 962559141B39AF1A005E4360 /* Release */, 689 | ); 690 | defaultConfigurationIsVisible = 0; 691 | defaultConfigurationName = Release; 692 | }; 693 | 962559151B39AF1A005E4360 /* Build configuration list for PBXNativeTarget "Early Math Prototype Player" */ = { 694 | isa = XCConfigurationList; 695 | buildConfigurations = ( 696 | 962559161B39AF1A005E4360 /* Debug */, 697 | 962559171B39AF1A005E4360 /* Release */, 698 | ); 699 | defaultConfigurationIsVisible = 0; 700 | defaultConfigurationName = Release; 701 | }; 702 | /* End XCConfigurationList section */ 703 | }; 704 | rootObject = 962558EE1B39AF1A005E4360 /* Project object */; 705 | } 706 | --------------------------------------------------------------------------------