[
  {
    "path": ".gitignore",
    "content": "# OS X\n.DS_Store\n\n# Xcode\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\nprofile\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n\n# Bundler\n.bundle\nDemo/Pods/\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n# \n# Note: if you ignore the Pods directory, make sure to uncomment\n# `pod install` in .travis.yml\n#\nDemo/Pods/\n"
  },
  {
    "path": ".travis.yml",
    "content": "# references:\n# * http://www.objc.io/issue-6/travis-ci.html\n# * https://github.com/supermarin/xcpretty#usage\nosx_image: xcode7\nlanguage: objective-c\ncache: cocoapods\npodfile: Demo/Podfile\nbefore_install:\n- gem install cocoapods # Since Travis is not always on latest version\n- pod install --project-directory=Demo\ninstall:\n- gem install xcpretty --no-rdoc --no-ri --no-document --quiet\nscript:\n- set -o pipefail && xcodebuild test -workspace Demo/Demo.xcworkspace -scheme EasyIOS-Swift -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c\n- pod lib lint --quick\nnotifications:\n  webhooks: https://hooks.pubu.im/services/21x4lqp4vepnfbn\n"
  },
  {
    "path": "Demo/Demo/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {\n        \n        \n        CODE_KEY = \"code\"//错误码\n        MSG_KEY = \"msg\" //网络请求的msg信息\n    \n        \n        LIVE_LOAD_PATH = NSURL(fileURLWithPath: __FILE__).URLByDeletingLastPathComponent!.path!+\"/xml.bundle\"   //xml文件的路径（项目路径）\n        CRTPTO_KEY = \"easyios\"  //这是自定义的密钥\n        \n        URLManager.loadConfigFromPlist(NSBundle.mainBundle().pathForResource(\"url\", ofType: \"plist\"))  // 初始化URLManager\n        \n        let firstVc = MainScene()\n        let nav = EZNavigationController(rootViewController: firstVc)\n        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)\n        self.window!.rootViewController = nav\n        self.window!.backgroundColor = UIColor.whiteColor()\n        self.window!.makeKeyAndVisible()\n        \n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(application: UIApplication) {\n        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.\n    }\n\n    func applicationDidEnterBackground(application: UIApplication) {\n        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n    }\n\n    func applicationWillEnterForeground(application: UIApplication) {\n        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.\n    }\n\n    func applicationDidBecomeActive(application: UIApplication) {\n        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n    }\n\n    func applicationWillTerminate(application: UIApplication) {\n        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n    }\n\n\n}\n\n"
  },
  {
    "path": "Demo/Demo/Base.lproj/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"6214\" systemVersion=\"14A314h\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"6207\"/>\n        <capability name=\"Constraints with non-1.0 multipliers\" minToolsVersion=\"5.1\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"  Copyright (c) 2015年 zhuchao. All rights reserved.\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ie-xW-0ye\">\n                    <rect key=\"frame\" x=\"20\" y=\"439\" width=\"441\" height=\"21\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n                <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Demo\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kId-c2-rCX\">\n                    <rect key=\"frame\" x=\"20\" y=\"140\" width=\"441\" height=\"43\"/>\n                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                    <color key=\"textColor\" cocoaTouchSystemColor=\"darkTextColor\"/>\n                    <nil key=\"highlightedColor\"/>\n                </label>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"5cJ-9S-tgC\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"kId-c2-rCX\" secondAttribute=\"centerX\" id=\"Koa-jz-hwk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"bottom\" constant=\"20\" id=\"Kzo-t9-V3l\"/>\n                <constraint firstItem=\"8ie-xW-0ye\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"MfP-vx-nX0\"/>\n                <constraint firstAttribute=\"centerX\" secondItem=\"8ie-xW-0ye\" secondAttribute=\"centerX\" id=\"ZEH-qu-HZ9\"/>\n                <constraint firstItem=\"kId-c2-rCX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fvb-Df-36g\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"548\" y=\"455\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "Demo/Demo/CollectionCellViewModel.swift",
    "content": "//\n//  CollectionCellViewModel.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\nclass CollectionCellViewModel: EZViewModel {\n\n    var url:EZString?\n    var name:EZString?\n    init(url:String?,name:String?){\n        if url != nil {\n            self.url = EZString(url!)\n        }\n        if name != nil {\n            self.name = EZString(name!)\n        }\n    }\n}\n"
  },
  {
    "path": "Demo/Demo/CollectionScene.swift",
    "content": "//\n//  CollectionScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\nimport Bond\nimport SVProgressHUD\n\nclass CollectionScene: EUScene,UICollectionViewDelegate {\n\n    var sceneModel = CollectionSceneModel()\n    var collectionView:UICollectionView?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.showBarButton(.LEFT, title: \"返回\", fontColor: UIColor.greenColor())\n        self.sceneModel.req.requestNeedActive.value = true\n        \n        self.sceneModel.req.state.observe{\n            switch $0 {\n            case .Sending :\n                SVProgressHUD.show()\n            case .Success,.SuccessFromCache :\n                SVProgressHUD.dismiss()\n                self.collectionView?.pullToRefreshView?.stopAnimating()\n            case .Error :\n                SVProgressHUD.showErrorWithStatus(\"数据加载失败\")\n            default :\n                return\n            }\n        }\n        // Do any additional setup after loading the view.\n    }\n\n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n\n    \n    override func eu_collectionViewDidLoad(collectionView: UICollectionView?) {\n        self.collectionView = collectionView\n        collectionView?.delegate = self\n        \n        \n        define(\"handlePullRefresh\"){\n            self.sceneModel.req.requestNeedActive.value = true\n        }\n        \n        define(\"handleInfinite\"){\n            let delayTime = dispatch_time(DISPATCH_TIME_NOW,\n                Int64(3.0 * Double(NSEC_PER_SEC)))\n            dispatch_after(delayTime, dispatch_get_main_queue()) {\n                self.collectionView?.infiniteScrollingView?.stopAnimating()\n                self.collectionView?.infiniteScrollingView?.setEnded()\n            }\n        }\n        \n        self.sceneModel.viewModelList.lift().bindTo(collectionView!) { (indexPath, dataArray, collectionView) -> UICollectionViewCell in\n            collectionView.dequeueReusableCell(\"cell\",\n                forIndexPath: indexPath,\n                target: self,\n                bind: dataArray[indexPath.section][indexPath.row])\n        }\n    }\n\n    override func leftButtonTouch() {\n        URLNavigation.dismissCurrentAnimated(true)\n    }\n}\n"
  },
  {
    "path": "Demo/Demo/CollectionSceneModel.swift",
    "content": "//\n//  CollectionCellViewModel.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\nimport Bond\nimport ObjectMapper\n\nclass FeedModel :Mappable{\n    var url:String?\n    var name:String?\n    \n    required init?(_ map: Map){\n        \n    }\n\n    func mapping(map: Map) {\n        url    <- map[\"url\"]\n        name   <- map[\"name\"]\n    }\n}\n\nclass FeedList:Mappable {\n    var list:[FeedModel]?\n    \n    required init?(_ map: Map){\n        \n    }\n\n    func mapping(map: Map) {\n        list <- map[\"list\"]\n    }\n}\n\nclass CollectionSceneModel: EZSceneModel {\n    var req = FeedRequest()\n    var modelList:FeedList?\n    \n    var viewModelList =  ObservableArray<CollectionCellViewModel>([CollectionCellViewModel]())\n    override init (){\n        super.init()\n    \n        self.req.requestBlock = {\n            EZAction.SEND_IQ_CACHE(self.req)\n        }\n        self.req.state.observe{[unowned self] value in\n            switch value {\n            case .Success,.SuccessFromCache :\n                if let theData: AnyObject = self.req.output[\"data\"] {\n                    \n                    self.modelList = Mapper<FeedList>().map(theData)\n                    if let array = self.modelList?.list?.map({\n                        (model) -> CollectionCellViewModel in\n                        return CollectionCellViewModel(url: model.url, name: model.name)\n                    }) {\n                        self.viewModelList.removeAll()\n                        self.viewModelList.extend(array)\n                    }\n                }\n            default :\n                return\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Demo/Demo/EncodeLoginScene.swift",
    "content": "//\n//  EncodeLoginScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/26.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport EasyIOS\n\nclass EncodeLoginScene: EUScene {\n    \n    override func loadView() {\n        self.SUFFIX = \"crypto\"  //修改后缀为加密版本的\n        super.loadView()\n    }\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.showBarButton(.LEFT, title: \"返回\", fontColor: UIColor.greenColor())\n    }\n    \n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n    \n    override func leftButtonTouch() {\n        URLNavigation.dismissCurrentAnimated(true)\n    }\n    \n}\n\n"
  },
  {
    "path": "Demo/Demo/FeedRequest.swift",
    "content": "//\n//  FeedRequest.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/14.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\nclass FeedRequest: EZRequest {\n    \n    //如果不使用staticPath，可以设置如下参数，同OC版本的使用方法\n    \n//    var feedId:String?\n//    var type:String?\n    \n    override init() {\n        super.init()\n        self.staticPath = \"http://7tsz2s.com1.z0.glb.clouddn.com/feedlists.txt\"\n        \n    }\n}\n"
  },
  {
    "path": "Demo/Demo/FlexScene.swift",
    "content": "//\n//  FlexScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/10/14.\n//  Copyright © 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\nclass FlexScene: EZScene {\n    var container:FLEXBOXContainerView!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        container  = FLEXBOXContainerView(frame: self.view.bounds)\n        container.flexJustifyContent = FLEXBOXJustification.Center\n        container.flexAlignItems = FLEXBOXAlignment.Center\n        container.flexDirection = FLEXBOXFlexDirection.Column\n        container.backgroundColor = UIColor.grayColor()\n        \n        let v1 = UILabel()\n        v1.text = \"123123\"\n        v1.backgroundColor = UIColor.blueColor()\n        v1.textAlignment = NSTextAlignment.Center\n        v1.flexMargin = UIEdgeInsetsMake(8, 8, 8, 8)\n        v1.flexPadding = UIEdgeInsetsMake(10, 10, 10, 10)\n        v1.flex = 0\n        container.addSubview(v1)\n        \n        let v2 = UILabel()\n        v2.text = \"321\"\n        v2.backgroundColor = UIColor.blueColor()\n        v2.textAlignment = NSTextAlignment.Center\n        v2.flexMargin = UIEdgeInsetsMake(8, 8, 8, 8)\n        v2.flexPadding = UIEdgeInsetsMake(10, 10, 10, 10)\n        v2.flex = 0\n        container.addSubview(v2)\n        self.view.addSubview(container)\n    }\n}\n"
  },
  {
    "path": "Demo/Demo/FlexXmlScene.swift",
    "content": "//\n//  FlexXmlScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/10/14.\n//  Copyright © 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\nclass FlexXmlScene: EUScene {\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.title = \"FLEX BOX\"\n        // Do any additional setup after loading the view, typically from a nib.\n    }\n    \n}\n"
  },
  {
    "path": "Demo/Demo/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Demo/Demo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Demo/Demo/LabelScene.swift",
    "content": "//\n//  LabelScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/18.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport EasyIOS\nimport TTTAttributedLabel\n\nclass LabelScene: EUScene {\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.showBarButton(.LEFT, title: \"返回\", fontColor: UIColor.greenColor())\n        self.title = \"界面里只有1个Label\"\n        \n        \n        if let label = getElementById(\"labelId\") as? TTTAttributedLabel {\n            //do someting\n        }\n       \n        // Do any additional setup after loading the view, typically from a nib.\n    }\n    \n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n    \n    override func eu_viewWillLoad() {\n        self.attributedLabelDelegate = MainLabelDeleage()\n    }\n    \n    override func leftButtonTouch() {\n        URLNavigation.dismissCurrentAnimated(true)\n    }\n}\n\n"
  },
  {
    "path": "Demo/Demo/LoginScene.swift",
    "content": "//\n//  ViewController.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport EasyIOS\n\nclass LoginScene: EUScene {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.showBarButton(.LEFT, title: \"返回\", fontColor: UIColor.greenColor())\n        \n//        define(\"login\"){\n//            println(\"登陆回调\")\n//        }\n        \n        //在模拟器中调用下面这个方法可以生成一个加密文件\n//        EUI.encode(\"LoginScene\", suffix: \"xml\", toPath: \"/Users/zhuchao/Desktop/EncodeLoginScene.crypto\")\n        // Do any additional setup after loading the view, typically from a nib.\n    }\n\n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n    \n    override func leftButtonTouch() {\n        URLNavigation.dismissCurrentAnimated(true)\n    }\n}\n\n"
  },
  {
    "path": "Demo/Demo/MainLabelDeleage.swift",
    "content": "//\n//  MainLabelDeleage.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/17.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport EasyIOS\nimport TTTAttributedLabel\n\nclass MainLabelDeleage: TTTAttributedLabelDelegateHandle {\n    func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithURL url: NSURL!) {\n        URLManager.pushURL(url, animated: true)\n    }\n}"
  },
  {
    "path": "Demo/Demo/MainScene.swift",
    "content": "//\n//  MainScene.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nimport Bond\nimport EasyIOS\n\n\nclass MainScene: EUScene,UITableViewDelegate{\n    var sceneModel = MainSceneModel()\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        self.title = \"EasyIOS\"\n\n//        let label = UILabel()\n//        label.flexAlignItems = FLEXBOXAlignment.Center\n        \n        // Do any additional setup after loading the view.\n    }\n    \n    override func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n    \n    //do someThing init before loadTheView\n    override func eu_viewWillLoad() {\n        self.attributedLabelDelegate = MainLabelDeleage()\n    }\n    \n    override func eu_tableViewDidLoad(tableView:UITableView?){\n        \n        tableView?.delegate = self\n        \n        //定义一个可以给JS调用的下拉刷新回调方法handlePullRefresh()\n        define(\"handlePullRefresh\"){\n            let delayTime = dispatch_time(DISPATCH_TIME_NOW,\n                Int64(3.0 * Double(NSEC_PER_SEC)))\n            dispatch_after(delayTime, dispatch_get_main_queue()) {\n                tableView?.pullToRefreshView?.stopAnimating()\n            }\n        }\n        \n        ObservableArray([\n            self.sceneModel.dataArray,\n            self.sceneModel.dataArray,\n            self.sceneModel.dataArray])\n            .bindTo(tableView!) { (indexPath, dataArray, tableView) -> UITableViewCell in\n                let data = dataArray[indexPath.section][indexPath.row]\n                let cell = tableView.dequeueReusableCell(\"cell\", forIndexPath: indexPath, target: self, bind: data)\n                cell.selectionStyle = .None\n                return cell\n        }\n\n    }\n\n    //xml里已经有了tap点击事件，这里就不调用了\n//    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {\n//        var model = self.sceneModel.dataArray[indexPath.row]\n//        if let link = model.link {\n//            URLManager.pushURLString(link, animated: true)\n//        }\n//    }\n    \n\n    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {\n        return 23.0\n    }\n    \n    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {\n        tableView\n        return tableView.getSectionViewByTagId(\"bgView\", target: self,bind:sceneModel.sectionArray[section])\n    }\n    \n    \n}\n"
  },
  {
    "path": "Demo/Demo/MainSceneModel.swift",
    "content": "//\n//  MainSsceneModel.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport Bond\nimport EasyIOS\n\nclass MainCellViewModel: EZViewModel {\n    var title:String?\n    var subTitle:NSData?\n    var srcUrl:NSURL?\n    var link:String?\n    init(title:String,subTitle:String = \"\",srcUrl:String = \"\",link:String = \"\"){\n        self.title = title\n        if let data = subTitle.toData() {\n            self.subTitle = data\n        }\n        self.srcUrl = NSURL(string: srcUrl)\n        self.link = link\n    }\n}\n\n\nclass MainSectionViewModel: EZViewModel {\n    var title:String?\n    init(title:String){\n        self.title = title\n    }\n}\n\nclass MainSceneModel: EZSceneModel {\n    \n    var dataArray =  ObservableArray<MainCellViewModel>(Array<MainCellViewModel>())\n    var sectionArray = ObservableArray<MainSectionViewModel>(Array<MainSectionViewModel>())\n    override init (){\n        super.init()\n        \n        self.dataArray.append(MainCellViewModel(\n                title: \"一个简单的登陆页面\",\n                subTitle: \"UIScrollView的使用Demo\",\n                srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n                link:\"demo://login\"))\n        self.dataArray.append(MainCellViewModel(\n            title: \"还是登陆界面不过是加密版本\",\n            subTitle: \"UIScrollView的使用Demo\",\n            srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n            link:\"demo://encodelogin\"))\n        \n        self.dataArray.append(MainCellViewModel(\n                title: \"Collection+网络请求+下拉控件\",\n                subTitle: \"UICollectionView的使用Demo,包含了网络请求\",\n                srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n                link:\"demo://collection\"))\n        self.dataArray.append(MainCellViewModel(\n            title: \"HTML版的Label,采用TTTAttributeLabel\",\n            subTitle: \"<p>Hello <a href='demo://login'>World!</a></p>\",\n            srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n            link:\"demo://LabelScene\"))\n        self.dataArray.append(MainCellViewModel(\n            title: \"native版本的flex模型演示\",\n            subTitle: \"native版本的flex模型演示\",\n            srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n            link:\"demo://flex\"))\n        self.dataArray.append(MainCellViewModel(\n            title: \"xml版本的flex模型演示\",\n            subTitle: \"xml版本的flex模型演示\",\n            srcUrl: \"http://d.hiphotos.baidu.com/zhidao/pic/item/562c11dfa9ec8a13e028c4c0f603918fa0ecc0e4.jpg\",\n            link:\"demo://flexml\"))\n    \n        \n        self.sectionArray.append(MainSectionViewModel(\n            title: \"section 1\"))\n        self.sectionArray.append(MainSectionViewModel(\n            title: \"section 2\"))\n        self.sectionArray.append(MainSectionViewModel(\n            title: \"section 3\"))\n    }\n    \n}"
  },
  {
    "path": "Demo/Demo/url.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>demo</key>\n\t<dict>\n\t\t<key>demo://flexml</key>\n\t\t<string>FlexXmlScene</string>\n\t\t<key>demo://flex</key>\n\t\t<string>FlexScene</string>\n\t\t<key>demo://encodelogin</key>\n\t\t<string>EncodeLoginScene</string>\n\t\t<key>demo://collection</key>\n\t\t<string>CollectionScene</string>\n\t\t<key>demo://login</key>\n\t\t<string>LoginScene</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Demo/Demo/xml.bundle/CollectionScene.xml",
    "content": "<body>\n    <div id=\"collectionView\" align=\"0 0 0 0\" type=\"UICollectionView\" flow-layout=\"scroll-direction:Vertical;item-size:{300,50};section-inset:{3,3,0,3};minimum-interitem-spacing:3;minimum-line-spacing:3\" content-inset=\"{64,0,0,0}\" background-color=\"white\" pull-to-refresh=\"handlePullRefresh()\" infinite-scrolling=\"handleInfinite()\">\n        <div align=\"0 0 0 0\" type=\"cell\"  id=\"cell\"  background-color=\"red\">\n            <span align=\"10 10 -10 -10\" font=\"10 system\">{{name}}</span>\n        </div>\n    </div>\n</body>"
  },
  {
    "path": "Demo/Demo/xml.bundle/EncodeLoginScene.crypto",
    "content": "VTWWEpHde9NHKxqWASruTqqmlAB2w6yrgF3k4/6aH5xLCWW09IBo0wCd/XDQTXFG\nH/fTwKRPrtiF85H9augC+XEcQ2BavK7sIbi99qwL0TaJOnmMoEt8n65i/BpOuCXe\nU/uYXAQTOc8L43XQMRQ5o6bd0928uEK8tm/khgYB7ho2nc/LnSyk387N+7fVWasI\n7ygbDY1yzWsbLYXdBju9fKvku6rqyRFUTLR3Y0LyyhNaqcK3QWkPGf0C1SpEvZN5\nf/XX8+YL0sf/bMngbrOaNKQtZVQJfxJUSP4BUOHXql9Bca7o1hGERQ2JJRhBtfis\no/YWFO58QO16gHRrkqmXzHndkOknrBB0lalewwMathppGCUztFS3+D4c4Bxb8kzD\neBHwU/e5V/NWTKbje0EpX2aTLl1jHarGLqsybsEb2xACBoumJrdcATPdnXl/Ouou\nNiKoS2h8muGLO46oFyusalX+/1o7wIQDG3rwhwsMKpZvTatpaAhRJlvY5/yHUDUN\niLTu0JO73PctuRI8nTpx6D9+nlw2zo/OmsuvvxldLmv9FhAs5XvcJnrnMr4z6S8o\n4ohBH79i9UJfDaYxAaofMrI5szIYu3DG4qCM8NyNFQc7YoeKN1wQjat41Wenxx5B\nRrtMke5dKlE0ATstakRmdNa4zqzPFkhxtVPuK4gVn7n5EPUDaz/flC3VA4zxxD7k\nuo0FfD4uEREvM9UcKIXuaV+8Riu26ly2khMbPznGkKxTVeu2SWecu/HHQRPANz5S\nueyPZvELpAbiR7usH4IY37IUWz2vteVOYmwHPV+09E74YfRsoHtOEO8r4YAi+OyO\nZsXa2wn5+TSUFODny6k7y7XWpp4XIcQBDW+08lg+eLuXfoEUttw/JzqSgxxcs/F+\nR9tbVIW0MAVXThjVcaD3IHnvRYeZsdj3JUDpeGOv9WbIqcYz0Fgwkg7Lav4QOy+U\nSNPXnuCDw7OhsCfbifmxTCTuDPZ6HjGtFauiGEN83EpJzQGAYEktvyyEXhhS8LKk\neL/JRag25fR0VLQPCNk/5e2SP/dOI7ReR5y4l9NR5oFteKDuQytUrDiHm9f6Bn+T\nMMuK4jhQ3QpmuaT1Ps8jSW3hnK6zUXStFmOgRzmDTQnGqkzHybo9W9Ewj9nWINEO\nPIz/wPpVO4ok7PuxP+sLo6xdUCY6oZFhRCU4k03SQhyk6jari2PxHD4DuiyjcLLU\nIW+dFxscF5dhPi0TTdSZfrD6T53NsHeLDXBECmabKT+mugc2IsV+GG9N3rhwXhyO\n4mduo2v0XsNLaYAqJdZue6zcw/o40mWoPCpK37ZfSeaABEey5UUVlc+fJR6+ct20\nwRlvazYrOqWKW8C5I/ZXD/ei0v7hB+KB87Q40RBEJ27uDH8mITgWqg/pwMqBAs30\n7+5lrddB79wuRRHIbE907uad8seRXT8CA0QBpSER9aXfet5SK6YkhP6Ve/p7OIt5\nYm4ZhtR377+YV3dLh08xNlFJ4Fd8iE/NSvRFoVFUb0s5DPQaUL42Sd2hH3WFz3U4\nW2dMZ4Cnj89i56XNnA+Gwe+eaqrQmHpLVIeAfTlnmXjUWaOFHj6Xg91drLPPyFTH\n64olhQImSa6xGN3wVdDDUEN6Oz3D2YBI5gV7YQVQkMZyqV7fgjUwY7uDCStgvHDc\nb64/PrtWlDCqGN79ncTKomuHhUszIhnrRxspp4u5dPim2nd45/34LEvVMF7+exZ5\nRUXRKIlg4wXznUhmuAwjCuRgH88dk3UWbIfYFt52sOC1rTm5mMNcF15jRgvxZHua\n89/jcEJoTfelbMTqgoJoNQ7ZiOldxHyseqxjVHaZg/yVUgWaK+yl9n/8vXC+eGsn\nBm86QHd3JCwlaKoW8hvo2R7ntnLlyp6to+gzq//o3h/wzoQJehkubFyYug7cq1xd\n7pMf/OFSiTulbDK8NzGqU+JN1EHalRgoNLZMKsrHgwlW0CVDDq1TO2WLjrk+cZXB\njBbiQqW35gUK81vkqFm01BFUd/vWWG1X+cGfRgLPcMNYNHUdkYhR2MXE13o+yVUf\nchDkfRgiif68lYAoP74njGQcXwAugTB9bkQIYyQCuMIxaT1W+rgieCX4ieqaa+hw\nHmSd9D96UVPbhhISqZINkbmzoKsEA+iD4qqWl9/L7Kt9QESiTnRZvQW9Pi3hkEcU\nd79thZ8DwCkS/1KeFJonFxe59adBZyL5d6ttXDoTBNfGrfVNEntzkj/fmTWpNYpx\nLuDrc92OEylJs7Z0Utz3XX9dGU24qBCfQeEVoAK78eggtBwFxRgJmZ9f8acBI5tP\nezLDkl9eioV0hoSI1Pgfdgc38QzNJJIG98zh4mPeOmOB/aumVW1iT/cZpEPK09XH\nn7vAcQxhQL6ksZdKXSqEXcDQPgrUro19qqW6fwCZcNvuvZQOA9PKmg=="
  },
  {
    "path": "Demo/Demo/xml.bundle/FlexXmlScene.xml",
    "content": "<body>\n    <div align=\"0 0 0 0\">\n        <div align=\"64 0 * 0\" height=\"100\"\n            justify-content=\"center\"\n            flex-direction=\"row\"\n            align-items=\"flex-end\"\n            background-color=\"gray\"\n            id=\"first\"\n            >\n            <span\n                text-alignment=\"center\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                flex=\"3\"\n                background-color=\"blue\"\n                >3</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"2\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >2</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n        </div>\n        <div align=\"left:0;right:0\" margin=\"top:10 first\" height=\"200\"\n            justify-content=\"center\"\n            flex-direction=\"column\"\n            align-items=\"flex-end\"\n            background-color=\"gray\"\n            id=\"second\">\n            <span\n                text-alignment=\"center\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                flex=\"3\"\n                background-color=\"blue\"\n                >3</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"2\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >2</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n        </div>\n        <div align=\"left:0;right:0\" margin=\"top:10 second\" height=\"100\"\n            justify-content=\"center\"\n            flex-direction=\"row\"\n            align-items=\"center\"\n            background-color=\"gray\"\n            id=\"third\"\n            >\n            <span\n                text-alignment=\"center\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                flex=\"1\"\n                background-color=\"blue\"\n                >1</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n            <span\n                text-alignment=\"center\"\n                flex=\"1\"\n                flex-padding=\"{10,10,10,10}\"\n                flex-margin=\"{8,8,8,8}\"\n                background-color=\"blue\"\n                >1</span>\n        </div>\n        \n    </div>\n\n</body>"
  },
  {
    "path": "Demo/Demo/xml.bundle/LabelHtml.xml",
    "content": "<h1>\n    <a id=\"user-content-easyios-for-swift\" class=\"anchor\" href=\"#easyios-for-swift\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>EasyIOS For Swift</h1>\n<h2>\n    <a id=\"user-content-star-is-the-best-way-to-support-easyios-\" class=\"anchor\" href=\"#star-is-the-best-way-to-support-easyios-\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>Star is the Best Way to Support EasyIOS !</h2>\n\n<ul>\n    <li><a href=\"http://www.iosx.me\">IOSX - EasyIOS Official Forum</a></li>\n    <li><a href=\"https://github.com/EasyIOS/EasyIOS\">EasyIOS-ObjC</a></li>\n</ul>\n\n<h2>\n    <a id=\"user-content-features\" class=\"anchor\" href=\"#features\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>Features</h2>\n\n<ul>\n    <li>MVVM : <code>Model-View-ViewModel</code> inspired by <a href=\"http://en.wikipedia.org/wiki/Functional_reactive_programming\">Functional Reactive Programming</a> </li>\n    <li>HTML To Native : Transform HTML&amp;CSS to Native Control,</li>\n    <li>Reflect Cocoa Touch : Reflect all the Cocoa Touch Api ,we can use the Cocoa Touch Api via HTML </li>\n    <li>AutoLayout : The HTML layout based on the <code>AutoLayout</code>\n    </li>\n    <li>Live Load : Edit the HTML and the view in smulator will update automaticly without rebuild your app</li>\n    <li>Cryptographic HTML : To make the HTML be safety,we provide the <code>AES Encryption</code> to encrypt the HTML</li>\n    <li>URLManager : Push or Present the Controller by the custom URL </li>\n    <li>Elegant PullToRefresh : Add  PullToRefresh or InfiniteScrolling by HTML</li>\n</ul>\n\n<h2>\n    <a id=\"user-content-usage\" class=\"anchor\" href=\"#usage\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>Usage</h2>\n\n<p>To run the example project, clone the repo, and run <code>pod install</code> from the Demo directory first.</p>\n\n<h2>\n    <a id=\"user-content-requirements\" class=\"anchor\" href=\"#requirements\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>Requirements</h2>\n\n<ul>\n    <li>Swift</li>\n    <li>IOS8</li>\n</ul>\n<h2>\n    <a id=\"user-content-author\" class=\"anchor\" href=\"#author\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>Author</h2>\n\n<p>zhuchao, <a href=\"mailto:zhuchao@iosx.me\">zhuchao@iosx.me</a></p>\n\n<h2>\n    <a id=\"user-content-license\" class=\"anchor\" href=\"#license\" aria-hidden=\"true\"><span class=\"octicon octicon-link\"></span></a>License</h2>\n\n<p>EasyIOS-Swift is available under the MIT license. See the LICENSE file for more info.</p>"
  },
  {
    "path": "Demo/Demo/xml.bundle/LabelScene.xml",
    "content": "<style>\n    <!--支持css 样式设置，html中利用@的方式进行调用-->\n    .contentAlign{\n        edge:0 0 0 0;\n        left:0 root;\n        right:0 root;\n    }\n</style>\n\n<body>\n    <div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n        <div align=\"@contentAlign\">\n            <!--span标签设置了style属性则启用富文本模式，span内部可以支持原生HTML的所有属性，具体请看LabelHtml.xml文件-->\n            <span align=\"64 0 0 0\" id=\"labelId\" style=\"color:#ACACAC;font-size:18px;\" link-style=\"color:green;\" number-of-lines=\"0\">\n                <!--导入XML模板文件-->\n                    @import(LabelHtml)\n            </span>\n        </div>\n    </div>\n</body>"
  },
  {
    "path": "Demo/Demo/xml.bundle/LoginScene.xml",
    "content": "<style>\n    .contentAlign{\n        edge:0 0 0 0;\n        left:0 root;\n        right:0 root;\n    }\n    .inputStyle{\n        font-size:15;color:#999999;\n    }\n</style>\n<body>\n    <div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n        <div align=\"@contentAlign\">\n            <img id=\"logo\" image=\"login-logo\" user-interaction-enabled=\"YES\" ontap=\"tap()\" align=\"center-x:0;top:110;\"/>\n            <div id=\"username\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:30 logo\" height=\"45\">\n                <input class=\"userTextField\" id=\"userTextField\" align=\"edge:10 10 -10 -10;\" placeholder-style=\"@inputStyle\" keyboard-type=\"EmailAddress\" style=\"@inputStyle\" placeholder=\"上面的logo可以被点击\"/>\n            </div>\n            <div id=\"password\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:13 username\" height=\"45\">\n                <input id=\"passwordTextField\" secure-text-entry=\"YES\" align=\"10 10 -10 -10\" placeholder=\"密码\" placeholder-style=\"@inputStyle\" style=\"@inputStyle\" />\n            </div>\n            <button id=\"submit\" style=\"color:white;font-size:20;\" background-color=\"#3FBCFB\" align=\"* 15 -10 -15\" margin=\"top:25 password\" height=\"45\" layer_corner-radius=\"8\" onEvent=\"touch-up-inside:login()\">Login</button>\n        </div>\n    </div>\n</body>\n\n<script>\n    function tap(){\n        um.present('demo://login',true);\n    };\n    \n    function login(){\n        var password = document.getElementById(\"passwordTextField\");\n        password.attrs({\n            placeholder:\"hello\",\n            secureTextEntry:\"NO\"\n        });\n\n<!--        var logo = document.getElementById(\"logo\")-->\n<!--        password.callWithObject(\"test:\",logo);-->\n\n        console.log(password.val(\"text\"));\n    }\n</script>"
  },
  {
    "path": "Demo/Demo/xml.bundle/MainScene.xml",
    "content": "<body>\n    <div id=\"tableview\" align=\"64 0 0 0\" content-inset=\"{0,0,0,0}\" type=\"UITableView\"  estimated-row-height=\"100\"  separator-style=\"None\" pull-to-refresh=\"handlePullRefresh()\" infinite-scrolling=\"handleInfinite() PullFooter\">\n        <div align=\"0 0 0 0\" type=\"cell\" id=\"cell\" ontap-bind=\"um.push('{{link}}',true)\" >\n            <img id=\"avatar\" align=\"10 10 -10 *\" clips-to-bounds=\"YES\" width=\"45\" height=\"45\" layer_corner-radius=\"5\" src=\"{{srcUrl}}\" />\n            <span align=\"top:2 avatar;right:-10\" margin=\"left:12 avatar\"  font=\"15 system\" id=\"title\">{{title}}</span>\n            <span align=\"bottom:0 avatar;right:-10\" margin=\"left:12 avatar\" font=\"13 system\" text-color=\"#ACACAC\" id=\"subTitle\" style=\"color:#ACACAC;\" link-style=\"color:green;\" >{{subTitle}}</span>\n        </div>\n        \n        <div type=\"section\" id=\"bgView\" background-color=\"#F2F1F6\" >\n            <span align=\"left:15;center-y:0\" font=\"14 system\">{{title}}</span>\n        </div>\n    </div>\n</body>"
  },
  {
    "path": "Demo/Demo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t5B3FCA9A1BCDF6AB00AF20CD /* FlexScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3FCA991BCDF6AB00AF20CD /* FlexScene.swift */; settings = {ASSET_TAGS = (); }; };\n\t\t5B4C52211BCE2E91003E0016 /* FlexXmlScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4C52201BCE2E91003E0016 /* FlexXmlScene.swift */; settings = {ASSET_TAGS = (); }; };\n\t\t5B4C52291BCE547A003E0016 /* Chinese.md in Sources */ = {isa = PBXBuildFile; fileRef = 5B4C52271BCE547A003E0016 /* Chinese.md */; settings = {ASSET_TAGS = (); }; };\n\t\t5B4C522A1BCE547A003E0016 /* flexbox.png in Resources */ = {isa = PBXBuildFile; fileRef = 5B4C52281BCE547A003E0016 /* flexbox.png */; settings = {ASSET_TAGS = (); }; };\n\t\t5B6512B11B141A9E00B1BA89 /* EncodeLoginScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6512B01B141A9E00B1BA89 /* EncodeLoginScene.swift */; };\n\t\t5B7B80C51B08D8E00059CAEF /* MainLabelDeleage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7B80C41B08D8E00059CAEF /* MainLabelDeleage.swift */; };\n\t\t5B7B80DB1B0A0B2A0059CAEF /* LabelScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7B80DA1B0A0B2A0059CAEF /* LabelScene.swift */; };\n\t\t5B8240C01B03715600D58574 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8240BF1B03715600D58574 /* AppDelegate.swift */; };\n\t\t5B8240C21B03715600D58574 /* LoginScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8240C11B03715600D58574 /* LoginScene.swift */; };\n\t\t5B8240C71B03715600D58574 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5B8240C61B03715600D58574 /* Images.xcassets */; };\n\t\t5B8240CA1B03715600D58574 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B8240C81B03715600D58574 /* LaunchScreen.xib */; };\n\t\t5B8240D61B03715600D58574 /* DemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8240D51B03715600D58574 /* DemoTests.swift */; };\n\t\t5B8240E91B0377FC00D58574 /* EasyIOS-Swift.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 5B8240E61B0377FC00D58574 /* EasyIOS-Swift.podspec */; };\n\t\t5B8240EA1B0377FC00D58574 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 5B8240E71B0377FC00D58574 /* LICENSE */; };\n\t\t5B8240EB1B0377FC00D58574 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 5B8240E81B0377FC00D58574 /* README.md */; };\n\t\t5B90B5CD1B04BFF8000C848D /* FeedRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B90B5CC1B04BFF8000C848D /* FeedRequest.swift */; };\n\t\t5BBC33DA1BB3DFE00030B054 /* xml.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5BBC33D91BB3DFE00030B054 /* xml.bundle */; settings = {ASSET_TAGS = (); }; };\n\t\t5BDBF0CE1B038B7300E95ACF /* login-logo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BDBF0CD1B038B7300E95ACF /* login-logo@2x.png */; };\n\t\t5BDBF0D01B038C1700E95ACF /* MainScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDBF0CF1B038C1700E95ACF /* MainScene.swift */; };\n\t\t5BDBF0D51B038C7800E95ACF /* MainSceneModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDBF0D41B038C7800E95ACF /* MainSceneModel.swift */; };\n\t\t5BDBF0D91B038F0D00E95ACF /* url.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5BDBF0D81B038F0D00E95ACF /* url.plist */; };\n\t\t5BDC06BB1B0394C200C486E0 /* CollectionScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC06BA1B0394C200C486E0 /* CollectionScene.swift */; };\n\t\t5BDC06BD1B03950500C486E0 /* CollectionSceneModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC06BC1B03950500C486E0 /* CollectionSceneModel.swift */; };\n\t\t5BDC06BF1B03955A00C486E0 /* CollectionCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC06BE1B03955A00C486E0 /* CollectionCellViewModel.swift */; };\n\t\t87D67298D115B9D5014DB706 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55CB89BDD03972BB5036E6DF /* Pods.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t5B8240D01B03715600D58574 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 5B8240B21B03715600D58574 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 5B8240B91B03715600D58574;\n\t\t\tremoteInfo = Demo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t0BAFEE4C5E077414790C2042 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = \"Pods/Target Support Files/Pods/Pods.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t55CB89BDD03972BB5036E6DF /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5B3FCA991BCDF6AB00AF20CD /* FlexScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexScene.swift; sourceTree = \"<group>\"; };\n\t\t5B4C52201BCE2E91003E0016 /* FlexXmlScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexXmlScene.swift; sourceTree = \"<group>\"; };\n\t\t5B4C52271BCE547A003E0016 /* Chinese.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Chinese.md; sourceTree = \"<group>\"; };\n\t\t5B4C52281BCE547A003E0016 /* flexbox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = flexbox.png; sourceTree = \"<group>\"; };\n\t\t5B6512B01B141A9E00B1BA89 /* EncodeLoginScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncodeLoginScene.swift; sourceTree = \"<group>\"; };\n\t\t5B7B80C41B08D8E00059CAEF /* MainLabelDeleage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainLabelDeleage.swift; sourceTree = \"<group>\"; };\n\t\t5B7B80DA1B0A0B2A0059CAEF /* LabelScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelScene.swift; sourceTree = \"<group>\"; };\n\t\t5B8240BA1B03715600D58574 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5B8240BE1B03715600D58574 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t5B8240BF1B03715600D58574 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t5B8240C11B03715600D58574 /* LoginScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScene.swift; sourceTree = \"<group>\"; };\n\t\t5B8240C61B03715600D58574 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\t5B8240C91B03715600D58574 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\t5B8240CF1B03715600D58574 /* DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t5B8240D41B03715600D58574 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t5B8240D51B03715600D58574 /* DemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoTests.swift; sourceTree = \"<group>\"; };\n\t\t5B8240E61B0377FC00D58574 /* EasyIOS-Swift.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = \"EasyIOS-Swift.podspec\"; path = \"../EasyIOS-Swift.podspec\"; sourceTree = \"<group>\"; };\n\t\t5B8240E71B0377FC00D58574 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = \"<group>\"; };\n\t\t5B8240E81B0377FC00D58574 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = \"<group>\"; };\n\t\t5B90B5CC1B04BFF8000C848D /* FeedRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedRequest.swift; sourceTree = \"<group>\"; };\n\t\t5BBC33D91BB3DFE00030B054 /* xml.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; path = xml.bundle; sourceTree = \"<group>\"; };\n\t\t5BDBF0CD1B038B7300E95ACF /* login-logo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"login-logo@2x.png\"; sourceTree = \"<group>\"; };\n\t\t5BDBF0CF1B038C1700E95ACF /* MainScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainScene.swift; sourceTree = \"<group>\"; };\n\t\t5BDBF0D41B038C7800E95ACF /* MainSceneModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainSceneModel.swift; sourceTree = \"<group>\"; };\n\t\t5BDBF0D81B038F0D00E95ACF /* url.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = url.plist; sourceTree = \"<group>\"; };\n\t\t5BDC06BA1B0394C200C486E0 /* CollectionScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionScene.swift; sourceTree = \"<group>\"; };\n\t\t5BDC06BC1B03950500C486E0 /* CollectionSceneModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionSceneModel.swift; sourceTree = \"<group>\"; };\n\t\t5BDC06BE1B03955A00C486E0 /* CollectionCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionCellViewModel.swift; sourceTree = \"<group>\"; };\n\t\t6FA5AECAF1463C83BB66DE59 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = \"Pods/Target Support Files/Pods/Pods.debug.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t5B8240B71B03715600D58574 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t87D67298D115B9D5014DB706 /* Pods.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5B8240CC1B03715600D58574 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t1729A45EA55A2C898A1E3A6F /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6FA5AECAF1463C83BB66DE59 /* Pods.debug.xcconfig */,\n\t\t\t\t0BAFEE4C5E077414790C2042 /* Pods.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B3FCA981BCDF68B00AF20CD /* FlexScene */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B3FCA991BCDF6AB00AF20CD /* FlexScene.swift */,\n\t\t\t\t5B4C52201BCE2E91003E0016 /* FlexXmlScene.swift */,\n\t\t\t);\n\t\t\tname = FlexScene;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B4C52261BCE547A003E0016 /* README */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B4C52271BCE547A003E0016 /* Chinese.md */,\n\t\t\t\t5B4C52281BCE547A003E0016 /* flexbox.png */,\n\t\t\t);\n\t\t\tname = README;\n\t\t\tpath = ../README;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B7B80D91B0A0B0F0059CAEF /* LabelScene */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B7B80DA1B0A0B2A0059CAEF /* LabelScene.swift */,\n\t\t\t);\n\t\t\tname = LabelScene;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240B11B03715600D58574 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240DF1B0372B500D58574 /* PodMeta */,\n\t\t\t\t5B8240BC1B03715600D58574 /* Demo */,\n\t\t\t\t5B8240D21B03715600D58574 /* DemoTests */,\n\t\t\t\t5B8240BB1B03715600D58574 /* Products */,\n\t\t\t\t1729A45EA55A2C898A1E3A6F /* Pods */,\n\t\t\t\t82578B0764B5D4425C7B4BC5 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240BB1B03715600D58574 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240BA1B03715600D58574 /* Demo.app */,\n\t\t\t\t5B8240CF1B03715600D58574 /* DemoTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240BC1B03715600D58574 /* Demo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B3FCA981BCDF68B00AF20CD /* FlexScene */,\n\t\t\t\t5B7B80D91B0A0B0F0059CAEF /* LabelScene */,\n\t\t\t\t5B90B5C11B043889000C848D /* LoginScene */,\n\t\t\t\t5BDC06B91B03949900C486E0 /* CollectionScene */,\n\t\t\t\t5BDBF0D31B038C6400E95ACF /* MainScene */,\n\t\t\t\t5BDBF0CC1B038B6800E95ACF /* Rescource */,\n\t\t\t\t5B8240BF1B03715600D58574 /* AppDelegate.swift */,\n\t\t\t\t5B8240C61B03715600D58574 /* Images.xcassets */,\n\t\t\t\t5B8240C81B03715600D58574 /* LaunchScreen.xib */,\n\t\t\t\t5B8240BD1B03715600D58574 /* Supporting Files */,\n\t\t\t\t5BBC33D91BB3DFE00030B054 /* xml.bundle */,\n\t\t\t);\n\t\t\tpath = Demo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240BD1B03715600D58574 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240BE1B03715600D58574 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240D21B03715600D58574 /* DemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240D51B03715600D58574 /* DemoTests.swift */,\n\t\t\t\t5B8240D31B03715600D58574 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = DemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240D31B03715600D58574 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240D41B03715600D58574 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B8240DF1B0372B500D58574 /* PodMeta */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B4C52261BCE547A003E0016 /* README */,\n\t\t\t\t5B8240E61B0377FC00D58574 /* EasyIOS-Swift.podspec */,\n\t\t\t\t5B8240E71B0377FC00D58574 /* LICENSE */,\n\t\t\t\t5B8240E81B0377FC00D58574 /* README.md */,\n\t\t\t);\n\t\t\tname = PodMeta;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5B90B5C11B043889000C848D /* LoginScene */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240C11B03715600D58574 /* LoginScene.swift */,\n\t\t\t\t5B6512B01B141A9E00B1BA89 /* EncodeLoginScene.swift */,\n\t\t\t);\n\t\t\tname = LoginScene;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5BDBF0CC1B038B6800E95ACF /* Rescource */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5BDBF0D81B038F0D00E95ACF /* url.plist */,\n\t\t\t\t5BDBF0CD1B038B7300E95ACF /* login-logo@2x.png */,\n\t\t\t);\n\t\t\tname = Rescource;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5BDBF0D31B038C6400E95ACF /* MainScene */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5BDBF0CF1B038C1700E95ACF /* MainScene.swift */,\n\t\t\t\t5BDBF0D41B038C7800E95ACF /* MainSceneModel.swift */,\n\t\t\t\t5B7B80C41B08D8E00059CAEF /* MainLabelDeleage.swift */,\n\t\t\t);\n\t\t\tname = MainScene;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5BDC06B91B03949900C486E0 /* CollectionScene */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5BDC06BA1B0394C200C486E0 /* CollectionScene.swift */,\n\t\t\t\t5BDC06BC1B03950500C486E0 /* CollectionSceneModel.swift */,\n\t\t\t\t5BDC06BE1B03955A00C486E0 /* CollectionCellViewModel.swift */,\n\t\t\t\t5B90B5CC1B04BFF8000C848D /* FeedRequest.swift */,\n\t\t\t);\n\t\t\tname = CollectionScene;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t82578B0764B5D4425C7B4BC5 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t55CB89BDD03972BB5036E6DF /* Pods.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t5B8240B91B03715600D58574 /* Demo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 5B8240D91B03715600D58574 /* Build configuration list for PBXNativeTarget \"Demo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t58FFA88B0BBAEE141CD3F935 /* Check Pods Manifest.lock */,\n\t\t\t\t5B8240B61B03715600D58574 /* Sources */,\n\t\t\t\t5B8240B71B03715600D58574 /* Frameworks */,\n\t\t\t\t5B8240B81B03715600D58574 /* Resources */,\n\t\t\t\tB9036220CE63B1B76499B1DF /* Embed Pods Frameworks */,\n\t\t\t\tB0EA13793EF213CED106EF77 /* Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Demo;\n\t\t\tproductName = Demo;\n\t\t\tproductReference = 5B8240BA1B03715600D58574 /* Demo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t5B8240CE1B03715600D58574 /* DemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 5B8240DC1B03715600D58574 /* Build configuration list for PBXNativeTarget \"DemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t5B8240CB1B03715600D58574 /* Sources */,\n\t\t\t\t5B8240CC1B03715600D58574 /* Frameworks */,\n\t\t\t\t5B8240CD1B03715600D58574 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t5B8240D11B03715600D58574 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = DemoTests;\n\t\t\tproductName = DemoTests;\n\t\t\tproductReference = 5B8240CF1B03715600D58574 /* DemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t5B8240B21B03715600D58574 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftMigration = 0700;\n\t\t\t\tLastSwiftUpdateCheck = 0700;\n\t\t\t\tLastUpgradeCheck = 0700;\n\t\t\t\tORGANIZATIONNAME = zhuchao;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t5B8240B91B03715600D58574 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3.1;\n\t\t\t\t\t};\n\t\t\t\t\t5B8240CE1B03715600D58574 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3.1;\n\t\t\t\t\t\tTestTargetID = 5B8240B91B03715600D58574;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 5B8240B51B03715600D58574 /* Build configuration list for PBXProject \"Demo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 5B8240B11B03715600D58574;\n\t\t\tproductRefGroup = 5B8240BB1B03715600D58574 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t5B8240B91B03715600D58574 /* Demo */,\n\t\t\t\t5B8240CE1B03715600D58574 /* DemoTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t5B8240B81B03715600D58574 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5BBC33DA1BB3DFE00030B054 /* xml.bundle in Resources */,\n\t\t\t\t5B8240CA1B03715600D58574 /* LaunchScreen.xib in Resources */,\n\t\t\t\t5B8240E91B0377FC00D58574 /* EasyIOS-Swift.podspec in Resources */,\n\t\t\t\t5BDBF0CE1B038B7300E95ACF /* login-logo@2x.png in Resources */,\n\t\t\t\t5B8240C71B03715600D58574 /* Images.xcassets in Resources */,\n\t\t\t\t5BDBF0D91B038F0D00E95ACF /* url.plist in Resources */,\n\t\t\t\t5B4C522A1BCE547A003E0016 /* flexbox.png in Resources */,\n\t\t\t\t5B8240EA1B0377FC00D58574 /* LICENSE in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5B8240CD1B03715600D58574 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t58FFA88B0BBAEE141CD3F935 /* Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_ROOT}/../Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [[ $? != 0 ]] ; then\\n    cat << EOM\\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\nEOM\\n    exit 1\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tB0EA13793EF213CED106EF77 /* Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tB9036220CE63B1B76499B1DF /* Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t5B8240B61B03715600D58574 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5BDC06BD1B03950500C486E0 /* CollectionSceneModel.swift in Sources */,\n\t\t\t\t5B90B5CD1B04BFF8000C848D /* FeedRequest.swift in Sources */,\n\t\t\t\t5B6512B11B141A9E00B1BA89 /* EncodeLoginScene.swift in Sources */,\n\t\t\t\t5B4C52291BCE547A003E0016 /* Chinese.md in Sources */,\n\t\t\t\t5B4C52211BCE2E91003E0016 /* FlexXmlScene.swift in Sources */,\n\t\t\t\t5BDBF0D51B038C7800E95ACF /* MainSceneModel.swift in Sources */,\n\t\t\t\t5BDC06BF1B03955A00C486E0 /* CollectionCellViewModel.swift in Sources */,\n\t\t\t\t5B3FCA9A1BCDF6AB00AF20CD /* FlexScene.swift in Sources */,\n\t\t\t\t5BDC06BB1B0394C200C486E0 /* CollectionScene.swift in Sources */,\n\t\t\t\t5B7B80DB1B0A0B2A0059CAEF /* LabelScene.swift in Sources */,\n\t\t\t\t5B8240EB1B0377FC00D58574 /* README.md in Sources */,\n\t\t\t\t5BDBF0D01B038C1700E95ACF /* MainScene.swift in Sources */,\n\t\t\t\t5B8240C21B03715600D58574 /* LoginScene.swift in Sources */,\n\t\t\t\t5B8240C01B03715600D58574 /* AppDelegate.swift in Sources */,\n\t\t\t\t5B7B80C51B08D8E00059CAEF /* MainLabelDeleage.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t5B8240CB1B03715600D58574 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5B8240D61B03715600D58574 /* DemoTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t5B8240D11B03715600D58574 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 5B8240B91B03715600D58574 /* Demo */;\n\t\t\ttargetProxy = 5B8240D01B03715600D58574 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t5B8240C81B03715600D58574 /* LaunchScreen.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t5B8240C91B03715600D58574 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t5B8240D71B03715600D58574 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5B8240D81B03715600D58574 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t5B8240DA1B03715600D58574 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 6FA5AECAF1463C83BB66DE59 /* Pods.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tINFOPLIST_FILE = Demo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"me.iosx.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_INSTALL_OBJC_HEADER = NO;\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5B8240DB1B03715600D58574 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 0BAFEE4C5E077414790C2042 /* Pods.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tINFOPLIST_FILE = Demo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"me.iosx.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_INSTALL_OBJC_HEADER = NO;\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t5B8240DD1B03715600D58574 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = DemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"me.iosx.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/Demo.app/Demo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t5B8240DE1B03715600D58574 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = DemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"me.iosx.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/Demo.app/Demo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t5B8240B51B03715600D58574 /* Build configuration list for PBXProject \"Demo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5B8240D71B03715600D58574 /* Debug */,\n\t\t\t\t5B8240D81B03715600D58574 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t5B8240D91B03715600D58574 /* Build configuration list for PBXNativeTarget \"Demo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5B8240DA1B03715600D58574 /* Debug */,\n\t\t\t\t5B8240DB1B03715600D58574 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t5B8240DC1B03715600D58574 /* Build configuration list for PBXNativeTarget \"DemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t5B8240DD1B03715600D58574 /* Debug */,\n\t\t\t\t5B8240DE1B03715600D58574 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 5B8240B21B03715600D58574 /* Project object */;\n}\n"
  },
  {
    "path": "Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Demo.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Demo/Demo.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Demo.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Demo/DemoTests/DemoTests.swift",
    "content": "//\n//  DemoTests.swift\n//  DemoTests\n//\n//  Created by zhuchao on 15/5/13.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport XCTest\n\nclass DemoTests: XCTestCase {\n    \n    override func setUp() {\n        super.setUp()\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    func testExample() {\n        // This is an example of a functional test case.\n        XCTAssert(true, \"Pass\")\n    }\n    \n    func testPerformanceExample() {\n        // This is an example of a performance test case.\n        self.measureBlock() {\n            // Put the code you want to measure the time of here.\n        }\n    }\n    \n}\n"
  },
  {
    "path": "Demo/DemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Demo/Podfile",
    "content": "platform :ios, '8.0'\nuse_frameworks!\npod \"EasyIOS-Swift\", :path => \"../\"\npod 'SVProgressHUD', '~> 1.1.3'"
  },
  {
    "path": "EasyIOS-Swift.podspec",
    "content": "#\n# Be sure to run `pod lib lint EasyIOS-Swift.podspec' to ensure this is a\n# valid spec and remove all comments before submitting the spec.\n#\n# Any lines starting with a # are optional, but encouraged\n#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html\n#\n\nPod::Spec.new do |s|\n  s.name             = \"EasyIOS-Swift\"\n  s.version          = \"2.0.1\"\n  s.summary          = \"The Swift version of EasyIOS\"\n  s.description      = <<-DESC\n                      EasyIOS is a new generation of development framework based on `Model-View-ViewModel`,`HTML To Native`,`Live Load`,`FlexBox`.\n                       DESC\n  s.homepage         = \"https://github.com/EasyIOS/EasyIOS-Swift\"\n  # s.screenshots     = \"www.example.com/screenshots_1\", \"www.example.com/screenshots_2\"\n  s.license          = 'MIT'\n  s.author           = { \"zhuchao\" => \"zhuchao@iosx.me\" }\n  s.source           = { :git => \"https://github.com/EasyIOS/EasyIOS-Swift.git\", :tag => s.version.to_s }\n  #s.source           = { :git => \"/Users/zhuchao/Documents/EasyIOS-Swift\"}\n  s.social_media_url = 'https://twitter.com/zhuchaowe'\n\n  s.platform     = :ios, '8.0'\n  s.requires_arc = true\n  s.module_name = \"EasyIOS\"\n  s.source_files = 'Pod/Classes/**/*'\n  s.resource_bundles = {'EasyIOS-Swift' => ['Pod/Assets/*.png']}\n    s.dependency 'HanekeSwift'\n    s.dependency 'Bond'\n    s.dependency 'Alamofire'\n    s.dependency 'SnapKit'\n    s.dependency 'Kingfisher'\n    s.dependency 'ObjectMapper'\n    s.dependency 'ReachabilitySwift'\n    s.dependency 'TTTAttributedLabel'\ns.public_header_files = 'Pod/Classes/Easy/**/*.h','Pod/Classes/Extend/**/*.h','Pod/Classes/Private/**/*.h'\ns.frameworks = 'UIKit','JavaScriptCore'\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015 zhuchao <zhuchao@iosx.me>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "Pod/Assets/.gitkeep",
    "content": ""
  },
  {
    "path": "Pod/Classes/.gitkeep",
    "content": ""
  },
  {
    "path": "Pod/Classes/Easy/Core/EZAction.swift",
    "content": "//\n//  Action.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/25.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Alamofire\nimport Haneke\nimport Bond\nimport ReachabilitySwift\n\npublic var HOST_URL = \"\" //服务端域名:端口\npublic var CODE_KEY = \"\" //错误码key,暂不支持路径 如 code\npublic var RIGHT_CODE = 0  //正确校验码\npublic var MSG_KEY = \"\" //消息提示msg,暂不支持路径 如 msg\n\n\nprivate var networkReachabilityHandle: UInt8 = 2;\n\npublic class EZAction: NSObject {\n    \n    //使用缓存策略 仅首次读取缓存\n    public class func SEND_IQ_CACHE (req:EZRequest) {\n        req.useCache = true\n        req.dataFromCache = req.isFirstRequest\n        self.Send(req)\n    }\n    \n    //使用缓存策略 优先从缓存读取\n    public class func SEND_CACHE (req:EZRequest) {\n        req.useCache = true\n        req.dataFromCache = true\n        self.Send(req)\n    }\n    \n    //不使用缓存策略\n    public class func SEND (req:EZRequest) {\n        req.useCache = false\n        req.dataFromCache = false\n        self.Send(req)\n    }\n    \n    \n    public class func Send (req :EZRequest){\n        var url = \"\"\n        var requestParams = Dictionary<String,AnyObject>()\n        \n        if !req.staticPath.characters.isEmpty {\n            url = req.staticPath\n        }else{\n            if req.scheme.characters.isEmpty {\n                req.scheme = \"http\"\n            }\n            if req.host.characters.isEmpty {\n                req.host = HOST_URL\n            }\n            url = req.scheme + \"://\" + req.host + req.path\n            if  req.appendPathInfo.characters.isEmpty {\n                requestParams = req.requestParams\n            }else{\n                url = url + req.appendPathInfo\n            }\n        }\n        req.state.value = RequestState.Sending\n        \n        req.op = req.manager\n            .request(req.method, url, parameters: requestParams, encoding: req.parameterEncoding)\n            .validate(statusCode: 200..<300)\n            .validate(contentType: req.acceptableContentTypes)\n            .responseJSON { response  in\n                 req.response = response\n                if response.result.isFailure{\n                    req.error = response.result.error\n                    self.failed(req)\n                }else{\n                    req.output = response.result.value as! Dictionary<String, AnyObject>\n                    self.checkCode(req)\n                }\n            }\n        req.url = req.op?.request!.URL\n        self.getCacheJson(req)\n    }\n    \n    public class func Upload (req :EZRequest){\n        req.state.value = RequestState.Sending\n        req.op = req.manager\n            .upload(.POST, req.uploadUrl, data: req.uploadData!)\n            .validate(statusCode: 200..<300)\n            .validate(contentType: req.acceptableContentTypes)\n            .progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in\n                req.totalBytesWritten = Double(totalBytesWritten)\n                req.totalBytesExpectedToWrite = Double(totalBytesExpectedToWrite)\n                req.progress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)\n            }.responseJSON { response in\n                req.response = response\n                if response.result.isFailure{\n                    req.error = response.result.error\n                    self.failed(req)\n                }else{\n                    req.output = response.result.value as! Dictionary<String, AnyObject>\n                    self.checkCode(req)\n                }\n            }\n        req.url = req.op?.request!.URL\n    }\n    \n    public class func Download (req :EZRequest){\n        req.state.value = RequestState.Sending\n        req.op = req.manager\n            .download(.GET, req.downloadUrl, destination: { (temporaryURL, response) in\n            let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory,\n                    inDomains: .UserDomainMask)[0]\n            return directoryURL.URLByAppendingPathComponent(req.targetPath + response.suggestedFilename!)\n        })\n            .validate(statusCode: 200..<300)\n            .progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead) in\n                req.totalBytesRead = Double(totalBytesRead)\n                req.totalBytesExpectedToRead = Double(totalBytesExpectedToRead)\n                req.progress = Double(totalBytesRead) / Double(totalBytesExpectedToRead)\n            }\n            .response { (request, response, _, error) in\n                if error != nil{\n                    req.error = error\n                    self.failed(req)\n                }else{\n                    req.state.value = RequestState.Success\n                }\n            }\n        req.url = req.op?.request!.URL\n    }\n    \n    private class func cacheJson (req: EZRequest) {\n        if req.useCache {\n            let cache = Shared.JSONCache\n            cache.set(value: .Dictionary(req.output), key: req.cacheKey, formatName: HanekeGlobals.Cache.OriginalFormatName){ JSON in\n                EZPrintln(\"Cache Success for key: \\(req.cacheKey)\")\n            }\n        }\n    }\n    \n    private class func getCacheJson (req: EZRequest) {\n        let cache = Shared.JSONCache\n        cache.fetch(key: req.cacheKey).onSuccess { JSON in\n            req.output = JSON.dictionary\n            if req.dataFromCache && !isEmpty(req.output) {\n                let delayTime = dispatch_time(DISPATCH_TIME_NOW,\n                    Int64(0.1 * Double(NSEC_PER_SEC)))\n            \n                dispatch_after(delayTime, dispatch_get_main_queue()) {\n                    self.loadFromCache(req)\n                }\n            }\n        }\n    }\n    \n    private class func loadFromCache (req: EZRequest){\n        if req.needCheckCode && req.state.value != .Success {\n            req.codeKey = req.output[CODE_KEY] as? Int\n            if req.codeKey == RIGHT_CODE {\n                req.message = req.output[MSG_KEY] as? String\n                req.state.value = RequestState.SuccessFromCache\n                EZPrintln(\"Fetch  Success from Cache by key: \\(req.cacheKey)\")\n            }else{\n                req.message = req.output[MSG_KEY] as? String\n                req.state.value = RequestState.ErrorFromCache\n                EZPrintln(req.message)\n            }\n        }\n    }\n    \n    private class func checkCode (req: EZRequest) {\n        if req.needCheckCode {\n            req.codeKey = req.output[CODE_KEY] as? Int\n            if req.codeKey == RIGHT_CODE {\n                self.success(req)\n                self.cacheJson(req)\n            }else{\n                self.error(req)\n            }\n        }else{\n            req.state.value = RequestState.Success\n            self.cacheJson(req)\n        }\n    }\n\n    \n    private class func success (req: EZRequest) {\n        req.isFirstRequest = false\n        req.message = req.output[MSG_KEY] as? String\n        if req.output.isEmpty {\n            req.state.value = RequestState.Error\n        }else{\n            req.state.value = RequestState.Success\n        }\n    }\n    \n    private class func failed (req: EZRequest) {\n        req.message = req.error.debugDescription\n        req.state.value = RequestState.Failed\n        EZPrintln(req.message)\n    }\n    \n    private class func error (req: EZRequest) {\n        req.message = req.output[MSG_KEY] as? String\n        req.state.value = RequestState.Error\n        EZPrintln(req.message)\n    }\n    \n    /* Usage\n    EZAction.networkReachability *->> Bond<NetworkStatus>{ status in\n        switch (status) {\n        case .NotReachable:\n        EZPrintln(\"NotReachable\")\n        case .ReachableViaWiFi:\n        EZPrintln(\"ReachableViaWiFi\")\n        case .ReachableViaWWAN:\n        EZPrintln(\"ReachableViaWWAN\")\n        default:\n        EZPrintln(\"default\")\n        }\n    }\n    */\n    \n    public class var networkReachability: Observable<Reachability.NetworkStatus>? {\n        if let d: AnyObject = objc_getAssociatedObject(self, &networkReachabilityHandle) {\n            return d as? Observable<Reachability.NetworkStatus>\n        } else {\n            do {\n                let reachability = try Reachability.reachabilityForInternetConnection()\n                let d = Observable<Reachability.NetworkStatus>(reachability.currentReachabilityStatus)\n                reachability.whenReachable = { reachability in\n                    dispatch_async(dispatch_get_main_queue()) {\n                        d.value = reachability.currentReachabilityStatus\n                    }\n                }\n                reachability.whenUnreachable = { reachability in\n                    dispatch_async(dispatch_get_main_queue()) {\n                        d.value = reachability.currentReachabilityStatus\n                    }\n                }\n                try reachability.startNotifier()\n                objc_setAssociatedObject(self, &networkReachabilityHandle, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n                return d\n            } catch {\n                print(\"Unable to create Reachability\")\n                return nil\n            }\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZCollectionView.swift",
    "content": "//\n//  EZCollectionView.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/26.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\npublic class EZCollectionView: UICollectionView {\n\n    /*\n    // Only override drawRect: if you perform custom drawing.\n    // An empty implementation adversely affects performance during animation.\n    override func drawRect(rect: CGRect) {\n        // Drawing code\n    }\n    */\n\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZNavigationController.swift",
    "content": "//\n//  EZNavigationController.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/24.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\npublic class EZNavigationController: UINavigationController,UINavigationControllerDelegate,UIGestureRecognizerDelegate{\n\n    public var popGestureRecognizerEnabled = true\n    \n    override public func viewDidLoad() {\n        super.viewDidLoad()\n        self.configGestureRecognizer()\n        // Do any additional setup after loading the view.\n    }\n\n    override public func didReceiveMemoryWarning() {\n        super.didReceiveMemoryWarning()\n        // Dispose of any resources that can be recreated.\n    }\n    \n    public func configGestureRecognizer() {\n        if let target = self.interactivePopGestureRecognizer?.delegate {\n            let pan = UIPanGestureRecognizer(target: target, action: Selector(\"handleNavigationTransition:\"))\n            pan.delegate = self\n            self.view.addGestureRecognizer(pan)\n        }\n        //禁掉系统的侧滑手势\n        weak var weekSelf = self\n        self.interactivePopGestureRecognizer?.enabled = false;\n        self.interactivePopGestureRecognizer?.delegate = weekSelf;\n    }\n\n    public func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {\n        if gestureRecognizer != self.interactivePopGestureRecognizer && self.viewControllers.count > 1 && self.popGestureRecognizerEnabled{\n            return true\n        }else{\n            return false\n        }\n    }\n    \n    override public func  pushViewController(viewController: UIViewController, animated: Bool) {\n        self.interactivePopGestureRecognizer?.enabled = false\n        super.pushViewController(viewController, animated: animated)\n    }\n    \n    //UINavigationControllerDelegate\n    public func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {\n        if self.popGestureRecognizerEnabled {\n            self.interactivePopGestureRecognizer?.enabled = true\n        }\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZRequest.swift",
    "content": "//\n//  Request.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/24.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\nimport Alamofire\n\npublic enum RequestState : Int {\n    case Default  //初始化状态\n    case Success \n    case Failed\n    case Sending\n    case Error\n    case Cancle\n    case Suspend\n    case SuccessFromCache\n    case ErrorFromCache\n}\nprivate var enabledDynamicHandleRequest: UInt8 = 0\nprivate var stateDynamicHandleRequest: UInt8 = 1\nprivate var managerHandle: UInt8 = 2\n\npublic class EZRequest: NSObject {\n    public var output = Dictionary<String,AnyObject>() // 序列化后的数据\n    public var params = Dictionary<String,AnyObject>() //使用字典参数\n    public var response:Response<AnyObject, NSError>? // 获取字符串数据\n    public var error:ErrorType? //请求的错误\n    public var state = Observable<RequestState>(.Default) //Request状态\n    public var url:NSURL? //请求的链接\n    public var message:String? //错误消息或者服务器返回的MSG\n    public var codeKey:Int?  // 错误码返回\n    \n    //upload上传相关参数\n    public var uploadUrl:URLStringConvertible = \"\" //上传图片到这个URL协议\n    public var uploadData:NSData?  //上传文件\n    public var progress = 0.0 //上传进度\n    public var totalBytesWritten = 0.0 //已上传数据大小\n    public var totalBytesExpectedToWrite = 0.0  //全部需要上传的数据大小\n    \n    // download下载相关参数\n    public var downloadUrl:URLStringConvertible = \"\"//下载图片URL\n    public var targetPath = \"\" //下载到路径\n    public var totalBytesRead = 0.0 //已下载传数据大小\n    public var totalBytesExpectedToRead = 0.0 //全部需要下载的数据大小\n    \n    public var scheme = \"http\"  //协议\n    public var host = \"\"           //域名\n    public var path = \"\"       //请求路径\n    public var staticPath = \"\" //其他路径\n    public var method = Method.GET     //提交方式\n    public var parameterEncoding = ParameterEncoding.URL //编码方式 Http头参数设置\n    public var needCheckCode = true  //是否需要检查错误码\n    \n    public var acceptableContentTypes = [\"application/json\",\"text/plain\"]  //可接受的序列化返回数据的格式\n    public var requestBlock:(Void->())?\n    public var isFirstRequest = false\n    \n    //HttpHeader timeoutInterval Cookies 等都在这里设置\n    public var sessionConfiguration:NSURLSessionConfiguration?\n    public var op:Request?\n    \n    public var requestNeedActive: Observable<Bool> {\n        if let d: AnyObject = objc_getAssociatedObject(self, &enabledDynamicHandleRequest) {\n            return (d as? Observable<Bool>)!\n        } else {\n            let d = Observable<Bool>(false)\n            d.observe{ [weak self] v in if let s = self {\n                if v {\n                    d.value = false\n                    s.requestBlock?()\n                }\n            }}\n            objc_setAssociatedObject(self, &enabledDynamicHandleRequest, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return d\n        }\n    }\n\n    var useCache = false\n    var dataFromCache = false\n\n    \n    public var requestKey :String {\n        return self.nameOfClass\n    }\n    \n    public class var requestKey:String {\n        return self.nameOfClass\n    }\n    \n    public var requestParams :Dictionary<String,AnyObject>{\n        return self.listProperties()\n    }\n    \n    public var appendPathInfo :String {\n        var pathInfo = self.pathInfo\n        if pathInfo != nil && !(pathInfo!).characters.isEmpty {\n            for (key,nsValue) in self.requestParams {\n                let par = \"(\\\\{\\(key)\\\\})\"\n                let str = \"\\(nsValue)\"\n                pathInfo = (try? NSRegularExpression(pattern: par, options: NSRegularExpressionOptions.CaseInsensitive))?.stringByReplacingMatchesInString(str, options: NSMatchingOptions.ReportCompletion, range: NSMakeRange(0, (pathInfo!).characters.count), withTemplate: str)\n            }\n        }\n        if pathInfo == nil {\n            pathInfo = \"\"\n        }\n        return pathInfo!\n    }\n    \n    public var pathInfo :String?{\n        return nil\n    }\n    \n    //the key for cache\n    public var cacheKey :String{\n        if self.method == .GET {\n            return self.url!.absoluteString.MD5\n        }else if !isEmpty(self.requestParams) {\n            return (self.url!.absoluteString + self.requestParams.joinPath).MD5\n        }else{\n            return self.url!.absoluteString.MD5\n        }\n    }\n    \n    public func suspend() {\n        self.op?.suspend()\n        self.state.value = .Suspend\n    }\n    \n    public func resume() {\n        self.op?.resume()\n        self.state.value = .Sending\n    }\n    \n    public func cancel() {\n        self.op?.cancel()\n        self.state.value = .Cancle\n    }\n    \n    public var manager:Manager {\n        get{\n            if let reqManager = objc_getAssociatedObject(self, &managerHandle) as? Manager {\n                return reqManager\n            }else if let configuration = sessionConfiguration{\n                let aManager = Alamofire.Manager(configuration: configuration)\n                objc_setAssociatedObject(self, &managerHandle, aManager, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n                return aManager\n            }else{\n                return Alamofire.Manager.sharedInstance\n            }\n        }set(aManager){\n            objc_setAssociatedObject(self, &managerHandle, aManager, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZScene.swift",
    "content": "//\n//  Scene.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/22.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport SnapKit\n\npublic enum NAV : Int {\n    case LEFT\n    case RIGHT\n}\n\npublic enum EXTEND : Int{\n    case NONE\n    case TOP\n    case BOTTOM\n    case TOP_BOTTOM\n}\n\npublic enum INSET : Int{\n    case NONE\n    case TOP\n    case BOTTOM\n    case TOP_BOTTOM\n}\n\npublic class EZScene: UIViewController {\n    \n    //parentScene 保留设计，必要的时候保存parentScene\n    public weak var parentScene:EZScene?\n\n    //导航条左右按钮设置 NAV是一个枚举值：.LEFT,.RIGHT\n    public func showBarButton(position:NAV,title:String,fontColor:UIColor){\n        self.showBarButton(position, button: UIButton(navTitle: title, color: fontColor))\n    }\n    \n    public func showBarButton(position:NAV,imageName:String) -> Void{\n        self.showBarButton(position, button: UIButton(navImage: UIImage(named: imageName)!))\n    }\n    \n    public func showBarButton(position:NAV,button:UIButton?){\n        if position == .LEFT {\n            button?.addTarget(self, action: Selector(\"leftButtonTouch\"), forControlEvents: UIControlEvents.TouchUpInside)\n            self.navigationItem.leftBarButtonItem = nil\n            self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button!)\n            self.navigationController?.interactivePopGestureRecognizer?.delegate = nil\n        }else if position == .RIGHT {\n            button?.addTarget(self, action: Selector(\"rightButtonTouch\"), forControlEvents: UIControlEvents.TouchUpInside)\n            self.navigationItem.rightBarButtonItem = nil\n            self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button!)\n        }\n    }\n    \n    public func leftButtonTouch(){\n        self.navigationController?.popViewControllerAnimated(true)\n    }\n    \n    public func rightButtonTouch(){\n        \n    }\n    \n    public func setTitleView(titleView:UIView){\n        self.navigationItem.titleView = titleView\n    }\n    \n    public func addSubView(view:UIView,extend:EXTEND){\n        self.view.addSubview(view)\n        self.view.sendSubviewToBack(view)\n        \n        self.automaticallyAdjustsScrollViewInsets = false\n        self.extendedLayoutIncludesOpaqueBars = true\n        self.edgesForExtendedLayout = UIRectEdge.All\n        view.snp_makeConstraints { (make) -> Void in\n            //TODO\n//            make.edges.equalTo(view.superview!).inset(\n//                EdgeInsetsMake((extend == EXTEND.TOP||extend == EXTEND.TOP_BOTTOM) ? 64:0, left:0,bottom:(extend == EXTEND.BOTTOM||extend == EXTEND.TOP_BOTTOM) ? 49:0, right: 0)\n//            )\n        }\n    }\n\n    public func addScrollView(view:UIScrollView,extend:EXTEND,inset:INSET){\n        self.addSubView(view, extend: extend)\n//        view.contentInset = UIEdgeInsetsMake((inset == INSET.TOP || inset == INSET.TOP_BOTTOM) ? 64:0, 0,\n//            (inset == INSET.BOTTOM || inset == INSET.TOP_BOTTOM) ? 49:0, 0)\n    }\n    \n    \n\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZSceneModel.swift",
    "content": "//\n//  SceneModel.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/26.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\npublic class EZSceneModel: NSObject {\n\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZTableView.swift",
    "content": "//\n//  EZTableView.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/26.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\npublic class EZTableView: UITableView {\n\n    /*\n    // Only override drawRect: if you perform custom drawing.\n    // An empty implementation adversely affects performance during animation.\n    override func drawRect(rect: CGRect) {\n        // Drawing code\n    }\n    */\n\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Core/EZViewModel.swift",
    "content": "//\n//  EZViewModel.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/11.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\npublic class EZData:NSObject {\n    public var dym:Observable<NSData>?\n    \n    public var value:NSData?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    \n    public init(_ data:NSData) {\n        self.dym = Observable<NSData>(data)\n    }\n}\n\npublic class EZString:NSObject {\n    public var dym:Observable<String>?\n    \n    public var value:String?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    \n    public init(_ str:String) {\n        self.dym = Observable<String>(str)\n    }\n}\n\npublic class EZURL:NSObject {\n    public var dym:Observable<NSURL?>?\n    public var value:NSURL?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ url:NSURL?) {\n        self.dym = Observable<NSURL?>(url)\n    }\n}\n\npublic class EZAttributedString:NSObject {\n    public var dym:Observable<NSAttributedString>?\n    public var value:NSAttributedString?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ str:NSAttributedString) {\n        self.dym = Observable<NSAttributedString>(str)\n    }\n}\n\npublic class EZImage:NSObject {\n    public var dym:Observable<UIImage?>?\n    public var value:UIImage?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ image:UIImage?) {\n        self.dym = Observable<UIImage?>(image)\n    }\n}\n\npublic class EZColor:NSObject {\n    public var dym:Observable<UIColor>?\n    public var value:UIColor?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ color:UIColor) {\n        self.dym = Observable<UIColor>(color)\n    }\n}\n\npublic class EZBool:NSObject {\n    public var dym:Observable<Bool>?\n    public var value:Bool?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ b:Bool) {\n        self.dym = Observable<Bool>(b)\n    }\n}\n\npublic class EZFloat:NSObject {\n    public var dym:Observable<CGFloat>?\n    public var value:CGFloat?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ fl:CGFloat) {\n        self.dym = Observable<CGFloat>(fl)\n    }\n}\n\npublic class EZInt:NSObject {\n    public var dym:Observable<Int>?\n    public var value:Int?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ i:Int) {\n        self.dym = Observable<Int>(i)\n    }\n}\n\npublic class EZNumber:NSObject {\n    public var dym:Observable<NSNumber>?\n    public var value:NSNumber?{\n        get{\n            return self.dym?.value\n        }set(value){\n            self.dym?.value = value!\n        }\n    }\n    public init(_ i:NSNumber) {\n        self.dym = Observable<NSNumber>(i)\n    }\n}\n\nextension NSObject{\n    public var model_properyies :Dictionary<String,AnyObject>{\n        return self.listProperties()\n    }\n    \n    public func model_hasKey(key:String) -> Bool{\n        return self.model_properyies.keys.contains(key)\n    }\n}\n\npublic class EZViewModel:NSObject {\n\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZCoreDataManager.swift",
    "content": "//\n//  EZCoreDataManager.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/31.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\nprivate var managedObjectContextHandle:UInt8 = 0\nprivate var persistentStoreCoordinatorHandle:UInt8 = 1\nprivate var databaseNameHandle:UInt8 = 2\nprivate var modelNameHandle:UInt8 = 3\nprivate var managedObjectModelHandle:UInt8 = 4\n\npublic class EZCoreDataManager {\n    \n    private static let appName = NSBundle.mainBundle().infoDictionary![\"CFBundleName\"] as! String\n    \n    public var databaseName: String {\n        get {\n            if let db = objc_getAssociatedObject(self, &databaseNameHandle) as? String {\n                return db\n            } else {\n                return EZCoreDataManager.appName + \".sqlite\"\n            }\n        }\n        set(value){\n            objc_setAssociatedObject(self, &databaseNameHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &managedObjectContextHandle, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &persistentStoreCoordinatorHandle, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public var modelName: String {\n        get {\n            if let model = objc_getAssociatedObject(self, &modelNameHandle) as? String {\n                return model\n            } else {\n                return EZCoreDataManager.appName\n            }\n        }\n        set(value) {\n            objc_setAssociatedObject(self, &modelNameHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &managedObjectContextHandle, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &persistentStoreCoordinatorHandle, nil, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public var managedObjectContext: NSManagedObjectContext {\n        get {\n            if let context = objc_getAssociatedObject(self, &managedObjectContextHandle) as? NSManagedObjectContext  {\n                return context\n            } else {\n                let c = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)\n                c.persistentStoreCoordinator = persistentStoreCoordinator\n                objc_setAssociatedObject(self, &managedObjectContextHandle, c, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n                return c\n            }\n        }\n        set (value){\n            objc_setAssociatedObject(self, &managedObjectContextHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public var persistentStoreCoordinator: NSPersistentStoreCoordinator {\n        get {\n            if let store = objc_getAssociatedObject(self, &persistentStoreCoordinatorHandle) as? NSPersistentStoreCoordinator  {\n                return store\n            } else {\n                let p = self.persistentStoreCoordinator(NSSQLiteStoreType, storeURL: self.sqliteStoreURL)\n                objc_setAssociatedObject(self, &persistentStoreCoordinatorHandle, p, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n                return p\n            }\n        }set(value){\n            objc_setAssociatedObject(self, &persistentStoreCoordinatorHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n\n    public var managedObjectModel: NSManagedObjectModel {\n        if let m = objc_getAssociatedObject(self, &managedObjectModelHandle) as? NSManagedObjectModel {\n            return m\n        } else {\n            let modelURL = NSBundle.mainBundle().URLForResource(self.modelName, withExtension: \"momd\")\n            let model = NSManagedObjectModel(contentsOfURL: modelURL!)\n            objc_setAssociatedObject(self, &managedObjectModelHandle, model, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return model!\n        }\n    }\n    \n    public func useInMemoryStore() {\n        persistentStoreCoordinator = self.persistentStoreCoordinator(NSInMemoryStoreType, storeURL: nil)\n    }\n    \n    public func saveContext() -> Bool {\n        return self.managedObjectContext.saveData()\n    }\n    \n    private var sqliteStoreURL: NSURL {\n        #if os(iOS)\n            let dir = EZCoreDataManager.applicationDocumentsDirectory\n            #else\n            let dir = EZCoreDataManager.applicationSupportDirectory\n            self.createApplicationSupportDirIfNeeded(dir)\n        #endif\n        return dir!.URLByAppendingPathComponent(self.databaseName)\n        \n    }\n    \n    private func persistentStoreCoordinator(storeType: String, storeURL: NSURL?) -> NSPersistentStoreCoordinator {\n        let c = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)\n        let error = NSErrorPointer()\n        do {\n            try c.addPersistentStoreWithType(storeType, configuration: nil, URL: storeURL, options: [NSMigratePersistentStoresAutomaticallyOption:true,NSInferMappingModelAutomaticallyOption:true])\n        } catch let error1 as NSError {\n            error.memory = error1\n            print(\"ERROR WHILE CREATING PERSISTENT STORE COORDINATOR! \" + error.debugDescription)\n        }\n        return c\n    }\n    \n    private static var applicationDocumentsDirectory:NSURL? {\n        return NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last\n    }\n    \n    private static var applicationSupportDirectory:NSURL? {\n        return NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.ApplicationSupportDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last?.URLByAppendingPathComponent(EZCoreDataManager.appName)\n    }\n    \n    private static func createApplicationSupportDirIfNeeded(dir: NSURL) {\n        if NSFileManager.defaultManager().fileExistsAtPath(dir.absoluteString) {\n            return\n        }\n        do {\n            try NSFileManager.defaultManager().createDirectoryAtURL(dir, withIntermediateDirectories: true, attributes: nil)\n        } catch _ {\n        }\n    }\n    // singleton\n    public static let sharedManager = EZCoreDataManager()\n}\n\n\npublic extension NSManagedObjectContext {\n    \n    public static var defaultContext: NSManagedObjectContext {\n        return EZCoreDataManager.sharedManager.managedObjectContext\n    }\n    \n    func createFetchRequest(entityName:String) -> NSFetchRequest {\n        let request = NSFetchRequest()\n        request.entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext: self)\n        return request\n    }\n    \n    func saveData() -> Bool {\n        if !self.hasChanges {\n            return true\n        }\n        let error = NSErrorPointer()\n        let save: Bool\n        do {\n            try self.save()\n            save = true\n        } catch let error1 as NSError {\n            error.memory = error1\n            save = false\n        }\n        \n        if (!save) {\n            print(\"Unresolved error in saving context for entity:\")\n            print(self)\n            print(\"!\\nError: \" + error.debugDescription)\n            return false\n        }\n        return true\n    }\n}\n\n\npublic extension NSPredicate{\n    \n    public func condition(condition: AnyObject?) -> NSPredicate?{\n        if let cond: AnyObject = condition {\n            return NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates:[self, NSPredicate.predicate(cond)])\n        }\n        return self\n    }\n    \n    public func orCondition(condition: AnyObject?) -> NSPredicate?{\n        if let cond: AnyObject = condition {\n            return NSCompoundPredicate(type: NSCompoundPredicateType.OrPredicateType, subpredicates:[self, NSPredicate.predicate(cond)])\n        }\n        return self\n    }\n    \n    private static func predicate(properties: [String:AnyObject]) -> NSPredicate {\n        var preds = [NSPredicate]()\n        for (key, value) in properties {\n            preds.append(NSPredicate(format: \"%K = %@\", argumentArray: [key, value]))\n        }\n        return NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: preds)\n    }\n    \n    private static func predicate(condition: AnyObject) -> NSPredicate {\n        if condition is NSPredicate {\n            return condition as! NSPredicate\n        }\n        if let d = condition as? [String:AnyObject] {\n            return self.predicate(d)\n        }\n        return NSPredicate()\n    }\n}\n\npublic extension NSFetchRequest{\n    \n    public func condition(condition: AnyObject?) -> NSFetchRequest{\n         if let cond: AnyObject = condition {\n            if let pred = self.predicate {\n                self.predicate = pred.condition(cond)\n            }else{\n                self.predicate = NSPredicate.predicate(cond)\n            }\n        }\n        return self\n    }\n    \n    public func orCondition(condition: AnyObject?) -> NSFetchRequest{\n        if let cond: AnyObject = condition,let pred = self.predicate  {\n            self.predicate = pred.orCondition(cond)\n        }\n        return self\n    }\n    \n    public func orderBy(key:String,_ order:String = \"ASC\") -> NSFetchRequest{\n        let sortDescriptor = NSSortDescriptor(key: key, ascending: order.uppercaseString==\"ASC\")\n        if self.sortDescriptors == nil{\n            self.sortDescriptors = [sortDescriptor]\n        }else{\n            self.sortDescriptors?.append(sortDescriptor)\n        }\n        return self\n    }\n    \n    /**\n    * Set the \"limit\" value of the query.\n    *\n    * @param int value\n    * @return self\n    * @static\n    */\n    public func limit(value:Int) -> NSFetchRequest{\n        self.fetchLimit = value\n        self.fetchOffset = 0\n        return self\n    }\n    \n    /**\n    * Alias to set the \"limit\" value of the query.\n    *\n    * @param int value\n    * @return NSFetchRequest\n    */\n    public func take(value:Int) -> NSFetchRequest{\n        return self.limit(value)\n    }\n    \n    /**\n    * Set the limit and offset for a given page.\n    *\n    * @param int page\n    * @param int perPage\n    * @return NSFetchRequest\n    */\n    public func forPage(page:Int,_ perPage:Int) -> NSFetchRequest{\n        self.fetchLimit = perPage\n        self.fetchOffset = (page - 1) * perPage\n        return self\n    }\n    \n    public func first() -> NSManagedObject?{\n        return self.take(1).get().first\n    }\n    \n    public func delete() -> NSInteger{\n        var i = 0\n        for o in self.get() {\n            o.delete()\n            i++\n        }\n        return i\n    }\n    \n    public func get() -> [NSManagedObject]{\n        return (try! NSManagedObjectContext.defaultContext.executeFetchRequest(self)) as! [NSManagedObject] \n    }\n    \n    public func count() -> Int {\n        return NSManagedObjectContext.defaultContext.countForFetchRequest(self, error: nil)\n    }\n    \n    public func exists() -> Bool {\n        return self.count() > 0\n    }\n    \n}\n\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+Array.swift",
    "content": "//\n//  EZExtend+Array.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nextension Array {\n    \n    func stringAtIndex(index:Int,other:String) -> String{\n        if self.count >= index + 1 {\n            return (self[index] as! String).trim\n        }else{\n            return other\n        }\n    }\n    \n    func floatAtIndex(index:Int,other:CGFloat) -> CGFloat{\n        if self.count >= index + 1 {\n            return (self[index] as! String).trim.floatValue\n        }else{\n            return other\n        }\n    }\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+Bond.swift",
    "content": "//\n//  EZBond.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/27.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Bond\nimport TTTAttributedLabel\n\n@objc class TapGestureDynamicHelper:NSObject\n{\n    weak var view: UIView?\n    let sink:  (UITapGestureRecognizer) -> Void\n    init(view: UIView,number:NSInteger,sink:((UITapGestureRecognizer) -> Void)) {\n        self.view = view\n        self.sink = sink\n        super.init()\n        view.addTapGesture(number, target: self, action: Selector(\"tapHandle:\"))\n    }\n\n    \n    func tapHandle(gesture: UITapGestureRecognizer) {\n        sink(gesture)\n    }\n}\n\n@objc class PanGestureDynamicHelper:NSObject{\n    weak var view: UIView?\n    let sink:  (UIPanGestureRecognizer) -> Void\n    init(view: UIView,number:NSInteger,sink:((UIPanGestureRecognizer) -> Void)) {\n        self.view = view\n        self.sink = sink\n        super.init()\n        view.addPanGesture(self, action: Selector(\"panHandle:\"))\n    }\n    func panHandle(gestureRecognizer:UIPanGestureRecognizer) {\n        sink(gestureRecognizer)\n    }\n}\n\n@objc class SwipeGestureDynamicHelper:NSObject\n{\n    weak var view: UIView?\n    let sink:  ((UISwipeGestureRecognizer) -> Void)\n    var number:NSInteger = 1\n    init(view: UIView,number:NSInteger,sink:((UISwipeGestureRecognizer) -> Void)) {\n        self.view = view\n        self.number = number\n        self.sink = sink\n        super.init()\n        view.addSwipeGesture(UISwipeGestureRecognizerDirection.Right, numberOfTouches: number, target: self, action: Selector(\"swipeRightHandle:\"))\n        view.addSwipeGesture(UISwipeGestureRecognizerDirection.Up, numberOfTouches: number, target: self, action: Selector(\"swipeUpHandle:\"))\n        view.addSwipeGesture(UISwipeGestureRecognizerDirection.Down, numberOfTouches: number, target: self, action: Selector(\"swipeDownHandle:\"))\n        view.addSwipeGesture(UISwipeGestureRecognizerDirection.Left, numberOfTouches: number, target: self, action: Selector(\"swipeLeftHandle:\"))\n    }\n    \n    func swipeRightHandle(gestureRecognizer:UISwipeGestureRecognizer) {\n        sink(gestureRecognizer)\n    }\n    func swipeUpHandle(gestureRecognizer:UISwipeGestureRecognizer) {\n        sink(gestureRecognizer)\n    }\n    func swipeDownHandle(gestureRecognizer:UISwipeGestureRecognizer) {\n        sink(gestureRecognizer)\n    }\n    func swipeLeftHandle(gestureRecognizer:UISwipeGestureRecognizer) {\n        sink(gestureRecognizer)\n    }\n}\n\nextension UIView{\n    private struct AssociatedKeys {\n        static var PanGestureEventKey = \"bnd_PanGestureEventKey\"\n        static var PanGestureEventHelperKey = \"bnd_PanGestureEventHelperKey\"\n        static var SwipeGestureEventKey = \"bnd_SwipeGestureEventKey\"\n        static var SwipeGestureEventHelperKey = \"bnd_SwipeGestureEventHelperKey\"\n        static var TapGestureEventKey = \"bnd_TapGestureEventKey\"\n        static var TapGestureEventHelperKey = \"bnd_TapGestureEventHelperKey\"\n        \n    }\n    \n    public func bnd_swipeGestureEvent(number:NSInteger) ->EventProducer<UISwipeGestureRecognizer> {\n        if let bnd_swipeGestureEvent: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.SwipeGestureEventKey) {\n            return bnd_swipeGestureEvent as! EventProducer<UISwipeGestureRecognizer>\n        } else {\n            var capturedSink: (UISwipeGestureRecognizer -> ())! = nil\n            let bnd_swipeGestureEvent = EventProducer<UISwipeGestureRecognizer> { sink in\n                capturedSink = sink\n                return nil\n            }\n            let controlHelper =  SwipeGestureDynamicHelper(view: self, number: number, sink: capturedSink)\n            objc_setAssociatedObject(self, &AssociatedKeys.SwipeGestureEventHelperKey, controlHelper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &AssociatedKeys.SwipeGestureEventKey, bnd_swipeGestureEvent, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return bnd_swipeGestureEvent\n        }\n    }\n    \n    public func bnd_tapGestureEvent(number:NSInteger) ->EventProducer<UITapGestureRecognizer> {\n        if let bnd_tapGestureEvent: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.TapGestureEventKey) {\n            return bnd_tapGestureEvent as! EventProducer<UITapGestureRecognizer>\n        } else {\n            var capturedSink: (UITapGestureRecognizer -> ())! = nil\n            let bnd_tapGestureEvent = EventProducer<UITapGestureRecognizer> { sink in\n                capturedSink = sink\n                return nil\n            }\n            let controlHelper =  TapGestureDynamicHelper(view: self, number: number, sink: capturedSink)\n            objc_setAssociatedObject(self, &AssociatedKeys.TapGestureEventHelperKey, controlHelper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &AssociatedKeys.TapGestureEventKey, bnd_tapGestureEvent, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return bnd_tapGestureEvent\n        }\n    }\n    \n    public var bnd_panGestureEvent:EventProducer<UIPanGestureRecognizer> {\n        if let bnd_panGestureEvent: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.PanGestureEventKey) {\n            return bnd_panGestureEvent as! EventProducer<UIPanGestureRecognizer>\n        } else {\n            var capturedSink: (UIPanGestureRecognizer -> ())! = nil\n            let bnd_panGestureEvent = EventProducer<UIPanGestureRecognizer> { sink in\n                capturedSink = sink\n                return nil\n            }\n            let controlHelper =  PanGestureDynamicHelper(view: self, number: 1, sink: capturedSink)\n            objc_setAssociatedObject(self, &AssociatedKeys.PanGestureEventHelperKey, controlHelper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            objc_setAssociatedObject(self, &AssociatedKeys.PanGestureEventKey, bnd_panGestureEvent, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return bnd_panGestureEvent\n        }\n    }\n}\n\n\n\nextension UIImageView {\n    private struct AssociatedKeys {\n        static var UrlImageDynamicHandleUIImageView = \"UrlImageDynamicHandleUIImageView\"\n    }\n    public var bnd_URLImage: Observable<NSURL?> {\n        if let d: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.UrlImageDynamicHandleUIImageView) {\n            return (d as? Observable<NSURL?>)!\n        } else {\n            let d = Observable<NSURL?>(NSURL())\n            d.observe { [weak self] v in if let s = self {\n                if v != nil {\n                    s.kf_setImageWithURL(v!)\n                }\n            } }\n            objc_setAssociatedObject(self, &AssociatedKeys.UrlImageDynamicHandleUIImageView, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return d\n        }\n    }\n}\n\nextension TTTAttributedLabel {\n    private struct AssociatedKeys {\n        static var textDynamicHandleTTTAttributeLabel = \"textDynamicHandleTTTAttributeLabel\"\n        static var attributedTextDynamicHandleTTTAttributeLabel = \"attributedTextDynamicHandleTTTAttributeLabel\"\n        static var dataDynamicHandleTTTAttributeLabel = \"dataDynamicHandleTTTAttributeLabel\"\n    }\n    \n     public var dynTTText: Observable<String> {\n        if let d: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.textDynamicHandleTTTAttributeLabel) {\n            return (d as? Observable<String>)!\n        } else {\n            let d = Observable<String>(self.text ?? \"\")\n            d.observe { [weak self] v in if let s = self {\n                s.setText(v)\n            } }\n            objc_setAssociatedObject(self, &AssociatedKeys.textDynamicHandleTTTAttributeLabel, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return d\n        }\n    }\n    \n    public var dynTTTData: Observable<NSData> {\n        if let d: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.dataDynamicHandleTTTAttributeLabel) {\n            return (d as? Observable<NSData>)!\n        } else {\n            let d = Observable<NSData>(NSData())\n            d.observe{ [weak self] v in if let s = self {\n                s.setText(NSAttributedString(fromHTMLData: v, attributes: [\"dict\":s.tagProperty.style]))\n            }}\n            objc_setAssociatedObject(self, &AssociatedKeys.dataDynamicHandleTTTAttributeLabel, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return d\n        }\n    }\n    \n    public var dynTTTAttributedText: Observable<NSAttributedString> {\n        if let d: AnyObject = objc_getAssociatedObject(self, &AssociatedKeys.attributedTextDynamicHandleTTTAttributeLabel) {\n            return (d as? Observable<NSAttributedString>)!\n        } else {\n            let d = Observable<NSAttributedString>(self.attributedText ?? NSAttributedString(string: \"\"))\n            d.observe { [weak self] v in if let s = self {\n                s.setText(v) } }\n            objc_setAssociatedObject(self, &AssociatedKeys.attributedTextDynamicHandleTTTAttributeLabel, d, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n            return d\n        }\n    }\n\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+Dictionary.swift",
    "content": "//\n//  Dictionary+EZExtend.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/25.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nextension Dictionary {\n    \n    //join the Dictionary with \"&\" to a url path\n    var joinPath : String{\n        var array = ArraySlice<String>()\n        for (key,value) in self {\n           array.append(\"\\(key)=\\(value)\")\n        }\n        return array.joinWithSeparator(\"&\")\n    }\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+NSDate.swift",
    "content": "//\n//  EZExtend+NSDate.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/9.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nextension NSDate {\n    //format :yyyy-MM-dd\n    public func formatTo(format:String) -> String{\n        let dateFormatter = NSDateFormatter()\n        dateFormatter.dateFormat = format\n        let currentDateStr = dateFormatter.stringFromDate(self)\n        return currentDateStr\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+String.swift",
    "content": "//\n//  EZExtend+String.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n// MARK: - String\n\npublic func trimToArray (str:String) -> Array<String>{\n    return str.trim.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter(){\n        return !$0.characters.isEmpty\n    }\n}\n\npublic func trimToArrayBy (str:String,by:String) -> Array<String>{\n    return str.trim.componentsSeparatedByString(by).filter(){\n        return !$0.characters.isEmpty\n    }\n}\n\n\n\nextension String {\n    public subscript (i: Int) -> String {\n        return String(Array(self.characters)[i])\n    }\n    \n    public var urlencode :String? {\n        return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.letterCharacterSet())\n    }\n    \n    public var urldecode :String? {\n        return self.stringByRemovingPercentEncoding;\n    }\n    \n    public var trim :String {\n        return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())\n    }\n    \n    public var trimArray : Array<String>{\n        return trimToArray(self)\n    }\n    \n    public func trimArrayBy (str:String) -> Array<String> {\n        return trimToArrayBy(self,by: str)\n    }\n    \n    public var toKeyPath :String {\n        let keyArray = self.trim.componentsSeparatedByString(\"-\")\n        var str = \"\"\n        var index = 0\n        for akey in keyArray {\n            if index == 0 {\n                str += akey\n            }else{\n                str += akey.capitalizedString\n            }\n            index++\n        }\n        if let reg = Regex(\"_\").replace(str, withTemplate: \".\") {\n            str = reg\n        }\n        return str\n    }\n    \n    public var floatValue: CGFloat {\n        return CGFloat((self as NSString).floatValue)\n    }\n    \n    public var integerValue: Int {\n        return (self as NSString).integerValue\n    }\n    \n    public var boolValue: Bool {\n        return (self as NSString).boolValue\n    }\n    \n    \n    public func anyValue(key:String) -> AnyObject{\n        if key == \"font\" {\n            if let font = UIFont.Font(self.trim) {\n                return font\n            }\n        }\n        return self.anyValue\n    }\n    \n    public var anyValue :AnyObject{\n        let str = self.trim\n        \n        if str.hasSuffix(\".cg\"){\n            if let color = UIColor(CSS: Regex(\".cg\").replace(str, withTemplate: \"\")){\n                return color.CGColor\n            }\n        }\n        \n        if [\"YES\",\"NO\",\"TRUE\",\"FALSE\"].contains(str.uppercaseString) {\n            return str.boolValue\n        }else if let color = UIColor(CSS: str){\n            return color\n        }else if let image = UIImage(named: str){\n            return image\n        }else if str.floatValue != 0.0 {\n            return str.floatValue\n        }else{\n            return str\n        }\n    }\n    \n    public var MD5 : String {\n        let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)\n        return data!.MD5String\n    }\n    \n    public func toData () -> NSData?{\n        return self.dataUsingEncoding(NSUTF8StringEncoding)?.dataByReplacingOccurrencesOfData(\"\\\\n\".dataUsingEncoding(NSUTF8StringEncoding), withData: \"\\n\".dataUsingEncoding(NSUTF8StringEncoding))\n    }\n    \n    public var chineseFirstLetter : String{\n        return HTFirstLetter.firstLetter(self)\n    }\n    \n    public var chineseFirstLetters : String {\n        return HTFirstLetter.firstLetters(self)\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIAlertController.swift",
    "content": "//\n//  EZExtend+UIAlertController.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\n// MARK: - UIAlertController\n\npublic func alert (title: String,\n    message: String,\n    cancelAction: ((UIAlertAction!)->Void)? = nil,\n    okAction: ((UIAlertAction!)->Void)? = nil) -> UIAlertController {\n        let a = UIAlertController (title: title, message: message, preferredStyle: .Alert)\n        \n        if let ok = okAction {\n            a.addAction(UIAlertAction(title: \"OK\", style: .Default, handler: ok))\n            a.addAction(UIAlertAction(title: \"Cancel\", style: .Cancel, handler: cancelAction))\n        } else {\n            a.addAction(UIAlertAction(title: \"OK\", style: .Cancel, handler: cancelAction))\n        }\n        \n        return a\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIButton.swift",
    "content": "//\n//  UIButton+EZExtend.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/22.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\n\nlet NAV_BAR_HEIGHT = CGFloat(40.0)\nlet NAV_BUTTON_MIN_WIDTH = CGFloat(40.0)\nlet NAV_BUTTON_MIN_HEIGHT = CGFloat(40.0)\n\nextension UIButton{\n    public convenience init(navImage: UIImage){\n        var buttonFrame = CGRectMake(CGFloat(0.0), CGFloat(0.0), navImage.size.width, NAV_BAR_HEIGHT)\n        if  buttonFrame.size.width < NAV_BUTTON_MIN_WIDTH\n        {\n            buttonFrame.size.width = NAV_BUTTON_MIN_WIDTH\n        }\n        if buttonFrame.size.height < NAV_BUTTON_MIN_HEIGHT\n        {\n            buttonFrame.size.height = NAV_BUTTON_MIN_HEIGHT\n        }\n        self.init(frame:buttonFrame)\n        self.contentMode = UIViewContentMode.ScaleAspectFill\n        self.backgroundColor = UIColor.clearColor()\n        self.setImage(navImage, forState: UIControlState.Normal)\n    }\n    \n    public convenience init(navTitle: String,color: UIColor){\n        let titleSize = navTitle.boundingRectWithSize(CGSizeMake(999999.0, NAV_BAR_HEIGHT), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: Dictionary(dictionaryLiteral: (NSFontAttributeName,UIFont.systemFontOfSize(16.0))), context: nil).size\n        var buttonFrame = CGRectMake(CGFloat(0.0), CGFloat(0.0), titleSize.width, NAV_BAR_HEIGHT)\n        if  buttonFrame.size.width < NAV_BUTTON_MIN_WIDTH\n        {\n            buttonFrame.size.width = NAV_BUTTON_MIN_WIDTH\n        }\n        if buttonFrame.size.height < NAV_BUTTON_MIN_HEIGHT\n        {\n            buttonFrame.size.height = NAV_BUTTON_MIN_HEIGHT\n        }\n        self.init(frame: buttonFrame)\n        self.contentMode = UIViewContentMode.ScaleAspectFill\n        self.backgroundColor = UIColor.clearColor()\n        self.titleLabel?.font = UIFont.systemFontOfSize(16.0)\n        self.setTitleColor(color, forState: UIControlState.Normal)\n        self.setTitle(navTitle, forState: UIControlState.Normal)\n    }\n    \n    public func setBackgroundImageWithColor(color: UIColor?, forState state: UIControlState){\n        if let c = color {\n            let image = UIImage.imageWithColor(c, size: CGSizeMake(1, 1))\n            self.setBackgroundImage(image, forState: state)\n        }\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIFont.swift",
    "content": "//\n//  EZExtend+UIFont.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n// MARK: - UIFont\n\nextension UIFont {\n    \n    public enum FontType: String {\n        case Regular = \"Regular\"\n        case Bold = \"Bold\"\n        case Light = \"Light\"\n        case UltraLight = \"UltraLight\"\n        case Italic = \"Italic\"\n        case Thin = \"Thin\"\n        case Book = \"Book\"\n        case Roman = \"Roman\"\n        case Medium = \"Medium\"\n        case MediumItalic = \"MediumItalic\"\n        case CondensedMedium = \"CondensedMedium\"\n        case CondensedExtraBold = \"CondensedExtraBold\"\n        case SemiBold = \"SemiBold\"\n        case BoldItalic = \"BoldItalic\"\n        case Heavy = \"Heavy\"\n    }\n    \n    public enum FontName: String {\n        case HelveticaNeue = \"HelveticaNeue\"\n        case Helvetica = \"Helvetica\"\n        case Futura = \"Futura\"\n        case Menlo = \"Menlo\"\n        case Avenir = \"Avenir\"\n        case AvenirNext = \"AvenirNext\"\n        case Didot = \"Didot\"\n        case AmericanTypewriter = \"AmericanTypewriter\"\n        case Baskerville = \"Baskerville\"\n        case Geneva = \"Geneva\"\n        case GillSans = \"GillSans\"\n        case SanFranciscoDisplay = \"SanFranciscoDisplay\"\n        case Seravek = \"Seravek\"\n    }\n    \n    public class func PrintFontFamily (font: FontName) {\n        let arr = UIFont.fontNamesForFamilyName(font.rawValue)\n        for name in arr {\n            print(name)\n        }\n    }\n    \n    public class func Font (str:String) -> UIFont?  {\n        var array = str.trimArray\n        if array.count >= 2{\n            let font = array[1] as String\n            if font == \"system\" {\n                return UIFont.systemFontOfSize(array[0].floatValue)\n            }else{\n                return UIFont(name: array[1], size: array[0].floatValue)\n            }\n        }else if array.count == 1{\n            return UIFont.systemFontOfSize(array[0].floatValue)\n        }\n        return nil\n    }\n    \n    public class func Font (name: FontName, type: FontType, size: CGFloat) -> UIFont {\n        return UIFont (name: name.rawValue + \"-\" + type.rawValue, size: size)!\n    }\n    \n    public class func HelveticaNeue (type: FontType, size: CGFloat) -> UIFont {\n        return Font(.HelveticaNeue, type: type, size: size)\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIImage.swift",
    "content": "//\n//  EZExtend+UIImage.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n// MARK: - UIImage\n\nextension UIImage {\n    public class func imageWithColor(color:UIColor,size:CGSize) -> UIImage {\n        let rect = CGRectMake(0, 0, size.width, size.height)\n        UIGraphicsBeginImageContextWithOptions(size, false, 0)\n        color.setFill()\n        UIRectFill(rect)\n        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return image\n    }\n    \n    public func aspectResizeWithWidth (width: CGFloat) -> UIImage {\n        let aspectSize = CGSize (width: width, height: aspectHeightForWidth(width))\n        \n        UIGraphicsBeginImageContext(aspectSize)\n        self.drawInRect(CGRect(origin: CGPointZero, size: aspectSize))\n        let img = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        \n        return img\n    }\n    \n    public func aspectResizeWithHeight (height: CGFloat) -> UIImage {\n        let aspectSize = CGSize (width: aspectWidthForHeight(height), height: height)\n        \n        UIGraphicsBeginImageContext(aspectSize)\n        self.drawInRect(CGRect(origin: CGPointZero, size: aspectSize))\n        let img = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        \n        return img\n    }\n    \n    public func aspectHeightForWidth (width: CGFloat) -> CGFloat {\n        return (width * self.size.height) / self.size.width\n    }\n    \n    public func aspectWidthForHeight (height: CGFloat) -> CGFloat {\n        return (height * self.size.width) / self.size.height\n    }\n    \n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UILabel.swift",
    "content": "//\n//  EZExtend+UILabel.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n// MARK: - UILabel\n\nprivate var UILabelAttributedStringArray: UInt8 = 0\nextension UILabel {\n    \n    public var attributedStrings: [NSAttributedString]? {\n        get {\n            return objc_getAssociatedObject(self, &UILabelAttributedStringArray) as? [NSAttributedString]\n        } set (value) {\n            objc_setAssociatedObject(self, &UILabelAttributedStringArray, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public  func addAttributedString (text: String,\n        color: UIColor,\n        font: UIFont) {\n            let att = NSAttributedString (string: text,\n                attributes: [NSFontAttributeName: font,\n                    NSForegroundColorAttributeName: color])\n            self.addAttributedString(att)\n    }\n    \n    public func addAttributedString (attributedString: NSAttributedString) {\n        var att: NSMutableAttributedString?\n        \n        if let a = self.attributedText {\n            att = NSMutableAttributedString (attributedString: a)\n            att?.appendAttributedString(attributedString)\n        } else {\n            att = NSMutableAttributedString (attributedString: attributedString)\n            attributedStrings = []\n        }\n        \n        attributedStrings?.append(attributedString)\n        self.attributedText = NSAttributedString (attributedString: att!)\n    }\n    \n    \n    public func updateAttributedStringAtIndex (index: Int,\n        attributedString: NSAttributedString) {\n            \n            if (attributedStrings?[index] != nil) {\n                attributedStrings?.removeAtIndex(index)\n                attributedStrings?.insert(attributedString, atIndex: index)\n                \n                let updated = NSMutableAttributedString ()\n                for att in attributedStrings! {\n                    updated.appendAttributedString(att)\n                }\n                \n                self.attributedText = NSAttributedString (attributedString: updated)\n            }\n    }\n    \n    public func updateAttributedStringAtIndex (index: Int,\n        newText: String) {\n            if let att = attributedStrings?[index] {\n                let newAtt = NSMutableAttributedString (string: newText)\n                \n                att.enumerateAttributesInRange(NSMakeRange(0, att.string.characters.count-1),\n                    options: NSAttributedStringEnumerationOptions.LongestEffectiveRangeNotRequired,\n                    usingBlock: { (attribute, range, stop) -> Void in\n                        for (key, value) in attribute {\n                            newAtt.addAttribute(key , value: value, range: range)\n                        }\n                })\n                \n                updateAttributedStringAtIndex(index, attributedString: newAtt)\n            }\n    }\n    \n    \n    public func getEstimatedHeight () -> CGFloat {\n        let att = NSAttributedString(string: self.text!, attributes: [NSFontAttributeName:font])\n        let rect = att.boundingRectWithSize(CGSize (width: w, height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)\n        return rect.height\n    }\n    \n    public func fitHeight () {\n        self.h = getEstimatedHeight()\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIView.swift",
    "content": "//\n//  EZExtend+UIView.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n// MARK: - UIView\n\nlet UIViewAnimationDuration: NSTimeInterval = 1\nlet UIViewAnimationSpringDamping: CGFloat = 0.5\nlet UIViewAnimationSpringVelocity: CGFloat = 0.5\nvar UIViewGestureUniqueArray:CGFloat = 0.6\nextension UIView {\n    \n//    public var gestureUniqueArray: [String:DisposableType] {\n//        get {\n//            if let viewGestureUniqueArray: AnyObject = objc_getAssociatedObject(self, &UIViewGestureUniqueArray) {\n//                return viewGestureUniqueArray as! Dictionary\n//            } else {\n//                let mapData = [String:DisposableType]()\n//                objc_setAssociatedObject(self, &UIViewGestureUniqueArray, mapData, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n//                return mapData\n//            }\n//        }set(value){\n////            if let viewGestureUniqueArray: AnyObject = objc_getAssociatedObject(self, &UIViewGestureUniqueArray) {\n////                \n////            } else {\n////                let mapData = [String:DisposableType]()\n////                mapData[]\n////            }\n//        \n//        }\n//       \n//    }\n    \n    // MARK: Custom Initilizer\n    \n    convenience init (x: CGFloat,\n        y: CGFloat,\n        w: CGFloat,\n        h: CGFloat) {\n            self.init (frame: CGRect (x: x, y: y, width: w, height: h))\n    }\n    \n    // MARK: Frame Extensions\n    \n    public var x: CGFloat {\n        get {\n            return self.frame.origin.x\n        } set (value) {\n            self.frame = CGRect (x: value, y: self.y, width: self.w, height: self.h)\n        }\n    }\n    \n    public var y: CGFloat {\n        get {\n            return self.frame.origin.y\n        } set (value) {\n            self.frame = CGRect (x: self.x, y: value, width: self.w, height: self.h)\n        }\n    }\n    \n    public var w: CGFloat {\n        get {\n            return self.frame.size.width\n        } set (value) {\n            self.frame = CGRect (x: self.x, y: self.y, width: value, height: self.h)\n        }\n    }\n    \n    public var h: CGFloat {\n        get {\n            return self.frame.size.height\n        } set (value) {\n            self.frame = CGRect (x: self.x, y: self.y, width: self.w, height: value)\n        }\n    }\n    \n    \n    public var left: CGFloat {\n        get {\n            return self.x\n        } set (value) {\n            self.x = value\n        }\n    }\n    \n     var right: CGFloat {\n        get {\n            return self.x + self.w\n        } set (value) {\n            self.x = value - self.w\n        }\n    }\n    \n    public var top: CGFloat {\n        get {\n            return self.y\n        } set (value) {\n            self.y = value\n        }\n    }\n    \n    public var bottom: CGFloat {\n        get {\n            return self.y + self.h\n        } set (value) {\n            self.y = value - self.h\n        }\n    }\n    \n    \n    public var position: CGPoint {\n        get {\n            return self.frame.origin\n        } set (value) {\n            self.frame = CGRect (origin: value, size: self.frame.size)\n        }\n    }\n    \n    public var size: CGSize {\n        get {\n            return self.frame.size\n        } set (value) {\n            self.frame = CGRect (origin: self.frame.origin, size: size)\n        }\n    }\n    \n    \n    public func leftWithOffset (offset: CGFloat) -> CGFloat {\n        return self.left - offset\n    }\n    \n    public func rightWithOffset (offset: CGFloat) -> CGFloat {\n        return self.right + offset\n    }\n    \n    public func topWithOffset (offset: CGFloat) -> CGFloat {\n        return self.top - offset\n    }\n    \n    public func botttomWithOffset (offset: CGFloat) -> CGFloat {\n        return self.bottom + offset\n    }\n    \n    \n    \n    // MARK: Transform Extensions\n    \n    public func setRotationX (x: CGFloat) {\n        var transform = CATransform3DIdentity\n        transform.m34 = 1.0 / -1000.0\n        transform = CATransform3DRotate(transform, degreesToRadians(x), 1.0, 0.0, 0.0)\n        \n        self.layer.transform = transform\n    }\n    \n    public func setRotationY (y: CGFloat) {\n        var transform = CATransform3DIdentity\n        transform.m34 = 1.0 / -1000.0\n        transform = CATransform3DRotate(transform, degreesToRadians(y), 0.0, 1.0, 0.0)\n        \n        self.layer.transform = transform\n    }\n    \n    public func setRotationZ (z: CGFloat) {\n        var transform = CATransform3DIdentity\n        transform.m34 = 1.0 / -1000.0\n        transform = CATransform3DRotate(transform, degreesToRadians(z), 0.0, 0.0, 1.0)\n        \n        self.layer.transform = transform\n    }\n    \n    public func setRotation (x: CGFloat,\n        y: CGFloat,\n        z: CGFloat) {\n            var transform = CATransform3DIdentity\n            transform.m34 = 1.0 / -1000.0\n            transform = CATransform3DRotate(transform, degreesToRadians(x), 1.0, 0.0, 0.0)\n            transform = CATransform3DRotate(transform, degreesToRadians(y), 0.0, 1.0, 0.0)\n            transform = CATransform3DRotate(transform, degreesToRadians(z), 0.0, 0.0, 1.0)\n            \n            self.layer.transform = transform\n    }\n    \n    \n    public func setScale (x: CGFloat,\n        y: CGFloat) {\n            var transform = CATransform3DIdentity\n            transform.m34 = 1.0 / -1000.0\n            transform = CATransform3DScale(transform, x, y, 1)\n            \n            self.layer.transform = transform\n    }\n    \n    \n    \n    // MARK: Anchor Extensions\n    \n    public func setAnchorPosition (anchorPosition: AnchorPosition) {\n        print(anchorPosition.rawValue)\n        self.layer.anchorPoint = anchorPosition.rawValue\n    }\n    \n    \n    \n    // MARK: Layer Extensions\n    \n    public func addShadow (offset: CGSize,\n        radius: CGFloat,\n        color: UIColor,\n        opacity: Float) {\n            self.layer.shadowOffset = offset\n            self.layer.shadowRadius = radius\n            self.layer.shadowOpacity = opacity\n            self.layer.shadowColor = color.CGColor\n    }\n    \n    public func addBorder (width: CGFloat,\n        color: UIColor) {\n            self.layer.borderWidth = width\n            self.layer.borderColor = color.CGColor\n            self.layer.masksToBounds = true\n    }\n    \n    \n    public func setCornerRadius (radius: CGFloat) {\n        self.layer.cornerRadius = radius\n        self.layer.masksToBounds = true\n    }\n    \n    \n    public func drawCircle (fillColor: UIColor,\n        strokeColor: UIColor,\n        strokeWidth: CGFloat) {\n            let path = UIBezierPath (roundedRect: CGRect (x: 0, y: 0, width: self.w, height: self.w), cornerRadius: self.w/2)\n            \n            let shapeLayer = CAShapeLayer ()\n            shapeLayer.path = path.CGPath\n            shapeLayer.fillColor = fillColor.CGColor\n            shapeLayer.strokeColor = strokeColor.CGColor\n            shapeLayer.lineWidth = strokeWidth\n            \n            self.layer.addSublayer(shapeLayer)\n    }\n    \n    public func drawStroke (width: CGFloat,\n        color: UIColor) {\n            let path = UIBezierPath (roundedRect: CGRect (x: 0, y: 0, width: self.w, height: self.w), cornerRadius: self.w/2)\n            \n            let shapeLayer = CAShapeLayer ()\n            shapeLayer.path = path.CGPath\n            shapeLayer.fillColor = UIColor.clearColor().CGColor\n            shapeLayer.strokeColor = color.CGColor\n            shapeLayer.lineWidth = width\n            \n            self.layer.addSublayer(shapeLayer)\n    }\n    \n    public func drawArc (from: CGFloat,\n        to: CGFloat,\n        clockwise: Bool,\n        width: CGFloat,\n        fillColor: UIColor,\n        strokeColor: UIColor,\n        lineCap: String) {\n            let path = UIBezierPath (arcCenter: self.center, radius: self.w/2, startAngle: degreesToRadians(from), endAngle: degreesToRadians(to), clockwise: clockwise)\n            \n            let shapeLayer = CAShapeLayer ()\n            shapeLayer.path = path.CGPath\n            shapeLayer.fillColor = fillColor.CGColor\n            shapeLayer.strokeColor = strokeColor.CGColor\n            shapeLayer.lineWidth = width\n            \n            self.layer.addSublayer(shapeLayer)\n    }\n    \n    \n    \n    // MARK: Animation Extensions\n    \n    public func spring (animations: (()->Void)!,\n        completion: ((Bool)->Void)? = nil) {\n            UIView.animateWithDuration(UIViewAnimationDuration,\n                delay: 0,\n                usingSpringWithDamping: UIViewAnimationSpringDamping,\n                initialSpringVelocity: UIViewAnimationSpringVelocity,\n                options: UIViewAnimationOptions.AllowAnimatedContent,\n                animations: animations,\n                completion: completion)\n    }\n    \n    public func animate (animations: (()->Void)!,\n        completion: ((Bool)->Void)? = nil) {\n            UIView.animateWithDuration(UIViewAnimationDuration,\n                animations: animations,\n                completion: completion)\n    }\n    \n    \n    \n    // MARK: Gesture Extensions\n    \n    public func addTapGesture (tapNumber: NSInteger,\n        target: AnyObject, action: Selector) {\n            let tap = UITapGestureRecognizer (target: target, action: action)\n            tap.numberOfTapsRequired = tapNumber\n            self.addGestureRecognizer(tap)\n    }\n    \n    public func addSwipeGesture (direction: UISwipeGestureRecognizerDirection,\n        numberOfTouches: Int,\n        target: AnyObject,\n        action: Selector) {\n            let swipe = UISwipeGestureRecognizer (target: target, action: action)\n            swipe.direction = direction\n            swipe.numberOfTouchesRequired = numberOfTouches\n            self.addGestureRecognizer(swipe)\n    }\n    \n    public func addPanGesture (target: AnyObject,\n        action: Selector) {\n            let pan = UIPanGestureRecognizer (target: target, action: action)\n            self.addGestureRecognizer(pan)\n    }\n    \n    public func whenTap(number:NSInteger = 1,block:()->Void) -> DisposableType{\n        self.userInteractionEnabled = true\n        return bnd_tapGestureEvent(number).observe { (_) -> () in\n            block()\n        }\n    }\n    \n    public func whenSwipe(number:NSInteger = 1,direction:UISwipeGestureRecognizerDirection,block:()->Void) -> DisposableType{\n        self.userInteractionEnabled = true\n        return bnd_swipeGestureEvent(number).observe { (_) -> () in\n            block()\n        }\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZExtend+UIViewController.swift",
    "content": "//\n//  EZExtend+UIViewController.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n// MARK: - UIViewController\n\nextension UIViewController {\n    \n    public var top: CGFloat {\n        get {\n            if let nav = self.navigationController {\n                if nav.navigationBarHidden {\n                    return view.top\n                } else {\n                    return nav.navigationBar.bottom\n                }\n            } else {\n                return view.top\n            }\n        }\n    }\n    \n    public var bottom: CGFloat {\n        get {\n            if let tab = tabBarController {\n                if tab.tabBar.hidden {\n                    return view.bottom\n                } else {\n                    return tab.tabBar.top\n                }\n            } else {\n                return view.bottom\n            }\n        }\n    }\n    \n    \n    public var navigationBarHeight: CGFloat {\n        get {\n            if let nav = self.navigationController {\n                return nav.navigationBar.h\n            }\n            \n            return 0\n        }\n    }\n    \n    public var navigationBarColor: UIColor? {\n        get {\n            return navigationController?.navigationBar.tintColor\n        } set (value) {\n            navigationController?.navigationBar.barTintColor = value\n        }\n    }\n    \n    public var navigationBar: UINavigationBar? {\n        get {\n            return navigationController?.navigationBar\n        }\n    }\n    \n    public var applicationFrame: CGRect {\n        get {\n            return CGRect (x: view.x, y: top, width: view.w, height: bottom - top)\n        }\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZKit.swift",
    "content": "//\n//  CEMKit.swift\n//  CEMKit-Swift\n//\n//  Created by Cem Olcay on 05/11/14.\n//  Copyright (c) 2014 Cem Olcay. All rights reserved.\n//\n\nimport UIKit\n\n\n\n// MARK: - UIBarButtonItem\n\npublic func barButtonItem (imageName: String,\n    action: (AnyObject)->()) -> UIBarButtonItem {\n        let button = BlockButton (frame: CGRect(x: 0, y: 0, width: 20, height: 20))\n        button.setImage(UIImage(named: imageName), forState: .Normal)\n        button.actionBlock = action\n        \n        return UIBarButtonItem (customView: button)\n}\n\npublic func barButtonItem (title: String,\n    color: UIColor,\n    action: (AnyObject)->()) -> UIBarButtonItem {\n        let button = BlockButton (frame: CGRect(x: 0, y: 0, width: 20, height: 20))\n        button.setTitle(title, forState: .Normal)\n        button.setTitleColor(color, forState: .Normal)\n        button.actionBlock = action\n        button.sizeToFit()\n        \n        return UIBarButtonItem (customView: button)\n}\n\n\n\n// MARK: - CGSize\n\npublic func + (left: CGSize, right: CGSize) -> CGSize {\n    return CGSize (width: left.width + right.width, height: left.height + right.height)\n}\n\npublic func - (left: CGSize, right: CGSize) -> CGSize {\n    return CGSize (width: left.width - right.width, height: left.width - right.width)\n}\n\n\n\n// MARK: - CGPoint\n\npublic func + (left: CGPoint, right: CGPoint) -> CGPoint {\n    return CGPoint (x: left.x + right.x, y: left.y + right.y)\n}\n\npublic func - (left: CGPoint, right: CGPoint) -> CGPoint {\n    return CGPoint (x: left.x - right.x, y: left.y - right.y)\n}\n\n\npublic enum AnchorPosition: CGPoint {\n    case TopLeft        = \"{0, 0}\"\n    case TopCenter      = \"{0.5, 0}\"\n    case TopRight       = \"{1, 0}\"\n    \n    case MidLeft        = \"{0, 0.5}\"\n    case MidCenter      = \"{0.5, 0.5}\"\n    case MidRight       = \"{1, 0.5}\"\n    \n    case BottomLeft     = \"{0, 1}\"\n    case BottomCenter   = \"{0.5, 1}\"\n    case BottomRight    = \"{1, 1}\"\n}\n\nextension CGPoint: StringLiteralConvertible {\n    \n    public init(stringLiteral value: StringLiteralType) {\n        self = CGPointFromString(value)\n    }\n    \n    public init(extendedGraphemeClusterLiteral value: StringLiteralType) {\n        self = CGPointFromString(value)\n    }\n    \n    public init(unicodeScalarLiteral value: StringLiteralType) {\n        self = CGPointFromString(value)\n    }\n}\n\n\n\n// MARK: - CGFloat\n\npublic func degreesToRadians (angle: CGFloat) -> CGFloat {\n    return (CGFloat (M_PI) * angle) / 180.0\n}\n\n\npublic func normalizeValue (value: CGFloat,\n    min: CGFloat,\n    max: CGFloat) -> CGFloat {\n    return (max - min) / value\n}\n\n\npublic func convertNormalizedValue (value: CGFloat,\n    min: CGFloat,\n    max: CGFloat) -> CGFloat {\n    return ((max - min) * value) + min\n}\n\n\n\n// MARK: - Block Classes\n\n\n// MARK: - BlockButton\n\npublic class BlockButton: UIButton {\n    \n    override init (frame: CGRect) {\n        super.init(frame: frame)\n    }\n    \n    required public init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n    }\n    \n    var actionBlock: ((sender: BlockButton) -> ())? {\n        didSet {\n            self.addTarget(self, action: \"action:\", forControlEvents: UIControlEvents.TouchUpInside)\n        }\n    }\n    \n    func action (sender: BlockButton) {\n        actionBlock! (sender: sender)\n    }\n}\n\n\n\n// MARK: - BlockWebView\n\npublic class BlockWebView: UIWebView, UIWebViewDelegate {\n    \n    var didStartLoad: ((NSURLRequest?) -> ())?\n    var didFinishLoad: ((NSURLRequest?) -> ())?\n    var didFailLoad: ((NSURLRequest?, NSError?) -> ())?\n    \n    var shouldStartLoadingRequest: ((NSURLRequest) -> (Bool))?\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        delegate = self\n    }\n    \n    public required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n    }\n    \n    \n    @objc public func webViewDidStartLoad(webView: UIWebView) {\n        didStartLoad? (webView.request)\n    }\n    \n    @objc public func webViewDidFinishLoad(webView: UIWebView) {\n        didFinishLoad? (webView.request)\n    }\n    @objc  public func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {\n        didFailLoad? (webView.request, error)\n    }\n    \n    @objc public func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {\n        if let should = shouldStartLoadingRequest {\n            return should (request)\n        } else {\n            return true\n        }\n    }\n    \n}\n\n\npublic func nsValueForAny(anyValue:Any) -> NSObject? {\n    switch(anyValue) {\n    case let intValue as Int:\n        return NSNumber(int: CInt(intValue))\n    case let doubleValue as Double:\n        return NSNumber(double: CDouble(doubleValue))\n    case let stringValue as String:\n        return stringValue as NSString\n    case let boolValue as Bool:\n        return NSNumber(bool: boolValue)\n    default:\n        return nil\n    }\n}\n\nextension NSObject{\n    public class var nameOfClass: String{\n        return NSStringFromClass(self).componentsSeparatedByString(\".\").last!\n    }\n    \n    public var nameOfClass: String{\n        return NSStringFromClass(self.dynamicType).componentsSeparatedByString(\".\").last!\n    }\n\n    \n    public func listProperties() -> Dictionary<String,AnyObject>{\n\n        var modelDictionary = Dictionary<String,AnyObject>()\n        Mirror(reflecting: self).children.forEach { (element) -> () in\n            if  element.label != \"super\" {\n                if let nsValue = nsValueForAny(element.value) {\n                    modelDictionary.updateValue(nsValue, forKey: element.label!)\n                }\n            }\n        }\n        return modelDictionary\n    }\n    \n}\n\n\npublic func isEmpty<C : NSObject>(x: C) -> Bool {\n    if x.isKindOfClass(NSNull) {\n        return true\n    }else if x.respondsToSelector(Selector(\"length\")) && NSData().self.length == 0 {\n        return true\n    }else if x.respondsToSelector(Selector(\"count\")) && NSArray().self.count == 0 {\n        return true\n    }\n    return false\n}\n\n\n\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZPrintln.swift",
    "content": "//\n//  EZPrintln.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/28.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nvar EZ_DEBUG_MODE = true\n/**\nWrites the textual representation of `object` and a newline character into the standard output.\nThe textual representation is obtained from the `object` using its protocol conformances,\nin the following order of preference: `Streamable`, `Printable`, `DebugPrintable`.\nThis functional also augments the original function with the filename, function name, and line number of the object that is being logged.\n- parameter object:   A textual representation of the object.\n- parameter file:     Defaults to the name of the file that called magic(). Do not override this default.\n- parameter function: Defaults to the name of the function within the file in which magic() was called. Do not override this default.\n- parameter line:     Defaults to the line number within the file in which magic() was called. Do not override this default.\n*/\npublic func EZPrintln<T>(object: T, _ file: String = __FILE__, _ function: String = __FUNCTION__, _ line: Int = __LINE__)\n{\n    if EZ_DEBUG_MODE {\n        let filename = NSURL(fileURLWithPath: file).lastPathComponent?.URLString\n        print(\"\\(filename).\\(function)[\\(line)]: \\(object)\\n\", terminator: \"\")\n    }\n}\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZSystemInfo.swift",
    "content": "//\n//  EZSystemInfo.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/22.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\n#if os(iOS)\nlet IOS10_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"10.0\") != NSComparisonResult.OrderedAscending)\nlet IOS9_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"9.0\") != NSComparisonResult.OrderedAscending)\nlet IOS8_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"8.0\") != NSComparisonResult.OrderedAscending)\nlet IOS7_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"7.0\") != NSComparisonResult.OrderedAscending)\nlet IOS6_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"6.0\") != NSComparisonResult.OrderedAscending)\nlet IOS5_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"5.0\") != NSComparisonResult.OrderedAscending)\nlet IOS4_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"4.0\") != NSComparisonResult.OrderedAscending)\nlet IOS3_OR_LATER = (UIDevice.currentDevice().systemVersion.caseInsensitiveCompare(\"3.0\") != NSComparisonResult.OrderedAscending)\n\nlet IOS9_OR_EARLIER = !IOS10_OR_LATER\nlet IOS8_OR_EARLIER = !IOS9_OR_LATER\nlet IOS7_OR_EARLIER = !IOS8_OR_LATER\nlet IOS6_OR_EARLIER = !IOS7_OR_LATER\nlet IOS5_OR_EARLIER = !IOS6_OR_LATER\nlet IOS4_OR_EARLIER = !IOS5_OR_LATER\nlet IOS3_OR_EARLIER = !IOS4_OR_LATER\n\nlet IS_SCREEN_4_INCH = CGSizeEqualToSize(CGSizeMake(640, 1136), UIScreen.mainScreen().currentMode!.size)\nlet IS_SCREEN_35_INCH = CGSizeEqualToSize(CGSizeMake(640, 960), UIScreen.mainScreen().currentMode!.size)\nlet IS_SCREEN_47_INCH = CGSizeEqualToSize(CGSizeMake(750, 1334), UIScreen.mainScreen().currentMode!.size)\nlet IS_SCREEN_55_INCH = CGSizeEqualToSize(CGSizeMake(1242, 2208), UIScreen.mainScreen().currentMode!.size)\n\n#else\nlet IOS9_OR_LATER = false\nlet IOS8_OR_LATER = false\nlet IOS7_OR_LATER = false\nlet IOS6_OR_LATER = false\nlet IOS5_OR_LATER = false\nlet IOS4_OR_LATER = false\nlet IOS3_OR_LATER = false\n    \nlet IOS9_OR_EARLIER = false\nlet IOS8_OR_EARLIER = false\nlet IOS7_OR_EARLIER = false\nlet IOS6_OR_EARLIER = false\nlet IOS5_OR_EARLIER = false\nlet IOS4_OR_EARLIER = false\nlet IOS3_OR_EARLIER = false\n    \nlet IS_SCREEN_4_INCH = false\nlet IS_SCREEN_35_INCH = false\nlet IS_SCREEN_47_INCH = false\nlet IS_SCREEN_55_INCH = false\n#endif\n\n\npublic var IsSimulator:Bool {\n#if (arch(i386) || arch(x86_64)) && os(iOS)\n    return true;\n#else\n    return false;\n#endif\n}\n\npublic func OSVersion() ->String{\n#if os(iOS)\n    return UIDevice.currentDevice().systemName + \" \" + UIDevice.currentDevice().systemVersion\n#else\t// #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)\n    return \"\"\n#endif\t// #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)\n}\n\n//func AppVersion() ->String{\n//    var value = NSBundle.mainBundle().infoDictionary[\"CFBundleVersion\"]\n//    if nil == value || 0 == value.length\n//    {\n//    value = NSBundle.mainBundle().infoDictionary[\"CFBundleShortVersion\"]\n//    }\n//    return value\n//}\n\n//func AppIdentifier() ->String{\n//#if os(iOS)\n//    var value = NSBundle.mainBundle().infoDictionary[\"CFBundleVersion\"]\n//    if nil == value || 0 == value.length\n//    {\n//    value = NSBundle.mainBundle().infoDictionary[\"CFBundleShortVersion\"]\n//    }\n//    return value\n//#else\t// #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)\n//    return \"\"\n//#endif\t// #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)\n//}\n\n\n\n\npublic var Orientation: UIInterfaceOrientation {\nget {\n    return UIApplication.sharedApplication().statusBarOrientation\n}\n}\n\npublic var ScreenWidth: CGFloat {\nget {\n    if UIInterfaceOrientationIsPortrait(Orientation) {\n        return UIScreen.mainScreen().bounds.size.width\n    } else {\n        return UIScreen.mainScreen().bounds.size.height\n    }\n}\n}\n\npublic var ScreenHeight: CGFloat {\nget {\n    if UIInterfaceOrientationIsPortrait(Orientation) {\n        return UIScreen.mainScreen().bounds.size.height\n    } else {\n        return UIScreen.mainScreen().bounds.size.width\n    }\n}\n}\n\npublic var StatusBarHeight: CGFloat {\nget {\n    return UIApplication.sharedApplication().statusBarFrame.height\n}\n}\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EZWatch.swift",
    "content": "\n//  EZWatch.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/29.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nfunc watchForChangesToFilePath(filePath:String,callback:dispatch_block_t) {\n    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)\n    let fileDescriptor = open(filePath, O_EVTONLY)\n    \n    if fileDescriptor <= 0 {\n        return\n    }\n    assert(fileDescriptor > 0, \"Error could subscribe to events for file at path: \\(filePath)\")\n    let source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, UInt(fileDescriptor), DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND, queue)\n    dispatch_source_set_event_handler(source){\n        let flags = dispatch_source_get_data(source)\n        if flags != 0 {\n            dispatch_source_cancel(source)\n            dispatch_async(dispatch_get_main_queue()){\n                 callback()\n            }\n            let popTime = dispatch_time(DISPATCH_TIME_NOW,  Int64(0.5*Double(NSEC_PER_SEC)))\n            dispatch_after(popTime, queue){\n                watchForChangesToFilePath(filePath, callback: callback)\n            }\n        }\n    }\n    dispatch_source_set_cancel_handler(source){\n        close(fileDescriptor)\n    }\n    dispatch_resume(source)\n}\n\n\n\n\n\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/EasyORM.swift",
    "content": "//\n//  NSManagedObject+EZExtend.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/30.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\npublic func DBQuery(aClass: NSManagedObject.Type!,entityName:String) -> NSFetchRequest {\n    return aClass.defaultContext().createFetchRequest(entityName)\n}\n\npublic class EasyORM {\n    \n    public static var generateRelationships = false\n    \n    public static func setUpEntities(entities: [String:NSManagedObject.Type]) {\n        nameToEntities = entities\n    }\n    \n    private static var nameToEntities: [String:NSManagedObject.Type] = [String:NSManagedObject.Type]()\n\n    \n}\n\npublic extension NSManagedObject{\n\n    public func defaultContext() -> NSManagedObjectContext{\n        return self.managedObjectContext ?? self.dynamicType.defaultContext()\n    }\n    \n    public static func defaultContext() -> NSManagedObjectContext{\n        return NSManagedObjectContext.defaultContext\n    }\n    \n    private static var query:NSFetchRequest{\n        return self.defaultContext().createFetchRequest(self.entityName())\n    }\n    \n    public static func condition(condition: AnyObject?) -> NSFetchRequest{\n        return self.query.condition(condition)\n    }\n    \n    public static func orderBy(key:String,_ order:String = \"ASC\") -> NSFetchRequest{\n        return self.query.orderBy(key, order)\n    }\n    \n    /**\n    * Set the \"limit\" value of the query.\n    *\n    * @param int value\n    * @return self\n    * @static\n    */\n    public static func limit(value:Int) -> NSFetchRequest{\n        return self.query.limit(value)\n    }\n    \n    /**\n    * Alias to set the \"limit\" value of the query.\n    *\n    * @param int value\n    * @return NSFetchRequest\n    */\n    public static func take(value:Int) -> NSFetchRequest{\n        return self.query.take(value)\n    }\n    \n    /**\n    * Set the limit and offset for a given page.\n    *\n    * @param int page\n    * @param int perPage\n    * @return NSFetchRequest\n    */\n    public static func forPage(page:Int,_ perPage:Int) -> NSFetchRequest{\n        return self.query.forPage(page,perPage)\n    }\n    \n    public static func all() -> [NSManagedObject] {\n        return self.query.get()\n    }\n    \n    public static func count() -> Int {\n        return self.query.count()\n    }\n    \n    public static func findAndUpdate(unique:[String:AnyObject],data:[String:AnyObject]) -> NSManagedObject?{\n        if let object = self.find(unique) {\n            object.update(data)\n            return object\n        }else{\n            return nil\n        }\n    }\n    \n    public static func updateOrCreate(unique:[String:AnyObject],data:[String:AnyObject]) -> NSManagedObject{\n        if let object = self.find(unique) {\n            object.update(data)\n            return object\n        }else{\n            return self.create(data)\n        }\n    }\n    \n    public static func findOrCreate(properties: [String:AnyObject]) -> NSManagedObject {\n        let transformed = self.transformProperties(properties)\n        let existing = self.find(properties)\n        return existing ?? self.create(transformed)\n    }\n    \n    public static func find(condition: AnyObject) -> NSManagedObject? {\n        return self.query.condition(condition).first()\n    }\n    \n    public func update(properties: [String:AnyObject]) {\n        \n        if (properties.count == 0) {\n            return\n        }\n        let transformed = self.dynamicType.transformProperties(properties)\n        //Finish\n        for (key, value) in transformed {\n            self.willChangeValueForKey(key)\n            self.setSafeValue(value, forKey: key)\n            self.didChangeValueForKey(key)\n        }\n    }\n    \n    public func save() -> Bool {\n        return self.defaultContext().saveData()\n    }\n    \n    public func delete() -> NSManagedObjectContext {\n        let context = self.defaultContext()\n        context.deleteObject(self)\n        return context\n    }\n    \n    public static func deleteAll() -> NSManagedObjectContext{\n        for o in self.all() {\n            o.delete()\n        }\n        return self.defaultContext()\n    }\n    \n    public static func create() -> NSManagedObject {\n        let o = NSEntityDescription.insertNewObjectForEntityForName(self.entityName(), inManagedObjectContext: self.defaultContext()) \n        if let idprop = self.autoIncrementingId() {\n            o.setPrimitiveValue(NSNumber(integer: self.nextId()), forKey: idprop)\n        }\n        return o\n    }\n    \n    public static func create(properties: [String:AnyObject]) -> NSManagedObject {\n        let newEntity: NSManagedObject = self.create()\n        newEntity.update(properties)\n        if let idprop = self.autoIncrementingId() {\n            if newEntity.primitiveValueForKey(idprop) == nil {\n                newEntity.setPrimitiveValue(NSNumber(integer: self.nextId()), forKey: idprop)\n            }\n        }\n        return newEntity\n    }\n    \n    public static func autoIncrements() -> Bool {\n        return self.autoIncrementingId() != nil\n    }\n    \n    public static func nextId() -> Int {\n        let key = \"SwiftRecord-\" + self.entityName() + \"-ID\"\n        if self.autoIncrementingId() != nil {\n            let id = NSUserDefaults.standardUserDefaults().integerForKey(key)\n            NSUserDefaults.standardUserDefaults().setInteger(id + 1, forKey: key)\n            return id\n        }\n        return 0\n    }\n    \n\n    public class func autoIncrementingId() -> String? {\n        return nil\n    }\n    \n    //Private\n    \n    private static func transformProperties(properties: [String:AnyObject]) -> [String:AnyObject]{\n        let entity = NSEntityDescription.entityForName(self.entityName(), inManagedObjectContext: self.defaultContext())!\n        let attrs = entity.attributesByName\n        let rels = entity.relationshipsByName\n        \n        var transformed = [String:AnyObject]()\n        for (key, value) in properties {\n            let localKey = self.keyForRemoteKey(key)\n            if attrs[localKey] != nil {\n                transformed[localKey] = value\n            } else if let rel = rels[localKey]  {\n                if EasyORM.generateRelationships {\n                    if rel.toMany {\n                        if let array = value as? [[String:AnyObject]] {\n                            transformed[localKey] = self.generateSet(rel, array: array)\n                        } else {\n                            #if DEBUG\n                                println(\"Invalid value for relationship generation in \\(NSStringFromClass(self)).\\(localKey)\")\n                                println(value)\n                            #endif\n                        }\n                    } else if let dict = value as? [String:AnyObject] {\n                        transformed[localKey] = self.generateObject(rel, dict: dict)\n                    } else {\n                        #if DEBUG\n                            println(\"Invalid value for relationship generation in \\(NSStringFromClass(self)).\\(localKey)\")\n                            println(value)\n                        #endif\n                    }\n                }\n            }\n        }\n        return transformed\n    }\n    \n    \n    private func setSafeValue(value: AnyObject?, forKey key: String) {\n        if (value == nil) {\n            self.setNilValueForKey(key)\n            return\n        }\n        let val: AnyObject = value!\n        if let attr = self.entity.attributesByName[key] {\n            let attrType = attr.attributeType\n            if attrType == NSAttributeType.StringAttributeType && value is NSNumber {\n                self.setPrimitiveValue((val as! NSNumber).stringValue, forKey: key)\n            } else if let s = val as? String {\n                if self.isIntegerAttributeType(attrType) {\n                    self.setPrimitiveValue(NSNumber(integer: val.integerValue), forKey: key)\n                    return\n                } else if attrType == NSAttributeType.BooleanAttributeType {\n                    self.setPrimitiveValue(NSNumber(bool: val.boolValue), forKey: key)\n                    return\n                } else if (attrType == NSAttributeType.FloatAttributeType) {\n                    self.setPrimitiveValue(NSNumber(floatLiteral: val.doubleValue), forKey: key)\n                    return\n                } else if (attrType == NSAttributeType.DateAttributeType) {\n                    self.setPrimitiveValue(self.dynamicType.dateFormatter.dateFromString(s), forKey: key)\n                    return\n                }\n            }\n        }\n        self.setPrimitiveValue(value, forKey: key)\n    }\n    \n    private func isIntegerAttributeType(attrType: NSAttributeType) -> Bool {\n        return attrType == NSAttributeType.Integer16AttributeType || attrType == NSAttributeType.Integer32AttributeType || attrType == NSAttributeType.Integer64AttributeType\n    }\n    \n    private static var dateFormatter: NSDateFormatter {\n        if _dateFormatter == nil {\n            _dateFormatter = NSDateFormatter()\n            _dateFormatter!.dateFormat = \"yyyy-MM-dd HH:mm:ss z\"\n        }\n        return _dateFormatter!\n    }\n    private static var _dateFormatter: NSDateFormatter?\n    \n    \n    public class func mappings() -> [String:String] {\n        return [String:String]()\n    }\n    \n    public static func keyForRemoteKey(remote: String) -> String {\n        if let s = cachedMappings[remote] {\n            return s\n        }\n        let entity = NSEntityDescription.entityForName(self.entityName(), inManagedObjectContext: self.defaultContext())!\n        let properties = entity.propertiesByName\n        if properties[remote] != nil {\n            _cachedMappings![remote] = remote\n            return remote\n        }\n        \n        let camelCased = remote.camelCase\n        if properties[camelCased] != nil {\n            _cachedMappings![remote] = camelCased\n            return camelCased\n        }\n        _cachedMappings![remote] = remote\n        return remote\n    }\n    private static var cachedMappings: [String:String] {\n        if let m = _cachedMappings {\n            return m\n        } else {\n            var m = [String:String]()\n            for (key, value) in mappings() {\n                m[value] = key\n            }\n            _cachedMappings = m\n            return m\n        }\n    }\n    private static var _cachedMappings: [String:String]?\n    \n    private static func generateSet(rel: NSRelationshipDescription, array: [[String:AnyObject]]) -> NSSet {\n        var cls: NSManagedObject.Type?\n        if EasyORM.nameToEntities.count > 0 {\n            cls = EasyORM.nameToEntities[rel.destinationEntity!.managedObjectClassName]\n        }\n        if cls == nil {\n            cls = (NSClassFromString(rel.destinationEntity!.managedObjectClassName) as! NSManagedObject.Type)\n        } else {\n            print(\"Got class name from entity setup\")\n        }\n        let set = NSMutableSet()\n        for d in array {\n            set.addObject(cls!.findOrCreate(d))\n        }\n        return set\n    }\n    \n    private static func generateObject(rel: NSRelationshipDescription, dict: [String:AnyObject]) -> NSManagedObject {\n        let entity = rel.destinationEntity!\n        \n        let cls: NSManagedObject.Type = NSClassFromString(entity.managedObjectClassName) as! NSManagedObject.Type\n        return cls.findOrCreate(dict)\n    }\n    \n    public static func primaryKey() -> String {\n        NSException(name: \"Primary key undefined in \" + NSStringFromClass(self), reason: \"Override primaryKey if you want to support automatic creation, otherwise disable this feature\", userInfo: nil).raise()\n        return \"\"\n    }\n    \n    private static func entityName() -> String {\n        var name = NSStringFromClass(self)\n        if name.rangeOfString(\".\") != nil {\n            let comp = name.characters.split {$0 == \".\"}.map { String($0) }\n            if comp.count > 1 {\n                name = comp.last!\n            }\n        }\n        if name.rangeOfString(\"_\") != nil {\n            var comp = name.characters.split {$0 == \"_\"}.map { String($0) }\n            var last: String = \"\"\n            var remove = -1\n            for (i,s) in Array(comp.reverse()).enumerate() {\n                if last == s {\n                    remove = i\n                }\n                last = s\n            }\n            if remove > -1 {\n                comp.removeAtIndex(remove)\n                name = comp.joinWithSeparator(\"_\")\n            }\n        }\n        return name\n    }\n}\n\npublic extension String {\n    var camelCase: String {\n        let spaced = self.stringByReplacingOccurrencesOfString(\"_\", withString: \" \", options: [], range:Range<String.Index>(start: self.startIndex, end: self.endIndex))\n        let capitalized = spaced.capitalizedString\n        let spaceless = capitalized.stringByReplacingOccurrencesOfString(\" \", withString: \"\", options:[], range:Range<String.Index>(start:self.startIndex, end:self.endIndex))\n        return spaceless.stringByReplacingCharactersInRange(Range<String.Index>(start:spaceless.startIndex, end:spaceless.startIndex.successor()), withString: \"\\(spaceless[spaceless.startIndex])\".lowercaseString)\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/NSData+EasyExtend.h",
    "content": "//\n//  NSData+EasyExtend.h\n//  fastSign\n//\n//  Created by EasyIOS on 14-4-10.\n//  Copyright (c) 2014年 zhuchao. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n@interface NSData (EasyExtend)\n\n@property (nonatomic, readonly) NSData *\tMD5;\n@property (nonatomic, readonly) NSString *\tMD5String;\n\n+ (NSData *)fromResource:(NSString *)resName;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/NSData+EasyExtend.m",
    "content": "//\n//  NSData+EasyExtend.m\n//\n//  Created by EasyIOS on 14-4-10.\n//  Copyright (c) 2014年 zhuchao. All rights reserved.\n//\n\n#import \"NSData+EasyExtend.h\"\n\n#import <CommonCrypto/CommonDigest.h>\n@implementation NSData (EasyExtend)\n\n- (NSData *)MD5\n{\n\tunsigned char\tmd5Result[CC_MD5_DIGEST_LENGTH + 1];\n\tCC_LONG\t\t\tmd5Length = (CC_LONG)[self length];\n\t\n\tCC_MD5( [self bytes], md5Length, md5Result );\n\t\n\t\n\tNSMutableData * retData = [[NSMutableData alloc] init];\n\tif ( nil == retData )\n\t\treturn nil;\n\t\n\t[retData appendBytes:md5Result length:CC_MD5_DIGEST_LENGTH];\n\treturn retData;\n}\n\n- (NSString *)MD5String\n{\n\tNSData * value = [self MD5];\n\tif ( value )\n\t{\n\t\tchar\t\t\ttmp[16];\n\t\tunsigned char *\thex = (unsigned char *)malloc( 2048 + 1 );\n\t\tunsigned char *\tbytes = (unsigned char *)[value bytes];\n\t\tunsigned long\tlength = [value length];\n\t\t\n\t\thex[0] = '\\0';\n\t\t\n\t\tfor ( unsigned long i = 0; i < length; ++i )\n\t\t{\n\t\t\tsprintf( tmp, \"%02X\", bytes[i] );\n\t\t\tstrcat( (char *)hex, tmp );\n\t\t}\n\t\t\n\t\tNSString * result = [NSString stringWithUTF8String:(const char *)hex];\n\t\tfree( hex );\n\t\treturn result;\n\t}\n\telse\n\t{\n\t\treturn nil;\n\t}\n}\n\n+ (NSData *)fromResource:(NSString *)resName\n{\n\tNSString *\textension = [resName pathExtension];\n\tNSString *\tfullName = [resName substringToIndex:(resName.length - extension.length - 1)];\n\t\n\tNSString * path = [[NSBundle mainBundle] pathForResource:fullName ofType:extension];\n\treturn [NSData dataWithContentsOfFile:path];\n}\n@end\n"
  },
  {
    "path": "Pod/Classes/Easy/Lib/PullRefresh/EZInfiniteScrolling.swift",
    "content": "//\n//  EZInfiniteScrolling.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/15.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\nlet EZInfiniteScrollingViewHeight:CGFloat = 60.0\n\npublic enum EZInfiniteScrollingState {\n    case Stopped\n    case Triggered\n    case Loading\n    case Pulling\n    case Ended\n}\n\npublic class Footer:UIView {\n    init(scrollView:UIScrollView,frame: CGRect = CGRectZero) {\n        super.init(frame: frame)\n        \n    }\n    \n    required public init?(coder aDecoder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    public func resetScrollViewContentInset(scrollView:UIScrollView){\n        var currentInsets = scrollView.contentInset\n        let newBottom = scrollView.infiniteScrollingView!.originalBottomInset + scrollView.infiniteScrollingView!.extendBottom;\n        if newBottom != currentInsets.bottom {\n            currentInsets.bottom = newBottom\n            self.setScrollViewContentInset(currentInsets, scrollView: scrollView)\n        }\n    }\n    \n    public func setScrollViewContentInsetForLoading(scrollView:UIScrollView){\n        var currentInsets = scrollView.contentInset\n        let newBottom  = scrollView.infiniteScrollingView!.originalBottomInset + scrollView.infiniteScrollingView!.extendBottom + EZInfiniteScrollingViewHeight;\n        if newBottom != currentInsets.bottom {\n            currentInsets.bottom = newBottom\n            self.setScrollViewContentInset(currentInsets, scrollView: scrollView)\n        }\n    }\n    \n    public func setScrollViewContentInset(contentInset:UIEdgeInsets,scrollView:UIScrollView){\n        UIView.animateWithDuration(0.3, delay: 0,\n            options: UIViewAnimationOptions.BeginFromCurrentState,\n            animations: {\n                scrollView.contentInset = contentInset\n            },completion:nil)\n    }\n}\n\npublic class EZInfiniteScrollingView :UIView {\n    public var state = Observable<EZInfiniteScrollingState>(.Stopped)\n    public var extendBottom:CGFloat = 0.0\n    public var originalBottomInset:CGFloat = 0.0\n    private var infiniteScrollingHandler:(Void -> ())?\n    private var oldState = EZInfiniteScrollingState.Stopped\n    \n    private func commonInit(){\n        self.autoresizingMask = UIViewAutoresizing.FlexibleWidth\n        \n        self.state.observe{ [unowned self] state in\n            if state == .Loading && self.oldState == .Triggered {\n                self.infiniteScrollingHandler?()\n            }\n            self.oldState = state\n        }\n    }\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        self.commonInit()\n    }\n    \n    required public init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        self.commonInit()\n    }\n    \n    func setCustomView(customView:UIView){\n        if customView.isKindOfClass(UIView) {\n            for view in self.subviews {\n                view.removeFromSuperview()\n            }\n            self.addSubview(customView)\n            let viewBounds = customView.bounds;\n            let origin = CGPointMake(\n                CGFloat(roundf(Float(self.bounds.size.width-viewBounds.size.width)/2)),\n                CGFloat(roundf(Float(self.bounds.size.height-viewBounds.size.height)/2)))\n            customView.frame =  CGRectMake(origin.x, origin.y, viewBounds.size.width, viewBounds.size.height)\n        }\n    }\n    \n    public func resetState(){\n        self.state.value = .Stopped;\n    }\n    \n    public func startAnimating(){\n        self.state.value = .Loading;\n    }\n    \n    public func stopAnimating(){\n        self.state.value = .Stopped;\n    }\n    \n    public func setEnded(){\n        self.state.value = .Ended;\n    }\n    \n    \n    public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {\n        let scrollView = object as! UIScrollView\n        if keyPath == \"contentOffset\" && scrollView.showsInfiniteScrolling {\n            if self.state.value != .Loading && self.state.value != .Ended  && scrollView.contentSize.height > 0{\n                let scrollViewContentHeight = scrollView.contentSize.height;\n                let scrollOffsetThreshold =  scrollViewContentHeight - scrollView.bounds.size.height + self.extendBottom\n                \n                if !scrollView.dragging && self.state.value == .Triggered {\n                    self.state.value = .Loading\n                }else if scrollView.dragging && self.state.value == .Pulling && scrollView.contentOffset.y - scrollOffsetThreshold > EZInfiniteScrollingViewHeight {\n                    self.state.value = .Triggered\n                }else if scrollView.contentOffset.y - scrollOffsetThreshold <= 1 && self.state.value != .Stopped {\n                    self.state.value = .Stopped\n                }else if scrollView.contentOffset.y - scrollOffsetThreshold > 0 && scrollView.contentOffset.y - scrollOffsetThreshold < EZInfiniteScrollingViewHeight  {\n                    self.state.value = .Pulling\n                }\n            }\n        }else if keyPath == \"contentSize\" && scrollView.contentSize.height >= scrollView.bounds.size.height && scrollView.showsInfiniteScrolling == false  {\n                scrollView.showsInfiniteScrolling = true // 当contentSize.height大于scrollView的高度时才显示上拉加载\n        }\n    }\n}\n\nprivate var InfiniteScrollingViewHandle :UInt8 = 1\nextension UIScrollView {\n    \n    public var infiniteScrollingView : EZInfiniteScrollingView? {\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &InfiniteScrollingViewHandle) {\n                return d as? EZInfiniteScrollingView\n            }else{\n                return nil\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &InfiniteScrollingViewHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    var showsInfiniteScrolling :Bool {\n        get{\n            return !self.infiniteScrollingView!.hidden\n        }set(value){\n            if value {\n                self.addObserver(self.infiniteScrollingView!, forKeyPath: \"contentOffset\", options:NSKeyValueObservingOptions.New, context: nil)\n                self.infiniteScrollingView?.hidden = false\n            }else if (self.infiniteScrollingView?.hidden == false){\n                self.removeObserver(self.infiniteScrollingView!, forKeyPath: \"contentOffset\")\n                self.infiniteScrollingView?.hidden = true\n            }\n        }\n    }\n    \n    public func addInfiniteScrollingWithActionHandler(customer:UIView? = nil,actionHandler:Void -> ()){\n        if self.infiniteScrollingView == nil {\n            let view = EZInfiniteScrollingView(frame: CGRectZero)\n            view.infiniteScrollingHandler = actionHandler\n            view.originalBottomInset = self.contentInset.bottom\n            view.hidden = true\n            self.infiniteScrollingView = view;\n            \n            self.addObserver(self.infiniteScrollingView!, forKeyPath: \"contentSize\", options:NSKeyValueObservingOptions.New, context: nil)\n            \n            self.addSubview(self.infiniteScrollingView!)\n        }\n        \n        if customer == nil {\n            self.infiniteScrollingView?.setCustomView(PullFooter(scrollView: self))\n        }else{\n            self.infiniteScrollingView?.setCustomView(customer!)\n        }\n    }\n    \n    public func triggerInfiniteScrolling(){\n        self.infiniteScrollingView?.oldState = .Triggered\n        self.infiniteScrollingView?.startAnimating()\n    }\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/PullRefresh/EZPullToRefresh.swift",
    "content": "//\n//  EZPullToRefresh.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/15.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\nlet EZPullToRefreshViewHeight:CGFloat = 60.0\n\npublic enum EZPullToRefreshState {\n    case Stopped\n    case Triggered\n    case Loading\n    case Pulling\n}\n\npublic class Header : UIView {\n    \n    init(scrollView:UIScrollView,frame: CGRect = CGRectZero) {\n        super.init(frame: frame)\n\n    }\n\n    required public init?(coder aDecoder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    public func resetScrollViewContentInset(scrollView:UIScrollView){\n        var currentInsets = scrollView.contentInset\n        currentInsets.top = scrollView.pullToRefreshView!.originalTopInset\n        self.setScrollViewContentInset(currentInsets, scrollView: scrollView)\n    }\n    \n    public func setScrollViewContentInsetForLoading(scrollView:UIScrollView){\n        let offset = max(EZPullToRefreshViewHeight, 0)\n        var currentInsets = scrollView.contentInset\n        currentInsets.top = max(offset, scrollView.pullToRefreshView!.originalTopInset + scrollView.pullToRefreshView!.bounds.size.height)\n        self.setScrollViewContentInset(currentInsets, scrollView: scrollView)\n    }\n    \n    public func setScrollViewContentInset(contentInset:UIEdgeInsets,scrollView:UIScrollView){\n        UIView.animateWithDuration(0.3, delay: 0,\n            options: UIViewAnimationOptions.BeginFromCurrentState,\n            animations: {\n            scrollView.contentInset = contentInset\n        },completion:nil)\n    }\n}\n\n\n\n\npublic class EZPullToRefreshView : UIView {\n    \n    public var state = Observable<EZPullToRefreshState>(.Stopped)\n    public var originalTopInset:CGFloat = 0.0\n    public var originalBottomInset:CGFloat = 0.0\n    public var originalOffset:CGFloat = 0.0\n    private var pullToRefreshActionHandler:(Void -> ())?\n    private var oldState = EZPullToRefreshState.Stopped\n    \n    private func commonInit(){\n        self.autoresizingMask = UIViewAutoresizing.FlexibleWidth\n        self.state.observe{ [unowned self] state in\n            if state == .Loading && self.oldState == .Triggered {\n                self.pullToRefreshActionHandler?()\n            }\n            self.oldState = state\n        }\n    }\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        self.commonInit()\n    }\n    \n    required public init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        self.commonInit()\n    }\n    \n    func setCustomView(customView:UIView){\n        if customView.isKindOfClass(UIView) {\n            for view in self.subviews {\n                view.removeFromSuperview()\n            }\n            self.addSubview(customView)\n            let viewBounds = customView.bounds;\n            let origin = CGPointMake(\n                CGFloat(roundf(Float(self.bounds.size.width-viewBounds.size.width)/2)),\n                CGFloat(roundf(Float(self.bounds.size.height-viewBounds.size.height)/2)))\n            customView.frame =  CGRectMake(origin.x, origin.y, viewBounds.size.width, viewBounds.size.height)\n        }\n    }\n    \n    public func startAnimating(){\n        self.state.value = .Loading\n    }\n\n    public func stopAnimating(){\n        self.state.value = .Stopped\n    }\n    \n    public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {\n        let scrollView = object as! UIScrollView\n        if keyPath == \"contentOffset\" && scrollView.showsPullToRefresh {\n            if self.state.value != .Loading{\n                let pullNum = scrollView.contentOffset.y + self.originalTopInset\n                if !scrollView.dragging && self.state.value == .Triggered {\n                    self.state.value = .Loading\n                }else if scrollView.dragging && self.state.value == .Pulling && pullNum < -EZPullToRefreshViewHeight {\n                    self.state.value = .Triggered\n                }else if pullNum <= -1 && pullNum > -EZPullToRefreshViewHeight {\n                    self.state.value = .Pulling\n                }else if pullNum > -1 {\n                    self.state.value = .Stopped\n                }\n            }\n        }\n    }\n}\n\nprivate var PullToRefreshViewHandle :UInt8 = 0\nextension UIScrollView {\n    \n    public var pullToRefreshView : EZPullToRefreshView? {\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &PullToRefreshViewHandle) {\n                return d as? EZPullToRefreshView\n            }else{\n                return nil\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &PullToRefreshViewHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    var showsPullToRefresh :Bool {\n        get{\n            return !self.pullToRefreshView!.hidden\n        }set(value){\n            if value {\n                self.addObserver(self.pullToRefreshView!, forKeyPath: \"contentOffset\", options:NSKeyValueObservingOptions.New, context: nil)\n                self.pullToRefreshView?.hidden = false\n            }else{\n                self.removeObserver(self.pullToRefreshView!, forKeyPath: \"contentOffset\")\n                self.pullToRefreshView?.hidden = true\n            }\n        }\n    }\n\n    public func addPullToRefreshWithActionHandler(customer:UIView? = nil,actionHandler:Void -> ()){\n        if self.pullToRefreshView == nil {\n            let view = EZPullToRefreshView(frame: CGRectZero)\n            view.pullToRefreshActionHandler = actionHandler\n            view.originalTopInset = self.contentInset.top;\n            view.originalBottomInset = self.contentInset.bottom;\n            self.pullToRefreshView = view;\n            self.showsPullToRefresh = true;\n            self.addSubview(self.pullToRefreshView!)\n        }\n        if customer == nil {\n            self.pullToRefreshView?.setCustomView(PullHeader(scrollView: self))\n        }else{\n            self.pullToRefreshView?.setCustomView(customer!)\n        }\n    }\n    \n    public func triggerPullToRefresh(){\n        self.pullToRefreshView?.oldState = .Triggered\n        self.pullToRefreshView?.startAnimating()\n    }\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/PullRefresh/PullFooter.swift",
    "content": "//\n//  PullFooter.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/16.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\npublic class PullFooter : Footer {\n    var arrowImage:UIImageView!\n    var activityView:UIActivityIndicatorView!\n    var statusLabel:UILabel!\n    \n    init (scrollView:UIScrollView){\n        super.init(\n            scrollView: scrollView,\n            frame: CGRectMake(0, 0, scrollView.superview!.size.width, EZInfiniteScrollingViewHeight))\n        self.commonInit()\n        \n        scrollView.infiniteScrollingView!.frame = CGRectMake(0,scrollView.contentSize.height, scrollView.superview!.size.width, EZInfiniteScrollingViewHeight)\n        scrollView.addObserver(self, forKeyPath: \"contentSize\", options: NSKeyValueObservingOptions.New, context: nil)\n        \n        \n        scrollView.infiniteScrollingView!.state.observe{state in\n            switch (state){\n            case .Ended:\n                self.arrowImage.hidden = true\n                self.activityView.stopAnimating()\n                self.statusLabel.text = \"没有了哦\"\n            case .Stopped:\n                UIView.animateWithDuration(0.25){ [unowned self] in\n                    self.resetScrollViewContentInset(scrollView)\n                    self.arrowImage.hidden = false\n                    self.activityView.stopAnimating()\n                    self.statusLabel.text = \"上拉加载\"\n                    self.arrowImage.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))\n                }\n            case .Pulling:\n                UIView.animateWithDuration(0.25){ [unowned self] in\n                    self.arrowImage.hidden = false\n                    self.activityView.stopAnimating();\n                    self.statusLabel.text = \"上拉加载\"\n                    self.arrowImage.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))\n                }\n            case .Triggered:\n                UIView.animateWithDuration(0.25){ [unowned self] in\n                    self.arrowImage.hidden = false;\n                    self.activityView.stopAnimating();\n                    self.statusLabel.text = \"释放加载\"\n                    self.arrowImage.transform = CGAffineTransformIdentity\n                }\n            case .Loading:\n                UIView.animateWithDuration(0.25){ [unowned self] in\n                    self.setScrollViewContentInsetForLoading(scrollView)\n                    self.arrowImage.hidden = true;\n                    self.activityView.startAnimating();\n                    self.statusLabel.text = \"正在加载...\"\n                }\n            }\n        }\n    }\n    \n    public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {\n        let scrollView = object as! UIScrollView\n        if keyPath == \"contentSize\" && scrollView.contentSize.height > scrollView.bounds.size.height && scrollView.bounds.size.height > 0  {\n            scrollView.infiniteScrollingView!.frame = CGRectMake(0, scrollView.contentSize.height, scrollView.superview!.size.width,EZInfiniteScrollingViewHeight)\n        }\n    }\n    \n    \n    required public init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        self.commonInit()\n    }\n    \n    func commonInit(){\n        let bundle = NSBundle(forClass: self.dynamicType)\n        let url = bundle.URLForResource(\"EasyIOS-Swift\", withExtension: \"bundle\")\n        let imageBundle = NSBundle(URL: url!)\n        if imageBundle?.loaded == false {\n            imageBundle?.load()\n        }\n        let arrow = UIImage(contentsOfFile: imageBundle!.pathForResource(\"arrow-down@2x\", ofType: \"png\")!)\n        \n        arrowImage = UIImageView(image: arrow)\n        arrowImage.autoresizingMask = [UIViewAutoresizing.FlexibleLeftMargin, UIViewAutoresizing.FlexibleRightMargin]\n        self.addSubview(arrowImage)\n        \n        activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)\n        activityView.autoresizingMask = arrowImage.autoresizingMask;\n        activityView.hidden = true\n        self.addSubview(activityView)\n        \n        statusLabel = UILabel()\n        statusLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth;\n        statusLabel.font = UIFont.boldSystemFontOfSize(13);\n        statusLabel.textColor = UIColor.blackColor();\n        statusLabel.backgroundColor = UIColor.clearColor();\n        statusLabel.textAlignment = NSTextAlignment.Center;\n        self.addSubview(statusLabel)\n        \n        arrowImage.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.centerY.equalTo(self.arrowImage.superview!)\n        }\n        activityView.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.edges.equalTo(self.arrowImage)\n        }\n        statusLabel.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.leading.equalTo(self.arrowImage).offset(30.0)\n            make.center.equalTo(self.statusLabel.superview!)\n        }\n    }\n\n}"
  },
  {
    "path": "Pod/Classes/Easy/Lib/PullRefresh/PullHeader.swift",
    "content": "//\n//  PullHeader.swift\n//  Demo\n//\n//  Created by zhuchao on 15/5/16.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport SnapKit\nimport Bond\n\npublic class PullHeader : Header {\n    var arrowImage:UIImageView!\n    var activityView:UIActivityIndicatorView!\n    var statusLabel:UILabel!\n    var lastUpdateTimeLabel:UILabel!\n    \n    init (scrollView:UIScrollView){\n        super.init(\n            scrollView: scrollView,\n            frame: CGRectMake(0, 0, scrollView.size.width, EZPullToRefreshViewHeight))\n        self.commonInit()\n        \n        scrollView.pullToRefreshView!.frame = CGRectMake(0, -EZPullToRefreshViewHeight, scrollView.superview!.size.width, EZPullToRefreshViewHeight)\n        \n        scrollView.pullToRefreshView!.state.observe{state in\n                switch (state){\n                case .Stopped:\n                    UIView.animateWithDuration(0.25){ [unowned self] in\n                        self.resetScrollViewContentInset(scrollView)\n                        self.arrowImage.hidden = false\n                        self.activityView.stopAnimating()\n                        self.statusLabel.text = \"下拉可以刷新\"\n                        self.arrowImage.transform = CGAffineTransformIdentity\n                        self.updateTimeLabel(NSDate())\n                    }\n                case .Pulling:\n                    UIView.animateWithDuration(0.25){ [unowned self] in\n                        self.arrowImage.hidden = false\n                        self.activityView.stopAnimating();\n                        self.statusLabel.text = \"下拉可以刷新\"\n                        self.arrowImage.transform = CGAffineTransformIdentity;\n                    }\n                case .Triggered:\n                    UIView.animateWithDuration(0.25){ [unowned self] in\n                        self.arrowImage.hidden = false;\n                        self.activityView.stopAnimating();\n                        self.statusLabel.text = \"释放可以刷新\"\n                        self.arrowImage.transform = CGAffineTransformMakeRotation(CGFloat(M_PI));\n                    }\n                case .Loading:\n                    UIView.animateWithDuration(0.25){ [unowned self] in\n                        self.setScrollViewContentInsetForLoading(scrollView)\n                        self.arrowImage.hidden = true;\n                        self.activityView.startAnimating();\n                        self.statusLabel.text = \"正在刷新...\"\n                    }\n                }\n        }\n    }\n    \n    required public init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        self.commonInit()\n    }\n    \n    func commonInit(){\n        \n        let bundle = NSBundle(forClass: self.dynamicType)\n        let url = bundle.URLForResource(\"EasyIOS-Swift\", withExtension: \"bundle\")\n        let imageBundle = NSBundle(URL: url!)\n        if imageBundle?.loaded == false {\n            imageBundle?.load()\n        }\n        let arrow = UIImage(contentsOfFile: imageBundle!.pathForResource(\"arrow-down@2x\", ofType: \"png\")!)\n        \n        arrowImage = UIImageView(image: arrow)\n        arrowImage.autoresizingMask = [UIViewAutoresizing.FlexibleLeftMargin, UIViewAutoresizing.FlexibleRightMargin]\n        self.addSubview(arrowImage)\n        \n        activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)\n        activityView.autoresizingMask = arrowImage.autoresizingMask;\n        activityView.hidden = true\n        self.addSubview(activityView)\n        \n        statusLabel = UILabel()\n        statusLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth;\n        statusLabel.font = UIFont.boldSystemFontOfSize(13);\n        statusLabel.textColor = UIColor.blackColor();\n        statusLabel.backgroundColor = UIColor.clearColor();\n        statusLabel.textAlignment = NSTextAlignment.Center;\n        self.addSubview(statusLabel)\n        \n        lastUpdateTimeLabel = UILabel()\n        lastUpdateTimeLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth;\n        lastUpdateTimeLabel.font = UIFont.boldSystemFontOfSize(12);\n        lastUpdateTimeLabel.textColor = UIColor.blackColor();\n        lastUpdateTimeLabel.backgroundColor = UIColor.clearColor();\n        lastUpdateTimeLabel.textAlignment = NSTextAlignment.Center;\n        self.updateTimeLabel(NSDate())\n        self.addSubview(lastUpdateTimeLabel)\n        \n        arrowImage.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.centerY.equalTo(self.arrowImage.superview!)\n        }\n        activityView.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.edges.equalTo(self.arrowImage)\n        }\n        statusLabel.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.top.equalTo(self.statusLabel.superview!).offset(10.0)\n            make.centerX.equalTo(self.statusLabel.superview!)\n        }\n        lastUpdateTimeLabel.snp_makeConstraints(){[unowned self] (make) -> Void in\n            make.bottom.equalTo(self.lastUpdateTimeLabel.superview!).offset(-15.0)\n            make.centerX.equalTo(self.lastUpdateTimeLabel.superview!)\n            make.leading.equalTo(self.arrowImage).offset(40)\n        }\n    }\n    \n    func updateTimeLabel(date:NSDate?){\n        if let aDate = date {\n            // 1.获得年月日\n            let calendar = NSCalendar.currentCalendar()\n            let unitFlags: NSCalendarUnit = [NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute]\n            \n            let cmp1 = calendar.components(unitFlags, fromDate: aDate)\n            let now = calendar.components(unitFlags, fromDate: NSDate())\n            \n            // 2.格式化日期\n            let formatter = NSDateFormatter()\n            if (cmp1.day == now.day) { // 今天\n                formatter.dateFormat = \"今天 HH:mm\";\n            } else if (cmp1.year == now.year) { // 今年\n                formatter.dateFormat = \"MM-dd HH:mm\";\n            } else {\n                formatter.dateFormat = \"yyyy-MM-dd HH:mm\";\n            }\n            // 3.显示日期\n            self.lastUpdateTimeLabel.text = \"最后更新：\" + formatter.stringFromDate(aDate)\n        }\n    }\n    \n    \n}"
  },
  {
    "path": "Pod/Classes/Extend/EUI/Defines.h",
    "content": "//\n// GTMDefines.h\n//\n//  Copyright 2008 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n//  use this file except in compliance with the License.  You may obtain a copy\n//  of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\n//  License for the specific language governing permissions and limitations under\n//  the License.\n//\n\n// ============================================================================\n\n#include <AvailabilityMacros.h>\n\n// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs\n#ifndef MAC_OS_X_VERSION_10_5\n#define MAC_OS_X_VERSION_10_5 1050\n#endif\n#ifndef MAC_OS_X_VERSION_10_6\n#define MAC_OS_X_VERSION_10_6 1060\n#endif\n\n// ----------------------------------------------------------------------------\n// CPP symbols that can be overridden in a prefix to control how the toolbox\n// is compiled.\n// ----------------------------------------------------------------------------\n\n\n// GTMHTTPFetcher will support logging by default but only hook its input\n// stream support for logging when requested.  You can control the inclusion of\n// the code by providing your own definitions for these w/in a prefix header.\n//\n#ifndef GTM_HTTPFETCHER_ENABLE_LOGGING\n#define GTM_HTTPFETCHER_ENABLE_LOGGING 1\n#endif // GTM_HTTPFETCHER_ENABLE_LOGGING\n#ifndef GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING\n#define GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 0\n#endif // GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING\n\n// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and\n// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens\n// when a validation fails. If you implement your own validators, you may want\n// to control their internals using the same macros for consistency.\n#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT\n#define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0\n#endif\n\n// Give ourselves a consistent way to do inlines.  Apple's macros even use\n// a few different actual definitions, so we're based off of the foundation\n// one.\n#if !defined(GTM_INLINE)\n#if defined (__GNUC__) && (__GNUC__ == 4)\n#define GTM_INLINE static __inline__ __attribute__((always_inline))\n#else\n#define GTM_INLINE static __inline__\n#endif\n#endif\n\n// Give ourselves a consistent way of doing externs that links up nicely\n// when mixing objc and objc++\n#if !defined (GTM_EXTERN)\n#if defined __cplusplus\n#define GTM_EXTERN extern \"C\"\n#else\n#define GTM_EXTERN extern\n#endif\n#endif\n\n// Give ourselves a consistent way of exporting things if we have visibility\n// set to hidden.\n#if !defined (GTM_EXPORT)\n#define GTM_EXPORT __attribute__((visibility(\"default\")))\n#endif\n\n// _GTMDevLog & _GTMDevAssert\n//\n// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for\n// developer level errors.  This implementation simply macros to NSLog/NSAssert.\n// It is not intended to be a general logging/reporting system.\n//\n// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert\n// for a little more background on the usage of these macros.\n//\n//    _GTMDevLog           log some error/problem in debug builds\n//    _GTMDevAssert        assert if conditon isn't met w/in a method/function\n//                           in all builds.\n//\n// To replace this system, just provide different macro definitions in your\n// prefix header.  Remember, any implementation you provide *must* be thread\n// safe since this could be called by anything in what ever situtation it has\n// been placed in.\n//\n\n// We only define the simple macros if nothing else has defined this.\n#ifndef _GTMDevLog\n\n#ifdef DEBUG\n#define _GTMDevLog(...) NSLog(__VA_ARGS__)\n#else\n#define _GTMDevLog(...) do { } while (0)\n#endif\n\n#endif // _GTMDevLog\n\n// Declared here so that it can easily be used for logging tracking if\n// necessary. See GTMUnitTestDevLog.h for details.\n@class NSString;\nGTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);\n\n#ifndef _GTMDevAssert\n// we directly invoke the NSAssert handler so we can pass on the varargs\n// (NSAssert doesn't have a macro we can use that takes varargs)\n#if !defined(NS_BLOCK_ASSERTIONS)\n#define _GTMDevAssert(condition, ...)                                       \\\ndo {                                                                      \\\n    if (!(condition)) {                                                     \\\n        [[NSAssertionHandler currentHandler]                                  \\\n         handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \\\n         file:[NSString stringWithUTF8String:__FILE__]  \\\n         lineNumber:__LINE__                                  \\\n         description:__VA_ARGS__];                             \\\n    }                                                                       \\\n} while(0)\n#else // !defined(NS_BLOCK_ASSERTIONS)\n#define _GTMDevAssert(condition, ...) do { } while (0)\n#endif // !defined(NS_BLOCK_ASSERTIONS)\n\n#endif // _GTMDevAssert\n\n// _GTMCompileAssert\n// _GTMCompileAssert is an assert that is meant to fire at compile time if you\n// want to check things at compile instead of runtime. For example if you\n// want to check that a wchar is 4 bytes instead of 2 you would use\n// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)\n// Note that the second \"arg\" is not in quotes, and must be a valid processor\n// symbol in it's own right (no spaces, punctuation etc).\n\n// Wrapping this in an #ifndef allows external groups to define their own\n// compile time assert scheme.\n#ifndef _GTMCompileAssert\n// We got this technique from here:\n// http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html\n\n#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg\n#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)\n#define _GTMCompileAssert(test, msg) \\\ntypedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]\n#endif // _GTMCompileAssert\n\n// Macro to allow fast enumeration when building for 10.5 or later, and\n// reliance on NSEnumerator for 10.4.  Remember, NSDictionary w/ FastEnumeration\n// does keys, so pick the right thing, nothing is done on the FastEnumeration\n// side to be sure you're getting what you wanted.\n#ifndef GTM_FOREACH_OBJECT\n#if defined(TARGET_OS_IPHONE) || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)\n#define GTM_FOREACH_OBJECT(element, collection) \\\nfor (element in collection)\n#define GTM_FOREACH_KEY(element, collection) \\\nfor (element in collection)\n#else\n#define GTM_FOREACH_OBJECT(element, collection) \\\nfor (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \\\n     (element = [_ ## element ## _enum nextObject]) != nil; )\n#define GTM_FOREACH_KEY(element, collection) \\\nfor (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \\\n     (element = [_ ## element ## _enum nextObject]) != nil; )\n#endif\n#endif\n\n// ============================================================================\n\n// ----------------------------------------------------------------------------\n// CPP symbols defined based on the project settings so the GTM code has\n// simple things to test against w/o scattering the knowledge of project\n// setting through all the code.\n// ----------------------------------------------------------------------------\n\n// Provide a single constant CPP symbol that all of GTM uses for ifdefing\n// iPhone code.\n#include <TargetConditionals.h>\n#if TARGET_OS_IPHONE // iPhone SDK\n// For iPhone specific stuff\n#define GTM_IPHONE_SDK 1\n#if TARGET_IPHONE_SIMULATOR\n#define GTM_IPHONE_SIMULATOR 1\n#else\n#define GTM_IPHONE_DEVICE 1\n#endif  // TARGET_IPHONE_SIMULATOR\n#else\n// For MacOS specific stuff\n#define GTM_MACOS_SDK 1\n#endif\n\n// Provide a symbol to include/exclude extra code for GC support.  (This mainly\n// just controls the inclusion of finalize methods).\n#ifndef GTM_SUPPORT_GC\n#if GTM_IPHONE_SDK\n// iPhone never needs GC\n#define GTM_SUPPORT_GC 0\n#else\n// We can't find a symbol to tell if GC is supported/required, so best we\n// do on Mac targets is include it if we're on 10.5 or later.\n#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4\n#define GTM_SUPPORT_GC 0\n#else\n#define GTM_SUPPORT_GC 1\n#endif\n#endif\n#endif\n\n// To simplify support for 64bit (and Leopard in general), we provide the type\n// defines for non Leopard SDKs\n#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4\n// NSInteger/NSUInteger and Max/Mins\n#ifndef NSINTEGER_DEFINED\n#if __LP64__ || NS_BUILD_32_LIKE_64\ntypedef long NSInteger;\ntypedef unsigned long NSUInteger;\n#else\ntypedef int NSInteger;\ntypedef unsigned int NSUInteger;\n#endif\n#define NSIntegerMax    LONG_MAX\n#define NSIntegerMin    LONG_MIN\n#define NSUIntegerMax   ULONG_MAX\n#define NSINTEGER_DEFINED 1\n#endif  // NSINTEGER_DEFINED\n// CGFloat\n#ifndef CGFLOAT_DEFINED\n#if defined(__LP64__) && __LP64__\n// This really is an untested path (64bit on Tiger?)\ntypedef double CGFloat;\n#define CGFLOAT_MIN DBL_MIN\n#define CGFLOAT_MAX DBL_MAX\n#define CGFLOAT_IS_DOUBLE 1\n#else /* !defined(__LP64__) || !__LP64__ */\ntypedef float CGFloat;\n#define CGFLOAT_MIN FLT_MIN\n#define CGFLOAT_MAX FLT_MAX\n#define CGFLOAT_IS_DOUBLE 0\n#endif /* !defined(__LP64__) || !__LP64__ */\n#define CGFLOAT_DEFINED 1\n#endif // CGFLOAT_DEFINED\n#endif  // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4"
  },
  {
    "path": "Pod/Classes/Extend/EUI/DesEncrypt.h",
    "content": "//\n//  DesEncrypt.h\n//  medical\n//\n//  Created by zhuchao on 15/5/4.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface DesEncrypt : NSObject\n+ (NSString *)encryptWithText:(NSString *)sText key:(NSString *)key;//加密\n+ (NSString *)decryptWithText:(NSString *)sText key:(NSString *)key;//解密\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/DesEncrypt.m",
    "content": "//\n//  DesEncrypt.m\n//  medical\n//\n//  Created by zhuchao on 15/5/4.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import \"DesEncrypt.h\"\n#import <CommonCrypto/CommonCrypto.h>\n@implementation DesEncrypt\n+ (NSString *)encryptWithText:(NSString *)sText key:(NSString *)key\n{\n    //kCCEncrypt 加密\n    return [self encrypt:sText encryptOrDecrypt:kCCEncrypt key:[NSString stringWithFormat:@\"%@\",key]];\n}\n\n+ (NSString *)decryptWithText:(NSString *)sText key:(NSString *)key\n{\n    //kCCDecrypt 解密\n    return [self encrypt:sText encryptOrDecrypt:kCCDecrypt key:[NSString stringWithFormat:@\"%@\",key]];\n}\n\n+ (NSString *)encrypt:(NSString *)sText encryptOrDecrypt:(CCOperation)encryptOperation key:(NSString *)key\n{\n    const void *dataIn;\n    size_t dataInLength;\n    \n    if (encryptOperation == kCCDecrypt)//传递过来的是decrypt 解码\n    {\n        //解码 base64\n//        [[sText dataUsingEncoding:NSUTF8StringEncoding] base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength]\n        \n        NSData *decryptData = [[NSData alloc]initWithBase64EncodedString:sText options:NSDataBase64DecodingIgnoreUnknownCharacters];//转成utf-8并decode\n        dataInLength = [decryptData length];\n        dataIn = [decryptData bytes];\n    }\n    else  //encrypt\n    {\n        NSData* encryptData = [sText dataUsingEncoding:NSUTF8StringEncoding];\n        dataInLength = [encryptData length];\n        dataIn = (const void *)[encryptData bytes];\n    }\n    \n    /*\n     DES加密 ：用CCCrypt函数加密一下，然后用base64编码下，传过去\n     DES解密 ：把收到的数据根据base64，decode一下，然后再用CCCrypt函数解密，得到原本的数据\n     */\n    CCCryptorStatus ccStatus;\n    uint8_t *dataOut = NULL; //可以理解位type/typedef 的缩写（有效的维护了代码，比如：一个人用int，一个人用long。最好用typedef来定义）\n    size_t dataOutAvailable = 0; //size_t  是操作符sizeof返回的结果类型\n    size_t dataOutMoved = 0;\n    \n    dataOutAvailable = (dataInLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);\n    dataOut = malloc( dataOutAvailable * sizeof(uint8_t));\n    memset((void *)dataOut, 0x0, dataOutAvailable);//将已开辟内存空间buffer的首 1 个字节的值设为值 0\n    \n    NSString *initIv = @\"12345678\";\n    const void *vkey = (const void *) [key UTF8String];\n    const void *iv = (const void *) [initIv UTF8String];\n    \n    //CCCrypt函数 加密/解密\n    ccStatus = CCCrypt(encryptOperation,//  加密/解密\n                       kCCAlgorithmDES,//  加密根据哪个标准（des，3des，aes。。。。）\n                       kCCOptionPKCS7Padding,//  选项分组密码算法(des:对每块分组加一次密  3DES：对每块分组加三个不同的密)\n                       vkey,  //密钥    加密和解密的密钥必须一致\n                       kCCKeySizeDES,//   DES 密钥的大小（kCCKeySizeDES=8）\n                       iv, //  可选的初始矢量\n                       dataIn, // 数据的存储单元\n                       dataInLength,// 数据的大小\n                       (void *)dataOut,// 用于返回数据\n                       dataOutAvailable,\n                       &dataOutMoved);\n    \n    NSString *result = nil;\n    \n    if (encryptOperation == kCCDecrypt)//encryptOperation==1  解码\n    {\n        //得到解密出来的data数据，改变为utf-8的字符串\n        result = [[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)dataOut length:(NSUInteger)dataOutMoved] encoding:NSUTF8StringEncoding];\n    }\n    else //encryptOperation==0  （加密过程中，把加好密的数据转成base64的）\n    {\n        //编码 base64\n        NSData *data = [NSData dataWithBytes:(const void *)dataOut length:(NSUInteger)dataOutMoved];\n        result = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];\n    }\n    \n    return result;\n}\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/ENSObject.swift",
    "content": "//\n//  ENSObject.swift\n//  Pods\n//\n//  Created by zhuchao on 15/7/21.\n//\n//\n\nimport Foundation\nimport JavaScriptCore\n\n@objc public protocol ENSObject:JSExport{\n    func val(keyPath:String) -> AnyObject?\n    func attr(keyPath:String,_ value:AnyObject?)\n    func attrs(dict:[NSObject : AnyObject]!)\n    func call(selector:String)\n    func call(selector:String,withObject object:AnyObject?)\n}\n\npublic extension NSObject{\n    \n    public func call(selector:String){\n        NSThread.detachNewThreadSelector(Selector(selector), toTarget:self, withObject: nil)\n    }\n    \n    public func call(selector:String,withObject object:AnyObject?){\n        NSThread.detachNewThreadSelector(Selector(selector), toTarget:self, withObject: object)\n    }\n    \n    public func attr(key:String,_ value:AnyObject?) {\n        SwiftTryCatch.`try`({\n            if let str = value as? String {\n                self.setValue(str.anyValue(key.toKeyPath), forKeyPath: key.toKeyPath)\n            }else{\n                self.setValue(value, forKeyPath: key.toKeyPath)\n            }\n        }, `catch`: { (error) in\n            print(\"JS Error:\\(error.description)\")\n        }, finally: nil)\n    }\n    \n    public func attrs(var dict:[String : AnyObject]!){\n        SwiftTryCatch.`try`({\n            for (key, value) in dict {\n                if let str = value as? String {\n                    dict[key.toKeyPath] = str.anyValue(key.toKeyPath)\n                }\n            }\n            self.setValuesForKeysWithDictionary(dict)\n        }, `catch`: { (error) in\n            print(\"JS Error:\\(error.description)\")\n        }, finally: nil)\n    }\n    \n    public func val(key:String) -> AnyObject? {\n        var result:AnyObject?\n        SwiftTryCatch.`try`({\n            result = self.valueForKeyPath(key.toKeyPath)\n            }, `catch`: { (error) in\n                print(\"JS Error:\\(error.description)\")\n            }, finally: nil)\n        return result\n    }\n}\n\n@objc public protocol EZActionJSExport:JSExport{\n    static func SEND_IQ_CACHE (req:EZRequest)\n    static func SEND_CACHE (req:EZRequest)\n    static func SEND (req:EZRequest)\n    static func Upload (req:EZRequest)\n    static func Download (req:EZRequest)\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+ButtonProperty.swift",
    "content": "//\n//  EUI+ButtonProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nclass ButtonProperty:ViewProperty{\n    \n    var highlightedStyle = \"\"\n    var disabledStyle = \"\"\n    var selectedStyle = \"\"\n    var applicationStyle = \"\"\n    var reservedStyle = \"\"\n    \n    var highlightedText:String?\n    var disabledText:String?\n    var selectedText:String?\n    var applicationText:String?\n    var reservedText:String?\n    var onEvent:SelectorAction?\n    \n    override func view() -> UIButton{\n        let view = UIButton()\n        view.tagProperty = self\n        \n        if self.style != \"\" {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.contentText?.toData(), attributes: [\"html\":self.style]), forState: UIControlState.Normal)\n        }\n        \n        if self.highlightedText != nil {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.highlightedText?.toData(), attributes: [\"html\":self.highlightedStyle]), forState: UIControlState.Highlighted)\n        }\n        \n        if self.disabledText != nil {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.disabledText?.toData(), attributes: [\"html\":self.disabledStyle]), forState: UIControlState.Disabled)\n        }\n        \n        if self.selectedText != nil {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.selectedText?.toData(), attributes: [\"html\":self.selectedStyle]), forState: UIControlState.Selected)\n        }\n        \n        if self.applicationText != nil {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.applicationText?.toData(), attributes: [\"html\":self.applicationStyle]), forState: UIControlState.Application)\n        }\n        \n        if self.reservedText != nil {\n            view.setAttributedTitle(NSAttributedString(fromHTMLData: self.reservedText?.toData(), attributes: [\"html\":self.reservedStyle]), forState: UIControlState.Reserved)\n        }\n\n        self.renderViewStyle(view)\n        return view\n    }\n    \n    override func renderTag(pelement: OGElement) {\n       \n        self.tagOut += [\"highlighted\",\"disabled\",\"selected\",\"application\",\"reserved\",\"disabled-text\",\n        \"selected-text\",\"application-text\",\"reserved-text\",\"highlighted-text\",\"onevent\"]\n        \n        super.renderTag(pelement)\n        \n        if let highlightedStyle = EUIParse.string(pelement,key: \"highlighted\") {\n            self.highlightedStyle = \"html{\" + highlightedStyle + \"}\"\n        }\n        \n        if let disabledStyle = EUIParse.string(pelement,key: \"disabled\") {\n            self.disabledStyle = \"html{\" + disabledStyle + \"}\"\n        }\n        \n        if let selectedStyle = EUIParse.string(pelement,key: \"selected\") {\n            self.selectedStyle = \"html{\" + selectedStyle + \"}\"\n        }\n        \n        if let applicationStyle = EUIParse.string(pelement,key: \"application\") {\n            self.applicationStyle = \"html{\" + applicationStyle + \"}\"\n        }\n        \n        if let reservedStyle = EUIParse.string(pelement,key: \"reserved\") {\n            self.reservedStyle = \"html{\" + reservedStyle + \"}\"\n        }\n\n        \n        self.disabledText = EUIParse.string(pelement,key: \"disabled-text\")\n        self.selectedText = EUIParse.string(pelement,key: \"selected-text\")\n        self.applicationText = EUIParse.string(pelement,key: \"application-text\")\n        self.reservedText = EUIParse.string(pelement,key: \"reserved-text\")\n        self.highlightedText = EUIParse.string(pelement,key: \"highlighted-text\")\n        \n        if let theSelector = EUIParse.string(pelement, key: \"onevent\") {\n            var values = theSelector.trimArrayBy(\":\")\n            if values.count == 2 {\n                self.onEvent = SelectorAction(selector: values[1], event: values[0])\n            }\n        }\n        \n        var html = \"\"\n        for child in pelement.children\n        {\n            html += child.html().trim\n        }\n        if let newHtml = self.bindTheKeyPath(html, key: \"text\") {\n            html = newHtml\n        }\n        self.contentText = html\n    }\n\n\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+CollectionViewProperty.swift",
    "content": "//\n//  EUI+CollectionViewProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/10.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport Bond\n\nclass CollectionViewProperty: ScrollViewProperty {\n    var separatorInset:UIEdgeInsets?\n    var reuseCell = Dictionary<String,ViewProperty>()\n    var flowLayout = Dictionary<String,String>()\n    var layout:String?\n    \n    override func view() -> UICollectionView{\n        let view = UICollectionView(frame: CGRectZero, collectionViewLayout: self.getLayout())\n        view.tagProperty = self\n        \n        self.renderViewStyle(view)\n        for (reuseId,_) in self.reuseCell {\n            view.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseId)\n        }\n        return view\n    }\n    \n    override func renderTag(pelement:OGElement){\n        self.tagOut += [\"delegate\",\"datasource\",\"flow-layout\",\"layout\"]\n        \n        super.renderTag(pelement)\n        if let layout = EUIParse.string(pelement, key: \"flow-layout\") {\n            let dict = layout.trimArrayBy(\";\")\n            for value in dict {\n                var array = value.trimArrayBy(\":\")\n                let key = array[0] as String\n                let val = array[1] as String\n                self.flowLayout[key.toKeyPath] = val\n            }\n        }\n        self.layout = EUIParse.string(pelement, key: \"layout\")\n    }\n\n    func getLayout() -> UICollectionViewLayout{\n        if let customlayout = self.layout,let nsobject = NSObject(fromString: customlayout) as? UICollectionViewLayout {\n            return nsobject\n        }\n        \n        let layout = UICollectionViewFlowLayout()\n        for (key,value) in self.flowLayout{\n            if key == \"minimumLineSpacing\" || key == \"minimumInteritemSpacing\"{\n                layout.setValue(value.floatValue, forKeyPath: key)\n            }else if key == \"itemSize\" {\n                layout.itemSize = CGSizeFromString(value)\n            }else if key == \"estimatedItemSize\" {\n                layout.estimatedItemSize = CGSizeFromString(value)\n            }else if key == \"headerReferenceSize\" {\n                layout.headerReferenceSize = CGSizeFromString(value)\n            }else if key == \"footerReferenceSize\"{\n                layout.footerReferenceSize = CGSizeFromString(value)\n            }else if key == \"sectionInset\" {\n                layout.sectionInset = UIEdgeInsetsFromString(value)\n            }else if key == \"scrollDirection\" {\n                if value.lowercaseString == \"Vertical\".lowercaseString {\n                    layout.scrollDirection = .Vertical\n                }else if value.lowercaseString == \"Horizontal\".lowercaseString {\n                    layout.scrollDirection = .Horizontal\n                }\n            }\n        }\n        return layout\n    }\n    \n    override func childLoop(pelement: OGElement) {\n        for element in pelement.children {\n            if let ele = element as? OGElement,\n                let type = EUIParse.string(ele, key: \"type\"),\n                let tagId = EUIParse.string(ele, key: \"id\"),\n                let property = EUIParse.loopElement(ele){\n                if type.lowercaseString == \"cell\"  {\n                    self.reuseCell[tagId] = property\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+ImageProperty.swift",
    "content": "//\n//  EUI+ImageProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nclass ImageProperty:ViewProperty{\n    var src = \"\"\n    override func view() -> UIImageView{\n        let view = UIImageView()\n        view.tagProperty = self\n        if !self.src.characters.isEmpty {\n            if self.src.hasPrefix(\"http\") {\n                view.kf_setImageWithURL(NSURL(string: self.src)!)\n            }else{\n                view.image = UIImage(named: self.src)\n            }\n        }\n        self.renderViewStyle(view)\n        for subTag in self.subTags {\n            view.addSubview(subTag.getView())\n        }\n        return view\n    }\n    \n    override func renderTag(pelement:OGElement){\n        self.tagOut += [\"src\"]\n        \n        super.renderTag(pelement)\n        if let src = EUIParse.string(pelement,key:\"src\"),let filterHtml = self.bindTheKeyPath(src, key: \"src\") {\n            self.src = filterHtml\n        }\n        \n    }\n    \n    override func childLoop(pelement: OGElement) {\n        \n    }\n\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+LabelProperty.swift",
    "content": "//\n//  EUI+LabelProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport JavaScriptCore\nimport TTTAttributedLabel\n\nclass LabelProperty:ViewProperty{\n    var linkStyle = Dictionary<NSObject,AnyObject>()\n    var activeLinkStyle = Dictionary<NSObject,AnyObject>()\n    var textAlignment:NSTextAlignment = .Left\n    \n    override func view() -> UIView{\n        if self.style.characters.isEmpty {\n            let view = UILabel()\n            view.tagProperty = self\n            view.text = self.contentText\n            self.renderViewStyle(view)\n            return view\n        }else{\n            let view = TTTAttributedLabel(frame: CGRectZero)\n            view.tagProperty = self\n            if self.linkStyle.count > 0 {\n                view.linkAttributes = self.linkStyle\n            }\n            if self.activeLinkStyle.count > 0 {\n                view.activeLinkAttributes = self.activeLinkStyle\n            }\n            view.setText(NSAttributedString(fromHTMLData: self.contentText?.toData(), attributes: [\"dict\":self.style]))\n            self.renderViewStyle(view)\n            return view\n        }\n    }\n    \n    override func renderTag(pelement: OGElement) {\n        \n        self.tagOut += [\"link-style\",\"active-link-style\",\"text-alignment\"]\n        super.renderTag(pelement)\n        \n        if let textAlignment = EUIParse.string(pelement,key:\"text-alignment\") {\n            self.textAlignment = textAlignment.textAlignment\n        }\n        \n        if let linkStyle = EUIParse.string(pelement,key:\"link-style\") {\n            self.linkStyle = linkStyle.linkStyleDict\n        }\n        \n        if let linkStyle = EUIParse.string(pelement,key:\"active-link-style\") {\n            self.activeLinkStyle = linkStyle.linkStyleDict\n        }\n        \n        var html = \"\"\n        for child in pelement.children\n        {\n            html += child.html().trim\n        }\n        var bindKey = \"text\"\n        if !self.style.characters.isEmpty {\n            bindKey = \"TTText\"\n        }\n        if let newHtml = self.bindTheKeyPath(html, key: bindKey) {\n            html = newHtml\n        }\n        self.contentText = html\n    }\n    \n    override func childLoop(pelement: OGElement) {\n        \n    }\n    \n    override func renderViewStyle(view:UIView){\n        super.renderViewStyle(view)\n        let sview = view as! UILabel\n        sview.textAlignment = self.textAlignment\n    }\n\n}"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+ScrollViewProperty.swift",
    "content": "//\n//  EUI+ScrollViewProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/2.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nclass ScrollViewProperty:ViewProperty{\n    var contentInset = UIEdgeInsetsZero\n    var contentOffset = CGPointZero\n    var contentSize = CGSizeZero\n    var scrollIndicatorInsets = UIEdgeInsetsZero\n    var indicatorStyle:UIScrollViewIndicatorStyle = .Default\n    var pullToRefresh:PullRefreshAction?\n    var infiniteScrolling:InfiniteScrollingAction?\n    \n    override func view() -> UIScrollView{\n        let view = UIScrollView()\n        view.tagProperty = self\n\n        self.renderViewStyle(view)\n        for subTag in self.subTags {\n            view.addSubview(subTag.getView())\n        }\n        return view\n    }\n    \n\n    override func renderViewStyle(view: UIView) {\n        super.renderViewStyle(view)\n        let sview = view as! UIScrollView\n        sview.contentInset = self.contentInset\n        sview.contentOffset =  self.contentOffset\n        sview.contentSize = self.contentSize\n        sview.scrollIndicatorInsets = self.scrollIndicatorInsets\n        sview.indicatorStyle = self.indicatorStyle\n    }\n    \n    override func renderTag(pelement:OGElement){\n        self.tagOut += [\"content-offset\",\"content-inset\",\"content-size\",\"scroll-indicator-insets\",\"indicator-style\",\"pull-to-refresh\",\"infinite-scrolling\"]\n        \n        super.renderTag(pelement)\n        if let contentInset = EUIParse.string(pelement,key:\"content-inset\") {\n            self.contentInset = UIEdgeInsetsFromString(contentInset)\n        }\n        if let contentOffset = EUIParse.string(pelement,key:\"content-offset\") {\n            self.contentOffset = CGPointFromString(contentOffset)\n        }\n        \n        if let contentSize = EUIParse.string(pelement,key:\"content-size\") {\n            self.contentSize = CGSizeFromString(contentSize)\n        }\n        \n        if let indicatorStyle = EUIParse.string(pelement,key:\"indicator-style\") {\n            self.indicatorStyle = indicatorStyle.scrollViewIndicatorStyle\n        }\n        \n        if let scrollIndicatorInsets = EUIParse.string(pelement,key:\"scroll-indicator-insets\") {\n            self.scrollIndicatorInsets = UIEdgeInsetsFromString(scrollIndicatorInsets)\n        }\n        \n        if let thePullRefresh = EUIParse.string(pelement, key: \"pull-to-refresh\") {\n            var values = thePullRefresh.trimArray\n            if values.count == 1 {\n                self.pullToRefresh = PullRefreshAction(selector: values[0])\n            }else if values.count == 2 {\n                self.pullToRefresh = PullRefreshAction(selector: values[0], viewClass: values[1])\n            }\n        }\n        \n        if let theInfiniteScrolling = EUIParse.string(pelement, key: \"infinite-scrolling\") {\n            var values = theInfiniteScrolling.trimArray\n            if values.count == 1 {\n                self.infiniteScrolling = InfiniteScrollingAction(selector: values[0])\n            }else if values.count == 2 {\n                self.infiniteScrolling = InfiniteScrollingAction(selector: values[0], viewClass: values[1])\n            }\n        }\n        \n    }\n\n}"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+TableViewProperty.swift",
    "content": "//\n//  EUI+TableViewProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/2.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\nimport Bond\n\nclass TableViewProperty:ScrollViewProperty{\n    var tableViewStyle = UITableViewStyle.Plain\n    var separatorInset:UIEdgeInsets?\n    var rowHeight = UITableViewAutomaticDimension\n    \n    var reuseCell = Dictionary<String,ViewProperty>()\n    var sectionView = Dictionary<String,ViewProperty>()\n    var separatorStyle = UITableViewCellSeparatorStyle.SingleLine\n\n    override func view() -> UITableView{\n        let view = UITableView(frame: CGRectZero, style: self.tableViewStyle)\n        view.tagProperty = self\n        view.rowHeight = self.rowHeight\n        view.separatorStyle = self.separatorStyle;\n        \n        if let inset = self.separatorInset {\n            view.separatorInset = inset;\n        }\n\n        self.renderViewStyle(view)\n        for (reuseId,_) in self.reuseCell {\n            view.registerClass(UITableViewCell.self, forCellReuseIdentifier: reuseId)\n        }\n        return view\n    }\n    \n\n    override func renderTag(pelement:OGElement){\n        self.tagOut += [\"table-view-style\",\"separator-inset\",\"delegate\",\"datasource\",\"row-height\",\"separator-style\"]\n        \n        super.renderTag(pelement)\n        if let style = EUIParse.string(pelement,key:\"table-view-style\") {\n            self.tableViewStyle = style.tableViewStyle\n        }\n\n        if let rowHeight = EUIParse.string(pelement, key: \"row-height\") {\n            self.rowHeight = rowHeight.floatValue\n        }\n        \n        if let separatorInset = EUIParse.string(pelement,key:\"separator-inset\") {\n            self.separatorInset = UIEdgeInsetsFromString(separatorInset)\n        }\n        \n        if let separatorStyle = EUIParse.string(pelement, key: \"separator-style\") {\n            self.separatorStyle = separatorStyle.separatorStyle\n        }\n    }\n    \n    override func childLoop(pelement: OGElement) {\n        for element in pelement.children {\n            if let ele = element as? OGElement,\n                let type = EUIParse.string(ele, key: \"type\"),\n                let tagId = EUIParse.string(ele, key: \"id\"),\n                let property = EUIParse.loopElement(ele){\n                    \n                if type.lowercaseString == \"cell\" || type.lowercaseString == \"UITableViewCell\" {\n                    self.reuseCell[tagId] = property\n                }else if type.lowercaseString == \"section\" || type.lowercaseString == \"UITableViewSection\"{\n                    self.sectionView[tagId] = property\n                }\n            }\n        }\n    }\n    \n}"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+TextFieldProperty.swift",
    "content": "//\n//  EUI+TextFieldProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\nclass TextFieldProperty:ViewProperty{\n    var placeholder:NSData?\n    var placeholderStyle = \"\"\n    var text:NSData?\n    var keyboardType = UIKeyboardType.Default\n    \n    override func view() -> UITextField{\n        let view = UITextField()\n        view.tagProperty = self\n        view.keyboardType = self.keyboardType\n        \n        let str = NSAttributedString(fromHTMLData:self.text, attributes: [\"html\":self.style])\n        view.defaultTextAttributes = str.attributesAtIndex(0, effectiveRange:nil)\n        view.attributedPlaceholder = NSAttributedString(fromHTMLData: self.placeholder, attributes: [\"html\":self.placeholderStyle])\n        \n        self.renderViewStyle(view)\n        return view\n    }\n    \n    override func renderTag(pelement: OGElement) {\n        self.tagOut += [\"placeholder\",\"placeholder-style\",\"text\",\"keyboard-type\"]\n        \n        super.renderTag(pelement)\n        if let text = EUIParse.string(pelement, key: \"text\"),\n           let newHtml = Regex(\"\\\\{\\\\{(\\\\w+)\\\\}\\\\}\").replace(text, withBlock: { (regx) -> String in\n                let keyPath = regx.subgroupMatchAtIndex(0)?.trim\n                self.bind[\"text\"] = keyPath\n                return \"\"\n            }) {\n            self.contentText = newHtml\n        }\n        \n        self.text = \"1\".dataUsingEncoding(NSUTF8StringEncoding)?.dataByReplacingOccurrencesOfData(\"\\\\n\".dataUsingEncoding(NSUTF8StringEncoding), withData: \"\\n\".dataUsingEncoding(NSUTF8StringEncoding))\n        \n        if let placeholderStyle = EUIParse.string(pelement,key: \"placeholder-style\") {\n            self.placeholderStyle = \"html{\" + placeholderStyle + \"}\"\n        }\n        if let placeholder = EUIParse.string(pelement,key: \"placeholder\") {\n            self.placeholder = placeholder.dataUsingEncoding(NSUTF8StringEncoding)?.dataByReplacingOccurrencesOfData(\"\\\\n\".dataUsingEncoding(NSUTF8StringEncoding), withData: \"\\n\".dataUsingEncoding(NSUTF8StringEncoding))\n        }\n        \n        if let keyboardType = EUIParse.string(pelement, key: \"keyboard-type\") {\n            self.keyboardType = keyboardType.keyboardType\n        }\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI+ViewProperty.swift",
    "content": "//\n//  EUI+ViewProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/2.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport Foundation\n\n\nclass ViewProperty :NSObject{\n    \n    var tag:GumboTag?\n    var tagId = \"\"\n    var style = \"\"\n    var type = \"\"\n    var subTags = Array<ViewProperty>()\n    var otherProperty = Dictionary<String,AnyObject>()\n    var tagOut = Array<String>()\n    var imageMode = UIViewContentMode.ScaleAspectFill\n    var align = Array<Constrain>()\n    var margin = Array<Constrain>()\n    var width:Constrain?\n    var height:Constrain?\n    var onTap:TapGestureAction?\n    var onSwipe:SwipeGestureAction?\n    var onTapBind:TapGestureAction?\n    var onSwipeBind:SwipeGestureAction?\n    var frame:CGRect?\n    var bind = Dictionary<String,String>()\n    var contentText:String?\n    var flexEnable = false\n    \n    var flexDirection:FLEXBOXFlexDirection = .Column\n    var flexContentDirection:FLEXBOXContentDirection = .LeftToRight\n    var flexJustifyContent:FLEXBOXJustification = .FlexStart\n    var flexAlignSelf:FLEXBOXAlignment = .Auto\n    var flexAlignItems:FLEXBOXAlignment = .Stretch\n    \n    var flexMargin = UIEdgeInsetsZero\n    var flexPadding = UIEdgeInsetsZero\n    var flexWrap = false\n    var flex:CGFloat = 0.0\n    var flexFixedSize = CGSizeZero\n    var flexMinimumSize = CGSizeZero\n    var flexMaximumSize = CGSizeMake(CGFloat.max, CGFloat.max)\n    \n    \n    func getView() -> UIView{\n        if self.tag == nil {\n            return UIView()\n        }\n        return self.view()\n    }\n    \n    func view() -> UIView{\n        if(flexEnable){\n            let view = FLEXBOXContainerView()\n            view.tagProperty = self\n            self.renderViewStyle(view)\n            for subTag in self.subTags {\n                view.addSubview(subTag.getView())\n            }\n            return view\n        }else{\n            let view = UIView()\n            view.tagProperty = self\n            self.renderViewStyle(view)\n            for subTag in self.subTags {\n                view.addSubview(subTag.getView())\n            }\n            return view\n        }\n    }\n    \n    func renderTag(pelement:OGElement){\n        self.tagOut += [\"id\",\"style\",\"align\",\"margin\",\"type\",\"image-mode\",\"name\",\"width\",\"height\",\"class\",\"ontap\",\"onswipe\",\"ontap-bind\",\"onswipe-bind\",\"frame\",\"reuseid\",\"push\",\"present\",\"align-self\",\"align-items\",\"justify-content\",\"flex-direction\",\"content-direction\",\"flex-margin\",\"flex-padding\",\"flex-wrap\",\"flex\",\"flex-minimum-size\"]\n        \n        self.tag = pelement.tag\n        \n        if let flexMinimumSize = EUIParse.string(pelement, key: \"flex-minimum-size\"){\n            self.flexEnable = true\n            self.flexMinimumSize = CGSizeFromString(flexMinimumSize)\n        }\n        \n        if let flexMaximumSize = EUIParse.string(pelement, key: \"flex-maximum-size\"){\n            self.flexEnable = true\n            self.flexMaximumSize = CGSizeFromString(flexMaximumSize)\n        }\n        \n        if let flexFixedSize = EUIParse.string(pelement, key: \"flex-fixed-size\"){\n            self.flexEnable = true\n            self.flexFixedSize = CGSizeFromString(flexFixedSize)\n        }\n        \n        if let flexMargin = EUIParse.string(pelement, key: \"flex-margin\"){\n            self.flexEnable = true\n            self.flexMargin = UIEdgeInsetsFromString(flexMargin)\n        }\n        if let flexPadding = EUIParse.string(pelement, key: \"flex-padding\"){\n            self.flexEnable = true\n            self.flexPadding = UIEdgeInsetsFromString(flexPadding)\n        }\n        if let flexWrap = EUIParse.string(pelement, key: \"flex-wrap\"){\n            self.flexEnable = true\n            self.flexWrap = flexWrap.boolValue\n        }\n        if let flex = EUIParse.string(pelement, key: \"flex\"){\n            self.flexEnable = true\n            self.flex = flex.floatValue\n        }\n        \n        if let alignSelf = EUIParse.string(pelement, key: \"align-self\"){\n            self.flexEnable = true\n            self.flexAlignSelf = alignSelf.alignItems\n        }\n        if let alignItems = EUIParse.string(pelement, key: \"align-items\"){\n            self.flexEnable = true\n            self.flexAlignItems = alignItems.alignItems\n        }\n        if let justifyContent = EUIParse.string(pelement, key: \"justify-content\"){\n            self.flexEnable = true\n            self.flexJustifyContent = justifyContent.justifyContent\n        }\n        if let flexDirection = EUIParse.string(pelement, key: \"flex-direction\"){\n            self.flexEnable = true\n            self.flexDirection = flexDirection.flexDirection\n        }\n        if let contentDirection = EUIParse.string(pelement, key: \"content-direction\"){\n            self.flexEnable = true\n            self.flexContentDirection = contentDirection.flexContentDirection\n        }\n        \n        if let tagId = EUIParse.string(pelement,key:\"id\") {\n            self.tagId = tagId\n        }\n      \n        if let style = EUIParse.string(pelement,key:\"style\") {\n            self.style = \"html{\" + style + \"}\"\n        }\n        \n        if let theAlign = EUIParse.getStyleProperty(pelement,key: \"align\") {\n            self.align = theAlign\n        }\n        \n        if let theMargin = EUIParse.getStyleProperty(pelement,key: \"margin\") {\n            self.margin = theMargin\n        }\n        \n        if let theWidth = EUIParse.string(pelement,key:\"width\") {\n            var values = theWidth.trimArray\n            if values.count == 1 {\n                if values[0].hasSuffix(\"%\") {\n                    var val = values[0]\n                    val.removeAtIndex(val.startIndex.advancedBy(val.characters.count - 1))\n                    self.width = Constrain(name:.Width,value: CGFloat(val.floatValue/100))\n                }else{\n                    self.width = Constrain(name:.Width,value: CGFloat(values[0].trim.floatValue),target:\"\")\n                }\n            }else if values.count >= 2 && values[0].trim.hasSuffix(\"%\"){\n                var val = values[0].trim\n                val.removeAtIndex(val.startIndex.advancedBy(val.characters.count - 1))\n                self.width = Constrain(name:.Width,value: CGFloat(val.floatValue/100),target:values[1].trim)\n            }\n        }\n        \n        if let theHeight = EUIParse.string(pelement,key:\"height\") {\n            var values = theHeight.trimArray\n            if values.count == 1 {\n                if values[0].hasSuffix(\"%\") {\n                    var val = values[0]\n                    val.removeAtIndex(val.startIndex.advancedBy(val.characters.count - 1))\n                    self.height = Constrain(name:.Height,value: CGFloat(val.floatValue/100))\n                }else{\n                    self.height = Constrain(name:.Height,value: CGFloat(values[0].trim.floatValue),target:\"\")\n                }\n            }else if values.count >= 2 && values[0].trim.hasSuffix(\"%\"){\n                var val = values[0].trim\n                val.removeAtIndex(val.startIndex.advancedBy(val.characters.count - 1))\n                self.height = Constrain(name:.Height,value: CGFloat(val.floatValue/100),target:values[1].trim)\n            }\n        }\n        \n        if let frame = EUIParse.string(pelement, key: \"frame\") {\n            self.frame = CGRectFromString(frame)\n        }\n        \n        if let theType = EUIParse.string(pelement,key:\"type\") {\n            self.type = theType\n        }\n        \n        if let theImageMode = EUIParse.string(pelement,key:\"image-mode\") {\n            self.imageMode = theImageMode.viewContentMode\n        }\n        \n        if let theGestureAction = EUIParse.string(pelement, key: \"ontap\") {\n            var values = theGestureAction.trimArray\n            if values.count == 1 {\n                self.onTap = TapGestureAction(selector: values[0])\n            }else if values.count >= 2 {\n                self.onTap = TapGestureAction(selector: values[0], tapNumber: values[1])\n            }\n        }\n        \n        if let theGestureAction = EUIParse.string(pelement, key: \"onswipe\") {\n            var values = theGestureAction.trimArray\n            if values.count == 2 {\n                self.onSwipe = SwipeGestureAction(selector: values[0], direction: values[1])\n            }else if values.count >= 3 {\n                self.onSwipe = SwipeGestureAction(selector: values[0], direction: values[1], numberOfTouches: values[2])\n            }\n        }\n        \n        \n        if let theGestureAction = EUIParse.string(pelement, key: \"ontap-bind\") {\n            var values = theGestureAction.trimArray\n            if values.count == 1 {\n                self.onTapBind = TapGestureAction(selector: values[0])\n            }else if values.count >= 2 {\n                self.onTapBind = TapGestureAction(selector: values[0], tapNumber: values[1])\n            }\n        }\n        \n        if let theGestureAction = EUIParse.string(pelement, key: \"onswipe-bind\") {\n            var values = theGestureAction.trimArray\n            if values.count == 2 {\n                self.onSwipeBind = SwipeGestureAction(selector: values[0], direction: values[1])\n            }else if values.count >= 3 {\n                self.onSwipeBind = SwipeGestureAction(selector: values[0], direction: values[1], numberOfTouches: values[2])\n            }\n        }\n        \n        for (key,value) in pelement.attributes {\n            if self.tagOut.contains((key as! String)) == false {\n                self.otherProperty[key as! String] = value\n            }\n        }\n        self.childLoop(pelement)\n    }\n    \n    func renderViewStyle(view:UIView){\n        view.contentMode = self.imageMode;\n        if(self.flexEnable){\n            view.flexDirection = self.flexDirection\n            view.flexContentDirection = self.flexContentDirection\n            view.flexAlignItems = self.flexAlignItems\n            view.flexAlignSelf = self.flexAlignSelf\n            view.flexJustifyContent = self.flexJustifyContent\n            view.flexMargin = self.flexMargin\n            view.flexPadding = self.flexPadding\n            view.flexWrap = self.flexWrap\n            view.flex = self.flex\n            view.flexFixedSize = self.flexFixedSize\n            view.flexMinimumSize = self.flexMinimumSize\n            view.flexMaximumSize = self.flexMaximumSize\n        }\n        \n        if let frame = self.frame {\n            view.frame = frame\n        }\n        \n        for (key,value) in self.otherProperty {\n            var theValue: AnyObject = value\n            if let str = value as? String {\n                if let newValue = self.bindTheKeyPath(str, key: key) {\n                    theValue = newValue\n                }\n                if theValue as! String == \"\" {\n                    continue\n                }\n            }\n            view.attr(key, value)\n        }\n    }\n    \n    func childLoop(pelement:OGElement){\n        for element in pelement.children {\n            if let ele = element as? OGElement,let pro = EUIParse.loopElement(ele) {\n                self.subTags.append(pro)\n            }\n        }\n    }\n\n    func bindTheKeyPath(str:String,key:String) -> String?{\n        let value =  Regex(\"\\\\{\\\\{(\\\\w+)\\\\}\\\\}\").replace(str, withBlock: { (regx) -> String in\n            let keyPath = regx.subgroupMatchAtIndex(0)?.trim\n            self.bind[key] = keyPath\n            return \"\"\n        })\n        return value\n    }\n}\n\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUI.swift",
    "content": "//\n//  EUI.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/5.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\npublic class EUI: NSObject {\n    public class func encode(fileName:String,suffix:String = \"xml\",toPath:String){\n        let path = NSBundle.mainBundle().pathForResource(fileName, ofType: suffix)!\n        if  NSFileManager.defaultManager().fileExistsAtPath(path) == false{\n            return\n        }\n        if let str = try? String(contentsOfFile: path, encoding: NSUTF8StringEncoding) {\n            if let encrypt = DesEncrypt.encryptWithText(str, key: CRTPTO_KEY) {\n                var error:NSError?\n                do {\n                    try encrypt.writeToFile(toPath, atomically: true, encoding: NSUTF8StringEncoding)\n                    EZPrintln(\"success\")\n                } catch let error1 as NSError {\n                    error = error1\n                    EZPrintln(error)\n                }\n            }\n        }\n    }\n    \n    public class func setLiveLoad(controller:EUScene,suffix:String){\n        if IsSimulator && suffix == \"xml\"{\n            let paths = self.loadLiveFile(controller,suffix:suffix)\n            if paths?.count > 0 {\n                for path in paths! {\n                    watchForChangesToFilePath(path) {\n                        self.loadLiveFile(controller,suffix:suffix)\n                        controller.eu_viewWillLoad()\n                        controller.loadEZLayout()\n                    }\n                }\n            }\n        }else{\n            self.loadHtml(controller, suffix: suffix)\n        }\n        controller.eu_viewWillLoad()\n    }\n    \n    private class func loadLiveFile(controller:EUScene,suffix:String) -> [String]?{\n        let fileName = controller.nameOfClass\n        \n        let path = NSBundle(path: LIVE_LOAD_PATH)!.pathForResource(fileName, ofType: suffix)!\n        if  NSFileManager.defaultManager().fileExistsAtPath(path) == false{\n            return nil\n        }\n        var paths = Array<String>()\n        paths.append(path)\n        \n        do{\n            if let html = try? String(contentsOfFile: path, encoding: NSUTF8StringEncoding){\n                var finalHtml = html\n                if let newHtml = Regex(\"@import\\\\(([^\\\\)]*)\\\\)\").replace(finalHtml,withBlock: { (regx) -> String in\n                    let subFile = regx.subgroupMatchAtIndex(0)?.trim\n                    let subPath = NSBundle(path: LIVE_LOAD_PATH)!.pathForResource(subFile, ofType: suffix)!\n                    if NSFileManager.defaultManager().fileExistsAtPath(subPath) {\n                        paths.append(subPath)\n                        return try! String(contentsOfFile:subPath, encoding: NSUTF8StringEncoding)\n                    }else{\n                        return \"\"\n                    }\n                }) {\n                    finalHtml = newHtml\n                }\n                \n                if let regMatchs = Regex(\"<style>([\\\\s\\\\S]*?)</style>\").match(finalHtml) {\n                    for regx in regMatchs {\n                        if let styleString = regx.subgroupMatchAtIndex(0)?.trim,\n                            let regxsubs = Regex(\"\\\\.([\\\\w]*)[\\\\s]*\\\\{[\\\\s]?([^}]*)[\\\\s]?\\\\}\").match(styleString){\n                                for regxsub in regxsubs {\n                                    let className = regxsub.subgroupMatchAtIndex(0)!.trim\n                                    let values = regxsub.subgroupMatchAtIndex(1)!.trim\n                                    if let aHtml = Regex(\"@\"+className).replace(finalHtml, withTemplate: values) {\n                                        finalHtml = aHtml\n                                    }\n                                }\n                        }\n                    }\n                }\n                \n                if let regMatchs = Regex(\"<script\\\\b[^>]*>([\\\\s\\\\S]*?)</script>\").match(finalHtml) {\n                    var scriptStrings = \"\";\n                    for regx in regMatchs {\n                        if let scriptString = regx.subgroupMatchAtIndex(0)?.trim{\n                            scriptStrings += scriptString\n                        }\n                    }\n                    controller.scriptString = scriptStrings\n                }\n                \n                if let cleanHtml = Regex(\"@[\\\\w]*\").replace(finalHtml, withTemplate: \"\") {\n                    finalHtml = cleanHtml\n                }\n              \n                SwiftTryCatch.`try`({\n                    let body = EUIParse.ParseHtml(finalHtml)\n                    var views = [UIView]()\n                    for aview in body {\n                        views.append(aview.getView())\n                    }\n                    controller.eu_subViews = views\n                    }, `catch`: { (error) in\n                        print(controller.nameOfClass + \"Error:\\(error.description)\")\n                    }, finally: nil)\n             \n            }else{\n                throw NSError(domain: \"EasyIOS\", code: -1, userInfo: [\"err\":\"can not open \"+path.URLString])\n            }\n        }catch let error as NSError{\n            print(\"error is \\(error)\")\n        }\n        \n        return paths\n    }\n    \n    private class func loadHtml (controller:EUScene,suffix:String){\n        let fileName = controller.nameOfClass\n        \n        let path = NSBundle(path: BUNDLE_PATH)!.pathForResource(fileName, ofType: suffix)!\n        if  NSFileManager.defaultManager().fileExistsAtPath(path) == false{\n            return\n        }\n        if let html = try? String(contentsOfFile: path, encoding: NSUTF8StringEncoding) {\n            var finalHtml = html\n            if suffix == \"crypto\" && CRTPTO_KEY != \"\" {\n                if let aHtml = DesEncrypt.decryptWithText(finalHtml, key: CRTPTO_KEY) {\n                    finalHtml = aHtml\n                }\n            }\n            if let newHtml = Regex(\"@import\\\\(([^\\\\)]*)\\\\)\").replace(finalHtml,withBlock: { (regx) -> String in\n                let subFile = regx.subgroupMatchAtIndex(0)?.trim\n                let subPath = NSBundle(path: BUNDLE_PATH)!.pathForResource(subFile, ofType: suffix)!\n                \n                if NSFileManager.defaultManager().fileExistsAtPath(subPath) {\n                    return try! String(contentsOfFile:subPath, encoding: NSUTF8StringEncoding)\n                }else{\n                    return \"\"\n                }\n            }) {\n                finalHtml = newHtml\n            }\n            \n            \n            if let regMatchs = Regex(\"<style>([\\\\s\\\\S]*?)</style>\").match(finalHtml) {\n                for regx in regMatchs {\n                    if let styleString = regx.subgroupMatchAtIndex(0)?.trim,\n                        let regxsubs = Regex(\"\\\\.([\\\\w]*)[\\\\s]*\\\\{[\\\\s]?([^}]*)[\\\\s]?\\\\}\").match(styleString){\n                            for regxsub in regxsubs {\n                                let className = regxsub.subgroupMatchAtIndex(0)!.trim\n                                let values = regxsub.subgroupMatchAtIndex(1)!.trim\n                                if let aHtml = Regex(\"@\"+className).replace(finalHtml, withTemplate: values) {\n                                    finalHtml = aHtml\n                                }\n                            }\n                    }\n                }\n            }\n            \n            if let regMatchs = Regex(\"<script\\\\b[^>]*>([\\\\s\\\\S]*?)</script>\").match(finalHtml) {\n                var scriptStrings = \"\";\n                for regx in regMatchs {\n                    if let scriptString = regx.subgroupMatchAtIndex(0)?.trim{\n                        scriptStrings += scriptString\n                    }\n                }\n                controller.scriptString = scriptStrings\n            }\n        \n            \n            if let cleanHtml = Regex(\"@[\\\\w]*\").replace(finalHtml, withTemplate: \"\") {\n                finalHtml = cleanHtml\n            }\n            \n            SwiftTryCatch.`try`({\n                    let body = EUIParse.ParseHtml(finalHtml)\n                    var views = [UIView]()\n                    for aview in body {\n                        views.append(aview.getView())\n                    }\n                    controller.eu_subViews = views\n                }, `catch`: { (error) in\n                    print(controller.nameOfClass + \"Error:\\(error.description)\")\n                }, finally: nil)\n        }\n    }\n    \n    \n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUIExtend+UIView.swift",
    "content": "//\n//  EUIExtend+UIView.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/1.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport SnapKit\nimport Bond\nimport Kingfisher\nimport TTTAttributedLabel\n\nprivate var UIViewTagIdHandle :UInt8 = 1\nprivate var UIViewViewPropertyHandle :UInt8 = 2\nprivate var UIViewConstraintGroupHandle :UInt8 = 3\nprivate var UIViewWatchHandle :UInt8 = 4\nprivate var UIViewDisposeBag :UInt8 = 5\n//private var CollectionViewDataSourceBond :UInt8 = 6\nprivate var attributedLabelDelegateHandle :UInt8 = 7\n\n\npublic class TTTAttributedLabelDelegateHandle:NSObject,TTTAttributedLabelDelegate{\n    \n}\nextension EUScene{\n     public var attributedLabelDelegate:TTTAttributedLabelDelegateHandle? {\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &attributedLabelDelegateHandle) {\n                return d as? TTTAttributedLabelDelegateHandle\n            }else{\n                return nil\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &attributedLabelDelegateHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public func eu_viewByTag(tagId:String) ->UIView?{\n        if let subViews = self.eu_subViews {\n            for view in subViews {\n                if view.subviews.count > 0 {\n                    if let aview = view.getSubViewByTagId(tagId){\n                        return aview\n                    }\n                }\n                if view.tagProperty.tagId == tagId {\n                    return view\n                }\n            }\n        }\n        return nil\n    }\n\n    func loadEZLayout(){\n        self.view.clearEZView()\n        if let subViews = self.eu_subViews {\n            for view in subViews {\n                self.view.addSubview(view)\n            }\n            self.view.subRender(self)\n        }\n        \n        self.context.setObject(self, forKeyedSubscript: \"document\")\n        self.eval(self.scriptString)\n        self.eu_viewDidLoad()\n    }\n}\n\nextension UIView {\n    \n    public var disposeBag:DisposeBag?{\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &UIViewDisposeBag) {\n                return d as? DisposeBag\n            }else{\n                return nil\n            }\n        }set(b){\n            objc_setAssociatedObject(self, &UIViewDisposeBag, b, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    public class func formTag(tag:String) -> UIView {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) {\n                return view\n            }\n        }\n        return UIView()\n    }\n    \n    func clearEZView(){\n        for view in self.subviews {\n            let aview = view \n            aview.clearEZView()\n            aview.removeFromSuperview()\n        }\n    }\n    \n    var tagProperty:ViewProperty{\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &UIViewViewPropertyHandle) {\n                return d as! ViewProperty\n            }else{\n                return ViewProperty()\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &UIViewViewPropertyHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n\n    public func getSubViewByTagId(tagId:String) -> UIView?{\n        for view in self.subviews {\n            if view.subviews.count > 0 {\n                if let aview = view.getSubViewByTagId(tagId){\n                    return aview\n                }\n            }\n            if view.tagProperty.tagId == tagId {\n                return view \n            }\n        }\n        return nil\n    }\n    \n    public func getRootView() -> UIView {\n        if self.superview == nil {\n            return self\n        }else{\n            return self.superview!.getRootView()\n        }\n    }\n    \n    func getViewById(tagId:String) -> UIView? {\n        if tagId == \"\"{\n            return nil\n        }else if tagId == Constrain.targetRoot {\n            return self.getRootView()\n        }else if tagId == Constrain.targetSuper {\n            return self.superview\n        }else if tagId == Constrain.targetSelf || tagId == self.tagProperty.tagId{\n            return self\n        }else{\n            return self.getRootView().getSubViewByTagId(tagId)\n        }\n    }\n    \n    \n    func subRender(scene:EUScene) {\n        for subView in self.subviews {\n            let view = subView \n            view.renderTheView(scene)\n        }\n    }\n    \n    func renderTheView(scene:EUScene){\n        self.subRender(scene)\n        self.renderSelector(scene)\n        self.renderGesture(scene)\n        self.renderLayout()\n    }\n    \n    public func renderDataBinding(scene:EUScene,bind:NSObject?){\n        for subView in self.subviews {\n            subView.renderDataBinding(scene,bind: bind)\n        }\n        let property =  self.tagProperty as ViewProperty\n        \n        if let bindKey = property.bind[\"background-color\"] {\n            if let color = bind!.valueForKey(bindKey) as? EZColor {\n                color.dym!.bindTo(self.bnd_backgroundColor)\n            }\n        }\n        if let bindKey = property.bind[\"alpha\"] {\n            if let alpha = bind!.valueForKey(bindKey) as? EZFloat {\n                alpha.dym!.bindTo(self.bnd_alpha)\n            }\n        }\n        if let bindKey = property.bind[\"hidden\"] {\n            if let hidden = bind!.valueForKey(bindKey) as? EZBool {\n                hidden.dym!.bindTo(self.bnd_hidden)\n            }\n        }\n        \n        self.disposeBag?.dispose()\n        if let selector = property.onTapBind {\n            if self.disposeBag == nil {\n                self.disposeBag = DisposeBag()\n            }\n            self.disposeBag?.addDisposable(self.whenTap(selector.tapNumber){\n                let script = Regex(\"\\\\{\\\\{(\\\\w+)\\\\}\\\\}\").replace(selector.selector, withBlock: { (regx) -> String in\n                    let bindKey = regx.subgroupMatchAtIndex(0)?.trim\n                    if let value = bind!.valueForKey(bindKey!) as? String{\n                        return value\n                    }else if let value = bind!.valueForKey(bindKey!) as? Int{\n                        return String(value)\n                    }else if let value = bind!.valueForKey(bindKey!) as? Bool{\n                        return value ? \"true\" : \"false\"\n                    }\n                    return \"\"\n                })\n                scene.eval(script)\n            })\n        }\n        \n        if let selector = property.onSwipeBind {\n            if self.disposeBag == nil {\n                self.disposeBag = DisposeBag()\n            }\n            self.disposeBag?.addDisposable(self.whenSwipe(selector.numberOfTouches, direction: selector.direction){\n                let script = Regex(\"\\\\{\\\\{(\\\\w+)\\\\}\\\\}\").replace(selector.selector, withBlock: { (regx) -> String in\n                    let bindKey = regx.subgroupMatchAtIndex(0)?.trim\n                    if let value = bind!.valueForKey(bindKey!) as? String{\n                        return value\n                    }else if let value = bind!.valueForKey(bindKey!) as? Int{\n                        return String(value)\n                    }else if let value = bind!.valueForKey(bindKey!) as? Bool{\n                        return value ? \"true\" : \"false\"\n                    }\n                    return \"\"\n                })\n                scene.eval(script)\n            })\n        }\n        \n    }\n\n    \n    func renderGesture(scene:EUScene){\n        let property =  self.tagProperty as ViewProperty\n        \n        self.disposeBag?.dispose()\n        if let selector = property.onTap {\n            if self.disposeBag == nil {\n                self.disposeBag = DisposeBag()\n            }\n            self.disposeBag?.addDisposable(self.whenTap(selector.tapNumber){\n                scene.eval(selector.selector)\n            })\n        }\n        \n        if let selector = property.onSwipe {\n            if self.disposeBag == nil {\n                self.disposeBag = DisposeBag()\n            }\n            self.disposeBag?.addDisposable(self.whenSwipe(selector.numberOfTouches, direction: selector.direction){\n                scene.eval(selector.selector)\n            })\n        }\n    }\n    \n    func renderSelector(scene:EUScene){\n      \n    }\n    \n    \n    func renderLayout(){\n        var consList = self.tagProperty.align + self.tagProperty.margin\n        \n        if let width = self.tagProperty.width {\n            consList.append(width)\n        }\n        \n        if let height = self.tagProperty.height {\n            consList.append(height)\n        }\n        \n        if consList.count == 0 {\n            return\n        }\n        self.snp_remakeConstraints(){[unowned self] (make) -> Void in\n            for cons  in consList {\n                let targetView = self.getViewById(cons.target)\n                let value = cons.value\n                let key = cons.constrainName\n                if targetView != nil {\n                    switch key {\n                    case .AlignRight:\n                        make.right.equalTo(targetView!).offset(value)\n                    case .AlignLeft:\n                        make.left.equalTo(targetView!).offset(value)\n                    case .AlignTop:\n                        make.top.equalTo(targetView!).offset(value)\n                    case .AlignBottom:\n                        make.bottom.equalTo(targetView!).offset(value)\n                    case .AlignCenterX:\n                        make.centerX.equalTo(targetView!).offset(value)\n                    case .AlignCenterY:\n                        make.centerY.equalTo(targetView!).offset(value)\n                    case .MarginTop:\n                        make.top.equalTo(targetView!.snp_bottom).offset(value)\n                    case .MarginLeft:\n                        make.left.equalTo(targetView!.snp_right).offset(value)\n                    case .MarginRight:\n                        make.right.equalTo(targetView!.snp_left).offset(-value)\n                    case .MarginBottom:\n                        make.bottom.equalTo(targetView!.snp_top).offset(-value)\n                    case .Width:\n                        make.width.equalTo(targetView!.snp_width).multipliedBy(value)\n                    case .Height:\n                        make.height.equalTo(targetView!.snp_height).multipliedBy(value)\n                    default:\n                        EZPrintln(\"remake default\")\n                    }\n                }else {\n                    switch key {\n                    case .Width:\n                        make.width.equalTo(Int(value))\n                    case .Height:\n                        make.height.equalTo(Int(value))\n                    default:\n                        EZPrintln(\"remake default\")\n                    }\n                }\n            }\n        }\n    }\n}\n\nextension UIImageView {\n    override public class func formTag(tag:String) -> UIImageView {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UIImageView {\n                return view\n            }\n        }\n        return UIImageView()\n    }\n    \n    override public func renderDataBinding(scene:EUScene,bind:NSObject?){\n        super.renderDataBinding(scene,bind: bind)\n        if let bindKey = self.tagProperty.bind[\"src\"] {\n            if let image = bind!.valueForKey(bindKey) as? EZImage {\n                image.dym!.bindTo(self.bnd_image)\n            }else if let src = bind!.valueForKey(bindKey) as? EZURL {\n                src.dym!.bindTo(self.bnd_URLImage)\n            }else if let image = bind!.valueForKey(bindKey) as? UIImage {\n                self.image = image\n            }else if let url = bind!.valueForKey(bindKey) as? NSURL {\n                self.kf_setImageWithURL(url)\n            }else if let str = bind!.valueForKey(bindKey) as? String {\n                if let image = UIImage(named: str) {\n                    self.image = image\n                }else if let url = NSURL(string: str) {\n                    self.kf_setImageWithURL(url)\n                }\n            }\n        }else if let bindKey = self.tagProperty.bind[\"image\"] {\n            if let image = bind!.valueForKey(bindKey) as? EZImage {\n                image.dym!.bindTo(self.bnd_image)\n            }else if let image = bind!.valueForKey(bindKey) as? UIImage {\n                self.image = image\n            }\n        }\n    }\n}\n\nextension UILabel {\n    override public class func formTag(tag:String) -> UILabel {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UILabel {\n                return view\n            }\n        }\n        return UILabel()\n    }\n    \n    override public func renderDataBinding(scene:EUScene,bind:NSObject?){\n        super.renderDataBinding(scene,bind: bind)\n        if let bindKey = self.tagProperty.bind[\"text\"] {\n            if let text = bind!.valueForKey(bindKey) as? EZAttributedString {\n                text.dym!.bindTo(self.bnd_attributedText)\n            }else if let text = bind!.valueForKey(bindKey) as? EZString {\n                text.dym!.bindTo(self.bnd_text)\n            }else if let text = bind!.valueForKey(bindKey) as? String {\n                self.text = text\n            }else if let data = bind!.valueForKey(bindKey) as? NSData {\n                self.attributedText = NSAttributedString(fromHTMLData: data, attributes: [\"dict\":self.tagProperty.style])\n            }else if let string = bind!.valueForKey(bindKey) as? NSAttributedString {\n                self.attributedText = string\n            }\n        }\n        if let bindKey = self.tagProperty.bind[\"text-color\"] {\n            if let color = bind!.valueForKey(bindKey) as? EZColor {\n                color.dym!.bindTo(self.bnd_textColor)\n            }else if let color = bind!.valueForKey(bindKey) as? UIColor {\n                self.textColor = color\n            }\n        }\n    }\n}\n\nextension TTTAttributedLabel {\n    override public class func formTag(tag:String) -> TTTAttributedLabel {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? TTTAttributedLabel {\n                return view\n            }\n        }\n        return TTTAttributedLabel(frame: CGRectZero)\n    }\n    \n    override public func renderDataBinding(scene:EUScene,bind:NSObject?){\n        super.renderDataBinding(scene,bind: bind)\n        if let bindKey = self.tagProperty.bind[\"TTText\"] {\n            if let text = bind!.valueForKey(bindKey) as? EZAttributedString {\n                text.dym! ->> self.dynTTTAttributedText\n            }else if let text = bind!.valueForKey(bindKey) as? EZString {\n                text.dym! ->> self.dynTTText\n            }else if let data = bind!.valueForKey(bindKey) as? EZData {\n                data.dym! ->> self.dynTTTData\n            }else if let text = bind!.valueForKey(bindKey) as? String {\n                self.setText(text)\n            }else if let data = bind!.valueForKey(bindKey) as? NSData {\n                self.setText(NSAttributedString(fromHTMLData: data, attributes: [\"dict\":self.tagProperty.style]))\n            }else if let string = bind!.valueForKey(bindKey) as? NSAttributedString {\n                self.setText(string)\n            }\n        }\n    }\n    \n    override func renderSelector(scene:EUScene){\n        if let delegate = scene.attributedLabelDelegate {\n            self.delegate = delegate\n        }\n    }\n}\n\nextension UITextField {\n    override public class func formTag(tag:String) -> UITextField {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UITextField {\n                return view\n            }\n        }\n        return UITextField()\n    }\n    \n    override public func renderDataBinding(scene:EUScene,bind:NSObject?){\n        super.renderDataBinding(scene,bind:bind)\n        if let bindKey = self.tagProperty.bind[\"text\"] {\n            if let text = bind!.valueForKey(bindKey) as? EZString {\n                text.dym!.bindTo(self.bnd_text)\n            }else if let text = bind!.valueForKey(bindKey) as? String {\n                self.text = text\n            }\n        }\n    }\n}\n\nextension UIButton {\n    override public class func formTag(tag:String) -> UIButton {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UIButton {\n                return view\n            }\n        }\n        return UIButton()\n    }\n    \n    override func renderSelector(scene:EUScene){\n        let property =  self.tagProperty as? ButtonProperty\n        if let selector = property?.onEvent {\n            self.bnd_controlEvent.filter{$0 == selector.event}.map{ e in}.observe({\n                scene.eval(selector.selector)\n            })\n        }\n    }\n}\n\nprivate var UITableViewCellHandle :UInt8 = 5\nextension UITableView {\n    override public class func formTag(tag:String) -> UITableView {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UITableView {\n                return view\n            }\n        }\n        return UITableView()\n    }\n    \n    public func getSectionViewByTagId(tagId:String,target:EUScene,bind:NSObject? = nil) -> UIView?{\n        let property = self.tagProperty as? TableViewProperty\n        if let pro = property?.sectionView[tagId] {\n            let view = pro.getView()\n            view.renderTheView(target)\n            view.renderDataBinding(target,bind: bind)\n            return view\n        }\n        return nil\n    }\n    \n    var reusableViews:Dictionary<String,UIView>{\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &UITableViewCellHandle) {\n                return d as! Dictionary<String,UIView>\n            }else{\n                return  Dictionary<String,UIView>()\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &UITableViewCellHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    override func subRender(scene:EUScene) {\n        scene.eu_tableViewDidLoad(self)\n    }\n    \n    public func dequeueReusableCell(reuseId:String,forIndexPath:NSIndexPath,target:EUScene,bind:NSObject? = nil) -> UITableViewCell{\n        let cell = self.dequeueReusableCellWithIdentifier(reuseId, forIndexPath: forIndexPath)\n        if cell.contentView.subviews.count == 0 {\n            SwiftTryCatch.`try`({\n                let property = self.tagProperty as! TableViewProperty\n                if let cellProperty = property.reuseCell[reuseId] {\n                    let view = cellProperty.getView()\n                    cell.contentView.addSubview(view)\n                    view.renderTheView(target)\n                }}, `catch`: { (error) in\n                    print(self.nameOfClass + \"Error:\\(error.description)\")\n                }, finally:nil)\n        }\n        if let view = cell.contentView.subviews.first {\n            view.renderDataBinding(target,bind: bind)\n        }\n        return cell\n    }\n}\n\nprivate var UICollectionViewCellHandle :UInt8 = 5\nextension UICollectionView {\n    override public class func formTag(tag:String) -> UICollectionView {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UICollectionView {\n                return view\n            }\n        }\n        return UICollectionView()\n    }\n    \n    var reusableViews:Dictionary<String,UIView>{\n        get{\n            if let d: AnyObject = objc_getAssociatedObject(self, &UICollectionViewCellHandle) {\n                return d as! Dictionary<String,UIView>\n            }else{\n                return  Dictionary<String,UIView>()\n            }\n        }set (value){\n            objc_setAssociatedObject(self, &UICollectionViewCellHandle, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n    \n    override func subRender(scene:EUScene) {\n        scene.eu_collectionViewDidLoad(self)\n    }\n    \n    public func dequeueReusableCell(reuseId:String,forIndexPath:NSIndexPath,target:EUScene,bind:NSObject? = nil) -> UICollectionViewCell{\n        let cell = self.dequeueReusableCellWithReuseIdentifier(reuseId, forIndexPath: forIndexPath)\n        if cell.contentView.subviews.count == 0 {\n            SwiftTryCatch.`try`({\n                let property = self.tagProperty as! CollectionViewProperty\n                if let cellProperty = property.reuseCell[reuseId] {\n                let view = cellProperty.getView()\n                cell.contentView.addSubview(view)\n                view.renderTheView(target)\n            }}, `catch`: { (error) in\n                print(self.nameOfClass + \"Error:\\(error.description)\")\n            }, finally: nil)\n        }\n        if let view = cell.contentView.subviews.first{\n            view.renderDataBinding(target,bind:bind)\n        }\n        return cell\n    }\n}\n\nextension UIScrollView {\n    override public class func formTag(tag:String) -> UIScrollView {\n        if let scene = URLNavigation.currentViewController() as? EUScene {\n            if let view = scene.eu_viewByTag(tag) as? UIScrollView {\n                return view\n            }\n        }\n        return UIScrollView()\n    }\n    \n    override func renderSelector(scene:EUScene){\n        let property =  self.tagProperty as? ScrollViewProperty\n        \n        if let pullRefresh = property?.pullToRefresh {\n            if pullRefresh.viewClass.characters.isEmpty {\n                self.addPullToRefreshWithActionHandler(){\n                    scene.eval(pullRefresh.selector)\n                }\n            }else if let view =  NSObject(fromString: pullRefresh.viewClass) as? UIView {\n                self.addPullToRefreshWithActionHandler(view) {\n                    scene.eval(pullRefresh.selector)\n                }\n            }\n        }\n        \n        if let infiniteScrolling = property?.infiniteScrolling {\n            if infiniteScrolling.viewClass.characters.isEmpty {\n                self.addInfiniteScrollingWithActionHandler(){\n                    scene.eval(infiniteScrolling.selector)\n                }\n            }else if let view =  NSObject(fromString: infiniteScrolling.viewClass) as? UIView {\n                self.addInfiniteScrollingWithActionHandler(view) {\n                   scene.eval(infiniteScrolling.selector)\n                }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUIKit.swift",
    "content": "//\n//  EUIView.swift\n//  Pods\n//\n//  Created by zhuchao on 15/7/21.\n//\n//\n\nimport CoreImage\nimport UIKit\nimport JavaScriptCore\n\n@objc public protocol EUIView:JSExport,ENSObject{\n    \n}\n\n@objc public protocol EUIImageView:JSExport,EUIView,ENSObject{\n    init(image: UIImage!)\n    init(image: UIImage!, highlightedImage: UIImage?)\n}\n\n@objc public protocol EUITextField:JSExport,EUIView,ENSObject{\n\n}\n\n@objc public protocol EUIButton:JSExport,EUIView,ENSObject{\n    \n}\n\n@objc public protocol EUIScrollView:JSExport,EUIView,ENSObject{\n    \n}\n\n@objc public protocol EUITableView:JSExport,EUIScrollView,ENSObject{\n    \n}\n\n@objc public protocol EUICollectionView:JSExport,EUIScrollView,ENSObject{\n    \n}\n\n\n@objc public protocol EUILabel:JSExport,EUIView,ENSObject{\n    \n}\n\n@objc public protocol EUIColor:JSExport,ENSObject{\n    static func blackColor() -> UIColor // 0.0 white\n    static func darkGrayColor() -> UIColor // 0.333 white\n    static func lightGrayColor() -> UIColor // 0.667 white\n    static func whiteColor() -> UIColor // 1.0 white\n    static func grayColor() -> UIColor // 0.5 white\n    static func redColor() -> UIColor // 1.0, 0.0, 0.0 RGB\n    static func greenColor() -> UIColor // 0.0, 1.0, 0.0 RGB\n    static func blueColor() -> UIColor // 0.0, 0.0, 1.0 RGB\n    static func cyanColor() -> UIColor // 0.0, 1.0, 1.0 RGB\n    static func yellowColor() -> UIColor // 1.0, 1.0, 0.0 RGB\n    static func magentaColor() -> UIColor // 1.0, 0.0, 1.0 RGB\n    static func orangeColor() -> UIColor // 1.0, 0.5, 0.0 RGB\n    static func purpleColor() -> UIColor // 0.5, 0.0, 0.5 RGB\n    static func brownColor() -> UIColor // 0.6, 0.4, 0.2 RGB\n    static func clearColor() -> UIColor // 0.0 white, 0.0 alpha\n}\n\n@objc public protocol EUIImage:JSExport,ENSObject{\n    init(named name: String)// load from main bundle\n    @available(iOS, introduced=8.0)\n    init(named name: String, inBundle bundle: NSBundle?, compatibleWithTraitCollection traitCollection: UITraitCollection?)\n    init?(contentsOfFile path: String)\n}\n\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUIParse.swift",
    "content": "//\n//  EZUI.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/30.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport SnapKit\n\nclass EUIParse: NSObject {\n    class func ParseHtml(html:String) -> [ViewProperty]{\n        let data = ObjectiveGumbo.parseDocumentWithString(html)\n        let body = data.elementsWithTag(GUMBO_TAG_BODY).first as! OGElement\n        var viewArray = [ViewProperty]()\n        for element in body.children {\n            if element.isKindOfClass(OGElement) {\n                if let pro = self.loopElement(element as! OGElement) {\n                    viewArray.append(pro)\n                }\n            }\n        }\n        return viewArray\n    }\n    \n    // 对子节点进行递归解析\n    class func loopElement(pelement:OGElement) -> ViewProperty?{\n        var tagProperty:ViewProperty?\n        var type:String?\n        \n        switch (pelement.tag.rawValue){\n            case GUMBO_TAG_IMG.rawValue :\n                type = \"UIImageView\"\n            case GUMBO_TAG_SPAN.rawValue :\n                type = \"UILabel\"\n            case GUMBO_TAG_BUTTON.rawValue :\n                type = \"UIButton\"\n            case GUMBO_TAG_INPUT.rawValue :\n                type = \"UITextField\"\n            default :\n                type = self.string(pelement,key:\"type\")\n        }\n        \n        if let atype = type {\n            switch (atype){\n            case \"UIScrollView\",\"scroll\":\n                tagProperty = ScrollViewProperty()\n            case \"UITableView\",\"table\":\n                tagProperty = TableViewProperty()\n            case \"UICollectionView\",\"collection\":\n                tagProperty = CollectionViewProperty()\n            case \"UIImageView\",\"imageView\":\n                tagProperty = ImageProperty()\n            case \"UILabel\",\"label\":\n                tagProperty = LabelProperty()\n            case \"UIButton\",\"button\":\n                tagProperty = ButtonProperty()\n            case \"UITextField\",\"field\":\n                tagProperty = TextFieldProperty()\n            default :\n                tagProperty = ViewProperty()\n            }\n        }else{\n            tagProperty = ViewProperty()\n        }\n    \n        if tagProperty != nil {\n            tagProperty!.renderTag(pelement)\n        }\n        return tagProperty\n    }\n    \n    class func string (element:OGElement,key:String) ->String?{\n        if let str = element.attributes?[key] as? String {\n            return str\n        }\n        return nil\n    }\n    \n    class func getStyleProperty (element:OGElement,key:String) -> Array<Constrain>? {\n        if element.attributes?[key] == nil {\n            return nil\n        }\n        var style = Array<Constrain>()\n        let origin = element.attributes?[key] as! String\n        let firstArray = origin.trimArrayBy(\";\")\n        \n        for str in firstArray {\n            var secondArray = str.trimArrayBy(\":\")\n            if secondArray.count == 2 {\n                let raw = secondArray[0] as String\n                let rawKey = CSS(rawValue: key+\"-\"+raw.trim)\n                if rawKey == nil {\n                    continue\n                }\n                var values = secondArray[1].trimArray\n                if key == \"align\" {\n                    switch rawKey! {\n                    case .AlignTop,.AlignBottom,.AlignLeft,.AlignRight,.AlignCenterX,.AlignCenterY:\n                        if values.count == 1 {\n                            style.append(Constrain(name:rawKey!,value: values[0].trim.floatValue))\n                        }else if(values.count >= 2){\n                            style.append(Constrain(name:rawKey!,value: values[0].trim.floatValue,target:values[1].trim))\n                        }\n                    case .AlignCenter:\n                        if values.count >= 1 {\n                            style.append(Constrain(name:.AlignCenterX,value: values[0].trim.floatValue))\n                        }\n                        if values.count >= 2 {\n                            style.append(Constrain(name:.AlignCenterY,value: values[1].trim.floatValue))\n                        }\n                    case .AlignEdge:\n                        if values.count >= 1 && values[0].trim != \"*\" {\n                            style.append(Constrain(name:.AlignTop,value: values[0].trim.floatValue))\n                        }\n                        if values.count >= 2 && values[1].trim != \"*\" {\n                            style.append(Constrain(name:.AlignLeft,value: values[1].trim.floatValue))\n                        }\n                        if values.count >= 3 && values[2].trim != \"*\" {\n                            style.append(Constrain(name:.AlignBottom,value: values[2].trim.floatValue))\n                        }\n                        if values.count >= 4 && values[3].trim != \"*\" {\n                            style.append(Constrain(name:.AlignRight,value: values[3].trim.floatValue))\n                        }\n                    default :\n                        print(raw.trim + \" is jumped\")\n                    }\n\n                }else if key == \"margin\" {\n                    switch rawKey! {\n                    case .MarginTop,.MarginBottom,.MarginLeft,.MarginRight:\n                        if values.count == 1 {\n                            style.append(Constrain(name:rawKey!,value: values[0].trim.floatValue))\n                        }else if(values.count >= 2){\n                            style.append(Constrain(name:rawKey!,value: values[0].trim.floatValue,target:values[1].trim))\n                        }\n                    default :\n                        print(raw.trim + \" is jumped\")\n                    }\n\n                }\n            }else if secondArray.count == 1 &&  key == \"align\" {\n                \n                var values = secondArray[0].trimArray\n                if values.count >= 1 && values[0].trim != \"*\" {\n                    style.append(Constrain(name:.AlignTop,value: values[0].trim.floatValue))\n                }\n                if values.count >= 2 && values[1].trim != \"*\" {\n                    style.append(Constrain(name:.AlignLeft,value: values[1].trim.floatValue))\n                }\n                if values.count >= 3 && values[2].trim != \"*\" {\n                    style.append(Constrain(name:.AlignBottom,value: values[2].trim.floatValue))\n                }\n                if values.count >= 4 && values[3].trim != \"*\" {\n                    style.append(Constrain(name:.AlignRight,value: values[3].trim.floatValue))\n                }\n            }\n        }\n        return style\n\n    }\n}\n\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUIProperty.swift",
    "content": "//\n//  EUIProperty.swift\n//  medical\n//\n//  Created by zhuchao on 15/4/30.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\n\nenum CSS:String{\n    case MarginTop = \"margin-top\"\n    case MarginLeft = \"margin-left\"\n    case MarginRight = \"margin-right\"\n    case MarginBottom = \"margin-bottom\"\n    \n    case AlignTop = \"align-top\"\n    case AlignBottom = \"align-bottom\"\n    case AlignLeft = \"align-left\"\n    case AlignRight = \"align-right\"\n    case AlignCenter = \"align-center\"\n    case AlignCenterX = \"align-center-x\"\n    case AlignCenterY = \"align-center-y\"\n    case AlignEdge = \"align-edge\"\n    \n    case Width = \"width\"\n    case Height = \"height\"\n    \n}\n\nstruct Constrain{\n    static var targetSelf = \"self\"\n    static var targetSuper = \"super\"\n    static var targetRoot = \"root\"\n    \n    var value:CGFloat = 0.0\n    var target = targetSuper\n    var constrainName = CSS.AlignEdge\n    \n    init(name:CSS,value:CGFloat,target:String = targetSuper){\n        self.constrainName = name\n        self.value = value\n        self.target = target\n    }\n}\n\nstruct SelectorAction{\n    var selector:String = \"\"\n    var event:UIControlEvents = UIControlEvents.TouchUpInside\n    \n    init(selector:String,event:String = \"TouchUpInside\"){\n        self.selector = selector\n        self.event = event.controlEvent\n    }\n}\n\nstruct PullRefreshAction {\n    var selector:String = \"\"\n    var viewClass:String = \"\"\n    \n    init(selector:String,viewClass:String = \"\"){\n        self.selector = selector\n        self.viewClass = viewClass\n    }\n}\n\nstruct InfiniteScrollingAction {\n    var selector:String = \"\"\n    var viewClass:String = \"\"\n    \n    init(selector:String,viewClass:String = \"\"){\n        self.selector = selector\n        self.viewClass = viewClass\n    }\n}\n\nstruct TapGestureAction{\n    var selector:String = \"\"\n    var tapNumber:NSInteger = 1\n    init(selector:String,tapNumber:String = \"1\"){\n        self.selector = selector\n        self.tapNumber = tapNumber.integerValue\n    }\n}\n\nstruct SwipeGestureAction {\n    \n    var direction: UISwipeGestureRecognizerDirection\n    var selector:String\n    var numberOfTouches:Int = 1\n    \n    init(selector:String,direction:String,numberOfTouches:String = \"1\"){\n        self.selector = selector\n        self.numberOfTouches = numberOfTouches.integerValue\n        switch direction.lowercaseString {\n        case \"up\" :\n            self.direction = .Up\n        case \"down\" :\n            self.direction = .Down\n        case \"right\" :\n            self.direction = .Right\n        case \"left\" :\n            self.direction = .Left\n        default :\n            self.direction = .Up\n        }\n    }\n}\n\n\n\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EUScene.swift",
    "content": "//\n//  EUScene.swift\n//  medical\n//\n//  Created by zhuchao on 15/5/6.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\nimport UIKit\nimport JavaScriptCore\n\npublic var LIVE_LOAD_PATH = NSBundle.mainBundle().pathForResource(\"xml\", ofType: \"bundle\")!\npublic var BUNDLE_PATH = NSBundle.mainBundle().pathForResource(\"xml\", ofType: \"bundle\")!\n\npublic var CRTPTO_KEY = \"\"\n\n\n@objc protocol EUSceneExport:JSExport {\n    func getElementById(id:String) -> UIView\n}\n\npublic class EUScene: EZScene,EUSceneExport{\n    \n    \n    public func getElementById(id:String) -> UIView {\n        return UIView.formTag(id)\n    }\n    \n    public var SUFFIX = \"xml\"\n    public var eu_subViews:[UIView]?\n    public var scriptString:String?\n    \n    public var context = EZJSContext()\n    \n    public func define(funcName:String,actionBlock:@convention(block) ()->Void){\n        context.define(funcName, actionBlock: actionBlock)\n    }\n    \n    public func eval(script: String?) -> JSValue?{\n        if let str =  script {\n            var result:JSValue?\n            SwiftTryCatch.`try`({\n                result = self.context.evaluateScript(str)\n                }, `catch`: { (error) in\n                    print(\"JS Error:\\(error.description)\")\n                }, finally: nil)\n            return result\n        }else{\n            return nil\n        }\n    }\n    \n    override public func loadView() {\n        super.loadView()\n        EUI.setLiveLoad(self,suffix: SUFFIX)\n        \n    }\n    \n    override public func viewDidLoad() {\n        super.viewDidLoad()\n        self.automaticallyAdjustsScrollViewInsets = false;\n        self.extendedLayoutIncludesOpaqueBars = true;\n        self.edgesForExtendedLayout = UIRectEdge.All;\n        self.view.backgroundColor = UIColor.whiteColor()\n        self.loadEZLayout()\n    }\n    \n    public func eu_viewWillLoad(){\n    \n    }\n    \n    public func eu_viewDidLoad(){\n\n    }\n\n    public func eu_tableViewDidLoad(tableView:UITableView?){\n        \n    }\n    \n    public func eu_collectionViewDidLoad(collectionView:UICollectionView?){\n        \n    }\n\n    \n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/EZJSCore.swift",
    "content": "import UIKit\nimport JavaScriptCore\n\n\n@objc protocol ConsoleExport:JSExport {\n    static func log(object:AnyObject?)\n}\n\n@objc public class Console:NSObject,ConsoleExport {\n    static public func log(object:AnyObject?){\n        if let obj: AnyObject = object{\n            print(obj)\n        }\n    }\n}\n\n\n@objc protocol JSURLManagerExport:JSExport {\n    static func present(url:String,_ animated:Bool)\n    static func push(url:String,_ animated:Bool)\n    static func dismiss(animated:Bool)\n}\n\npublic class JSURLManager:NSObject,JSURLManagerExport {\n    static public func present(url:String,_ animated:Bool){\n        let viewController = UIViewController.initFromString(url, fromConfig: URLManager.shareInstance().config)\n        let nav = EZNavigationController(rootViewController: viewController)\n        URLNavigation.presentViewController(nav, animated: animated)\n    }\n    \n    static public func push(url:String,_ animated:Bool){\n        URLManager.pushURLString(url, animated: animated)\n    }\n    \n    static public func dismiss(animated:Bool){\n        URLNavigation.dismissCurrentAnimated(animated)\n    }\n}\n\npublic class EZJSContext:JSContext{\n    \n    override init(){\n        super.init()\n        \n        self.setObject(Console.self, forKeyedSubscript: \"console\")\n        self.setObject(JSURLManager.self, forKeyedSubscript: \"um\")\n        \n        class_addProtocol(EZAction.self, EZActionJSExport.self)\n        self.setObject(EZAction.self, forKeyedSubscript: \"EZAction\")\n        \n        class_addProtocol(UIColor.self, EUIColor.self)\n        self.setObject(UIColor.self, forKeyedSubscript: \"UIColor\")\n        \n        class_addProtocol(UIImage.self, EUIImage.self)\n        self.setObject(UIImage.self, forKeyedSubscript: \"UIImage\")\n        \n        class_addProtocol(UIView.self, EUIView.self)\n        self.setObject(UIView.self, forKeyedSubscript: \"UIView\")\n        \n        class_addProtocol(UIImageView.self, EUIImageView.self)\n        self.setObject(UIImageView.self, forKeyedSubscript: \"UIImageView\")\n        \n        class_addProtocol(UITextField.self, EUITextField.self)\n        self.setObject(UITextField.self, forKeyedSubscript: \"UITextField\")\n\n        class_addProtocol(UIButton.self, EUIButton.self)\n        self.setObject(UIButton.self, forKeyedSubscript: \"UIButton\")\n\n        class_addProtocol(UILabel.self, EUILabel.self)\n        self.setObject(UILabel.self, forKeyedSubscript: \"UILabel\")\n\n        class_addProtocol(UIScrollView.self, EUIScrollView.self)\n        self.setObject(UIScrollView.self, forKeyedSubscript: \"UIScrollView\")\n\n        class_addProtocol(UITableView.self, EUITableView.self)\n        self.setObject(UITableView.self, forKeyedSubscript: \"UITableView\")\n        \n        class_addProtocol(UICollectionView.self, EUICollectionView.self)\n        self.setObject(UICollectionView.self, forKeyedSubscript: \"UICollectionView\")\n        \n        \n        self.exceptionHandler = { context, exception in\n            print(\"JS Error: \\(exception)\")\n        }\n    }\n    \n    override init(virtualMachine: JSVirtualMachine!) {\n        super.init(virtualMachine:virtualMachine)\n    }\n\n    \n    public func define(funcName:String,actionBlock:@convention(block) ()->Void){\n        self.setObject(unsafeBitCast(actionBlock, AnyObject.self), forKeyedSubscript:funcName)\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/NSAttributedString+HTMLStyle.h",
    "content": "//\n//  NSAttributedString+HTMLStyle.h\n//  QRContentMobilizer\n//\n//  Created by Wojciech Czekalski on 22.03.2014.\n//  Copyright (c) 2014 Wojciech Czekalski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\ntypedef NSString QRHTMLAttribute;\n\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeParagraph;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeLink;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader1;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader2;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader3;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader4;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader5;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHeader6;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeEmphasis;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeStrong;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeBold;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeAlternateVoice;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeSmall;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeSubscripted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeSuperscripted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeInserted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeDeleted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeHighlighted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeCode;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeKeyboardText;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeSampleCode;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeVariable;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributePreformatted;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeAbbreviation;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeAddress;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeBlockQuote;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeInlineQuote;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeTitle;\nFOUNDATION_EXPORT QRHTMLAttribute * const QRHTMLAttributeDefinition;\n\n/**\n *  Creation of NSAttributedString out of HTML with per-tag attributes made easy.\n */\n\n@interface NSAttributedString (HTMLStyle)\n/**\n *  Creates an attributed string from HTML data. Assumes `NSUTF8StringEncoding`.\n *\n *  @param data Data to be processed.\n *\n *  @return Returns a new instance of `NSAttributedString` or nil if given data was invalid.\n */\n+ (instancetype)attributedStringFromHTMLData:(NSData *)data;\n\n/**\n *  Creates an attributed string from HTML string and CSS string with attributes.\n *\n *  @param html A string containing HTML.\n *  @param css  A CSS string. If nil, use attributedStringFromHTMLData: instead.\n *\n *  @abstract Don't convert your HTML and CSS into NSStrings from NSData objects. Use `attributedStringFromHTMLData:CSSData:` instead.\n *\n *  @return Returns a new instance of `NSAttributedString` or nil if given data was invalid.\n */\n\n+ (instancetype)attributedStringFromHTMLString:(NSString *)html CSSString:(NSString *)css;\n\n/**\n *  Creates an attributed string from merged HTML and CSS data.\n *\n *  @param html HTML data to be processed\n *  @param css  CSS data to be processed\n *\n *  @return Returns a new instance of NSAttributedString or nil if given data was invalid.\n */\n\n+ (instancetype)attributedStringFromHTMLData:(NSData *)html CSSData:(NSData *)css;\n\n/**\n *  Creates an attributed string from merged HTML and CSS files.\n *\n *  @param html URL of a CSS file.\n *  @param css  URL of a CSS file.\n *\n *  @return Returns a new instance of NSAttributedString or nil if given data was invalid.\n */\n\n+ (instancetype)attributedStringFromHTMLFileAtURL:(NSURL *)html CSSURL:(NSURL *)css;\n\n/**\n *  Creates an attributed string from HTML data and attributes parsed from attributes dict.\n *\n *  @param data       HTML data to be processed\n *  @param attributes Key-Value pairs of NSAttributedString attributes keyed under HTML tags.\n *\n *  @return Returns a new instance of NSAttributedString or nil if given data was invalid.\n */\n\n+ (instancetype)attributedStringFromHTMLData:(NSData *)data attributes:(NSDictionary *)attributes;\n@end\n\n/**\n *  Convinience methods for dealing with adding attributes to `NSAttributedStrings` from HTML.\n */\n\n@interface NSMutableDictionary (CSS)\n\n/**\n *  Sets attributes for a given HTML tag.\n *\n *  @param attributes NSDictionary containing key-value pairs of `NSAttributedString` attributes.\n *  @param tag        `HTML` tag to be assigned to the attributes\n *  @param flatten    if flatten set to yes, the dictionary is converted into CSS string before being added to the receiver.\n */\n\n- (void)addAttributes:(NSDictionary *)attributes forHTMLAttribute:(QRHTMLAttribute *)tag flatten:(BOOL)flatten;\n\n@end\n\n@interface NSDictionary (CSS)\n\n/**\n *  Parses receiver and creates a `NSString` with `CSS` attributes.\n *\n *  @return Returns a `NSString` with `CSS` attributes.\n */\n\n- (NSString *)CSSStringFromAttributes;\n\n@end\n\n/**\n *  NSData category which adds method allowing to replace occurencies of given data with another data.\n */\n\n@interface NSData (HTMLAdditions)\n\n/**\n *  Creates `NSData` instance with replaced occurencies.\n *\n *  @param data            `NSData` to be replaced.\n *  @param replacementData `NSData` to be inserted in place of `data`.\n *\n *  This method replaces all occurencies of `data` with `replacementData`.\n *\n *  @return Returns `NSData` with replaced contents.\n */\n\n- (NSData *)dataByReplacingOccurrencesOfData:(NSData *)data withData:(NSData *)replacementData;\n@end"
  },
  {
    "path": "Pod/Classes/Extend/EUI/NSAttributedString+HTMLStyle.m",
    "content": "//\n//  NSAttributedString+HTMLStyle.m\n//  QRContentMobilizer\n//\n//  Created by Wojciech Czekalski on 22.03.2014.\n//  Copyright (c) 2014 Wojciech Czekalski. All rights reserved.\n//\n\n#import \"NSAttributedString+HTMLStyle.h\"\n#import \"regex.h\"\n#import <UIKit/UIKit.h>\n\nQRHTMLAttribute * const QRHTMLAttributeParagraph = @\"p\";\nQRHTMLAttribute * const QRHTMLAttributeLink = @\"a\";\nQRHTMLAttribute * const QRHTMLAttributeHeader1 = @\"h1\";\nQRHTMLAttribute * const QRHTMLAttributeHeader2 = @\"h2\";\nQRHTMLAttribute * const QRHTMLAttributeHeader3 = @\"h3\";\nQRHTMLAttribute * const QRHTMLAttributeHeader4 = @\"h4\";\nQRHTMLAttribute * const QRHTMLAttributeHeader5 = @\"h5\";\nQRHTMLAttribute * const QRHTMLAttributeHeader6 = @\"h6\";\nQRHTMLAttribute * const QRHTMLAttributeEmphasis = @\"em\";\nQRHTMLAttribute * const QRHTMLAttributeStrong = @\"strong\";\nQRHTMLAttribute * const QRHTMLAttributeBold = @\"b\";\nQRHTMLAttribute * const QRHTMLAttributeAlternateVoice = @\"i\";\nQRHTMLAttribute * const QRHTMLAttributeSmall = @\"small\";\nQRHTMLAttribute * const QRHTMLAttributeSubscripted = @\"sub\";\nQRHTMLAttribute * const QRHTMLAttributeSuperscripted = @\"sup\";\nQRHTMLAttribute * const QRHTMLAttributeInserted = @\"ins\";\nQRHTMLAttribute * const QRHTMLAttributeDeleted = @\"del\";\nQRHTMLAttribute * const QRHTMLAttributeHighlighted = @\"mark\";\nQRHTMLAttribute * const QRHTMLAttributeCode = @\"code\";\nQRHTMLAttribute * const QRHTMLAttributeKeyboardText = @\"kbd\";\nQRHTMLAttribute * const QRHTMLAttributeSampleCode = @\"samp\";\nQRHTMLAttribute * const QRHTMLAttributeVariable = @\"var\";\nQRHTMLAttribute * const QRHTMLAttributePreformatted = @\"pre\";\nQRHTMLAttribute * const QRHTMLAttributeAbbreviation = @\"abbr\";\nQRHTMLAttribute * const QRHTMLAttributeAddress = @\"address\";\nQRHTMLAttribute * const QRHTMLAttributeBlockQuote = @\"blockquote\";\nQRHTMLAttribute * const QRHTMLAttributeInlineQuote = @\"q\";\nQRHTMLAttribute * const QRHTMLAttributeTitle = @\"cite\";\nQRHTMLAttribute * const QRHTMLAttributeDefinition = @\"dfn\";\n\n@implementation NSAttributedString (HTMLStyle)\n\n+ (instancetype)attributedStringFromHTMLFileAtURL:(NSURL *)html CSSURL:(NSURL *)css {\n    return [self attributedStringFromHTMLData:[NSData dataWithContentsOfURL:html] CSSData:[NSData dataWithContentsOfURL:css]];\n}\n\n+ (instancetype)attributedStringFromHTMLString:(NSString *)html CSSString:(NSString *)css {\n    return [self attributedStringFromHTMLData:[html dataUsingEncoding:NSUTF8StringEncoding] CSSData:[css dataUsingEncoding:NSUTF8StringEncoding]];\n}\n\n+ (instancetype)attributedStringFromHTMLData:(NSData *)data {\n    return [[self alloc] initWithData:data options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:NULL error:nil];\n}\n\n+ (instancetype)attributedStringFromHTMLData:(NSData *)html CSSData:(NSData *)css {\n    if (css) {\n        NSMutableData *newHTMLData = [css mutableCopy];\n        [newHTMLData appendData:html];\n        return [self attributedStringFromHTMLData:newHTMLData];\n    }\n    return [self attributedStringFromHTMLData:html];\n}\n\n+ (instancetype)attributedStringFromHTMLData:(NSData *)data attributes:(NSDictionary *)attributes {\n    return [self attributedStringFromHTMLData:data CSSData:[[attributes CSSStringFromAttributes] dataUsingEncoding:NSUTF8StringEncoding]];\n}\n\n@end\n\n@interface UIColor (HTMLRGBString)\n- (NSString *)HTMLRGBString;\n@end\n\n@implementation UIColor (HTMLRGBString)\n\n- (NSString *)HTMLRGBString {\n    UIColor *color = self;\n    \n    CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;\n    \n    if (CGColorGetNumberOfComponents(color.CGColor) == 2) {\n        CGFloat white = 0.f, alpha = 0.f;\n        [color getWhite:&white alpha:&alpha];\n        red = white;\n        green = white;\n        blue = white;\n    } else {\n        [color getRed:&red green:&green blue:&blue alpha:&alpha];\n    }\n    \n    return [NSString stringWithFormat:@\"rgb(%li, %li, %li)\", lroundf(red*255.f), lroundf(green*255.f), lroundf(blue*255.f)];\n}\n\n@end\n\n@implementation NSDictionary (CSS)\n\n+ (NSString *)cssStringWithValues:(NSDictionary *)attributes HTMLTag:(QRHTMLAttribute *)tag {\n    \n    NSMutableString *cssString = [NSMutableString stringWithFormat:@\"%@ {\", tag];\n    \n    for (NSString *key in attributes) {\n        \n#if DEBUG\n        NSSet *set = [NSSet setWithObjects:NSLigatureAttributeName, NSKernAttributeName, NSStrikethroughStyleAttributeName, NSStrikethroughColorAttributeName, NSUnderlineStyleAttributeName, NSStrokeColorAttributeName, NSStrokeWidthAttributeName, NSTextEffectAttributeName, NSObliquenessAttributeName, NSExpansionAttributeName, NSWritingDirectionAttributeName, NSVerticalGlyphFormAttributeName, NSUnderlineColorAttributeName, NSAttachmentAttributeName, NSLinkAttributeName, NSBaselineOffsetAttributeName, nil];\n        NSAssert(![set containsObject:key], @\"Invalid Key. This library doesn't support %@ yet.\", key);\n#endif\n\n        \n        if (key == NSFontAttributeName) {\n            UIFont *font = attributes[NSFontAttributeName];\n            [cssString appendFormat:@\"font-family:'%@'; font-size: %0.fpx; \", font.fontName, roundf(font.pointSize)];;\n        } else if (key == NSParagraphStyleAttributeName) {\n            NSParagraphStyle *style = attributes[key];\n            \n            NSString *alignment;\n            \n            switch (style.alignment) {\n                case NSTextAlignmentCenter:\n                    alignment = @\"center\";\n                    break;\n                case NSTextAlignmentJustified:\n                    alignment = @\"justify\";\n                    break;\n                case NSTextAlignmentLeft:\n                    alignment = @\"left\";\n                    break;\n                case NSTextAlignmentNatural:\n                    alignment = @\"initial\";\n                    break;\n                case NSTextAlignmentRight:\n                    alignment = @\"right\";\n                    break;\n                default:\n                    alignment = @\"left\";\n                    break;\n            }\n            \n            [cssString appendFormat:@\"line-height:%0.1f%%; text-align:%@;\", style.lineHeightMultiple*100, alignment];\n            if (style.baseWritingDirection == NSWritingDirectionRightToLeft){\n                [cssString appendString:@\"direction:rtl;\"];\n            }else{\n                [cssString appendString:@\"direction:ltr;\"];\n            }\n            \n            \n        } else if (key == NSForegroundColorAttributeName) {\n            [cssString appendFormat:@\"color:%@; \", [attributes[key] HTMLRGBString]];\n        } else if (key == NSBackgroundColorAttributeName ) {\n            [cssString appendFormat:@\"background-color:%@; \", [attributes[key] HTMLRGBString]];;\n        } else if (key == NSShadowAttributeName) {\n            NSShadow *shadow = attributes[NSShadowAttributeName];\n            [cssString appendFormat:@\"text-shadow: %fpx %fpx %fpx %@; \", shadow.shadowOffset.width, shadow.shadowOffset.height, shadow.shadowBlurRadius, [shadow.shadowColor HTMLRGBString]];\n        }\n    }\n    \n    [cssString appendString:@\"}\"];\n    \n    return cssString;\n}\n\n- (NSString *)CSSStringFromAttributes {\n    NSMutableString *string = [NSMutableString stringWithString:@\"<style>\"];\n    \n    for (NSString *key in self) {\n        id object = self[key];\n        if ([object isKindOfClass:[NSDictionary class]]) {\n            [string appendString:[NSDictionary cssStringWithValues:object HTMLTag:key]];\n        } else if ([object isKindOfClass:[NSString class]]) {\n            [string appendString:object];\n        }\n    }\n    \n    [string appendString:@\"</style>\"];\n    \n    return string;\n}\n\n@end\n\n@implementation NSMutableDictionary (CSS)\n\n- (void)addAttributes:(NSDictionary *)attributes forHTMLAttribute:(QRHTMLAttribute *)tag flatten:(BOOL)flatten {\n    if (!flatten) {\n        [self setObject:attributes forKey:tag];\n    } else {\n        [self setObject:[NSDictionary cssStringWithValues:attributes HTMLTag:tag] forKey:tag];\n    }\n}\n\n@end\n\n@implementation NSData (HTMLAdditions)\n\n- (NSData *)dataByReplacingOccurrencesOfData:(NSData *)data withData:(NSData *)replacementData {\n    NSMutableData *mutableSelf = [self mutableCopy];\n    const void *replacementBytes = [replacementData bytes];\n    NSUInteger replacementBytesLength = [replacementData length];\n    \n    NSRange rangeOfCharacters = [mutableSelf rangeOfData:data options:0 range:NSMakeRange(0, [mutableSelf length])];\n    \n    while (rangeOfCharacters.location != NSNotFound) {\n        [mutableSelf replaceBytesInRange:rangeOfCharacters withBytes:replacementBytes];\n        NSUInteger searchLocation = replacementBytesLength + rangeOfCharacters.location;\n        rangeOfCharacters = [mutableSelf rangeOfData:data options:0 range:NSMakeRange(searchLocation, [mutableSelf length]-searchLocation)];\n    }\n    \n    return [NSData dataWithData:mutableSelf];\n}\n\n@end"
  },
  {
    "path": "Pod/Classes/Extend/EUI/StringFormat.swift",
    "content": "//\n//  StringFormat.swift\n//  Pods\n//\n//  Created by zhuchao on 15/10/15.\n//\n//\n\nimport Foundation\n\nextension String{\n    var viewContentMode:UIViewContentMode{\n        var dict = Dictionary<String,UIViewContentMode>()\n        dict[\"ScaleToFill\"] = UIViewContentMode.ScaleToFill\n        dict[\"ScaleAspectFit\"] = UIViewContentMode.ScaleAspectFit\n        dict[\"ScaleAspectFill\"] = UIViewContentMode.ScaleAspectFill\n        dict[\"Redraw\"] = UIViewContentMode.Redraw\n        dict[\"Center\"] = UIViewContentMode.Center\n        dict[\"Top\"] = UIViewContentMode.Top\n        dict[\"Bottom\"] = UIViewContentMode.Bottom\n        dict[\"Left\"] = UIViewContentMode.Left\n        dict[\"Right\"] = UIViewContentMode.Right\n        dict[\"TopLeft\"] = UIViewContentMode.TopLeft\n        dict[\"TopRight\"] = UIViewContentMode.TopRight\n        dict[\"BottomLeft\"] = UIViewContentMode.BottomLeft\n        dict[\"BottomRight\"] = UIViewContentMode.BottomRight\n        if let mode = dict[self.trim]{\n            return mode\n        }else{\n            return UIViewContentMode.ScaleToFill\n        }\n    }\n    \n    var flexContentDirection:FLEXBOXContentDirection{\n        switch self.trim {\n        case \"ltr\":\n            return .LeftToRight\n        case \"rtl\":\n            return .RightToLeft\n        case \"inherit\":\n            return .Inherit\n        default:\n            return .LeftToRight\n        }\n    }\n    \n    var justifyContent:FLEXBOXJustification{\n        switch self.trim {\n        case \"center\":\n            return .Center\n        case \"flex-start\":\n            return .FlexStart\n        case \"flex-end\":\n            return .FlexEnd\n        case \"space-between\":\n            return .SpaceBetween\n        case \"space-around\":\n            return .SpaceAround\n        default:\n            return .FlexStart\n        }\n    }\n    \n    var alignItems:FLEXBOXAlignment{\n        switch self.trim {\n        case \"center\":\n            return .Center\n        case \"flex-start\":\n            return .FlexStart\n        case \"flex-end\":\n            return .FlexEnd\n        case \"stretch\":\n            return .Stretch\n        case \"auto\":\n            return .Auto\n        default:\n            return .Auto\n        }\n    }\n    \n    var flexDirection:FLEXBOXFlexDirection{\n        switch self.trim {\n        case \"column\":\n            return .Column\n        case \"row\":\n            return .Row\n        case \"row-reverse\":\n            return .RowReverse\n        case \"column-reverse\":\n            return .ColumnReverse\n        default:\n            return .Row\n        }\n    }\n    \n    var separatorStyle:UITableViewCellSeparatorStyle{\n        switch self.trim{\n        case \"None\" :\n            return .None\n        case \"SingleLine\":\n            return .SingleLine\n        case \"SingleLineEtched\":\n            return .SingleLineEtched\n        default:\n            return .SingleLine\n        }\n    }\n    \n    var tableViewStyle:UITableViewStyle{\n        switch self.trim{\n        case \"plain\":\n            return .Plain\n        case \"grouped\":\n            return .Grouped\n        default:\n            return .Plain\n        }\n    }\n    \n    var scrollViewIndicatorStyle:UIScrollViewIndicatorStyle{\n        switch self.trim{\n        case \"white\":\n            return .White\n        case \"black\":\n            return .Black\n        default:\n            return .Default\n        }\n    }\n    \n    var textAlignment:NSTextAlignment {\n        switch(self.trim){\n        case \"center\":\n            return NSTextAlignment.Center\n        case \"left\":\n            return NSTextAlignment.Left\n        case \"right\":\n            return NSTextAlignment.Right\n        case \"justified\":\n            return NSTextAlignment.Justified\n        case \"natural\":\n            return NSTextAlignment.Natural\n        default:\n            return NSTextAlignment.Left\n        }\n    }\n    \n    var linkStyleDict:[NSObject:AnyObject]{\n        let linkArray = self.trimArrayBy(\";\")\n        var dict = Dictionary<NSObject,AnyObject>()\n        for str in linkArray {\n            var strArray = str.trimArrayBy(\":\")\n            if strArray.count == 2 {\n                switch strArray[0] {\n                case \"color\":\n                    dict[kCTForegroundColorAttributeName] = UIColor(CSS: strArray[1].trim)\n                case \"text-decoration\":\n                    dict[NSUnderlineStyleAttributeName] = strArray[1].trim.underlineStyle.rawValue\n                default :\n                    dict[NSUnderlineStyleAttributeName] = NSUnderlineStyle.StyleSingle.rawValue\n                }\n            }\n        }\n        return dict\n    }\n    \n    \n    var keyboardType:UIKeyboardType {\n        \n        switch self.lowercaseString {\n        case \"Default\".lowercaseString:\n            return UIKeyboardType.Default\n        case \"ASCIICapable\".lowercaseString:\n            return UIKeyboardType.ASCIICapable\n        case \"NumbersAndPunctuation\".lowercaseString:\n            return UIKeyboardType.NumbersAndPunctuation\n        case \"URL\".lowercaseString:\n            return UIKeyboardType.URL\n        case \"NumberPad\".lowercaseString:\n            return UIKeyboardType.NumberPad\n        case \"PhonePad\".lowercaseString:\n            return UIKeyboardType.PhonePad\n        case \"NamePhonePad\".lowercaseString:\n            return UIKeyboardType.NamePhonePad\n        case \"EmailAddress\".lowercaseString:\n            return UIKeyboardType.EmailAddress\n        case \"DecimalPad\".lowercaseString:\n            return UIKeyboardType.DecimalPad\n        case \"Twitter\".lowercaseString:\n            return UIKeyboardType.Twitter\n        case \"Twitter\".lowercaseString:\n            return UIKeyboardType.WebSearch\n        default:\n            return UIKeyboardType.Default\n        }\n    }\n    \n    \n    var underlineStyle:NSUnderlineStyle{\n        switch self.lowercaseString {\n        case \"None\".lowercaseString :\n            return NSUnderlineStyle.StyleNone\n        case \"StyleSingle\".lowercaseString :\n            return NSUnderlineStyle.StyleSingle\n        case \"StyleThick\".lowercaseString :\n            return NSUnderlineStyle.StyleThick\n        case \"StyleDouble\".lowercaseString :\n            return NSUnderlineStyle.StyleDouble\n        case \"PatternDot\".lowercaseString :\n            return NSUnderlineStyle.PatternDot\n        case \"PatternDash\".lowercaseString :\n            return NSUnderlineStyle.PatternDash\n        case \"PatternDashDot\".lowercaseString :\n            return NSUnderlineStyle.PatternDashDot\n        case \"PatternDashDotDot\".lowercaseString :\n            return NSUnderlineStyle.PatternDashDotDot\n        case \"ByWord\".lowercaseString :\n            return NSUnderlineStyle.ByWord\n        default :\n            return NSUnderlineStyle.StyleSingle\n        }\n    }\n    \n    var controlEvent: UIControlEvents{\n        switch self.lowercaseString {\n        case \"TouchDown\".lowercaseString :\n            return UIControlEvents.TouchDown\n        case \"TouchDownRepeat\".lowercaseString :\n            return UIControlEvents.TouchDownRepeat\n        case \"TouchDragInside\".lowercaseString :\n            return UIControlEvents.TouchDragInside\n        case \"TouchDragOutside\".lowercaseString :\n            return UIControlEvents.TouchDragOutside\n        case \"TouchDragEnter\".lowercaseString :\n            return UIControlEvents.TouchDragEnter\n        case \"TouchDragExit\".lowercaseString :\n            return UIControlEvents.TouchDragExit\n        case \"TouchUpInside\".lowercaseString :\n            return UIControlEvents.TouchUpInside\n        case \"TouchUpOutside\".lowercaseString :\n            return UIControlEvents.TouchUpOutside\n        case \"ValueChanged\".lowercaseString :\n            return UIControlEvents.ValueChanged\n        case \"TouchCancel\".lowercaseString :\n            return UIControlEvents.TouchCancel\n        case \"EditingDidBegin\".lowercaseString :\n            return UIControlEvents.EditingDidBegin\n        case \"EditingChanged\".lowercaseString :\n            return UIControlEvents.EditingChanged\n        case \"EditingDidEnd\".lowercaseString :\n            return UIControlEvents.EditingDidEnd\n        case \"EditingDidEndOnExit\".lowercaseString :\n            return UIControlEvents.EditingDidEndOnExit\n        case \"AllTouchEvents\".lowercaseString :\n            return UIControlEvents.AllTouchEvents\n        case \"AllEditingEvents\".lowercaseString :\n            return UIControlEvents.AllEditingEvents\n        case \"ApplicationReserved\".lowercaseString :\n            return UIControlEvents.ApplicationReserved\n        case \"SystemReserved\".lowercaseString :\n            return UIControlEvents.SystemReserved\n        case \"AllEvents\".lowercaseString :\n            return UIControlEvents.AllEvents\n        default :\n            return UIControlEvents.TouchUpInside\n        }\n    }\n    \n}"
  },
  {
    "path": "Pod/Classes/Extend/EUI/SwiftTryCatch.h",
    "content": "//\n//  SwiftTryCatch.h\n//\n//  Created by William Falcon on 10/10/14.\n//  Copyright (c) 2014 William Falcon. All rights reserved.\n//\n/*\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n#import <Foundation/Foundation.h>\n@import UIKit;\n\n@interface SwiftTryCatch : NSObject\n\n/**\n Provides try catch functionality for swift by wrapping around Objective-C\n */\n+ (void)try:(void(^)())try catch:(void(^)(NSException*exception))catch finally:(void(^)())finally;\n+ (void)throwString:(NSString*)s;\n+ (void)throwException:(NSException*)e;\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/SwiftTryCatch.m",
    "content": "//\n//  SwiftTryCatch.h\n//\n//  Created by William Falcon on 10/10/14.\n//  Copyright (c) 2014 William Falcon. All rights reserved.\n//\n/*\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n\n#import \"SwiftTryCatch.h\"\n\n@implementation SwiftTryCatch\n\n/**\n Provides try catch functionality for swift by wrapping around Objective-C\n */\n+(void)try:(void (^)())try catch:(void (^)(NSException *))catch finally:(void (^)())finally{\n    @try {\n        try ? try() : nil;\n    }\n    \n    @catch (NSException *exception) {\n        catch ? catch(exception) : nil;\n    }\n    @finally {\n        finally ? finally() : nil;\n    }\n}\n\n+ (void)throwString:(NSString*)s\n{\n\t@throw [NSException exceptionWithName:s reason:s userInfo:nil];\n}\n\n+ (void)throwException:(NSException*)e\n{\n\t@throw e;\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/EUI/UIColor+HTMLColors.h",
    "content": "//\n//  UIColor+HTMLColors.h\n//\n//  Created by James Lawton on 12/9/12.\n//  Copyright (c) 2012 James Lawton. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n/**\n * Extensions to read and write colors in the formats supported by CSS.\n * Emphasis has been given to parsing corrently formatted colors, rather\n * than rejecting technically invalid colors.\n */\n@interface UIColor (HTMLColors)\n\n/**\n * Reads a color from a string containing hex, RGB, HSL or X11 named color.\n * Returns `nil` on failure.\n */\n+ (UIColor *)colorWithCSS:(NSString *)cssColor;\n\n/**\n * Reads a color from a string containing a hex color, of the form\n * \"#FFFFFF\" or \"#FFF\".\n * Returns `nil` on failure.\n */\n+ (UIColor *)colorWithHexString:(NSString *)hexColor;\n\n/**\n * Reads a color from a string containing an RGB color, of the form\n * \"rgb(255, 255, 255)\" or \"rgba(255, 255, 255, 1.0)\". Supports components\n * represented as percentages.\n * Returns `nil` on failure.\n */\n+ (UIColor *)colorWithRGBString:(NSString *)rgbColor;\n\n/**\n * Reads a color from a string containing an HSL color, of the form\n * \"hsl(359, 100%, 100%)\" or \"hsla(359, 100%, 100%, 1.0)\".\n * Returns `nil` on failure.\n */\n+ (UIColor *)colorWithHSLString:(NSString *)hslColor;\n\n/**\n * Reads a color from a string containing a W3C named color.\n * Returns `nil` on failure.\n */\n+ (UIColor *)colorWithW3CNamedColor:(NSString *)namedColor;\n\n/**\n * Returns a representation of this color as a hex string, of the form \"#FFFFFF\".\n * Alpha information is not represented.\n */\n- (NSString *)hexStringValue;\n\n/**\n * Returns a representation of this color as an RGB string, of the form\n * \"rgb(255, 255, 255)\" or \"rgba(255, 255, 255, 1.0)\".\n * Returns `nil` on failure.\n */\n- (NSString *)rgbStringValue;\n\n/**\n * Returns a representation of this color as an RGB string, of the form\n * \"hsl(359, 100%, 100%)\" or \"hsla(359, 100%, 100%, 1.0)\".\n * Returns `nil` on failure.\n */\n- (NSString *)hslStringValue;\n\n/**\n * FOR DEBUGGING - All the supported W3C color names.\n */\n+ (NSArray *)W3CColorNames;\n\n@end\n\n\n/**\n * Extensions to scan colors in the formats supported by CSS.\n */\n@interface NSScanner (HTMLColors)\n\n/**\n * Scan a color hex, RGB, HSL or X11 named color.\n */\n- (BOOL)scanCSSColor:(UIColor **)color;\n\n/**\n * Scan an RGB color (\"rgb(255, 255, 255)\", \"rgba(255, 255, 255, 1.0)\").\n */\n- (BOOL)scanRGBColor:(UIColor **)color;\n\n/**\n * Scan an HSL color (\"hsl(359, 100%, 100%)\", \"hsla(359, 100%, 100%, 1.0)\").\n */\n- (BOOL)scanHSLColor:(UIColor **)color;\n\n/**\n * Scan a hex color (\"#FFFFFF\", \"#FFF\").\n */\n- (BOOL)scanHexColor:(UIColor **)color;\n\n/**\n * Scan a CSS3/SVG named color. These are similar to the X11 named colors.\n * See: http://www.w3.org/TR/css3-color/#svg-color\n */\n- (BOOL)scanW3CNamedColor:(UIColor **)color;\n\n@end"
  },
  {
    "path": "Pod/Classes/Extend/EUI/UIColor+HTMLColors.m",
    "content": "//\n//  UIColor+HTMLColors.m\n//\n//  Created by James Lawton on 12/9/12.\n//  Copyright (c) 2012 James Lawton. All rights reserved.\n//\n\n#import \"UIColor+HTMLColors.h\"\n\n\ntypedef struct {\n    CGFloat a, b, c;\n} CMRFloatTriple;\n\ntypedef struct {\n    CGFloat a, b, c, d;\n} CMRFloatQuad;\n\n// CSS uses HSL, but we have to specify UIColor as HSB\nstatic inline CMRFloatTriple HSB2HSL(CGFloat hue, CGFloat saturation, CGFloat brightness);\nstatic inline CMRFloatTriple HSL2HSB(CGFloat hue, CGFloat saturation, CGFloat lightness);\n\nstatic NSArray *CMRW3CColorNames(void);\nstatic NSDictionary *CMRW3CNamedColors(void);\n\n\n@implementation UIColor (HTMLColors)\n\n#pragma mark - Reading\n\n+ (UIColor *)colorWithCSS:(NSString *)cssColor\n{\n    UIColor *color = nil;\n    NSScanner *scanner = [NSScanner scannerWithString:cssColor];\n    [scanner scanCSSColor:&color];\n    return (scanner.isAtEnd) ? color : nil;\n}\n\n+ (UIColor *)colorWithHexString:(NSString *)hexColor\n{\n    UIColor *color = nil;\n    NSScanner *scanner = [NSScanner scannerWithString:hexColor];\n    [scanner scanHexColor:&color];\n    return (scanner.isAtEnd) ? color : nil;\n}\n\n+ (UIColor *)colorWithRGBString:(NSString *)rgbColor\n{\n    UIColor *color = nil;\n    NSScanner *scanner = [NSScanner scannerWithString:rgbColor];\n    [scanner scanRGBColor:&color];\n    return (scanner.isAtEnd) ? color : nil;\n}\n\n+ (UIColor *)colorWithHSLString:(NSString *)hslColor\n{\n    UIColor *color = nil;\n    NSScanner *scanner = [NSScanner scannerWithString:hslColor];\n    [scanner scanHSLColor:&color];\n    return (scanner.isAtEnd) ? color : nil;\n}\n\n+ (UIColor *)colorWithW3CNamedColor:(NSString *)namedColor\n{\n    UIColor *color = nil;\n    NSScanner *scanner = [NSScanner scannerWithString:namedColor];\n    [scanner scanW3CNamedColor:&color];\n    return (scanner.isAtEnd) ? color : nil;\n}\n\n#pragma mark - Writing\n\nstatic inline unsigned ToByte(CGFloat f)\n{\n    f = MAX(0, MIN(f, 1)); // Clamp\n    return (unsigned)round(f * 255);\n}\n\n- (NSString *)hexStringValue\n{\n    NSString *hex = nil;\n    CGFloat red, green, blue, alpha;\n    if ([self cmr_getRed:&red green:&green blue:&blue alpha:&alpha]) {\n        hex = [NSString stringWithFormat:@\"#%02X%02X%02X\",\n               ToByte(red), ToByte(green), ToByte(blue)];\n    }\n    return hex;\n}\n\n- (NSString *)rgbStringValue\n{\n    NSString *rgb = nil;\n    CGFloat red, green, blue, alpha;\n    if ([self cmr_getRed:&red green:&green blue:&blue alpha:&alpha]) {\n        if (alpha == 1.0) {\n            rgb = [NSString stringWithFormat:@\"rgb(%u, %u, %u)\",\n                   ToByte(red), ToByte(green), ToByte(blue)];\n        } else {\n            rgb = [NSString stringWithFormat:@\"rgba(%u, %u, %u, %g)\",\n                   ToByte(red), ToByte(green), ToByte(blue), alpha];\n        }\n    }\n    return rgb;\n}\n\nstatic inline unsigned ToDeg(CGFloat f)\n{\n    return (unsigned)round(f * 360) % 360;\n}\n\nstatic inline unsigned ToPercentage(CGFloat f)\n{\n    f = MAX(0, MIN(f, 1)); // Clamp\n    return (unsigned)round(f * 100);\n}\n\n- (NSString *)hslStringValue\n{\n    NSString *hsl = nil;\n    CGFloat hue, saturation, brightness, alpha;\n    if ([self cmr_getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha]) {\n        CMRFloatTriple hslVal = HSB2HSL(hue, saturation, brightness);\n        if (alpha == 1.0) {\n            hsl = [NSString stringWithFormat:@\"hsl(%u, %u%%, %u%%)\",\n                   ToDeg(hslVal.a), ToPercentage(hslVal.b), ToPercentage(hslVal.c)];\n        } else {\n            hsl = [NSString stringWithFormat:@\"hsla(%u, %u%%, %u%%, %g)\",\n                   ToDeg(hslVal.a), ToPercentage(hslVal.b), ToPercentage(hslVal.c), alpha];\n        }\n    }\n    return hsl;\n}\n\n// Fix up getting color components\n- (BOOL)cmr_getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha\n{\n    if ([self getRed:red green:green blue:blue alpha:alpha]) {\n        return YES;\n    }\n\n    CGFloat white;\n    if ([self getWhite:&white alpha:alpha]) {\n        if (red)\n            *red = white;\n        if (green)\n            *green = white;\n        if (blue)\n            *blue = white;\n        return YES;\n    }\n\n    return NO;\n}\n\n- (BOOL)cmr_getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha\n{\n    if ([self getHue:hue saturation:saturation brightness:brightness alpha:alpha]) {\n        return YES;\n    }\n\n    CGFloat white;\n    if ([self getWhite:&white alpha:alpha]) {\n        if (hue)\n            *hue = 0;\n        if (saturation)\n            *saturation = 0;\n        if (brightness)\n            *brightness = white;\n        return YES;\n    }\n\n    return NO;\n}\n\n+ (NSArray *)W3CColorNames\n{\n    return [[CMRW3CNamedColors() allKeys] sortedArrayUsingSelector:@selector(compare:)];\n}\n\n@end\n\n\n@implementation NSScanner (HTMLColors)\n\n- (BOOL)scanCSSColor:(UIColor **)color\n{\n    return [self scanHexColor:color]\n        || [self scanRGBColor:color]\n        || [self scanHSLColor:color]\n        || [self cmr_scanTransparent:color]\n        || [self scanW3CNamedColor:color];\n}\n\n- (BOOL)scanRGBColor:(UIColor **)color\n{\n    return [self cmr_caseInsensitiveWithCleanup:^BOOL{\n        if ([self scanString:@\"rgba\" intoString:NULL]) {\n            CMRFloatQuad scale = {1.0/255.0, 1.0/255.0, 1.0/255.0, 1.0};\n            CMRFloatQuad q;\n            if ([self cmr_scanFloatQuad:&q scale:scale]) {\n                if (color) {\n                    *color = [UIColor colorWithRed:q.a green:q.b blue:q.c alpha:q.d];\n                }\n                return YES;\n            }\n        } else if ([self scanString:@\"rgb\" intoString:NULL]) {\n            CMRFloatTriple scale = {1.0/255.0, 1.0/255.0, 1.0/255.0};\n            CMRFloatTriple t;\n            if ([self cmr_scanFloatTriple:&t scale:scale]) {\n                if (color) {\n                    *color = [UIColor colorWithRed:t.a green:t.b blue:t.c alpha:1.0];\n                }\n                return YES;\n            }\n        }\n        return NO;\n    }];\n}\n\n// Wrap hues in a circle, where [0,1] = [0°,360°]\nstatic inline CGFloat CMRNormHue(CGFloat hue)\n{\n    return hue - floor(hue);\n}\n\n- (BOOL)scanHSLColor:(UIColor **)color\n{\n    return [self cmr_caseInsensitiveWithCleanup:^BOOL{\n        if ([self scanString:@\"hsla\" intoString:NULL]) {\n            CMRFloatQuad scale = {1.0/360.0, 1.0, 1.0, 1.0};\n            CMRFloatQuad q;\n            if ([self cmr_scanFloatQuad:&q scale:scale]) {\n                if (color) {\n                    CMRFloatTriple t = HSL2HSB(CMRNormHue(q.a), q.b, q.c);\n                    *color = [UIColor colorWithHue:t.a saturation:t.b brightness:t.c alpha:q.d];\n                }\n                return YES;\n            }\n        } else if ([self scanString:@\"hsl\" intoString:NULL]) {\n            CMRFloatTriple scale = {1.0/360.0, 1.0, 1.0};\n            CMRFloatTriple t;\n            if ([self cmr_scanFloatTriple:&t scale:scale]) {\n                if (color) {\n                    t = HSL2HSB(CMRNormHue(t.a), t.b, t.c);\n                    *color = [UIColor colorWithHue:t.a saturation:t.b brightness:t.c alpha:1.0];\n                }\n                return YES;\n            }\n        }\n        return NO;\n    }];\n}\n\n- (BOOL)scanHexColor:(UIColor **)color\n{\n    return [self cmr_resetScanLocationOnFailure:^BOOL{\n        return [self scanString:@\"#\" intoString:NULL]\n            && [self cmr_scanHexTriple:color];\n    }];\n}\n\n- (BOOL)scanW3CNamedColor:(UIColor **)color\n{\n    return [self cmr_caseInsensitiveWithCleanup:^BOOL{\n        NSArray *colorNames = CMRW3CColorNames();\n        NSDictionary *namedColors = CMRW3CNamedColors();\n        for (NSString *name in colorNames) {\n            if ([self scanString:name intoString:NULL]) {\n                if (color) {\n                    *color = [UIColor colorWithHexString:namedColors[name]];\n                }\n                return YES;\n            }\n        }\n        return NO;\n    }];\n}\n\n#pragma mark - Private\n\n- (void)cmr_withSkip:(NSCharacterSet *)chars run:(void (^)(void))block\n{\n    NSCharacterSet *skipped = self.charactersToBeSkipped;\n    self.charactersToBeSkipped = chars;\n    block();\n    self.charactersToBeSkipped = skipped;\n}\n\n- (void)cmr_withNoSkip:(void (^)(void))block\n{\n    NSCharacterSet *skipped = self.charactersToBeSkipped;\n    self.charactersToBeSkipped = nil;\n    block();\n    self.charactersToBeSkipped = skipped;\n}\n\n- (NSRange)cmr_rangeFromScanLocation\n{\n    NSUInteger loc = self.scanLocation;\n    NSUInteger len = self.string.length - loc;\n    return NSMakeRange(loc, len);\n}\n\n- (void)cmr_skipCharactersInSet:(NSCharacterSet *)chars\n{\n    [self cmr_withNoSkip:^{\n        [self scanCharactersFromSet:chars intoString:NULL];\n    }];\n}\n\n- (void)cmr_skip\n{\n    [self cmr_skipCharactersInSet:self.charactersToBeSkipped];\n}\n\n- (BOOL)cmr_resetScanLocationOnFailure:(BOOL (^)(void))block\n{\n    NSUInteger initialScanLocation = self.scanLocation;\n    if (!block()) {\n        self.scanLocation = initialScanLocation;\n        return NO;\n    }\n    return YES;\n}\n\n- (BOOL)cmr_caseInsensitiveWithCleanup:(BOOL (^)(void))block\n{\n    NSUInteger initialScanLocation = self.scanLocation;\n    BOOL caseSensitive = self.caseSensitive;\n    self.caseSensitive = NO;\n\n    BOOL success = block();\n    if (!success) {\n        self.scanLocation = initialScanLocation;\n    }\n\n    self.caseSensitive = caseSensitive;\n    return success;\n}\n\n// Scan, but only so far\n- (NSRange)cmr_scanCharactersInSet:(NSCharacterSet *)chars maxLength:(NSUInteger)maxLength intoString:(NSString **)outString\n{\n    NSRange range = [self cmr_rangeFromScanLocation];\n    range.length = MIN(range.length, maxLength);\n\n    NSUInteger len;\n    for (len = 0; len < range.length; ++len) {\n        if (![chars characterIsMember:[self.string characterAtIndex:(range.location + len)]]) {\n            break;\n        }\n    }\n\n    NSRange charRange = NSMakeRange(range.location, len);\n    if (outString) {\n        *outString = [self.string substringWithRange:charRange];\n    }\n\n    self.scanLocation = charRange.location + charRange.length;\n\n    return charRange;\n}\n\n// Hex characters\nstatic NSCharacterSet *CMRHexCharacters() {\n    static NSCharacterSet *hexChars;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        hexChars = [NSCharacterSet characterSetWithCharactersInString:@\"0123456789ABCDEFabcdef\"];\n    });\n    return hexChars;\n}\n\n// We know we've got hex already, so assume this works\nstatic NSUInteger CMRParseHex(NSString *str, BOOL repeated)\n{\n    unsigned int ans = 0;\n    if (repeated) {\n        str = [NSString stringWithFormat:@\"%@%@\", str, str];\n    }\n    NSScanner *scanner = [NSScanner scannerWithString:str];\n    [scanner scanHexInt:&ans];\n    return ans;\n}\n\n// Scan FFF or FFFFFF, doesn't reset scan location on failure\n- (BOOL)cmr_scanHexTriple:(UIColor **)color\n{\n    NSString *hex = nil;\n    NSRange range = [self cmr_scanCharactersInSet:CMRHexCharacters() maxLength:6 intoString:&hex];\n    CGFloat red, green, blue;\n    if (hex.length == 6) {\n        // Parse 2 chars per component\n        red   = CMRParseHex([hex substringWithRange:NSMakeRange(0, 2)], NO) / 255.0;\n        green = CMRParseHex([hex substringWithRange:NSMakeRange(2, 2)], NO) / 255.0;\n        blue  = CMRParseHex([hex substringWithRange:NSMakeRange(4, 2)], NO) / 255.0;\n    } else if (hex.length >= 3) {\n        // Parse 1 char per component, but repeat it to calculate hex value\n        red   = CMRParseHex([hex substringWithRange:NSMakeRange(0, 1)], YES) / 255.0;\n        green = CMRParseHex([hex substringWithRange:NSMakeRange(1, 1)], YES) / 255.0;\n        blue  = CMRParseHex([hex substringWithRange:NSMakeRange(2, 1)], YES) / 255.0;\n        self.scanLocation = range.location + 3;\n    } else {\n        return NO; // Fail\n    }\n    if (color) {\n        *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];\n    }\n    return YES;\n}\n\n// Scan \"transparent\"\n- (BOOL)cmr_scanTransparent:(UIColor **)color\n{\n    return [self cmr_caseInsensitiveWithCleanup:^BOOL{\n        if ([self scanString:@\"transparent\" intoString:NULL]) {\n            if (color) {\n                *color = [UIColor colorWithWhite:0 alpha:0];\n            }\n            return YES;\n        }\n        return NO;\n    }];\n}\n\n// Scan a float or percentage. Multiply float by `scale` if it was not a\n// percentage.\n- (BOOL)cmr_scanNum:(CGFloat *)value scale:(CGFloat)scale\n{\n    float f = 0.0;\n    if ([self scanFloat:&f]) {\n        if ([self scanString:@\"%\" intoString:NULL]) {\n            f *= 0.01;\n        } else {\n            f *= scale;\n        }\n        if (value) {\n            *value = f;\n        }\n        return YES;\n    }\n    return NO;\n}\n\n// Scan a triple of numbers \"(10, 10, 10)\". If they are not percentages, multiply\n// by the corresponding `scale` component.\n- (BOOL)cmr_scanFloatTriple:(CMRFloatTriple *)triple scale:(CMRFloatTriple)scale\n{\n    __block BOOL success = NO;\n    __block CMRFloatTriple t;\n    [self cmr_withSkip:[NSCharacterSet whitespaceAndNewlineCharacterSet] run:^{\n        success = [self scanString:@\"(\" intoString:NULL]\n            && [self cmr_scanNum:&(t.a) scale:scale.a]\n            && [self scanString:@\",\" intoString:NULL]\n            && [self cmr_scanNum:&(t.b) scale:scale.b]\n            && [self scanString:@\",\" intoString:NULL]\n            && [self cmr_scanNum:&(t.c) scale:scale.c]\n            && [self scanString:@\")\" intoString:NULL];\n    }];\n    if (triple) {\n        *triple = t;\n    }\n    return success;\n}\n\n// Scan a quad of numbers \"(10, 10, 10, 10)\". If they are not percentages,\n// multiply by the corresponding `scale` component.\n- (BOOL)cmr_scanFloatQuad:(CMRFloatQuad *)quad scale:(CMRFloatQuad)scale\n{\n    __block BOOL success = NO;\n    __block CMRFloatQuad q;\n    [self cmr_withSkip:[NSCharacterSet whitespaceAndNewlineCharacterSet] run:^{\n        success = [self scanString:@\"(\" intoString:NULL]\n            && [self cmr_scanNum:&(q.a) scale:scale.a]\n            && [self scanString:@\",\" intoString:NULL]\n            && [self cmr_scanNum:&(q.b) scale:scale.b]\n            && [self scanString:@\",\" intoString:NULL]\n            && [self cmr_scanNum:&(q.c) scale:scale.c]\n            && [self scanString:@\",\" intoString:NULL]\n            && [self cmr_scanNum:&(q.d) scale:scale.d]\n            && [self scanString:@\")\" intoString:NULL];\n    }];\n    if (quad) {\n        *quad = q;\n    }\n    return success;\n}\n\n@end\n\nstatic inline CMRFloatTriple HSB2HSL(CGFloat hue, CGFloat saturation, CGFloat brightness)\n{\n    CGFloat l = (2.0 - saturation) * brightness;\n    saturation *= brightness;\n    CGFloat satDiv = (l <= 1.0) ? l : (2.0 - l);\n    if (satDiv) {\n        saturation /= satDiv;\n    }\n    l *= 0.5;\n    CMRFloatTriple hsl = {\n        hue,\n        saturation,\n        l\n    };\n    return hsl;\n}\n\nstatic inline CMRFloatTriple HSL2HSB(CGFloat hue, CGFloat saturation, CGFloat l)\n{\n    l *= 2.0;\n    CGFloat s = saturation * ((l <= 1.0) ? l : (2.0 - l));\n    CGFloat brightness = (l + s) * 0.5;\n    if (s) {\n        s = (2.0 * s) / (l + s);\n    }\n    CMRFloatTriple hsb = {\n        hue,\n        s,\n        brightness\n    };\n    return hsb;\n}\n\n// Color names, longest first\nstatic NSArray *CMRW3CColorNames() {\n    static NSArray *colorNames;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        colorNames = [[CMRW3CNamedColors() allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString *k1, NSString *k2) {\n            NSInteger diff = k1.length - k2.length;\n            if (!diff) {\n                return NSOrderedSame;\n            } else if (diff > 0) {\n                return NSOrderedAscending;\n            } else {\n                return NSOrderedDescending;\n            }\n        }];\n    });\n    return colorNames;\n}\n\n// Color values as defined in CSS3 spec.\n// See: http://www.w3.org/TR/css3-color/#svg-color\nstatic NSDictionary *CMRW3CNamedColors() {\n    static NSDictionary *namedColors;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        namedColors = @{\n            @\"AliceBlue\" : @\"#F0F8FF\",\n            @\"AntiqueWhite\" : @\"#FAEBD7\",\n            @\"Aqua\" : @\"#00FFFF\",\n            @\"Aquamarine\" : @\"#7FFFD4\",\n            @\"Azure\" : @\"#F0FFFF\",\n            @\"Beige\" : @\"#F5F5DC\",\n            @\"Bisque\" : @\"#FFE4C4\",\n            @\"Black\" : @\"#000000\",\n            @\"BlanchedAlmond\" : @\"#FFEBCD\",\n            @\"Blue\" : @\"#0000FF\",\n            @\"BlueViolet\" : @\"#8A2BE2\",\n            @\"Brown\" : @\"#A52A2A\",\n            @\"BurlyWood\" : @\"#DEB887\",\n            @\"CadetBlue\" : @\"#5F9EA0\",\n            @\"Chartreuse\" : @\"#7FFF00\",\n            @\"Chocolate\" : @\"#D2691E\",\n            @\"Coral\" : @\"#FF7F50\",\n            @\"CornflowerBlue\" : @\"#6495ED\",\n            @\"Cornsilk\" : @\"#FFF8DC\",\n            @\"Crimson\" : @\"#DC143C\",\n            @\"Cyan\" : @\"#00FFFF\",\n            @\"DarkBlue\" : @\"#00008B\",\n            @\"DarkCyan\" : @\"#008B8B\",\n            @\"DarkGoldenRod\" : @\"#B8860B\",\n            @\"DarkGray\" : @\"#A9A9A9\",\n            @\"DarkGrey\" : @\"#A9A9A9\",\n            @\"DarkGreen\" : @\"#006400\",\n            @\"DarkKhaki\" : @\"#BDB76B\",\n            @\"DarkMagenta\" : @\"#8B008B\",\n            @\"DarkOliveGreen\" : @\"#556B2F\",\n            @\"DarkOrange\" : @\"#FF8C00\",\n            @\"DarkOrchid\" : @\"#9932CC\",\n            @\"DarkRed\" : @\"#8B0000\",\n            @\"DarkSalmon\" : @\"#E9967A\",\n            @\"DarkSeaGreen\" : @\"#8FBC8F\",\n            @\"DarkSlateBlue\" : @\"#483D8B\",\n            @\"DarkSlateGray\" : @\"#2F4F4F\",\n            @\"DarkSlateGrey\" : @\"#2F4F4F\",\n            @\"DarkTurquoise\" : @\"#00CED1\",\n            @\"DarkViolet\" : @\"#9400D3\",\n            @\"DeepPink\" : @\"#FF1493\",\n            @\"DeepSkyBlue\" : @\"#00BFFF\",\n            @\"DimGray\" : @\"#696969\",\n            @\"DimGrey\" : @\"#696969\",\n            @\"DodgerBlue\" : @\"#1E90FF\",\n            @\"FireBrick\" : @\"#B22222\",\n            @\"FloralWhite\" : @\"#FFFAF0\",\n            @\"ForestGreen\" : @\"#228B22\",\n            @\"Fuchsia\" : @\"#FF00FF\",\n            @\"Gainsboro\" : @\"#DCDCDC\",\n            @\"GhostWhite\" : @\"#F8F8FF\",\n            @\"Gold\" : @\"#FFD700\",\n            @\"GoldenRod\" : @\"#DAA520\",\n            @\"Gray\" : @\"#808080\",\n            @\"Grey\" : @\"#808080\",\n            @\"Green\" : @\"#008000\",\n            @\"GreenYellow\" : @\"#ADFF2F\",\n            @\"HoneyDew\" : @\"#F0FFF0\",\n            @\"HotPink\" : @\"#FF69B4\",\n            @\"IndianRed\" : @\"#CD5C5C\",\n            @\"Indigo\" : @\"#4B0082\",\n            @\"Ivory\" : @\"#FFFFF0\",\n            @\"Khaki\" : @\"#F0E68C\",\n            @\"Lavender\" : @\"#E6E6FA\",\n            @\"LavenderBlush\" : @\"#FFF0F5\",\n            @\"LawnGreen\" : @\"#7CFC00\",\n            @\"LemonChiffon\" : @\"#FFFACD\",\n            @\"LightBlue\" : @\"#ADD8E6\",\n            @\"LightCoral\" : @\"#F08080\",\n            @\"LightCyan\" : @\"#E0FFFF\",\n            @\"LightGoldenRodYellow\" : @\"#FAFAD2\",\n            @\"LightGray\" : @\"#D3D3D3\",\n            @\"LightGrey\" : @\"#D3D3D3\",\n            @\"LightGreen\" : @\"#90EE90\",\n            @\"LightPink\" : @\"#FFB6C1\",\n            @\"LightSalmon\" : @\"#FFA07A\",\n            @\"LightSeaGreen\" : @\"#20B2AA\",\n            @\"LightSkyBlue\" : @\"#87CEFA\",\n            @\"LightSlateGray\" : @\"#778899\",\n            @\"LightSlateGrey\" : @\"#778899\",\n            @\"LightSteelBlue\" : @\"#B0C4DE\",\n            @\"LightYellow\" : @\"#FFFFE0\",\n            @\"Lime\" : @\"#00FF00\",\n            @\"LimeGreen\" : @\"#32CD32\",\n            @\"Linen\" : @\"#FAF0E6\",\n            @\"Magenta\" : @\"#FF00FF\",\n            @\"Maroon\" : @\"#800000\",\n            @\"MediumAquaMarine\" : @\"#66CDAA\",\n            @\"MediumBlue\" : @\"#0000CD\",\n            @\"MediumOrchid\" : @\"#BA55D3\",\n            @\"MediumPurple\" : @\"#9370DB\",\n            @\"MediumSeaGreen\" : @\"#3CB371\",\n            @\"MediumSlateBlue\" : @\"#7B68EE\",\n            @\"MediumSpringGreen\" : @\"#00FA9A\",\n            @\"MediumTurquoise\" : @\"#48D1CC\",\n            @\"MediumVioletRed\" : @\"#C71585\",\n            @\"MidnightBlue\" : @\"#191970\",\n            @\"MintCream\" : @\"#F5FFFA\",\n            @\"MistyRose\" : @\"#FFE4E1\",\n            @\"Moccasin\" : @\"#FFE4B5\",\n            @\"NavajoWhite\" : @\"#FFDEAD\",\n            @\"Navy\" : @\"#000080\",\n            @\"OldLace\" : @\"#FDF5E6\",\n            @\"Olive\" : @\"#808000\",\n            @\"OliveDrab\" : @\"#6B8E23\",\n            @\"Orange\" : @\"#FFA500\",\n            @\"OrangeRed\" : @\"#FF4500\",\n            @\"Orchid\" : @\"#DA70D6\",\n            @\"PaleGoldenRod\" : @\"#EEE8AA\",\n            @\"PaleGreen\" : @\"#98FB98\",\n            @\"PaleTurquoise\" : @\"#AFEEEE\",\n            @\"PaleVioletRed\" : @\"#DB7093\",\n            @\"PapayaWhip\" : @\"#FFEFD5\",\n            @\"PeachPuff\" : @\"#FFDAB9\",\n            @\"Peru\" : @\"#CD853F\",\n            @\"Pink\" : @\"#FFC0CB\",\n            @\"Plum\" : @\"#DDA0DD\",\n            @\"PowderBlue\" : @\"#B0E0E6\",\n            @\"Purple\" : @\"#800080\",\n            @\"Red\" : @\"#FF0000\",\n            @\"RosyBrown\" : @\"#BC8F8F\",\n            @\"RoyalBlue\" : @\"#4169E1\",\n            @\"SaddleBrown\" : @\"#8B4513\",\n            @\"Salmon\" : @\"#FA8072\",\n            @\"SandyBrown\" : @\"#F4A460\",\n            @\"SeaGreen\" : @\"#2E8B57\",\n            @\"SeaShell\" : @\"#FFF5EE\",\n            @\"Sienna\" : @\"#A0522D\",\n            @\"Silver\" : @\"#C0C0C0\",\n            @\"SkyBlue\" : @\"#87CEEB\",\n            @\"SlateBlue\" : @\"#6A5ACD\",\n            @\"SlateGray\" : @\"#708090\",\n            @\"SlateGrey\" : @\"#708090\",\n            @\"Snow\" : @\"#FFFAFA\",\n            @\"SpringGreen\" : @\"#00FF7F\",\n            @\"SteelBlue\" : @\"#4682B4\",\n            @\"Tan\" : @\"#D2B48C\",\n            @\"Teal\" : @\"#008080\",\n            @\"Thistle\" : @\"#D8BFD8\",\n            @\"Tomato\" : @\"#FF6347\",\n            @\"Turquoise\" : @\"#40E0D0\",\n            @\"Violet\" : @\"#EE82EE\",\n            @\"Wheat\" : @\"#F5DEB3\",\n            @\"White\" : @\"#FFFFFF\",\n            @\"WhiteSmoke\" : @\"#F5F5F5\",\n            @\"Yellow\" : @\"#FFFF00\",\n            @\"YellowGreen\" : @\"#9ACD32\"\n        };\n    });\n    return namedColors;\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/FLEXBOXContainerView.h",
    "content": "//\n//  FLEXBOXContainerView.h\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 10/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface FLEXBOXContainerView : UIView\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/FLEXBOXContainerView.m",
    "content": "//\n//  FLEXBOXContainerView.m\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 10/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import \"FLEXBOXContainerView.h\"\n#import \"UIView+FLEXBOX.h\"\n\n@implementation FLEXBOXContainerView\n\n- (void)layoutSubviews\n{\n    //default flexbox container attributes\n    self.flex = self.flex < FLT_EPSILON ? 1 : self.flex;\n    self.flexContainer = YES;\n    \n    [super layoutSubviews];\n    [self flexLayoutSubviews];\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/FLEXBOXNode.h",
    "content": "//\n//  FLEXBOXNode.h\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 09/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import \"Layout.h\"\n@import UIKit;\n\ntypedef NS_ENUM(NSInteger, FLEXBOXFlexDirection) {\n    FLEXBOXFlexDirectionColumn = CSS_FLEX_DIRECTION_COLUMN,\n    FLEXBOXFlexDirectionRow = CSS_FLEX_DIRECTION_ROW,\n    FLEXBOXFlexDirectionRowReverse = CSS_FLEX_DIRECTION_ROW_REVERSE,\n    FLEXBOXFlexDirectionColumnReverse = CSS_FLEX_DIRECTION_COLUMN_REVERSE\n};\n\ntypedef NS_ENUM(NSInteger, FLEXBOXContentDirection) {\n    FLEXBOXContentDirectionInherit = CSS_DIRECTION_INHERIT,\n    FLEXBOXContentDirectionLeftToRight = CSS_DIRECTION_LTR,\n    FLEXBOXContentDirectionRightToLeft = CSS_DIRECTION_RTL\n};\n\ntypedef NS_ENUM(NSInteger, FLEXBOXJustification) {\n    FLEXBOXJustificationFlexStart = CSS_JUSTIFY_FLEX_START,\n    FLEXBOXJustificationCenter = CSS_JUSTIFY_CENTER,\n    FLEXBOXJustificationFlexEnd = CSS_JUSTIFY_FLEX_END,\n    FLEXBOXJustificationSpaceBetween = CSS_JUSTIFY_SPACE_BETWEEN,\n    FLEXBOXJustificationSpaceAround = CSS_JUSTIFY_SPACE_AROUND\n};\n\ntypedef NS_ENUM(NSInteger, FLEXBOXAlignment) {\n    FLEXBOXAlignmentAuto = CSS_ALIGN_AUTO,\n    FLEXBOXAlignmentFlexStart = CSS_ALIGN_FLEX_START,\n    FLEXBOXAlignmentCenter = CSS_ALIGN_CENTER,\n    FLEXBOXAlignmentFlexEnd = CSS_ALIGN_FLEX_END,\n    FLEXBOXAlignmentStretch = CSS_ALIGN_STRETCH\n};\n\nextern const CGFloat FLEXBOXUndefinedDimension;\n\n@interface FLEXBOXNode : NSObject\n\n@property (nonatomic, readonly, assign) css_node_t *node;\n@property (nonatomic, readonly, assign) CGRect frame;\n\n@property (nonatomic, copy) CGSize (^measureBlock)(CGFloat width);\n@property (nonatomic, copy) FLEXBOXNode *(^childrenAtIndexBlock)(NSUInteger i);\n@property (nonatomic, copy) NSUInteger (^childrenCountBlock)(void);\n\n\n/// Compute the layout for the node constrained to the width passed as argument\n/// @param maximumWidth The maximum width or FLEXBOXUndefinedDimension\n- (void)layoutConstrainedToMaximumWidth:(CGFloat)maximumWidth;\n\n// Style\n\n@property (nonatomic, assign) CGSize dimensions;\n@property (nonatomic, assign) CGSize minDimensions;\n@property (nonatomic, assign) CGSize maxDimensions;\n@property (nonatomic, assign) FLEXBOXFlexDirection flexDirection;\n@property (nonatomic, assign) UIEdgeInsets margin;\n@property (nonatomic, assign) UIEdgeInsets padding;\n@property (nonatomic, assign) BOOL flexWrap;\n@property (nonatomic, assign) FLEXBOXJustification justifyContent;\n@property (nonatomic, assign) FLEXBOXAlignment alignSelf;\n@property (nonatomic, assign) FLEXBOXAlignment alignItems;\n@property (nonatomic, assign) CGFloat flex;\n@property (nonatomic, assign) FLEXBOXContentDirection contentDirection;\n\n@end\n\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/FLEXBOXNode.m",
    "content": "//\n//  FLEXBOXNode.m\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 09/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import \"FLEXBOXNode.h\"\n\nconst CGFloat FLEXBOXUndefinedDimension = CSS_UNDEFINED;\n\nstatic bool FLEXBOX_alwaysDirty(void *context)\n{\n    return YES;\n}\n\nstatic css_node_t *FLEXBOX_getChild(void *context, int i)\n{\n    FLEXBOXNode *_self = (__bridge FLEXBOXNode*)context;\n    FLEXBOXNode *child = _self.childrenAtIndexBlock(i);\n    return child.node;\n}\n\nstatic css_dim_t FLEXBOX_measureNode(void *context, float width)\n{\n    FLEXBOXNode *_self = (__bridge FLEXBOXNode*)context;\n    CGSize size = _self.measureBlock(width);\n    return (css_dim_t){ size.width, size.height };\n}\n\n@implementation FLEXBOXNode\n\n#pragma mark - Lifecycle\n\n- (instancetype)init\n{\n    if (self = [super init]) {\n        \n        //initialise the css_node_t\n        _node = new_css_node();\n        _node->context = (__bridge void *)self;\n        _node->is_dirty = FLEXBOX_alwaysDirty;\n        _node->measure = FLEXBOX_measureNode;\n        _node->get_child = FLEXBOX_getChild;\n        \n        _maxDimensions = CGSizeZero;\n        _minDimensions = CGSizeZero;\n        \n        //defaults\n        self.flexDirection = FLEXBOXFlexDirectionColumn;\n        self.flexWrap = NO;\n        self.alignItems = FLEXBOXAlignmentStretch;\n        self.alignSelf = FLEXBOXAlignmentAuto;\n        self.margin = UIEdgeInsetsZero;\n        self.padding = UIEdgeInsetsZero;\n        self.justifyContent = FLEXBOXJustificationFlexStart;\n        self.flex = 0;\n        self.contentDirection = FLEXBOXContentDirectionInherit;\n    }\n    \n    return self;\n}\n\n- (void)dealloc\n{\n    free_css_node(_node);\n}\n\n#pragma mark - Layout and Internals\n\n- (void)prepareForLayout\n{\n    if (self.childrenAtIndexBlock == nil)\n        return;\n    \n    NSAssert(self.childrenCountBlock, nil);\n    NSUInteger count = self.childrenCountBlock();\n    \n    // prepares the nodes for the layout recursively\n    for (NSInteger i = 0; i < count; i++) {\n        FLEXBOXNode *node = self.childrenAtIndexBlock(i);\n        [node prepareForLayout];\n    }\n    \n    // Apparently we need to reset these before laying out, otherwise the layout\n    // has some weird additive effect.\n    self.node->layout.position[CSS_LEFT] = 0;\n    self.node->layout.position[CSS_TOP] = 0;\n    self.node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;\n    self.node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;\n}\n\n- (void)layoutConstrainedToMaximumWidth:(CGFloat)maximumWidth\n{\n    _node->children_count = (int)self.childrenCountBlock();\n    \n    maximumWidth = fabs(maximumWidth - FLT_MAX) < FLT_EPSILON ? FLEXBOXUndefinedDimension : maximumWidth;\n    [self prepareForLayout];\n    layoutNode(_node, maximumWidth, _node->style.direction);\n}\n\n- (CGRect)frame\n{\n    return (CGRect) {\n        .origin.x = self.node->layout.position[CSS_LEFT],\n        .origin.y = self.node->layout.position[CSS_TOP],\n        .size.width = self.node->layout.dimensions[CSS_WIDTH],\n        .size.height = self.node->layout.dimensions[CSS_HEIGHT]\n    };\n}\n\n#pragma mark - Style\n\n- (void)setDimensions:(CGSize)size\n{\n    _dimensions = size;\n    _node->style.dimensions[CSS_WIDTH] = size.width;\n    _node->style.dimensions[CSS_HEIGHT] = size.height;\n}\n\n- (void)setMinDimensions:(CGSize)size\n{\n    _minDimensions = size;\n//    _node->style.minDimensions[CSS_WIDTH] = size.width;\n//    _node->style.minDimensions[CSS_HEIGHT] = size.height;\n}\n\n- (void)setMaxDimensions:(CGSize)size\n{\n    _maxDimensions = size;\n//    _node->style.maxDimensions[CSS_WIDTH] = size.width;\n//    _node->style.maxDimensions[CSS_HEIGHT] = size.height;\n}\n\n- (void)setFlexDirection:(FLEXBOXFlexDirection)flexDirection\n{\n    _flexDirection = flexDirection;\n    _node->style.flex_direction = (int)flexDirection;\n}\n\n- (void)setMargin:(UIEdgeInsets)margin\n{\n    _margin = margin;\n    _node->style.margin[CSS_LEFT] = margin.left;\n    _node->style.margin[CSS_TOP] = margin.top;\n    _node->style.margin[CSS_RIGHT] = margin.right;\n    _node->style.margin[CSS_BOTTOM] = margin.bottom;\n}\n\n- (void)setPadding:(UIEdgeInsets)padding\n{\n    _padding = padding;\n    _node->style.padding[CSS_LEFT] = padding.left;\n    _node->style.padding[CSS_TOP] = padding.top;\n    _node->style.padding[CSS_RIGHT] = padding.right;\n    _node->style.padding[CSS_BOTTOM] = padding.bottom;\n}\n\n- (void)setFlex:(CGFloat)flex\n{\n    _flex = flex;\n    _node->style.flex = flex;\n}\n\n- (void)setFlexWrap:(BOOL)flexWrap\n{\n    _flexWrap = flexWrap;\n    _node->style.flex_wrap = flexWrap;\n}\n\n- (void)setJustifyContent:(FLEXBOXJustification)justifyContent\n{\n    _justifyContent = justifyContent;\n    _node->style.justify_content = (int)justifyContent;\n}\n\n- (void)setAlignItems:(FLEXBOXAlignment)alignItems\n{\n    _alignItems = alignItems;\n    _node->style.align_items = (int)alignItems;\n}\n\n- (void)setAlignSelf:(FLEXBOXAlignment)alignSelf\n{\n    _alignSelf = alignSelf;\n    _node->style.align_self = (int)alignSelf;\n}\n\n- (void)setContentDirection:(FLEXBOXContentDirection)contentDirection\n{\n    _contentDirection = contentDirection;\n    _node->style.direction = (int)contentDirection;\n}\n\n@end\n\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/FlexboxKit.h",
    "content": "//\n//  FlexboxKit.h\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 09/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n#import \"FLEXBOXNode.h\"\n#import \"UIView+FLEXBOX.h\"\n#import \"FLEXBOXContainerView.h\"\n\n//! Project version number for FlexboxKit.\nFOUNDATION_EXPORT double FlexboxKitVersionNumber;\n\n//! Project version string for FlexboxKit.\nFOUNDATION_EXPORT const unsigned char FlexboxKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <FlexboxKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/Layout.c",
    "content": "/**\n * Copyright (c) 2014, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#include <math.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"Layout.h\"\n\n#ifdef _MSC_VER\n#include <float.h>\n#define isnan _isnan\n\n/* define fmaxf if < VC12 */\n#if _MSC_VER < 1800\n__forceinline const float fmaxf(const float a, const float b) {\n  return (a > b) ? a : b;\n}\n#endif\n#endif\n\nbool isUndefined(float value) {\n  return isnan(value);\n}\n\nstatic bool eq(float a, float b) {\n  if (isUndefined(a)) {\n    return isUndefined(b);\n  }\n  return fabs(a - b) < 0.0001;\n}\n\nvoid init_css_node(css_node_t *node) {\n  node->style.align_items = CSS_ALIGN_STRETCH;\n  node->style.align_content = CSS_ALIGN_FLEX_START;\n\n  node->style.direction = CSS_DIRECTION_INHERIT;\n  node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;\n\n  // Some of the fields default to undefined and not 0\n  node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;\n  node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;\n\n  node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED;\n  node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED;\n\n  node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED;\n  node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED;\n\n  node->style.position[CSS_LEFT] = CSS_UNDEFINED;\n  node->style.position[CSS_TOP] = CSS_UNDEFINED;\n  node->style.position[CSS_RIGHT] = CSS_UNDEFINED;\n  node->style.position[CSS_BOTTOM] = CSS_UNDEFINED;\n\n  node->style.margin[CSS_START] = CSS_UNDEFINED;\n  node->style.margin[CSS_END] = CSS_UNDEFINED;\n  node->style.padding[CSS_START] = CSS_UNDEFINED;\n  node->style.padding[CSS_END] = CSS_UNDEFINED;\n  node->style.border[CSS_START] = CSS_UNDEFINED;\n  node->style.border[CSS_END] = CSS_UNDEFINED;\n\n  node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;\n  node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;\n\n  // Such that the comparison is always going to be false\n  node->layout.last_requested_dimensions[CSS_WIDTH] = -1;\n  node->layout.last_requested_dimensions[CSS_HEIGHT] = -1;\n  node->layout.last_parent_max_width = -1;\n  node->layout.last_direction = (css_direction_t)-1;\n  node->layout.should_update = true;\n}\n\ncss_node_t *new_css_node() {\n  css_node_t *node = (css_node_t *)calloc(1, sizeof(*node));\n  init_css_node(node);\n  return node;\n}\n\nvoid free_css_node(css_node_t *node) {\n  free(node);\n}\n\nstatic void indent(int n) {\n  for (int i = 0; i < n; ++i) {\n    printf(\"  \");\n  }\n}\n\nstatic void print_number_0(const char *str, float number) {\n  if (!eq(number, 0)) {\n    printf(\"%s: %g, \", str, number);\n  }\n}\n\nstatic void print_number_nan(const char *str, float number) {\n  if (!isnan(number)) {\n    printf(\"%s: %g, \", str, number);\n  }\n}\n\nstatic bool four_equal(float four[4]) {\n  return\n    eq(four[0], four[1]) &&\n    eq(four[0], four[2]) &&\n    eq(four[0], four[3]);\n}\n\n\nstatic void print_css_node_rec(\n  css_node_t *node,\n  css_print_options_t options,\n  int level\n) {\n  indent(level);\n  printf(\"{\");\n\n  if (node->print) {\n    node->print(node->context);\n  }\n\n  if (options & CSS_PRINT_LAYOUT) {\n    printf(\"layout: {\");\n    printf(\"width: %g, \", node->layout.dimensions[CSS_WIDTH]);\n    printf(\"height: %g, \", node->layout.dimensions[CSS_HEIGHT]);\n    printf(\"top: %g, \", node->layout.position[CSS_TOP]);\n    printf(\"left: %g\", node->layout.position[CSS_LEFT]);\n    printf(\"}, \");\n  }\n\n  if (options & CSS_PRINT_STYLE) {\n    if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) {\n      printf(\"flexDirection: 'column', \");\n    } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {\n      printf(\"flexDirection: 'columnReverse', \");\n    } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) {\n      printf(\"flexDirection: 'row', \");\n    } else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {\n      printf(\"flexDirection: 'rowReverse', \");\n    }\n\n    if (node->style.justify_content == CSS_JUSTIFY_CENTER) {\n      printf(\"justifyContent: 'center', \");\n    } else if (node->style.justify_content == CSS_JUSTIFY_FLEX_END) {\n      printf(\"justifyContent: 'flex-end', \");\n    } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_AROUND) {\n      printf(\"justifyContent: 'space-around', \");\n    } else if (node->style.justify_content == CSS_JUSTIFY_SPACE_BETWEEN) {\n      printf(\"justifyContent: 'space-between', \");\n    }\n\n    if (node->style.align_items == CSS_ALIGN_CENTER) {\n      printf(\"alignItems: 'center', \");\n    } else if (node->style.align_items == CSS_ALIGN_FLEX_END) {\n      printf(\"alignItems: 'flex-end', \");\n    } else if (node->style.align_items == CSS_ALIGN_STRETCH) {\n      printf(\"alignItems: 'stretch', \");\n    }\n\n    if (node->style.align_content == CSS_ALIGN_CENTER) {\n      printf(\"alignContent: 'center', \");\n    } else if (node->style.align_content == CSS_ALIGN_FLEX_END) {\n      printf(\"alignContent: 'flex-end', \");\n    } else if (node->style.align_content == CSS_ALIGN_STRETCH) {\n      printf(\"alignContent: 'stretch', \");\n    }\n\n    if (node->style.align_self == CSS_ALIGN_FLEX_START) {\n      printf(\"alignSelf: 'flex-start', \");\n    } else if (node->style.align_self == CSS_ALIGN_CENTER) {\n      printf(\"alignSelf: 'center', \");\n    } else if (node->style.align_self == CSS_ALIGN_FLEX_END) {\n      printf(\"alignSelf: 'flex-end', \");\n    } else if (node->style.align_self == CSS_ALIGN_STRETCH) {\n      printf(\"alignSelf: 'stretch', \");\n    }\n\n    print_number_nan(\"flex\", node->style.flex);\n\n    if (four_equal(node->style.margin)) {\n      print_number_0(\"margin\", node->style.margin[CSS_LEFT]);\n    } else {\n      print_number_0(\"marginLeft\", node->style.margin[CSS_LEFT]);\n      print_number_0(\"marginRight\", node->style.margin[CSS_RIGHT]);\n      print_number_0(\"marginTop\", node->style.margin[CSS_TOP]);\n      print_number_0(\"marginBottom\", node->style.margin[CSS_BOTTOM]);\n      print_number_0(\"marginStart\", node->style.margin[CSS_START]);\n      print_number_0(\"marginEnd\", node->style.margin[CSS_END]);\n    }\n\n    if (four_equal(node->style.padding)) {\n      print_number_0(\"padding\", node->style.margin[CSS_LEFT]);\n    } else {\n      print_number_0(\"paddingLeft\", node->style.padding[CSS_LEFT]);\n      print_number_0(\"paddingRight\", node->style.padding[CSS_RIGHT]);\n      print_number_0(\"paddingTop\", node->style.padding[CSS_TOP]);\n      print_number_0(\"paddingBottom\", node->style.padding[CSS_BOTTOM]);\n      print_number_0(\"paddingStart\", node->style.padding[CSS_START]);\n      print_number_0(\"paddingEnd\", node->style.padding[CSS_END]);\n    }\n\n    if (four_equal(node->style.border)) {\n      print_number_0(\"borderWidth\", node->style.border[CSS_LEFT]);\n    } else {\n      print_number_0(\"borderLeftWidth\", node->style.border[CSS_LEFT]);\n      print_number_0(\"borderRightWidth\", node->style.border[CSS_RIGHT]);\n      print_number_0(\"borderTopWidth\", node->style.border[CSS_TOP]);\n      print_number_0(\"borderBottomWidth\", node->style.border[CSS_BOTTOM]);\n      print_number_0(\"borderStartWidth\", node->style.border[CSS_START]);\n      print_number_0(\"borderEndWidth\", node->style.border[CSS_END]);\n    }\n\n    print_number_nan(\"width\", node->style.dimensions[CSS_WIDTH]);\n    print_number_nan(\"height\", node->style.dimensions[CSS_HEIGHT]);\n\n    if (node->style.position_type == CSS_POSITION_ABSOLUTE) {\n      printf(\"position: 'absolute', \");\n    }\n\n    print_number_nan(\"left\", node->style.position[CSS_LEFT]);\n    print_number_nan(\"right\", node->style.position[CSS_RIGHT]);\n    print_number_nan(\"top\", node->style.position[CSS_TOP]);\n    print_number_nan(\"bottom\", node->style.position[CSS_BOTTOM]);\n  }\n\n  if (options & CSS_PRINT_CHILDREN && node->children_count > 0) {\n    printf(\"children: [\\n\");\n    for (int i = 0; i < node->children_count; ++i) {\n      print_css_node_rec(node->get_child(node->context, i), options, level + 1);\n    }\n    indent(level);\n    printf(\"]},\\n\");\n  } else {\n    printf(\"},\\n\");\n  }\n}\n\nvoid print_css_node(css_node_t *node, css_print_options_t options) {\n  print_css_node_rec(node, options, 0);\n}\n\n\nstatic css_position_t leading[4] = {\n  /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,\n  /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,\n  /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,\n  /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT\n};\nstatic css_position_t trailing[4] = {\n  /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM,\n  /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP,\n  /* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT,\n  /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT\n};\nstatic css_position_t pos[4] = {\n  /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,\n  /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,\n  /* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,\n  /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT\n};\nstatic css_dimension_t dim[4] = {\n  /* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT,\n  /* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT,\n  /* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH,\n  /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH\n};\n\nstatic bool isRowDirection(css_flex_direction_t flex_direction) {\n  return flex_direction == CSS_FLEX_DIRECTION_ROW ||\n         flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE;\n}\n\nstatic bool isColumnDirection(css_flex_direction_t flex_direction) {\n  return flex_direction == CSS_FLEX_DIRECTION_COLUMN ||\n         flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE;\n}\n\nstatic float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) {\n    return node->style.margin[CSS_START];\n  }\n\n  return node->style.margin[leading[axis]];\n}\n\nstatic float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) {\n    return node->style.margin[CSS_END];\n  }\n\n  return node->style.margin[trailing[axis]];\n}\n\nstatic float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) &&\n      !isUndefined(node->style.padding[CSS_START]) &&\n      node->style.padding[CSS_START] >= 0) {\n    return node->style.padding[CSS_START];\n  }\n\n  if (node->style.padding[leading[axis]] >= 0) {\n    return node->style.padding[leading[axis]];\n  }\n\n  return 0;\n}\n\nstatic float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) &&\n      !isUndefined(node->style.padding[CSS_END]) &&\n      node->style.padding[CSS_END] >= 0) {\n    return node->style.padding[CSS_END];\n  }\n\n  if (node->style.padding[trailing[axis]] >= 0) {\n    return node->style.padding[trailing[axis]];\n  }\n\n  return 0;\n}\n\nstatic float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) &&\n      !isUndefined(node->style.border[CSS_START]) &&\n      node->style.border[CSS_START] >= 0) {\n    return node->style.border[CSS_START];\n  }\n\n  if (node->style.border[leading[axis]] >= 0) {\n    return node->style.border[leading[axis]];\n  }\n\n  return 0;\n}\n\nstatic float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) {\n  if (isRowDirection(axis) &&\n      !isUndefined(node->style.border[CSS_END]) &&\n      node->style.border[CSS_END] >= 0) {\n    return node->style.border[CSS_END];\n  }\n\n  if (node->style.border[trailing[axis]] >= 0) {\n    return node->style.border[trailing[axis]];\n  }\n\n  return 0;\n}\n\nstatic float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {\n  return getLeadingPadding(node, axis) + getLeadingBorder(node, axis);\n}\n\nstatic float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {\n  return getTrailingPadding(node, axis) + getTrailingBorder(node, axis);\n}\n\nstatic float getBorderAxis(css_node_t *node, css_flex_direction_t axis) {\n  return getLeadingBorder(node, axis) + getTrailingBorder(node, axis);\n}\n\nstatic float getMarginAxis(css_node_t *node, css_flex_direction_t axis) {\n  return getLeadingMargin(node, axis) + getTrailingMargin(node, axis);\n}\n\nstatic float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) {\n  return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis);\n}\n\nstatic css_position_type_t getPositionType(css_node_t *node) {\n  return node->style.position_type;\n}\n\nstatic css_justify_t getJustifyContent(css_node_t *node) {\n  return node->style.justify_content;\n}\n\nstatic css_align_t getAlignContent(css_node_t *node) {\n  return node->style.align_content;\n}\n\nstatic css_align_t getAlignItem(css_node_t *node, css_node_t *child) {\n  if (child->style.align_self != CSS_ALIGN_AUTO) {\n    return child->style.align_self;\n  }\n  return node->style.align_items;\n}\n\nstatic css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) {\n  css_direction_t direction = node->style.direction;\n\n  if (direction == CSS_DIRECTION_INHERIT) {\n    direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR;\n  }\n\n  return direction;\n}\n\nstatic css_flex_direction_t getFlexDirection(css_node_t *node) {\n  return node->style.flex_direction;\n}\n\nstatic css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) {\n  if (direction == CSS_DIRECTION_RTL) {\n    if (flex_direction == CSS_FLEX_DIRECTION_ROW) {\n      return CSS_FLEX_DIRECTION_ROW_REVERSE;\n    } else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {\n      return CSS_FLEX_DIRECTION_ROW;\n    }\n  }\n\n  return flex_direction;\n}\n\nstatic css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) {\n  if (isColumnDirection(flex_direction)) {\n    return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);\n  } else {\n    return CSS_FLEX_DIRECTION_COLUMN;\n  }\n}\n\nstatic float getFlex(css_node_t *node) {\n  return node->style.flex;\n}\n\nstatic bool isFlex(css_node_t *node) {\n  return (\n    getPositionType(node) == CSS_POSITION_RELATIVE &&\n    getFlex(node) > 0\n  );\n}\n\nstatic bool isFlexWrap(css_node_t *node) {\n  return node->style.flex_wrap == CSS_WRAP;\n}\n\nstatic float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) {\n  return node->layout.dimensions[dim[axis]] +\n    getLeadingMargin(node, axis) +\n    getTrailingMargin(node, axis);\n}\n\nstatic bool isDimDefined(css_node_t *node, css_flex_direction_t axis) {\n  float value = node->style.dimensions[dim[axis]];\n  return !isUndefined(value) && value > 0.0;\n}\n\nstatic bool isPosDefined(css_node_t *node, css_position_t position) {\n  return !isUndefined(node->style.position[position]);\n}\n\nstatic bool isMeasureDefined(css_node_t *node) {\n  return node->measure;\n}\n\nstatic float getPosition(css_node_t *node, css_position_t position) {\n  float result = node->style.position[position];\n  if (!isUndefined(result)) {\n    return result;\n  }\n  return 0;\n}\n\nstatic float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) {\n  float min = CSS_UNDEFINED;\n  float max = CSS_UNDEFINED;\n\n  if (isColumnDirection(axis)) {\n    min = node->style.minDimensions[CSS_HEIGHT];\n    max = node->style.maxDimensions[CSS_HEIGHT];\n  } else if (isRowDirection(axis)) {\n    min = node->style.minDimensions[CSS_WIDTH];\n    max = node->style.maxDimensions[CSS_WIDTH];\n  }\n\n  float boundValue = value;\n\n  if (!isUndefined(max) && max >= 0.0 && boundValue > max) {\n    boundValue = max;\n  }\n  if (!isUndefined(min) && min >= 0.0 && boundValue < min) {\n    boundValue = min;\n  }\n\n  return boundValue;\n}\n\n// When the user specifically sets a value for width or height\nstatic void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) {\n  // The parent already computed us a width or height. We just skip it\n  if (!isUndefined(node->layout.dimensions[dim[axis]])) {\n    return;\n  }\n  // We only run if there's a width or height defined\n  if (!isDimDefined(node, axis)) {\n    return;\n  }\n\n  // The dimensions can never be smaller than the padding and border\n  node->layout.dimensions[dim[axis]] = fmaxf(\n    boundAxis(node, axis, node->style.dimensions[dim[axis]]),\n    getPaddingAndBorderAxis(node, axis)\n  );\n}\n\nstatic void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) {\n    child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] -\n      child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]];\n  }\n\n// If both left and right are defined, then use left. Otherwise return\n// +left or -right depending on which is defined.\nstatic float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {\n  float lead = node->style.position[leading[axis]];\n  if (!isUndefined(lead)) {\n    return lead;\n  }\n  return -getPosition(node, trailing[axis]);\n}\n\nstatic void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {\n  /** START_GENERATED **/\n  css_direction_t direction = resolveDirection(node, parentDirection);\n  css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);\n  css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);\n  css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);\n\n  // Handle width and height style attributes\n  setDimensionFromStyle(node, mainAxis);\n  setDimensionFromStyle(node, crossAxis);\n\n  // Set the resolved resolution in the node's layout\n  node->layout.direction = direction;\n\n  // The position is set by the parent, but we need to complete it with a\n  // delta composed of the margin and left/top/right/bottom\n  node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) +\n    getRelativePosition(node, mainAxis);\n  node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) +\n    getRelativePosition(node, mainAxis);\n  node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) +\n    getRelativePosition(node, crossAxis);\n  node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) +\n    getRelativePosition(node, crossAxis);\n\n  if (isMeasureDefined(node)) {\n    float width = CSS_UNDEFINED;\n    if (isDimDefined(node, resolvedRowAxis)) {\n      width = node->style.dimensions[CSS_WIDTH];\n    } else if (!isUndefined(node->layout.dimensions[dim[resolvedRowAxis]])) {\n      width = node->layout.dimensions[dim[resolvedRowAxis]];\n    } else {\n      width = parentMaxWidth -\n        getMarginAxis(node, resolvedRowAxis);\n    }\n    width -= getPaddingAndBorderAxis(node, resolvedRowAxis);\n\n    // We only need to give a dimension for the text if we haven't got any\n    // for it computed yet. It can either be from the style attribute or because\n    // the element is flexible.\n    bool isRowUndefined = !isDimDefined(node, resolvedRowAxis) &&\n      isUndefined(node->layout.dimensions[dim[resolvedRowAxis]]);\n    bool isColumnUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) &&\n      isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]);\n\n    // Let's not measure the text if we already know both dimensions\n    if (isRowUndefined || isColumnUndefined) {\n      css_dim_t measureDim = node->measure(\n        node->context,\n        \n        width\n      );\n      if (isRowUndefined) {\n        node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +\n          getPaddingAndBorderAxis(node, resolvedRowAxis);\n      }\n      if (isColumnUndefined) {\n        node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] +\n          getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);\n      }\n    }\n    if (node->children_count == 0) {\n      return;\n    }\n  }\n\n  int i;\n  int ii;\n  css_node_t* child;\n  css_flex_direction_t axis;\n\n  // Pre-fill some dimensions straight from the parent\n  for (i = 0; i < node->children_count; ++i) {\n    child = node->get_child(node->context, i);\n    // Pre-fill cross axis dimensions when the child is using stretch before\n    // we call the recursive layout pass\n    if (getAlignItem(node, child) == CSS_ALIGN_STRETCH &&\n        getPositionType(child) == CSS_POSITION_RELATIVE &&\n        !isUndefined(node->layout.dimensions[dim[crossAxis]]) &&\n        !isDimDefined(child, crossAxis)) {\n      child->layout.dimensions[dim[crossAxis]] = fmaxf(\n        boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] -\n          getPaddingAndBorderAxis(node, crossAxis) -\n          getMarginAxis(child, crossAxis)),\n        // You never want to go smaller than padding\n        getPaddingAndBorderAxis(child, crossAxis)\n      );\n    } else if (getPositionType(child) == CSS_POSITION_ABSOLUTE) {\n      // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both\n      // left and right or top and bottom).\n      for (ii = 0; ii < 2; ii++) {\n        axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;\n        if (!isUndefined(node->layout.dimensions[dim[axis]]) &&\n            !isDimDefined(child, axis) &&\n            isPosDefined(child, leading[axis]) &&\n            isPosDefined(child, trailing[axis])) {\n          child->layout.dimensions[dim[axis]] = fmaxf(\n            boundAxis(child, axis, node->layout.dimensions[dim[axis]] -\n              getPaddingAndBorderAxis(node, axis) -\n              getMarginAxis(child, axis) -\n              getPosition(child, leading[axis]) -\n              getPosition(child, trailing[axis])),\n            // You never want to go smaller than padding\n            getPaddingAndBorderAxis(child, axis)\n          );\n        }\n      }\n    }\n  }\n\n  float definedMainDim = CSS_UNDEFINED;\n  if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) {\n    definedMainDim = node->layout.dimensions[dim[mainAxis]] -\n        getPaddingAndBorderAxis(node, mainAxis);\n  }\n\n  // We want to execute the next two loops one per line with flex-wrap\n  int startLine = 0;\n  int endLine = 0;\n  // int nextOffset = 0;\n  int alreadyComputedNextLayout = 0;\n  // We aggregate the total dimensions of the container in those two variables\n  float linesCrossDim = 0;\n  float linesMainDim = 0;\n  int linesCount = 0;\n  while (endLine < node->children_count) {\n    // <Loop A> Layout non flexible children and count children by type\n\n    // mainContentDim is accumulation of the dimensions and margin of all the\n    // non flexible children. This will be used in order to either set the\n    // dimensions of the node if none already exist, or to compute the\n    // remaining space left for the flexible children.\n    float mainContentDim = 0;\n\n    // There are three kind of children, non flexible, flexible and absolute.\n    // We need to know how many there are in order to distribute the space.\n    int flexibleChildrenCount = 0;\n    float totalFlexible = 0;\n    int nonFlexibleChildrenCount = 0;\n\n    float maxWidth;\n    for (i = startLine; i < node->children_count; ++i) {\n      child = node->get_child(node->context, i);\n      float nextContentDim = 0;\n\n      // It only makes sense to consider a child flexible if we have a computed\n      // dimension for the node->\n      if (!isUndefined(node->layout.dimensions[dim[mainAxis]]) && isFlex(child)) {\n        flexibleChildrenCount++;\n        totalFlexible += getFlex(child);\n\n        // Even if we don't know its exact size yet, we already know the padding,\n        // border and margin. We'll use this partial information, which represents\n        // the smallest possible size for the child, to compute the remaining\n        // available space.\n        nextContentDim = getPaddingAndBorderAxis(child, mainAxis) +\n          getMarginAxis(child, mainAxis);\n\n      } else {\n        maxWidth = CSS_UNDEFINED;\n        if (!isRowDirection(mainAxis)) {\n          maxWidth = parentMaxWidth -\n            getMarginAxis(node, resolvedRowAxis) -\n            getPaddingAndBorderAxis(node, resolvedRowAxis);\n\n          if (isDimDefined(node, resolvedRowAxis)) {\n            maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -\n              getPaddingAndBorderAxis(node, resolvedRowAxis);\n          }\n        }\n\n        // This is the main recursive call. We layout non flexible children.\n        if (alreadyComputedNextLayout == 0) {\n          layoutNode(child, maxWidth, direction);\n        }\n\n        // Absolute positioned elements do not take part of the layout, so we\n        // don't use them to compute mainContentDim\n        if (getPositionType(child) == CSS_POSITION_RELATIVE) {\n          nonFlexibleChildrenCount++;\n          // At this point we know the final size and margin of the element.\n          nextContentDim = getDimWithMargin(child, mainAxis);\n        }\n      }\n\n      // The element we are about to add would make us go to the next line\n      if (isFlexWrap(node) &&\n          !isUndefined(node->layout.dimensions[dim[mainAxis]]) &&\n          mainContentDim + nextContentDim > definedMainDim &&\n          // If there's only one element, then it's bigger than the content\n          // and needs its own line\n          i != startLine) {\n        nonFlexibleChildrenCount--;\n        alreadyComputedNextLayout = 1;\n        break;\n      }\n      alreadyComputedNextLayout = 0;\n      mainContentDim += nextContentDim;\n      endLine = i + 1;\n    }\n\n    // <Loop B> Layout flexible children and allocate empty space\n\n    // In order to position the elements in the main axis, we have two\n    // controls. The space between the beginning and the first element\n    // and the space between each two elements.\n    float leadingMainDim = 0;\n    float betweenMainDim = 0;\n\n    // The remaining available space that needs to be allocated\n    float remainingMainDim = 0;\n    if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) {\n      remainingMainDim = definedMainDim - mainContentDim;\n    } else {\n      remainingMainDim = fmaxf(mainContentDim, 0) - mainContentDim;\n    }\n\n    // If there are flexible children in the mix, they are going to fill the\n    // remaining space\n    if (flexibleChildrenCount != 0) {\n      float flexibleMainDim = remainingMainDim / totalFlexible;\n      float baseMainDim;\n      float boundMainDim;\n\n      // Iterate over every child in the axis. If the flex share of remaining\n      // space doesn't meet min/max bounds, remove this child from flex\n      // calculations.\n      for (i = startLine; i < endLine; ++i) {\n        child = node->get_child(node->context, i);\n        if (isFlex(child)) {\n          baseMainDim = flexibleMainDim * getFlex(child) +\n              getPaddingAndBorderAxis(child, mainAxis);\n          boundMainDim = boundAxis(child, mainAxis, baseMainDim);\n\n          if (baseMainDim != boundMainDim) {\n            remainingMainDim -= boundMainDim;\n            totalFlexible -= getFlex(child);\n          }\n        }\n      }\n      flexibleMainDim = remainingMainDim / totalFlexible;\n\n      // The non flexible children can overflow the container, in this case\n      // we should just assume that there is no space available.\n      if (flexibleMainDim < 0) {\n        flexibleMainDim = 0;\n      }\n      // We iterate over the full array and only apply the action on flexible\n      // children. This is faster than actually allocating a new array that\n      // contains only flexible children.\n      for (i = startLine; i < endLine; ++i) {\n        child = node->get_child(node->context, i);\n        if (isFlex(child)) {\n          // At this point we know the final size of the element in the main\n          // dimension\n          child->layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis,\n            flexibleMainDim * getFlex(child) + getPaddingAndBorderAxis(child, mainAxis)\n          );\n\n          maxWidth = CSS_UNDEFINED;\n          if (isDimDefined(node, resolvedRowAxis)) {\n            maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -\n              getPaddingAndBorderAxis(node, resolvedRowAxis);\n          } else if (!isRowDirection(mainAxis)) {\n            maxWidth = parentMaxWidth -\n              getMarginAxis(node, resolvedRowAxis) -\n              getPaddingAndBorderAxis(node, resolvedRowAxis);\n          }\n\n          // And we recursively call the layout algorithm for this child\n          layoutNode(child, maxWidth, direction);\n        }\n      }\n\n    // We use justifyContent to figure out how to allocate the remaining\n    // space available\n    } else {\n      css_justify_t justifyContent = getJustifyContent(node);\n      if (justifyContent == CSS_JUSTIFY_CENTER) {\n        leadingMainDim = remainingMainDim / 2;\n      } else if (justifyContent == CSS_JUSTIFY_FLEX_END) {\n        leadingMainDim = remainingMainDim;\n      } else if (justifyContent == CSS_JUSTIFY_SPACE_BETWEEN) {\n        remainingMainDim = fmaxf(remainingMainDim, 0);\n        if (flexibleChildrenCount + nonFlexibleChildrenCount - 1 != 0) {\n          betweenMainDim = remainingMainDim /\n            (flexibleChildrenCount + nonFlexibleChildrenCount - 1);\n        } else {\n          betweenMainDim = 0;\n        }\n      } else if (justifyContent == CSS_JUSTIFY_SPACE_AROUND) {\n        // Space on the edges is half of the space between elements\n        betweenMainDim = remainingMainDim /\n          (flexibleChildrenCount + nonFlexibleChildrenCount);\n        leadingMainDim = betweenMainDim / 2;\n      }\n    }\n\n    // <Loop C> Position elements in the main axis and compute dimensions\n\n    // At this point, all the children have their dimensions set. We need to\n    // find their position. In order to do that, we accumulate data in\n    // variables that are also useful to compute the total dimensions of the\n    // container!\n    float crossDim = 0;\n    float mainDim = leadingMainDim +\n      getLeadingPaddingAndBorder(node, mainAxis);\n\n    for (i = startLine; i < endLine; ++i) {\n      child = node->get_child(node->context, i);\n      child->line_index = linesCount;\n\n      if (getPositionType(child) == CSS_POSITION_ABSOLUTE &&\n          isPosDefined(child, leading[mainAxis])) {\n        // In case the child is position absolute and has left/top being\n        // defined, we override the position to whatever the user said\n        // (and margin/border).\n        child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +\n          getLeadingBorder(node, mainAxis) +\n          getLeadingMargin(child, mainAxis);\n      } else {\n        // If the child is position absolute (without top/left) or relative,\n        // we put it at the current accumulated offset.\n        child->layout.position[pos[mainAxis]] += mainDim;\n\n        // Define the trailing position accordingly.\n        if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) {\n          setTrailingPosition(node, child, mainAxis);\n        }\n      }\n\n      // Now that we placed the element, we need to update the variables\n      // We only need to do that for relative elements. Absolute elements\n      // do not take part in that phase.\n      if (getPositionType(child) == CSS_POSITION_RELATIVE) {\n        // The main dimension is the sum of all the elements dimension plus\n        // the spacing.\n        mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);\n        // The cross dimension is the max of the elements dimension since there\n        // can only be one element in that cross dimension.\n        crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis)));\n      }\n    }\n\n    float containerCrossAxis = node->layout.dimensions[dim[crossAxis]];\n    if (isUndefined(node->layout.dimensions[dim[crossAxis]])) {\n      containerCrossAxis = fmaxf(\n        // For the cross dim, we add both sides at the end because the value\n        // is aggregate via a max function. Intermediate negative values\n        // can mess this computation otherwise\n        boundAxis(node, crossAxis, crossDim + getPaddingAndBorderAxis(node, crossAxis)),\n        getPaddingAndBorderAxis(node, crossAxis)\n      );\n    }\n\n    // <Loop D> Position elements in the cross axis\n    for (i = startLine; i < endLine; ++i) {\n      child = node->get_child(node->context, i);\n\n      if (getPositionType(child) == CSS_POSITION_ABSOLUTE &&\n          isPosDefined(child, leading[crossAxis])) {\n        // In case the child is absolutely positionned and has a\n        // top/left/bottom/right being set, we override all the previously\n        // computed positions to set it correctly.\n        child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +\n          getLeadingBorder(node, crossAxis) +\n          getLeadingMargin(child, crossAxis);\n\n      } else {\n        float leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis);\n\n        // For a relative children, we're either using alignItems (parent) or\n        // alignSelf (child) in order to determine the position in the cross axis\n        if (getPositionType(child) == CSS_POSITION_RELATIVE) {\n          css_align_t alignItem = getAlignItem(node, child);\n          if (alignItem == CSS_ALIGN_STRETCH) {\n            // You can only stretch if the dimension has not already been set\n            // previously.\n            if (!isDimDefined(child, crossAxis)) {\n              child->layout.dimensions[dim[crossAxis]] = fmaxf(\n                boundAxis(child, crossAxis, containerCrossAxis -\n                  getPaddingAndBorderAxis(node, crossAxis) -\n                  getMarginAxis(child, crossAxis)),\n                // You never want to go smaller than padding\n                getPaddingAndBorderAxis(child, crossAxis)\n              );\n            }\n          } else if (alignItem != CSS_ALIGN_FLEX_START) {\n            // The remaining space between the parent dimensions+padding and child\n            // dimensions+margin.\n            float remainingCrossDim = containerCrossAxis -\n              getPaddingAndBorderAxis(node, crossAxis) -\n              getDimWithMargin(child, crossAxis);\n\n            if (alignItem == CSS_ALIGN_CENTER) {\n              leadingCrossDim += remainingCrossDim / 2;\n            } else { // CSS_ALIGN_FLEX_END\n              leadingCrossDim += remainingCrossDim;\n            }\n          }\n        }\n\n        // And we apply the position\n        child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim;\n\n        // Define the trailing position accordingly.\n        if (!isUndefined(node->layout.dimensions[dim[crossAxis]])) {\n          setTrailingPosition(node, child, crossAxis);\n        }\n      }\n    }\n\n    linesCrossDim += crossDim;\n    linesMainDim = fmaxf(linesMainDim, mainDim);\n    linesCount += 1;\n    startLine = endLine;\n  }\n\n  // <Loop E>\n  //\n  // Note(prenaux): More than one line, we need to layout the crossAxis\n  // according to alignContent.\n  //\n  // Note that we could probably remove <Loop D> and handle the one line case\n  // here too, but for the moment this is safer since it won't interfere with\n  // previously working code.\n  //\n  // See specs:\n  // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm\n  // section 9.4\n  //\n  if (linesCount > 1 &&\n      !isUndefined(node->layout.dimensions[dim[crossAxis]])) {\n    float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] -\n        getPaddingAndBorderAxis(node, crossAxis);\n    float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;\n\n    float crossDimLead = 0;\n    float currentLead = getLeadingPaddingAndBorder(node, crossAxis);\n\n    css_align_t alignContent = getAlignContent(node);\n    if (alignContent == CSS_ALIGN_FLEX_END) {\n      currentLead += remainingAlignContentDim;\n    } else if (alignContent == CSS_ALIGN_CENTER) {\n      currentLead += remainingAlignContentDim / 2;\n    } else if (alignContent == CSS_ALIGN_STRETCH) {\n      if (nodeCrossAxisInnerSize > linesCrossDim) {\n        crossDimLead = (remainingAlignContentDim / linesCount);\n      }\n    }\n\n    int endIndex = 0;\n    for (i = 0; i < linesCount; ++i) {\n      int startIndex = endIndex;\n\n      // compute the line's height and find the endIndex\n      float lineHeight = 0;\n      for (ii = startIndex; ii < node->children_count; ++ii) {\n        child = node->get_child(node->context, ii);\n        if (getPositionType(child) != CSS_POSITION_RELATIVE) {\n          continue;\n        }\n        if (child->line_index != i) {\n          break;\n        }\n        if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) {\n          lineHeight = fmaxf(\n            lineHeight,\n            child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis)\n          );\n        }\n      }\n      endIndex = ii;\n      lineHeight += crossDimLead;\n\n      for (ii = startIndex; ii < endIndex; ++ii) {\n        child = node->get_child(node->context, ii);\n        if (getPositionType(child) != CSS_POSITION_RELATIVE) {\n          continue;\n        }\n\n        css_align_t alignContentAlignItem = getAlignItem(node, child);\n        if (alignContentAlignItem == CSS_ALIGN_FLEX_START) {\n          child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);\n        } else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) {\n          child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]];\n        } else if (alignContentAlignItem == CSS_ALIGN_CENTER) {\n          float childHeight = child->layout.dimensions[dim[crossAxis]];\n          child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2;\n        } else if (alignContentAlignItem == CSS_ALIGN_STRETCH) {\n          child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);\n          // TODO(prenaux): Correctly set the height of items with undefined\n          //                (auto) crossAxis dimension.\n        }\n      }\n\n      currentLead += lineHeight;\n    }\n  }\n\n  bool needsMainTrailingPos = false;\n  bool needsCrossTrailingPos = false;\n\n  // If the user didn't specify a width or height, and it has not been set\n  // by the container, then we set it via the children.\n  if (isUndefined(node->layout.dimensions[dim[mainAxis]])) {\n    node->layout.dimensions[dim[mainAxis]] = fmaxf(\n      // We're missing the last padding at this point to get the final\n      // dimension\n      boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)),\n      // We can never assign a width smaller than the padding and borders\n      getPaddingAndBorderAxis(node, mainAxis)\n    );\n\n    needsMainTrailingPos = true;\n  }\n\n  if (isUndefined(node->layout.dimensions[dim[crossAxis]])) {\n    node->layout.dimensions[dim[crossAxis]] = fmaxf(\n      // For the cross dim, we add both sides at the end because the value\n      // is aggregate via a max function. Intermediate negative values\n      // can mess this computation otherwise\n      boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),\n      getPaddingAndBorderAxis(node, crossAxis)\n    );\n\n    needsCrossTrailingPos = true;\n  }\n\n  // <Loop F> Set trailing position if necessary\n  if (needsMainTrailingPos || needsCrossTrailingPos) {\n    for (i = 0; i < node->children_count; ++i) {\n      child = node->get_child(node->context, i);\n\n      if (needsMainTrailingPos) {\n        setTrailingPosition(node, child, mainAxis);\n      }\n\n      if (needsCrossTrailingPos) {\n        setTrailingPosition(node, child, crossAxis);\n      }\n    }\n  }\n\n  // <Loop G> Calculate dimensions for absolutely positioned elements\n  for (i = 0; i < node->children_count; ++i) {\n    child = node->get_child(node->context, i);\n    if (getPositionType(child) == CSS_POSITION_ABSOLUTE) {\n      // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both\n      // left and right or top and bottom).\n      for (ii = 0; ii < 2; ii++) {\n        axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;\n        if (!isUndefined(node->layout.dimensions[dim[axis]]) &&\n            !isDimDefined(child, axis) &&\n            isPosDefined(child, leading[axis]) &&\n            isPosDefined(child, trailing[axis])) {\n          child->layout.dimensions[dim[axis]] = fmaxf(\n            boundAxis(child, axis, node->layout.dimensions[dim[axis]] -\n              getBorderAxis(node, axis) -\n              getMarginAxis(child, axis) -\n              getPosition(child, leading[axis]) -\n              getPosition(child, trailing[axis])\n            ),\n            // You never want to go smaller than padding\n            getPaddingAndBorderAxis(child, axis)\n          );\n        }\n      }\n      for (ii = 0; ii < 2; ii++) {\n        axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;\n        if (isPosDefined(child, trailing[axis]) &&\n            !isPosDefined(child, leading[axis])) {\n          child->layout.position[leading[axis]] =\n            node->layout.dimensions[dim[axis]] -\n            child->layout.dimensions[dim[axis]] -\n            getPosition(child, trailing[axis]);\n        }\n      }\n    }\n  }\n  /** END_GENERATED **/\n}\n\nvoid layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {\n  css_layout_t *layout = &node->layout;\n  css_direction_t direction = node->style.direction;\n  layout->should_update = true;\n\n  bool skipLayout =\n    !node->is_dirty(node->context) &&\n    eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) &&\n    eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) &&\n    eq(layout->last_parent_max_width, parentMaxWidth);\n    eq(layout->last_direction, direction);\n\n  if (skipLayout) {\n    layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH];\n    layout->dimensions[CSS_HEIGHT] = layout->last_dimensions[CSS_HEIGHT];\n    layout->position[CSS_TOP] = layout->last_position[CSS_TOP];\n    layout->position[CSS_LEFT] = layout->last_position[CSS_LEFT];\n  } else {\n    layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];\n    layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];\n    layout->last_parent_max_width = parentMaxWidth;\n    layout->last_direction = direction;\n\n    layoutNodeImpl(node, parentMaxWidth, parentDirection);\n\n    layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];\n    layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];\n    layout->last_position[CSS_TOP] = layout->position[CSS_TOP];\n    layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT];\n  }\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/Layout.h",
    "content": "/**\n * Copyright (c) 2014, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#ifndef __LAYOUT_H\n#define __LAYOUT_H\n\n#include <math.h>\n#ifndef __cplusplus\n#include <stdbool.h>\n#endif\n\n// Not defined in MSVC++\n#ifndef NAN\nstatic const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};\n#define NAN (*(const float *)__nan)\n#endif\n\n#define CSS_UNDEFINED NAN\n\ntypedef enum {\n  CSS_DIRECTION_INHERIT = 0,\n  CSS_DIRECTION_LTR,\n  CSS_DIRECTION_RTL\n} css_direction_t;\n\ntypedef enum {\n  CSS_FLEX_DIRECTION_COLUMN = 0,\n  CSS_FLEX_DIRECTION_COLUMN_REVERSE,\n  CSS_FLEX_DIRECTION_ROW,\n  CSS_FLEX_DIRECTION_ROW_REVERSE\n} css_flex_direction_t;\n\ntypedef enum {\n  CSS_JUSTIFY_FLEX_START = 0,\n  CSS_JUSTIFY_CENTER,\n  CSS_JUSTIFY_FLEX_END,\n  CSS_JUSTIFY_SPACE_BETWEEN,\n  CSS_JUSTIFY_SPACE_AROUND\n} css_justify_t;\n\n// Note: auto is only a valid value for alignSelf. It is NOT a valid value for\n// alignItems.\ntypedef enum {\n  CSS_ALIGN_AUTO = 0,\n  CSS_ALIGN_FLEX_START,\n  CSS_ALIGN_CENTER,\n  CSS_ALIGN_FLEX_END,\n  CSS_ALIGN_STRETCH\n} css_align_t;\n\ntypedef enum {\n  CSS_POSITION_RELATIVE = 0,\n  CSS_POSITION_ABSOLUTE\n} css_position_type_t;\n\ntypedef enum {\n  CSS_NOWRAP = 0,\n  CSS_WRAP\n} css_wrap_type_t;\n\n// Note: left and top are shared between position[2] and position[4], so\n// they have to be before right and bottom.\ntypedef enum {\n  CSS_LEFT = 0,\n  CSS_TOP,\n  CSS_RIGHT,\n  CSS_BOTTOM,\n  CSS_START,\n  CSS_END,\n  CSS_POSITION_COUNT\n} css_position_t;\n\ntypedef enum {\n  CSS_WIDTH = 0,\n  CSS_HEIGHT\n} css_dimension_t;\n\ntypedef struct {\n  float position[4];\n  float dimensions[2];\n  css_direction_t direction;\n\n  // Instead of recomputing the entire layout every single time, we\n  // cache some information to break early when nothing changed\n  bool should_update;\n  float last_requested_dimensions[2];\n  float last_parent_max_width;\n  float last_dimensions[2];\n  float last_position[2];\n  css_direction_t last_direction;\n} css_layout_t;\n\ntypedef struct {\n  float dimensions[2];\n} css_dim_t;\n\ntypedef struct {\n  css_direction_t direction;\n  css_flex_direction_t flex_direction;\n  css_justify_t justify_content;\n  css_align_t align_content;\n  css_align_t align_items;\n  css_align_t align_self;\n  css_position_type_t position_type;\n  css_wrap_type_t flex_wrap;\n  float flex;\n  float margin[6];\n  float position[4];\n  /**\n   * You should skip all the rules that contain negative values for the\n   * following attributes. For example:\n   *   {padding: 10, paddingLeft: -5}\n   * should output:\n   *   {left: 10 ...}\n   * the following two are incorrect:\n   *   {left: -5 ...}\n   *   {left: 0 ...}\n   */\n  float padding[6];\n  float border[6];\n  float dimensions[2];\n  float minDimensions[2];\n  float maxDimensions[2];\n} css_style_t;\n\ntypedef struct css_node {\n  css_style_t style;\n  css_layout_t layout;\n  int children_count;\n  int line_index;\n\n  css_dim_t (*measure)(void *context, float width);\n  void (*print)(void *context);\n  struct css_node* (*get_child)(void *context, int i);\n  bool (*is_dirty)(void *context);\n  void *context;\n} css_node_t;\n\n\n// Lifecycle of nodes and children\ncss_node_t *new_css_node(void);\nvoid init_css_node(css_node_t *node);\nvoid free_css_node(css_node_t *node);\n\n// Print utilities\ntypedef enum {\n  CSS_PRINT_LAYOUT = 1,\n  CSS_PRINT_STYLE = 2,\n  CSS_PRINT_CHILDREN = 4,\n} css_print_options_t;\nvoid print_css_node(css_node_t *node, css_print_options_t options);\n\n// Function that computes the layout!\nvoid layoutNode(css_node_t *node, float maxWidth, css_direction_t parentDirection);\nbool isUndefined(float value);\n\n#endif\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/UIView+FLEXBOX.h",
    "content": "//\n//  UIView+FLEXBOX.h\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 09/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n@import UIKit;\n#import \"FLEXBOXNode.h\"\n\n@interface UIView (FLEXBOX)\n\n// Properties\n\n/// YES if this view contains subviews that you wish to layout using the flexbox engine\n/// @note You don't need to set this if your view is a FLEXBOXContainerView\n@property (nonatomic, assign) BOOL flexContainer;\n\n/// Set this if you wish to have a fixed size for this element\n@property (nonatomic, assign) CGSize flexFixedSize;\n\n/// The minumum size for this element\n@property (nonatomic, assign) CGSize flexMinimumSize;\n\n/// The maximum size for this element\n@property (nonatomic, assign) CGSize flexMaximumSize;\n\n/// It establishes the main-axis, thus defining the direction flex items are placed in the flex container.\n/// - row: same as text direction (@see FLEXBOXFlexDirectionColumn)\n/// - column (default): same as row but top to bottom (@see FLEXBOXFlexDirectionRow)\n/// - row-reverse: (@see FLEXBOXFlexDirectionRowReverse)\n/// - column-reverse: (@see FLEXBOXFlexDirectionColumnReverse)\n@property (nonatomic, assign) FLEXBOXFlexDirection flexDirection;\n\n/// The margins for this flex item (default is 0)\n@property (nonatomic, assign) UIEdgeInsets flexMargin;\n\n/// The padding for this flex item (default is 0)\n@property (nonatomic, assign) UIEdgeInsets flexPadding;\n\n/// Make the flexible items wrap if necesarry:\n/// - wrap YES\n/// - nowrap (default) NO\n@property (nonatomic, assign) BOOL flexWrap;\n\n/// It defines the alignment along the main axis. It helps distribute extra free\n/// space leftover when either all the flex items on a line are inflexible, or are\n/// flexible but have reached their maximum size. It also exerts some control over\n/// the alignment of items when they overflow the line.\n/// - flex-start (default): items are packed toward the start line (@see FLEXBOXJustificationFlexStart)\n/// - flex-end: items are packed toward to end line (@see FLEXBOXJustificationFlexEnd)\n/// - center: items are centered along the line (@see FLEXBOXJustificationCenter)\n/// - space-between: items are evenly distributed in the line; first item is on the start line, last item on the end line (@see FLEXBOXJustificationSpaceBetween)\n/// - space-around: items are evenly distributed in the line with equal space around them (@see FLEXBOXJustificationSpaceAround)\n@property (nonatomic, assign) FLEXBOXJustification flexJustifyContent;\n\n/// Center the alignments for one of the items inside a flexible element\n/// - auto (default): The element inherits its parent container's align-items property, or \"stretch\" if it has no parent container (@see FLEXBOXAlignmentAuto)\n/// - stretch: The element is positioned to fit the conatiner (@see FLEXBOXAlignmentStretch)\n/// - center: The element is positioned at the center of the container (@see FLEXBOXAlignmentCenter)\n/// - flex-start: The element is are positioned at the beginning of the container (@see FLEXBOXAlignmentFlexStart)\n/// - flex-end: The element is positioned at the end of the container (@see FLEXBOXAlignmentFlexEnd)\n@property (nonatomic, assign) FLEXBOXAlignment flexAlignSelf;\n\n/// Center the alignments for all the items of the flexible element:\n/// - stretch (default): The element is positioned to fit the conatiner (@see FLEXBOXAlignmentStretch)\n/// - center: The element is positioned at the center of the container (@see FLEXBOXAlignmentCenter)\n/// - flex-start: The element is are positioned at the beginning of the container (@see FLEXBOXAlignmentFlexStart)\n/// - flex-end: The element is positioned at the end of the container (@see FLEXBOXAlignmentFlexEnd)\n@property (nonatomic, assign) FLEXBOXAlignment flexAlignItems;\n\n/// The flex property specifies the initial length of a flexible item.\n/// A value between 0 and 1 (a ratio e.g. 1/2, 2/3)\n@property (nonatomic, assign) CGFloat flex;\n\n\n/// The node content directon (default is inherit)\n@property (nonatomic, assign) FLEXBOXContentDirection flexContentDirection;\n\n// Methods\n\n/// Entry point for defining the size for this flex item\n/// @note By default it calls -[UIView sizeThatFits:]\n- (CGSize)flexComputeSize:(CGSize)bounds;\n\n/// Call this method in -[UIView layoutSubviews] if you want the flexbox\n/// engine to compute the layout\n- (void)flexLayoutSubviews;\n\n/// Define this block if you want to specify some custom logic instead of\n/// calling -[UIView sizeThatFits:] in -[UIView flexComputeSize:]\n@property (nonatomic, copy) CGSize (^flexSizeThatFitsBlock)(CGSize size);\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/FlexboxKit/UIView+FLEXBOX.m",
    "content": "//\n//  UIView+FLEXBOX.m\n//  FlexboxKit\n//\n//  Created by Alex Usbergo on 09/05/15.\n//  Copyright (c) 2015 Alex Usbergo. All rights reserved.\n//\n\n#import \"UIView+FLEXBOX.h\"\n#import \"FLEXBOXContainerView.h\"\n#import <objc/runtime.h>\n\nconst void *FLEXBOXContainerKey;\nconst void *FLEXBOXNodeKey;\nconst void *FLEXBOXOffsetNodeKey;\nconst void *FLEXBOXOffsetKey;\nconst void *FLEXBOXSizeKey;\nconst void *FLEXBOXSizeThatFitsBlock;\n\n@interface UIView (_FLEXBOX)\n\n/// The associated flexbox node\n@property (nonatomic, strong) FLEXBOXNode *flexNode;\n@property (nonatomic, readonly, getter=isFlexOffsetNodeDefined) BOOL flexNodeDefined;\n\n@end\n\n\n@implementation UIView (FLEXBOX)\n\n- (FLEXBOXNode*)flexNode\n{\n    FLEXBOXNode *node = objc_getAssociatedObject(self, &FLEXBOXNodeKey);\n    \n    if (node == nil) {\n        node = [[FLEXBOXNode alloc] init];\n        self.flexNode = node;\n        \n        __weak __typeof(self) weakSelf = self;\n        \n        self.flexNode.childrenAtIndexBlock = ^FLEXBOXNode*(NSUInteger i) {\n            return [weakSelf.subviews[i] flexNode];\n        };\n        \n        self.flexNode.childrenCountBlock = ^NSUInteger(void) {\n            return weakSelf.subviews.count;\n        };\n        \n        self.flexNode.measureBlock = ^CGSize(CGFloat width) {\n            return [weakSelf flexComputeSize:(CGSize){width, NAN}];\n        };\n    }\n    \n    return node;\n}\n\n- (void)setFlexNode:(FLEXBOXNode*)flexNode\n{\n    objc_setAssociatedObject(self, &FLEXBOXNodeKey, flexNode, OBJC_ASSOCIATION_RETAIN);\n}\n\n\n- (BOOL)flexContainer\n{\n    return  [objc_getAssociatedObject(self, &FLEXBOXContainerKey) boolValue];\n}\n\n- (void)setFlexContainer:(BOOL)flexContainer\n{\n    objc_setAssociatedObject(self, &FLEXBOXContainerKey, @(flexContainer), OBJC_ASSOCIATION_RETAIN);\n    self.flex = flexContainer ? 1 : 0;\n}\n\n- (CGSize)flexFixedSize\n{\n    NSValue *value = objc_getAssociatedObject(self, &FLEXBOXSizeKey);\n    if (value != nil) {\n        return [value CGSizeValue];\n    } else {\n        return CGSizeZero;\n    }\n}\n\n- (void)setFlexFixedSize:(CGSize)flexFixedSize\n{\n    return objc_setAssociatedObject(self, &FLEXBOXSizeKey, [NSValue valueWithCGSize:flexFixedSize], OBJC_ASSOCIATION_RETAIN);\n}\n\n- (void)setFlexSizeThatFitsBlock:(CGSize (^)(CGSize))sizeThatFitsBlock\n{\n    objc_setAssociatedObject(self, &FLEXBOXSizeThatFitsBlock, [sizeThatFitsBlock copy], OBJC_ASSOCIATION_COPY);\n}\n\n- (CGSize (^)(CGSize))flexSizeThatFitsBlock\n{\n    return objc_getAssociatedObject(self, &FLEXBOXSizeThatFitsBlock);\n}\n\n- (CGSize)flexComputeSize:(CGSize)bounds\n{\n    if (!CGSizeEqualToSize(self.flexFixedSize, CGSizeZero))\n        return self.flexFixedSize;\n    \n    bounds.height = isnan(bounds.height) ? FLT_MAX : bounds.height;\n    bounds.width = isnan(bounds.width) ? FLT_MAX : bounds.width;\n    \n    CGSize size = CGSizeZero;\n\n    if (self.flexSizeThatFitsBlock != nil) {\n        size = self.flexSizeThatFitsBlock(bounds);\n    } else {\n         size = [self sizeThatFits:bounds];\n    }\n    \n    CGSize max = self.flexMaximumSize;\n    if (!CGSizeEqualToSize(max, CGSizeZero) || !CGSizeEqualToSize(max, (CGSize){FLT_MAX, FLT_MAX})) {\n        size.height = !isnan(max.height) && fabs(max.height) > FLT_EPSILON  && size.height > max.height ? max.height : size.height;\n        size.width = !isnan(max.width) && fabs(max.width) > FLT_EPSILON  && size.width > max.width ? max.width : size.width;\n    }\n    \n    CGSize min = self.flexMinimumSize;\n    if (!CGSizeEqualToSize(min, CGSizeZero) || !CGSizeEqualToSize(max, (CGSize){FLT_MIN, FLT_MIN})) {\n        size.height = !isnan(min.height) && fabs(min.height) > FLT_EPSILON && size.height < min.height ? min.height : size.height;\n        size.width = !isnan(min.width) && fabs(min.width) > FLT_EPSILON && size.width < min.width ? min.width : size.width;\n    }\n\n    return size;\n}\n\n- (void)flexLayoutSubviews\n{\n    self.flexNode.dimensions = self.bounds.size;\n    [self _flexLayoutSubviewsFromView:self];\n    self.frame = (CGRect){self.frame.origin, self.flexNode.frame.size};\n}\n\n- (void)_flexLayoutSubviewsFromView:(UIView*)view\n{\n    [view.flexNode layoutConstrainedToMaximumWidth:CGRectGetWidth(view.bounds)];\n    \n    for (NSUInteger i = 0; i < view.subviews.count; i++) {\n        \n        UIView *subview = view.subviews[i];\n        FLEXBOXNode *subnode = subview.flexNode;\n        subview.frame = CGRectIntegral(subnode.frame);\n    }\n    \n    for (NSUInteger i = 0; i < view.subviews.count; i++) {\n        UIView *subview = view.subviews[i];\n        \n        if (subview.flexContainer)\n            [self _flexLayoutSubviewsFromView:subview];\n    }\n}\n\n#pragma mark - Properties\n\n- (FLEXBOXFlexDirection)flexDirection\n{\n    return self.flexNode.flexDirection;\n}\n\n- (void)setFlexDirection:(FLEXBOXFlexDirection)flexDirection\n{\n    self.flexNode.flexDirection = flexDirection;\n}\n\n- (UIEdgeInsets)flexMargin\n{\n    return self.flexNode.margin;\n}\n\n- (void)setFlexMargin:(UIEdgeInsets)flexMargin\n{\n    self.flexNode.margin = flexMargin;\n}\n\n- (UIEdgeInsets)flexPadding\n{\n    return self.flexNode.padding;\n}\n\n- (void)setFlexPadding:(UIEdgeInsets)flexPadding\n{\n    self.flexNode.padding = flexPadding;\n}\n\n- (BOOL)flexWrap\n{\n    return self.flexNode.flexWrap;\n}\n\n- (void)setFlexWrap:(BOOL)flexWrap\n{\n    self.flexNode.flexWrap = flexWrap;\n}\n\n- (FLEXBOXJustification)flexJustifyContent\n{\n    return self.flexNode.justifyContent;\n}\n\n- (void)setFlexJustifyContent:(FLEXBOXJustification)flexJustifyContent\n{\n    self.flexNode.justifyContent = flexJustifyContent;\n}\n\n- (FLEXBOXAlignment)flexAlignSelf\n{\n    return self.flexNode.alignSelf;\n}\n\n- (void)setFlexAlignSelf:(FLEXBOXAlignment)flexAlignSelf\n{\n    self.flexNode.alignSelf = flexAlignSelf;\n}\n\n- (FLEXBOXAlignment)flexAlignItems\n{\n    return self.flexNode.alignItems;\n}\n\n- (void)setFlexAlignItems:(FLEXBOXAlignment)flexAlignItems\n{\n    self.flexNode.alignItems = flexAlignItems;\n}\n\n- (CGFloat)flex\n{\n    return self.flexNode.flex;\n}\n\n- (void)setFlex:(CGFloat)flex\n{\n    self.flexNode.flex = flex;\n}\n\n- (CGSize)flexMinimumSize\n{\n    return self.flexNode.minDimensions;\n}\n\n- (void)setFlexMinimumSize:(CGSize)flexMinimumSize\n{\n    self.flexNode.minDimensions = flexMinimumSize;\n}\n\n- (CGSize)flexMaximumSize\n{\n    return self.flexNode.maxDimensions;\n}\n\n- (void)setFlexMaximumSize:(CGSize)flexMaximumSize\n{\n    self.flexNode.maxDimensions = flexMaximumSize;\n}\n\n- (FLEXBOXContentDirection)flexContentDirection\n{\n    return self.flexNode.contentDirection;\n}\n\n- (void)setFlexContentDirection:(FLEXBOXContentDirection)flexContentDirection\n{\n    self.flexNode.contentDirection = flexContentDirection;\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/Pinyin/pinyin.h",
    "content": "/*\n *  pinyin.h\n *  Chinese Pinyin First Letter\n *\n *  Created by George on 4/21/10.\n *  Copyright 2010 RED/SAFI. All rights reserved.\n *\n */\n#import <Foundation/Foundation.h>\n@interface HTFirstLetter : NSObject\n\n+ (char)pinyinFirstLetter:(unsigned short )hanzi;\n//获取汉字首字母，如果参数既不是汉字也不是英文字母，则返回 @“#”\n+ (NSString *)firstLetter:(NSString *)chineseString;\n\n//返回参数中所有汉字的首字母，遇到其他字符，则用 # 替换\n+ (NSString *)firstLetters:(NSString *)chineseString;\n\n@end"
  },
  {
    "path": "Pod/Classes/Extend/Pinyin/pinyin.m",
    "content": "/*\n *  pinyin.c\n *  Chinese Pinyin First Letter\n *\n *  Created by George on 4/21/10.\n *  Copyright 2010 RED/SAFI. All rights reserved.\n *\n */\n\n#define HANZI_START 19968\n#define HANZI_COUNT 20902\n\n#import \"pinyin.h\"\n\nstatic char firstLetterArray[HANZI_COUNT] = \n\"ydkqsxnwzssxjbymgcczqpssqbycdscdqldylybssjgyqzjjfgcclzznwdwzjljpfyynnjjtmynzwzhflzppqhgccyynmjqyxxgd\"\n\"nnsnsjnjnsnnmlnrxyfsngnnnnqzggllyjlnyzssecykyyhqwjssggyxyqyjtwktjhychmnxjtlhjyqbyxdldwrrjnwysrldzjpc\"\n\"bzjjbrcfslnczstzfxxchtrqggddlyccssymmrjcyqzpwwjjyfcrwfdfzqpyddwyxkyjawjffxjbcftzyhhycyswccyxsclcxxwz\"\n\"cxnbgnnxbxlzsqsbsjpysazdhmdzbqbscwdzzyytzhbtsyyfzgntnxjywqnknphhlxgybfmjnbjhhgqtjcysxstkzglyckglysmz\"\n\"xyalmeldccxgzyrjxjzlnjzcqkcnnjwhjczccqljststbnhbtyxceqxkkwjyflzqlyhjxspsfxlmpbysxxxytccnylllsjxfhjxp\"\n\"jbtffyabyxbcczbzyclwlczggbtssmdtjcxpthyqtgjjxcjfzkjzjqnlzwlslhdzbwjncjzyzsqnycqynzcjjwybrtwpyftwexcs\"\n\"kdzctbyhyzqyyjxzcfbzzmjyxxsdczottbzljwfckscsxfyrlrygmbdthjxsqjccsbxyytswfbjdztnbcnzlcyzzpsacyzzsqqcs\"\n\"hzqydxlbpjllmqxqydzxsqjtzpxlcglqdcwzfhctdjjsfxjejjtlbgxsxjmyjjqpfzasyjnsydjxkjcdjsznbartcclnjqmwnqnc\"\n\"lllkbdbzzsyhqcltwlccrshllzntylnewyzyxczxxgdkdmtcedejtsyyssdqdfmxdbjlkrwnqlybglxnlgtgxbqjdznyjsjyjcjm\"\n\"rnymgrcjczgjmzmgxmmryxkjnymsgmzzymknfxmbdtgfbhcjhkylpfmdxlxjjsmsqgzsjlqdldgjycalcmzcsdjllnxdjffffjcn\"\n\"fnnffpfkhkgdpqxktacjdhhzdddrrcfqyjkqccwjdxhwjlyllzgcfcqjsmlzpbjjblsbcjggdckkdezsqcckjgcgkdjtjllzycxk\"\n\"lqccgjcltfpcqczgwbjdqyzjjbyjhsjddwgfsjgzkcjctllfspkjgqjhzzljplgjgjjthjjyjzccmlzlyqbgjwmljkxzdznjqsyz\"\n\"mljlljkywxmkjlhskjhbmclyymkxjqlbmllkmdxxkwyxwslmlpsjqqjqxyqfjtjdxmxxllcrqbsyjbgwynnggbcnxpjtgpapfgdj\"\n\"qbhbncfjyzjkjkhxqfgqckfhygkhdkllsdjqxpqyaybnqsxqnszswhbsxwhxwbzzxdmndjbsbkbbzklylxgwxjjwaqzmywsjqlsj\"\n\"xxjqwjeqxnchetlzalyyyszzpnkyzcptlshtzcfycyxyljsdcjqagyslcllyyysslqqqnldxzsccscadycjysfsgbfrsszqsbxjp\"\n\"sjysdrckgjlgtkzjzbdktcsyqpyhstcldjnhmymcgxyzhjdctmhltxzhylamoxyjcltyfbqqjpfbdfehthsqhzywwcncxcdwhowg\"\n\"yjlegmdqcwgfjhcsntmydolbygnqwesqpwnmlrydzszzlyqpzgcwxhnxpyxshmdqjgztdppbfbhzhhjyfdzwkgkzbldnzsxhqeeg\"\n\"zxylzmmzyjzgszxkhkhtxexxgylyapsthxdwhzydpxagkydxbhnhnkdnjnmyhylpmgecslnzhkxxlbzzlbmlsfbhhgsgyyggbhsc\"\n\"yajtxglxtzmcwzydqdqmngdnllszhngjzwfyhqswscelqajynytlsxthaznkzzsdhlaxxtwwcjhqqtddwzbcchyqzflxpslzqgpz\"\n\"sznglydqtbdlxntctajdkywnsyzljhhdzckryyzywmhychhhxhjkzwsxhdnxlyscqydpslyzwmypnkxyjlkchtyhaxqsyshxasmc\"\n\"hkdscrsgjpwqsgzjlwwschsjhsqnhnsngndantbaalczmsstdqjcjktscjnxplggxhhgoxzcxpdmmhldgtybynjmxhmrzplxjzck\"\n\"zxshflqxxcdhxwzpckczcdytcjyxqhlxdhypjqxnlsyydzozjnhhqezysjyayxkypdgxddnsppyzndhthrhxydpcjjhtcnnctlhb\"\n\"ynyhmhzllnnxmylllmdcppxhmxdkycyrdltxjchhznxclcclylnzsxnjzzlnnnnwhyqsnjhxynttdkyjpychhyegkcwtwlgjrlgg\"\n\"tgtygyhpyhylqyqgcwyqkpyyettttlhyylltyttsylnyzwgywgpydqqzzdqnnkcqnmjjzzbxtqfjkdffbtkhzkbxdjjkdjjtlbwf\"\n\"zpptkqtztgpdwntpjyfalqmkgxbcclzfhzcllllanpnxtjklcclgyhdzfgyddgcyyfgydxkssendhykdndknnaxxhbpbyyhxccga\"\n\"pfqyjjdmlxcsjzllpcnbsxgjyndybwjspcwjlzkzddtacsbkzdyzypjzqsjnkktknjdjgyepgtlnyqnacdntcyhblgdzhbbydmjr\"\n\"egkzyheyybjmcdtafzjzhgcjnlghldwxjjkytcyksssmtwcttqzlpbszdtwcxgzagyktywxlnlcpbclloqmmzsslcmbjcsdzkydc\"\n\"zjgqjdsmcytzqqlnzqzxssbpkdfqmddzzsddtdmfhtdycnaqjqkypbdjyyxtljhdrqxlmhkydhrnlklytwhllrllrcxylbnsrnzz\"\n\"symqzzhhkyhxksmzsyzgcxfbnbsqlfzxxnnxkxwymsddyqnggqmmyhcdzttfgyyhgsbttybykjdnkyjbelhdypjqnfxfdnkzhqks\"\n\"byjtzbxhfdsbdaswpawajldyjsfhblcnndnqjtjnchxfjsrfwhzfmdrfjyxwzpdjkzyjympcyznynxfbytfyfwygdbnzzzdnytxz\"\n\"emmqbsqehxfznbmflzzsrsyqjgsxwzjsprytjsjgskjjgljjynzjjxhgjkymlpyyycxycgqzswhwlyrjlpxslcxmnsmwklcdnkny\"\n\"npsjszhdzeptxmwywxyysywlxjqcqxzdclaeelmcpjpclwbxsqhfwrtfnjtnqjhjqdxhwlbyccfjlylkyynldxnhycstyywncjtx\"\n\"ywtrmdrqnwqcmfjdxzmhmayxnwmyzqtxtlmrspwwjhanbxtgzypxyyrrclmpamgkqjszycymyjsnxtplnbappypylxmyzkynldgy\"\n\"jzcchnlmzhhanqnbgwqtzmxxmllhgdzxnhxhrxycjmffxywcfsbssqlhnndycannmtcjcypnxnytycnnymnmsxndlylysljnlxys\"\n\"sqmllyzlzjjjkyzzcsfbzxxmstbjgnxnchlsnmcjscyznfzlxbrnnnylmnrtgzqysatswryhyjzmgdhzgzdwybsscskxsyhytsxg\"\n\"cqgxzzbhyxjscrhmkkbsczjyjymkqhzjfnbhmqhysnjnzybknqmcjgqhwlsnzswxkhljhyybqcbfcdsxdldspfzfskjjzwzxsddx\"\n\"jseeegjscssygclxxnwwyllymwwwgydkzjggggggsycknjwnjpcxbjjtqtjwdsspjxcxnzxnmelptfsxtllxcljxjjljsxctnswx\"\n\"lennlyqrwhsycsqnybyaywjejqfwqcqqcjqgxaldbzzyjgkgxbltqyfxjltpydkyqhpmatlcndnkxmtxynhklefxdllegqtymsaw\"\n\"hzmljtkynxlyjzljeeyybqqffnlyxhdsctgjhxywlkllxqkcctnhjlqmkkzgcyygllljdcgydhzwypysjbzjdzgyzzhywyfqdtyz\"\n\"szyezklymgjjhtsmqwyzljyywzcsrkqyqltdxwcdrjalwsqzwbdcqyncjnnszjlncdcdtlzzzacqqzzddxyblxcbqjylzllljddz\"\n\"jgyqyjzyxnyyyexjxksdaznyrdlzyyynjlslldyxjcykywnqcclddnyyynycgczhjxcclgzqjgnwnncqqjysbzzxyjxjnxjfzbsb\"\n\"dsfnsfpzxhdwztdmpptflzzbzdmyypqjrsdzsqzsqxbdgcpzswdwcsqzgmdhzxmwwfybpngphdmjthzsmmbgzmbzjcfzhfcbbnmq\"\n\"dfmbcmcjxlgpnjbbxgyhyyjgptzgzmqbqdcgybjxlwnkydpdymgcftpfxyztzxdzxtgkptybbclbjaskytssqyymscxfjhhlslls\"\n\"jpqjjqaklyldlycctsxmcwfgngbqxllllnyxtyltyxytdpjhnhgnkbyqnfjyyzbyyessessgdyhfhwtcqbsdzjtfdmxhcnjzymqw\"\n\"srxjdzjqbdqbbsdjgnfbknbxdkqhmkwjjjgdllthzhhyyyyhhsxztyyyccbdbpypzyccztjpzywcbdlfwzcwjdxxhyhlhwczxjtc\"\n\"nlcdpxnqczczlyxjjcjbhfxwpywxzpcdzzbdccjwjhmlxbqxxbylrddgjrrctttgqdczwmxfytmmzcwjwxyywzzkybzcccttqnhx\"\n\"nwxxkhkfhtswoccjybcmpzzykbnnzpbthhjdlszddytyfjpxyngfxbyqxzbhxcpxxtnzdnnycnxsxlhkmzxlthdhkghxxsshqyhh\"\n\"cjyxglhzxcxnhekdtgqxqypkdhentykcnymyyjmkqyyyjxzlthhqtbyqhxbmyhsqckwwyllhcyylnneqxqwmcfbdccmljggxdqkt\"\n\"lxkknqcdgcjwyjjlyhhqyttnwchhxcxwherzjydjccdbqcdgdnyxzdhcqrxcbhztqcbxwgqwyybxhmbymykdyecmqkyaqyngyzsl\"\n\"fnkkqgyssqyshngjctxkzycssbkyxhyylstycxqthysmnscpmmgcccccmnztasmgqzjhklosjylswtmqzyqkdzljqqyplzycztcq\"\n\"qpbbcjzclpkhqcyyxxdtdddsjcxffllchqxmjlwcjcxtspycxndtjshjwhdqqqckxyamylsjhmlalygxcyydmamdqmlmcznnyybz\"\n\"xkyflmcncmlhxrcjjhsylnmtjggzgywjxsrxcwjgjqhqzdqjdcjjskjkgdzcgjjyjylxzxxcdqhhheslmhlfsbdjsyyshfyssczq\"\n\"lpbdrfnztzdkykhsccgkwtqzckmsynbcrxqbjyfaxpzzedzcjykbcjwhyjbqzzywnyszptdkzpfpbaztklqnhbbzptpptyzzybhn\"\n\"ydcpzmmcycqmcjfzzdcmnlfpbplngqjtbttajzpzbbdnjkljqylnbzqhksjznggqstzkcxchpzsnbcgzkddzqanzgjkdrtlzldwj\"\n\"njzlywtxndjzjhxnatncbgtzcsskmljpjytsnwxcfjwjjtkhtzplbhsnjssyjbhbjyzlstlsbjhdnwqpslmmfbjdwajyzccjtbnn\"\n\"nzwxxcdslqgdsdpdzgjtqqpsqlyyjzlgyhsdlctcbjtktyczjtqkbsjlgnnzdncsgpynjzjjyyknhrpwszxmtncszzyshbyhyzax\"\n\"ywkcjtllckjjtjhgcssxyqyczbynnlwqcglzgjgqyqcczssbcrbcskydznxjsqgxssjmecnstjtpbdlthzwxqwqczexnqczgwesg\"\n\"ssbybstscslccgbfsdqnzlccglllzghzcthcnmjgyzazcmsksstzmmzckbjygqljyjppldxrkzyxccsnhshhdznlzhzjjcddcbcj\"\n\"xlbfqbczztpqdnnxljcthqzjgylklszzpcjdscqjhjqkdxgpbajynnsmjtzdxlcjyryynhjbngzjkmjxltbsllrzpylssznxjhll\"\n\"hyllqqzqlsymrcncxsljmlzltzldwdjjllnzggqxppskyggggbfzbdkmwggcxmcgdxjmcjsdycabxjdlnbcddygskydqdxdjjyxh\"\n\"saqazdzfslqxxjnqzylblxxwxqqzbjzlfbblylwdsljhxjyzjwtdjcyfqzqzzdzsxzzqlzcdzfxhwspynpqzmlpplffxjjnzzyls\"\n\"jnyqzfpfzgsywjjjhrdjzzxtxxglghtdxcskyswmmtcwybazbjkshfhgcxmhfqhyxxyzftsjyzbxyxpzlchmzmbxhzzssyfdmncw\"\n\"dabazlxktcshhxkxjjzjsthygxsxyyhhhjwxkzxssbzzwhhhcwtzzzpjxsyxqqjgzyzawllcwxznxgyxyhfmkhydwsqmnjnaycys\"\n\"pmjkgwcqhylajgmzxhmmcnzhbhxclxdjpltxyjkdyylttxfqzhyxxsjbjnayrsmxyplckdnyhlxrlnllstycyyqygzhhsccsmcct\"\n\"zcxhyqfpyyrpbflfqnntszlljmhwtcjqyzwtlnmlmdwmbzzsnzrbpdddlqjjbxtcsnzqqygwcsxfwzlxccrszdzmcyggdyqsgtnn\"\n\"nlsmymmsyhfbjdgyxccpshxczcsbsjyygjmpbwaffyfnxhydxzylremzgzzyndsznlljcsqfnxxkptxzgxjjgbmyyssnbtylbnlh\"\n\"bfzdcyfbmgqrrmzszxysjtznnydzzcdgnjafjbdknzblczszpsgcycjszlmnrznbzzldlnllysxsqzqlcxzlsgkbrxbrbzcycxzj\"\n\"zeeyfgklzlnyhgzcgzlfjhgtgwkraajyzkzqtsshjjxdzyznynnzyrzdqqhgjzxsszbtkjbbfrtjxllfqwjgclqtymblpzdxtzag\"\n\"bdhzzrbgjhwnjtjxlkscfsmwlldcysjtxkzscfwjlbnntzlljzllqblcqmqqcgcdfpbphzczjlpyyghdtgwdxfczqyyyqysrclqz\"\n\"fklzzzgffcqnwglhjycjjczlqzzyjbjzzbpdcsnnjgxdqnknlznnnnpsntsdyfwwdjzjysxyyczcyhzwbbyhxrylybhkjksfxtjj\"\n\"mmchhlltnyymsxxyzpdjjycsycwmdjjkqyrhllngpngtlyycljnnnxjyzfnmlrgjjtyzbsyzmsjyjhgfzqmsyxrszcytlrtqzsst\"\n\"kxgqkgsptgxdnjsgcqcqhmxggztqydjjznlbznxqlhyqgggthqscbyhjhhkyygkggcmjdzllcclxqsftgjslllmlcskctbljszsz\"\n\"mmnytpzsxqhjcnnqnyexzqzcpshkzzyzxxdfgmwqrllqxrfztlystctmjcsjjthjnxtnrztzfqrhcgllgcnnnnjdnlnnytsjtlny\"\n\"xsszxcgjzyqpylfhdjsbbdczgjjjqzjqdybssllcmyttmqnbhjqmnygjyeqyqmzgcjkpdcnmyzgqllslnclmholzgdylfzslncnz\"\n\"lylzcjeshnyllnxnjxlyjyyyxnbcljsswcqqnnyllzldjnllzllbnylnqchxyyqoxccqkyjxxxyklksxeyqhcqkkkkcsnyxxyqxy\"\n\"gwtjohthxpxxhsnlcykychzzcbwqbbwjqcscszsslcylgddsjzmmymcytsdsxxscjpqqsqylyfzychdjynywcbtjsydchcyddjlb\"\n\"djjsodzyqyskkyxdhhgqjyohdyxwgmmmazdybbbppbcmnnpnjzsmtxerxjmhqdntpjdcbsnmssythjtslmltrcplzszmlqdsdmjm\"\n\"qpnqdxcfrnnfsdqqyxhyaykqyddlqyyysszbydslntfgtzqbzmchdhczcwfdxtmqqsphqwwxsrgjcwnntzcqmgwqjrjhtqjbbgwz\"\n\"fxjhnqfxxqywyyhyscdydhhqmrmtmwctbszppzzglmzfollcfwhmmsjzttdhlmyffytzzgzyskjjxqyjzqbhmbzclyghgfmshpcf\"\n\"zsnclpbqsnjyzslxxfpmtyjygbxlldlxpzjyzjyhhzcywhjylsjexfszzywxkzjlnadymlymqjpwxxhxsktqjezrpxxzghmhwqpw\"\n\"qlyjjqjjzszcnhjlchhnxjlqwzjhbmzyxbdhhypylhlhlgfwlcfyytlhjjcwmscpxstkpnhjxsntyxxtestjctlsslstdlllwwyh\"\n\"dnrjzsfgxssyczykwhtdhwjglhtzdqdjzxxqgghltzphcsqfclnjtclzpfstpdynylgmjllycqhynspchylhqyqtmzymbywrfqyk\"\n\"jsyslzdnjmpxyyssrhzjnyqtqdfzbwwdwwrxcwggyhxmkmyyyhmxmzhnksepmlqqmtcwctmxmxjpjjhfxyyzsjzhtybmstsyjznq\"\n\"jnytlhynbyqclcycnzwsmylknjxlggnnpjgtysylymzskttwlgsmzsylmpwlcwxwqcssyzsyxyrhssntsrwpccpwcmhdhhxzdzyf\"\n\"jhgzttsbjhgyglzysmyclllxbtyxhbbzjkssdmalhhycfygmqypjyjqxjllljgclzgqlycjcctotyxmtmshllwlqfxymzmklpszz\"\n\"cxhkjyclctyjcyhxsgyxnnxlzwpyjpxhjwpjpwxqqxlxsdhmrslzzydwdtcxknstzshbsccstplwsscjchjlcgchssphylhfhhxj\"\n\"sxallnylmzdhzxylsxlmzykcldyahlcmddyspjtqjzlngjfsjshctsdszlblmssmnyymjqbjhrzwtyydchjljapzwbgqxbkfnbjd\"\n\"llllyylsjydwhxpsbcmljpscgbhxlqhyrljxyswxhhzlldfhlnnymjljyflyjycdrjlfsyzfsllcqyqfgqyhnszlylmdtdjcnhbz\"\n\"llnwlqxygyyhbmgdhxxnhlzzjzxczzzcyqzfngwpylcpkpykpmclgkdgxzgxwqbdxzzkzfbddlzxjtpjpttbythzzdwslcpnhslt\"\n\"jxxqlhyxxxywzyswttzkhlxzxzpyhgzhknfsyhntjrnxfjcpjztwhplshfcrhnslxxjxxyhzqdxqwnnhyhmjdbflkhcxcwhjfyjc\"\n\"fpqcxqxzyyyjygrpynscsnnnnchkzdyhflxxhjjbyzwttxnncyjjymswyxqrmhxzwfqsylznggbhyxnnbwttcsybhxxwxyhhxyxn\"\n\"knyxmlywrnnqlxbbcljsylfsytjzyhyzawlhorjmnsczjxxxyxchcyqryxqzddsjfslyltsffyxlmtyjmnnyyyxltzcsxqclhzxl\"\n\"wyxzhnnlrxkxjcdyhlbrlmbrdlaxksnlljlyxxlynrylcjtgncmtlzllcyzlpzpzyawnjjfybdyyzsepckzzqdqpbpsjpdyttbdb\"\n\"bbyndycncpjmtmlrmfmmrwyfbsjgygsmdqqqztxmkqwgxllpjgzbqrdjjjfpkjkcxbljmswldtsjxldlppbxcwkcqqbfqbccajzg\"\n\"mykbhyhhzykndqzybpjnspxthlfpnsygyjdbgxnhhjhzjhstrstldxskzysybmxjlxyslbzyslzxjhfybqnbylljqkygzmcyzzym\"\n\"ccslnlhzhwfwyxzmwyxtynxjhbyymcysbmhysmydyshnyzchmjjmzcaahcbjbbhblytylsxsnxgjdhkxxtxxnbhnmlngsltxmrhn\"\n\"lxqqxmzllyswqgdlbjhdcgjyqyymhwfmjybbbyjyjwjmdpwhxqldyapdfxxbcgjspckrssyzjmslbzzjfljjjlgxzgyxyxlszqkx\"\n\"bexyxhgcxbpndyhwectwwcjmbtxchxyqqllxflyxlljlssnwdbzcmyjclwswdczpchqekcqbwlcgydblqppqzqfnqdjhymmcxtxd\"\n\"rmzwrhxcjzylqxdyynhyyhrslnrsywwjjymtltllgtqcjzyabtckzcjyccqlysqxalmzynywlwdnzxqdllqshgpjfjljnjabcqzd\"\n\"jgthhsstnyjfbswzlxjxrhgldlzrlzqzgsllllzlymxxgdzhgbdphzpbrlwnjqbpfdwonnnhlypcnjccndmbcpbzzncyqxldomzb\"\n\"lzwpdwyygdstthcsqsccrsssyslfybnntyjszdfndpdhtqzmbqlxlcmyffgtjjqwftmnpjwdnlbzcmmcngbdzlqlpnfhyymjylsd\"\n\"chdcjwjcctljcldtljjcbddpndsszycndbjlggjzxsxnlycybjjxxcbylzcfzppgkcxqdzfztjjfjdjxzbnzyjqctyjwhdyczhym\"\n\"djxttmpxsplzcdwslshxypzgtfmlcjtacbbmgdewycyzxdszjyhflystygwhkjyylsjcxgywjcbllcsnddbtzbsclyzczzssqdll\"\n\"mjyyhfllqllxfdyhabxggnywyypllsdldllbjcyxjznlhljdxyyqytdlllbngpfdfbbqbzzmdpjhgclgmjjpgaehhbwcqxajhhhz\"\n\"chxyphjaxhlphjpgpzjqcqzgjjzzgzdmqyybzzphyhybwhazyjhykfgdpfqsdlzmljxjpgalxzdaglmdgxmmzqwtxdxxpfdmmssy\"\n\"mpfmdmmkxksyzyshdzkjsysmmzzzmdydyzzczxbmlstmdyemxckjmztyymzmzzmsshhdccjewxxkljsthwlsqlyjzllsjssdppmh\"\n\"nlgjczyhmxxhgncjmdhxtkgrmxfwmckmwkdcksxqmmmszzydkmsclcmpcjmhrpxqpzdsslcxkyxtwlkjyahzjgzjwcjnxyhmmbml\"\n\"gjxmhlmlgmxctkzmjlyscjsyszhsyjzjcdajzhbsdqjzgwtkqxfkdmsdjlfmnhkzqkjfeypzyszcdpynffmzqykttdzzefmzlbnp\"\n\"plplpbpszalltnlkckqzkgenjlwalkxydpxnhsxqnwqnkxqclhyxxmlnccwlymqyckynnlcjnszkpyzkcqzqljbdmdjhlasqlbyd\"\n\"wqlwdgbqcryddztjybkbwszdxdtnpjdtcnqnfxqqmgnseclstbhpwslctxxlpwydzklnqgzcqapllkqcylbqmqczqcnjslqzdjxl\"\n\"ddhpzqdljjxzqdjyzhhzlkcjqdwjppypqakjyrmpzbnmcxkllzllfqpylllmbsglzysslrsysqtmxyxzqzbscnysyztffmzzsmzq\"\n\"hzssccmlyxwtpzgxzjgzgsjzgkddhtqggzllbjdzlsbzhyxyzhzfywxytymsdnzzyjgtcmtnxqyxjscxhslnndlrytzlryylxqht\"\n\"xsrtzcgyxbnqqzfhykmzjbzymkbpnlyzpblmcnqyzzzsjztjctzhhyzzjrdyzhnfxklfzslkgjtctssyllgzrzbbjzzklpkbczys\"\n\"nnyxbjfbnjzzxcdwlzyjxzzdjjgggrsnjkmsmzjlsjywqsnyhqjsxpjztnlsnshrnynjtwchglbnrjlzxwjqxqkysjycztlqzybb\"\n\"ybyzjqdwgyzcytjcjxckcwdkkzxsnkdnywwyyjqyytlytdjlxwkcjnklccpzcqqdzzqlcsfqchqqgssmjzzllbjjzysjhtsjdysj\"\n\"qjpdszcdchjkjzzlpycgmzndjxbsjzzsyzyhgxcpbjydssxdzncglqmbtsfcbfdzdlznfgfjgfsmpnjqlnblgqcyyxbqgdjjqsrf\"\n\"kztjdhczklbsdzcfytplljgjhtxzcsszzxstjygkgckgynqxjplzbbbgcgyjzgczqszlbjlsjfzgkqqjcgycjbzqtldxrjnbsxxp\"\n\"zshszycfwdsjjhxmfczpfzhqhqmqnknlyhtycgfrzgnqxcgpdlbzcsczqlljblhbdcypscppdymzzxgyhckcpzjgslzlnscnsldl\"\n\"xbmsdlddfjmkdqdhslzxlsznpqpgjdlybdskgqlbzlnlkyyhzttmcjnqtzzfszqktlljtyyllnllqyzqlbdzlslyyzxmdfszsnxl\"\n\"xznczqnbbwskrfbcylctnblgjpmczzlstlxshtzcyzlzbnfmqnlxflcjlyljqcbclzjgnsstbrmhxzhjzclxfnbgxgtqncztmsfz\"\n\"kjmssncljkbhszjntnlzdntlmmjxgzjyjczxyhyhwrwwqnztnfjscpyshzjfyrdjsfscjzbjfzqzchzlxfxsbzqlzsgyftzdcszx\"\n\"zjbjpszkjrhxjzcgbjkhcggtxkjqglxbxfgtrtylxqxhdtsjxhjzjjcmzlcqsbtxwqgxtxxhxftsdkfjhzyjfjxnzldlllcqsqqz\"\n\"qwqxswqtwgwbzcgcllqzbclmqjtzgzyzxljfrmyzflxnsnxxjkxrmjdzdmmyxbsqbhgzmwfwygmjlzbyytgzyccdjyzxsngnyjyz\"\n\"nbgpzjcqsyxsxrtfyzgrhztxszzthcbfclsyxzlzqmzlmplmxzjssfsbysmzqhxxnxrxhqzzzsslyflczjrcrxhhzxqndshxsjjh\"\n\"qcjjbcynsysxjbqjpxzqplmlxzkyxlxcnlcycxxzzlxdlllmjyhzxhyjwkjrwyhcpsgnrzlfzwfzznsxgxflzsxzzzbfcsyjdbrj\"\n\"krdhhjxjljjtgxjxxstjtjxlyxqfcsgswmsbctlqzzwlzzkxjmltmjyhsddbxgzhdlbmyjfrzfcgclyjbpmlysmsxlszjqqhjzfx\"\n\"gfqfqbphngyyqxgztnqwyltlgwgwwhnlfmfgzjmgmgbgtjflyzzgzyzaflsspmlbflcwbjztljjmzlpjjlymqtmyyyfbgygqzgly\"\n\"zdxqyxrqqqhsxyyqxygjtyxfsfsllgnqcygycwfhcccfxpylypllzqxxxxxqqhhsshjzcftsczjxspzwhhhhhapylqnlpqafyhxd\"\n\"ylnkmzqgggddesrenzltzgchyppcsqjjhclljtolnjpzljlhymhezdydsqycddhgznndzclzywllznteydgnlhslpjjbdgwxpcnn\"\n\"tycklkclwkllcasstknzdnnjttlyyzssysszzryljqkcgdhhyrxrzydgrgcwcgzqffbppjfzynakrgywyjpqxxfkjtszzxswzddf\"\n\"bbqtbgtzkznpzfpzxzpjszbmqhkyyxyldkljnypkyghgdzjxxeaxpnznctzcmxcxmmjxnkszqnmnlwbwwqjjyhclstmcsxnjcxxt\"\n\"pcnfdtnnpglllzcjlspblpgjcdtnjjlyarscffjfqwdpgzdwmrzzcgodaxnssnyzrestyjwjyjdbcfxnmwttbqlwstszgybljpxg\"\n\"lbnclgpcbjftmxzljylzxcltpnclcgxtfzjshcrxsfysgdkntlbyjcyjllstgqcbxnhzxbxklylhzlqzlnzcqwgzlgzjncjgcmnz\"\n\"zgjdzxtzjxycyycxxjyyxjjxsssjstsstdppghtcsxwzdcsynptfbchfbblzjclzzdbxgcjlhpxnfzflsyltnwbmnjhszbmdnbcy\"\n\"sccldnycndqlyjjhmqllcsgljjsyfpyyccyltjantjjpwycmmgqyysxdxqmzhszxbftwwzqswqrfkjlzjqqyfbrxjhhfwjgzyqac\"\n\"myfrhcyybynwlpexcczsyyrlttdmqlrkmpbgmyyjprkznbbsqyxbhyzdjdnghpmfsgbwfzmfqmmbzmzdcgjlnnnxyqgmlrygqccy\"\n\"xzlwdkcjcggmcjjfyzzjhycfrrcmtznzxhkqgdjxccjeascrjthpljlrzdjrbcqhjdnrhylyqjsymhzydwcdfryhbbydtssccwbx\"\n\"glpzmlzjdqsscfjmmxjcxjytycghycjwynsxlfemwjnmkllswtxhyyyncmmcyjdqdjzglljwjnkhpzggflccsczmcbltbhbqjxqd\"\n\"jpdjztghglfjawbzyzjltstdhjhctcbchflqmpwdshyytqwcnntjtlnnmnndyyyxsqkxwyyflxxnzwcxypmaelyhgjwzzjbrxxaq\"\n\"jfllpfhhhytzzxsgqjmhspgdzqwbwpjhzjdyjcqwxkthxsqlzyymysdzgnqckknjlwpnsyscsyzlnmhqsyljxbcxtlhzqzpcycyk\"\n\"pppnsxfyzjjrcemhszmnxlxglrwgcstlrsxbygbzgnxcnlnjlclynymdxwtzpalcxpqjcjwtcyyjlblxbzlqmyljbghdslssdmxm\"\n\"bdczsxyhamlczcpjmcnhjyjnsykchskqmczqdllkablwjqsfmocdxjrrlyqchjmybyqlrhetfjzfrfksryxfjdwtsxxywsqjysly\"\n\"xwjhsdlxyyxhbhawhwjcxlmyljcsqlkydttxbzslfdxgxsjkhsxxybssxdpwncmrptqzczenygcxqfjxkjbdmljzmqqxnoxslyxx\"\n\"lylljdzptymhbfsttqqwlhsgynlzzalzxclhtwrrqhlstmypyxjjxmnsjnnbryxyjllyqyltwylqyfmlkljdnlltfzwkzhljmlhl\"\n\"jnljnnlqxylmbhhlnlzxqchxcfxxlhyhjjgbyzzkbxscqdjqdsndzsygzhhmgsxcsymxfepcqwwrbpyyjqryqcyjhqqzyhmwffhg\"\n\"zfrjfcdbxntqyzpcyhhjlfrzgpbxzdbbgrqstlgdgylcqmgchhmfywlzyxkjlypjhsywmqqggzmnzjnsqxlqsyjtcbehsxfszfxz\"\n\"wfllbcyyjdytdthwzsfjmqqyjlmqsxlldttkghybfpwdyysqqrnqwlgwdebzwcyygcnlkjxtmxmyjsxhybrwfymwfrxyymxysctz\"\n\"ztfykmldhqdlgyjnlcryjtlpsxxxywlsbrrjwxhqybhtydnhhxmmywytycnnmnssccdalwztcpqpyjllqzyjswjwzzmmglmxclmx\"\n\"nzmxmzsqtzppjqblpgxjzhfljjhycjsrxwcxsncdlxsyjdcqzxslqyclzxlzzxmxqrjmhrhzjbhmfljlmlclqnldxzlllfyprgjy\"\n\"nxcqqdcmqjzzxhnpnxzmemmsxykynlxsxtljxyhwdcwdzhqyybgybcyscfgfsjnzdrzzxqxrzrqjjymcanhrjtldbpyzbstjhxxz\"\n\"ypbdwfgzzrpymnnkxcqbyxnbnfyckrjjcmjegrzgyclnnzdnkknsjkcljspgyyclqqjybzssqlllkjftbgtylcccdblsppfylgyd\"\n\"tzjqjzgkntsfcxbdkdxxhybbfytyhbclnnytgdhryrnjsbtcsnyjqhklllzslydxxwbcjqsbxnpjzjzjdzfbxxbrmladhcsnclbj\"\n\"dstblprznswsbxbcllxxlzdnzsjpynyxxyftnnfbhjjjgbygjpmmmmsszljmtlyzjxswxtyledqpjmpgqzjgdjlqjwjqllsdgjgy\"\n\"gmscljjxdtygjqjjjcjzcjgdzdshqgzjggcjhqxsnjlzzbxhsgzxcxyljxyxyydfqqjhjfxdhctxjyrxysqtjxyefyyssyxjxncy\"\n\"zxfxcsxszxyyschshxzzzgzzzgfjdldylnpzgsjaztyqzpbxcbdztzczyxxyhhscjshcggqhjhgxhsctmzmehyxgebtclzkkwytj\"\n\"zrslekestdbcyhqqsayxcjxwwgsphjszsdncsjkqcxswxfctynydpccczjqtcwjqjzzzqzljzhlsbhpydxpsxshhezdxfptjqyzc\"\n\"xhyaxncfzyyhxgnqmywntzsjbnhhgymxmxqcnssbcqsjyxxtyyhybcqlmmszmjzzllcogxzaajzyhjmchhcxzsxsdznleyjjzjbh\"\n\"zwjzsqtzpsxzzdsqjjjlnyazphhyysrnqzthzhnyjyjhdzxzlswclybzyecwcycrylchzhzydzydyjdfrjjhtrsqtxyxjrjhojyn\"\n\"xelxsfsfjzghpzsxzszdzcqzbyyklsgsjhczshdgqgxyzgxchxzjwyqwgyhksseqzzndzfkwyssdclzstsymcdhjxxyweyxczayd\"\n\"mpxmdsxybsqmjmzjmtjqlpjyqzcgqhyjhhhqxhlhdldjqcfdwbsxfzzyyschtytyjbhecxhjkgqfxbhyzjfxhwhbdzfyzbchpnpg\"\n\"dydmsxhkhhmamlnbyjtmpxejmcthqbzyfcgtyhwphftgzzezsbzegpbmdskftycmhbllhgpzjxzjgzjyxzsbbqsczzlzscstpgxm\"\n\"jsfdcczjzdjxsybzlfcjsazfgszlwbczzzbyztzynswyjgxzbdsynxlgzbzfygczxbzhzftpbgzgejbstgkdmfhyzzjhzllzzgjq\"\n\"zlsfdjsscbzgpdlfzfzszyzyzsygcxsnxxchczxtzzljfzgqsqqxcjqccccdjcdszzyqjccgxztdlgscxzsyjjqtcclqdqztqchq\"\n\"qyzynzzzpbkhdjfcjfztypqyqttynlmbdktjcpqzjdzfpjsbnjlgyjdxjdcqkzgqkxclbzjtcjdqbxdjjjstcxnxbxqmslyjcxnt\"\n\"jqwwcjjnjjlllhjcwqtbzqqczczpzzdzyddcyzdzccjgtjfzdprntctjdcxtqzdtjnplzbcllctdsxkjzqdmzlbznbtjdcxfczdb\"\n\"czjjltqqpldckztbbzjcqdcjwynllzlzccdwllxwzlxrxntqjczxkjlsgdnqtddglnlajjtnnynkqlldzntdnycygjwyxdxfrsqs\"\n\"tcdenqmrrqzhhqhdldazfkapbggpzrebzzykyqspeqjjglkqzzzjlysyhyzwfqznlzzlzhwcgkypqgnpgblplrrjyxcccgyhsfzf\"\n\"wbzywtgzxyljczwhncjzplfflgskhyjdeyxhlpllllcygxdrzelrhgklzzyhzlyqszzjzqljzflnbhgwlczcfjwspyxzlzlxgccp\"\n\"zbllcxbbbbnbbcbbcrnnzccnrbbnnldcgqyyqxygmqzwnzytyjhyfwtehznjywlccntzyjjcdedpwdztstnjhtymbjnyjzlxtsst\"\n\"phndjxxbyxqtzqddtjtdyztgwscszqflshlnzbcjbhdlyzjyckwtydylbnydsdsycctyszyyebgexhqddwnygyclxtdcystqnygz\"\n\"ascsszzdzlcclzrqxyywljsbymxshzdembbllyyllytdqyshymrqnkfkbfxnnsbychxbwjyhtqbpbsbwdzylkgzskyghqzjxhxjx\"\n\"gnljkzlyycdxlfwfghljgjybxblybxqpqgntzplncybxdjyqydymrbeyjyyhkxxstmxrczzjwxyhybmcflyzhqyzfwxdbxbcwzms\"\n\"lpdmyckfmzklzcyqycclhxfzlydqzpzygyjyzmdxtzfnnyttqtzhgsfcdmlccytzxjcytjmkslpzhysnwllytpzctzccktxdhxxt\"\n\"qcyfksmqccyyazhtjplylzlyjbjxtfnyljyynrxcylmmnxjsmybcsysslzylljjgyldzdlqhfzzblfndsqkczfyhhgqmjdsxyctt\"\n\"xnqnjpyybfcjtyyfbnxejdgyqbjrcnfyyqpghyjsyzngrhtknlnndzntsmgklbygbpyszbydjzsstjztsxzbhbscsbzczptqfzlq\"\n\"flypybbjgszmnxdjmtsyskkbjtxhjcegbsmjyjzcstmljyxrczqscxxqpyzhmkyxxxjcljyrmyygadyskqlnadhrskqxzxztcggz\"\n\"dlmlwxybwsyctbhjhcfcwzsxwwtgzlxqshnyczjxemplsrcgltnzntlzjcyjgdtclglbllqpjmzpapxyzlaktkdwczzbncctdqqz\"\n\"qyjgmcdxltgcszlmlhbglkznnwzndxnhlnmkydlgxdtwcfrjerctzhydxykxhwfzcqshknmqqhzhhymjdjskhxzjzbzzxympajnm\"\n\"ctbxlsxlzynwrtsqgscbptbsgzwyhtlkssswhzzlyytnxjgmjrnsnnnnlskztxgxlsammlbwldqhylakqcqctmycfjbslxclzjcl\"\n\"xxknbnnzlhjphqplsxsckslnhpsfqcytxjjzljldtzjjzdlydjntptnndskjfsljhylzqqzlbthydgdjfdbyadxdzhzjnthqbykn\"\n\"xjjqczmlljzkspldsclbblnnlelxjlbjycxjxgcnlcqplzlznjtsljgyzdzpltqcssfdmnycxgbtjdcznbgbqyqjwgkfhtnbyqzq\"\n\"gbkpbbyzmtjdytblsqmbsxtbnpdxklemyycjynzdtldykzzxtdxhqshygmzsjycctayrzlpwltlkxslzcggexclfxlkjrtlqjaqz\"\n\"ncmbqdkkcxglczjzxjhptdjjmzqykqsecqzdshhadmlzfmmzbgntjnnlhbyjbrbtmlbyjdzxlcjlpldlpcqdhlhzlycblcxccjad\"\n\"qlmzmmsshmybhbnkkbhrsxxjmxmdznnpklbbrhgghfchgmnklltsyyycqlcskymyehywxnxqywbawykqldnntndkhqcgdqktgpkx\"\n\"hcpdhtwnmssyhbwcrwxhjmkmzngwtmlkfghkjyldyycxwhyyclqhkqhtdqkhffldxqwytyydesbpkyrzpjfyyzjceqdzzdlattpb\"\n\"fjllcxdlmjsdxegwgsjqxcfbssszpdyzcxznyxppzydlyjccpltxlnxyzyrscyyytylwwndsahjsygyhgywwaxtjzdaxysrltdps\"\n\"syxfnejdxyzhlxlllzhzsjnyqyqyxyjghzgjcyjchzlycdshhsgczyjscllnxzjjyyxnfsmwfpyllyllabmddhwzxjmcxztzpmlq\"\n\"chsfwzynctlndywlslxhymmylmbwwkyxyaddxylldjpybpwnxjmmmllhafdllaflbnhhbqqjqzjcqjjdjtffkmmmpythygdrjrdd\"\n\"wrqjxnbysrmzdbyytbjhpymyjtjxaahggdqtmystqxkbtzbkjlxrbyqqhxmjjbdjntgtbxpgbktlgqxjjjcdhxqdwjlwrfmjgwqh\"\n\"cnrxswgbtgygbwhswdwrfhwytjjxxxjyzyslphyypyyxhydqpxshxyxgskqhywbdddpplcjlhqeewjgsyykdpplfjthkjltcyjhh\"\n\"jttpltzzcdlyhqkcjqysteeyhkyzyxxyysddjkllpymqyhqgxqhzrhbxpllnqydqhxsxxwgdqbshyllpjjjthyjkyphthyyktyez\"\n\"yenmdshlzrpqfbnfxzbsftlgxsjbswyysksflxlpplbbblnsfbfyzbsjssylpbbffffsscjdstjsxtryjcyffsyzyzbjtlctsbsd\"\n\"hrtjjbytcxyyeylycbnebjdsysyhgsjzbxbytfzwgenhhhthjhhxfwgcstbgxklstyymtmbyxjskzscdyjrcythxzfhmymcxlzns\"\n\"djtxtxrycfyjsbsdyerxhljxbbdeynjghxgckgscymblxjmsznskgxfbnbbthfjyafxwxfbxmyfhdttcxzzpxrsywzdlybbktyqw\"\n\"qjbzypzjznjpzjlztfysbttslmptzrtdxqsjehbnylndxljsqmlhtxtjecxalzzspktlzkqqyfsyjywpcpqfhjhytqxzkrsgtksq\"\n\"czlptxcdyyzsslzslxlzmacpcqbzyxhbsxlzdltztjtylzjyytbzypltxjsjxhlbmytxcqrblzssfjzztnjytxmyjhlhpblcyxqj\"\n\"qqkzzscpzkswalqsplczzjsxgwwwygyatjbbctdkhqhkgtgpbkqyslbxbbckbmllndzstbklggqkqlzbkktfxrmdkbftpzfrtppm\"\n\"ferqnxgjpzsstlbztpszqzsjdhljqlzbpmsmmsxlqqnhknblrddnhxdkddjcyyljfqgzlgsygmjqjkhbpmxyxlytqwlwjcpbmjxc\"\n\"yzydrjbhtdjyeqshtmgsfyplwhlzffnynnhxqhpltbqpfbjwjdbygpnxtbfzjgnnntjshxeawtzylltyqbwjpgxghnnkndjtmszs\"\n\"qynzggnwqtfhclssgmnnnnynzqqxncjdqgzdlfnykljcjllzlmzznnnnsshthxjlzjbbhqjwwycrdhlyqqjbeyfsjhthnrnwjhwp\"\n\"slmssgzttygrqqwrnlalhmjtqjsmxqbjjzjqzyzkxbjqxbjxshzssfglxmxnxfghkzszggslcnnarjxhnlllmzxelglxydjytlfb\"\n\"kbpnlyzfbbhptgjkwetzhkjjxzxxglljlstgshjjyqlqzfkcgnndjsszfdbctwwseqfhqjbsaqtgypjlbxbmmywxgslzhglsgnyf\"\n\"ljbyfdjfngsfmbyzhqffwjsyfyjjphzbyyzffwotjnlmftwlbzgyzqxcdjygzyyryzynyzwegazyhjjlzrthlrmgrjxzclnnnljj\"\n\"yhtbwjybxxbxjjtjteekhwslnnlbsfazpqqbdlqjjtyyqlyzkdksqjnejzldqcgjqnnjsncmrfqthtejmfctyhypymhydmjncfgy\"\n\"yxwshctxrljgjzhzcyyyjltkttntmjlzclzzayyoczlrlbszywjytsjyhbyshfjlykjxxtmzyyltxxypslqyjzyzyypnhmymdyyl\"\n\"blhlsyygqllnjjymsoycbzgdlyxylcqyxtszegxhzglhwbljheyxtwqmakbpqcgyshhegqcmwyywljyjhyyzlljjylhzyhmgsljl\"\n\"jxcjjyclycjbcpzjzjmmwlcjlnqljjjlxyjmlszljqlycmmgcfmmfpqqmfxlqmcffqmmmmhnznfhhjgtthxkhslnchhyqzxtmmqd\"\n\"cydyxyqmyqylddcyaytazdcymdydlzfffmmycqcwzzmabtbyctdmndzggdftypcgqyttssffwbdttqssystwnjhjytsxxylbyyhh\"\n\"whxgzxwznnqzjzjjqjccchykxbzszcnjtllcqxynjnckycynccqnxyewyczdcjycchyjlbtzyycqwlpgpyllgktltlgkgqbgychj\"\n\"xy\";\n\n\n\n@interface NSString (enumrateCharater)\n\n- (void)enumerateCharaterUsingBlock:(void(^)(unsigned short letter, BOOL *stop))enumertae;\n\n@end\n\n@implementation NSString (enumrateCharater)\n\n- (void)enumerateCharaterUsingBlock:(void(^)(unsigned short letter, BOOL *stop))enumertae\n{\n    static BOOL stop;\n    for (NSInteger i = 0; i < [self length]; i++)\n    {\n        NSLog(@\"letter1:%c\", [self characterAtIndex:i]);\n        enumertae([self characterAtIndex:i], &stop);\n\n        if (stop) break;\n    }\n}\n\n@end\n\n@implementation HTFirstLetter\n\n+ (char)pinyinFirstLetter:(unsigned short )hanzi\n{\n    int index = hanzi - HANZI_START;\n\tif (index >= 0 && index <= HANZI_COUNT)\n\t{\n\t\treturn firstLetterArray[index];\n\t}\n\telse\n\t{\n\t\treturn '#';\n\t}\n}\n\n+ (NSString *)firstLetter:(NSString *)chineseString\n{\n    NSString *firstLetters = [HTFirstLetter firstLetters:chineseString];\n    NSArray *firstLetterArray = [firstLetters componentsSeparatedByString:@\" \"];\n    if ([firstLetterArray count] > 0)\n        firstLetters = [firstLetterArray objectAtIndex:0];\n    return firstLetters;\n}\n\n+ (NSString *)firstLetters:(NSString *)chineseString\n{\n    return [HTFirstLetter firstLetterUsingSeperate:@\" \" chineseString:chineseString];\n}\n\n+ (NSString *)firstLetterUsingSeperate:(NSString *)seperate chineseString:(NSString *)chineseString\n{\n    \n    __block NSString *firstLetters = @\"\";\n    [chineseString enumerateCharaterUsingBlock:^(unsigned short letter, BOOL *stop) {\n     \n     int index = letter - HANZI_START;\n     \n     if (index >= 0 && index <= HANZI_COUNT){\n     \n        if ([firstLetters length]){\n            firstLetters = [firstLetters stringByAppendingFormat:@\" %c\", firstLetterArray[index]];\n        }else {\n            firstLetters = [firstLetters stringByAppendingFormat:@\"%c\", firstLetterArray[index]];\n        }\n     \n     }else if ((letter > 'a' && letter < 'z') ||\n               (letter > 'A' && letter < 'Z')){\n\n        if ([firstLetters length]){\n            firstLetters = [firstLetters stringByAppendingFormat:@\" %c\", letter];\n        }else {\n            firstLetters = [firstLetters stringByAppendingFormat:@\"%c\", letter];\n        }\n\n     }else {\n         //如果是字母或其它符号，都返回 #\n        if ([firstLetters length]){\n            firstLetters = [firstLetters stringByAppendingFormat:@\" %c\",true ? '#' : letter];\n        }else {\n            firstLetters = [firstLetters stringByAppendingFormat:@\"%c\", true ? '#' : letter];\n        }\n     }\n\n     }];\n    \n    return firstLetters;\n}\n\n@end"
  },
  {
    "path": "Pod/Classes/Extend/SwiftRegex/Match.swift",
    "content": "//\n//  Match.swift\n//  Cupertino\n//\n//  Created by William Kent on 2/19/15.\n//  Copyright (c) 2015 William Kent. All rights reserved.\n//\n\nimport Foundation\n\nprivate func safeSubstring(whole: String, range: NSRange) -> String? {\n    if range.location != NSNotFound && range.length != 0 {\n        return (whole as NSString).substringWithRange(range)\n    } else {\n        return nil\n    }\n}\n\npublic struct RegexMatch {\n    private let sourceString: String\n    private let cocoaMatch: NSTextCheckingResult\n    \n    internal init(cocoaMatch: NSTextCheckingResult, inString source: String) {\n        self.sourceString = source\n        self.cocoaMatch = cocoaMatch\n    }\n    \n    public var range: NSRange {\n        get {\n            return cocoaMatch.range\n        }\n    }\n    \n    public var entireMatch: String? {\n        get {\n            return safeSubstring(sourceString, range: cocoaMatch.range)\n        }\n    }\n    \n    public var subgroupCount: Int {\n        get {\n            return cocoaMatch.numberOfRanges - 1\n        }\n    }\n    \n    public func subgroupRangeAtIndex(index: Int) -> NSRange? {\n        return cocoaMatch.rangeAtIndex(index + 1)\n    }\n    \n    public func subgroupMatchAtIndex(index: Int) -> String? {\n        let range = cocoaMatch.rangeAtIndex(index + 1)\n        return safeSubstring(sourceString, range: range)\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/SwiftRegex/Regex.swift",
    "content": "//\n//  Regex.swift\n//  Cupertino\n//\n//  Created by William Kent on 2/19/15.\n//  Copyright (c) 2015 William Kent. All rights reserved.\n//\n\nimport Foundation\n\nprivate func convertRange(range: NSRange, relativeToString string: String) -> Range<String.Index> {\n    let start = string.startIndex.advancedBy(range.location)\n    let end = string.startIndex.advancedBy(NSMaxRange(range))\n    return Range(start: start, end: end)\n}\n\npublic enum RegexFlags {\n    case CaseInsensitive\n    case AllowCommentsAndWhitespace\n    case IgnoreMetacharacters\n    case DotMatchesLineSeparators\n    case AnchorsMatchLines\n    case UseUnicodeWordBoundaries\n}\n\npublic struct Regex {\n    public let pattern: String\n    public var options: Set<RegexFlags>\n    \n    public init(_ pattern: String, options: Set<RegexFlags>) {\n        self.pattern = pattern\n        self.options = options\n    }\n    \n    public init(_ pattern: String) {\n        self.pattern = pattern\n        self.options = []\n    }\n    \n    private var matcherOptions: NSRegularExpressionOptions {\n        get {\n            var opts: NSRegularExpressionOptions = NSRegularExpressionOptions.CaseInsensitive\n            \n            if options.contains(.CaseInsensitive) {\n                opts = NSRegularExpressionOptions.CaseInsensitive\n            }\n            if options.contains(.AllowCommentsAndWhitespace) {\n                opts = NSRegularExpressionOptions.AllowCommentsAndWhitespace\n            }\n            if options.contains(.IgnoreMetacharacters) {\n                opts = NSRegularExpressionOptions.IgnoreMetacharacters\n            }\n            if options.contains(.DotMatchesLineSeparators) {\n                opts = NSRegularExpressionOptions.DotMatchesLineSeparators\n            }\n            if options.contains(.AnchorsMatchLines) {\n                opts = NSRegularExpressionOptions.AnchorsMatchLines\n            }\n            if options.contains(.UseUnicodeWordBoundaries) {\n                opts = NSRegularExpressionOptions.UseUnicodeWordBoundaries\n            }\n            \n            return opts\n        }\n    }\n    \n    private var matcher: NSRegularExpression? {\n        get {\n            return try? NSRegularExpression(pattern: self.pattern, options: self.matcherOptions)\n        }\n    }\n    \n    public func test(string: String) -> Bool? {\n        return test(string, options: [])\n    }\n    \n    public func test(string: String, options: NSMatchingOptions) -> Bool? {\n        // This function returns true if the regex matches, false if the regex does\n        // not match, or nil if there is a syntax error in the regex itself.\n        if let matcher = matcher {\n            return matcher.numberOfMatchesInString(string, options: options, range: NSMakeRange(0, string.characters.count)) != 0\n        } else {\n            return nil\n        }\n    }\n    \n    public func match(string: String) -> [RegexMatch]? {\n        return match(string, options: [])\n    }\n    \n    public func match(string: String, options: NSMatchingOptions) -> [RegexMatch]? {\n        if let matcher = matcher {\n            let cocoaMatches = matcher.matchesInString(string, options: options, range: NSMakeRange(0, string.characters.count))\n            var retval = [RegexMatch]()\n            \n            for match: AnyObject in cocoaMatches {\n                if let match = match as? NSTextCheckingResult {\n                    retval.append(RegexMatch(cocoaMatch: match, inString: string))\n                }\n            }\n            \n            return retval\n        } else {\n            return nil\n        }\n    }\n    \n    public func match(string: String, options: NSMatchingOptions, startPosition: Int) -> [RegexMatch]? {\n        if let matcher = matcher {\n            let cocoaMatches = matcher.matchesInString(string, options: options, range: NSMakeRange(startPosition, string.characters.count - startPosition))\n            var retval = [RegexMatch]()\n            \n            for match: AnyObject in cocoaMatches {\n                if let match = match as? NSTextCheckingResult {\n                    retval.append(RegexMatch(cocoaMatch: match, inString: string))\n                }\n            }\n            \n            return retval\n        } else {\n            return nil\n        }\n    }\n    \n    public func replace(string: String, withTemplate template: String) -> String? {\n        return replace(string, options: [], withTemplate: template)\n    }\n    \n    public func replace(string: String, options: NSMatchingOptions, withTemplate template: String) -> String? {\n        if let matcher = matcher {\n            let workString = NSMutableString(string: string)\n            matcher.replaceMatchesInString(workString, options: options, range: NSMakeRange(0, workString.length), withTemplate: template)\n            let retval = workString as NSString\n            return String(retval)\n        }\n        \n        return nil\n    }\n    \n    public func replace(string: String, withBlock block: (RegexMatch) -> String) -> String? {\n        return replace(string, options: [], withBlock: block)\n    }\n    \n    public func replace(string: String, options: NSMatchingOptions, withBlock block: (RegexMatch) -> String) -> String? {\n        if let matches = match(string, options: options) {\n            var replacements: [(NSRange, String)] = []\n            \n            for match in matches {\n                let replacedSubstring = block(match)\n                replacements.append((match.range, replacedSubstring))\n            }\n            \n            // Sort the replacements in order of location, then reverse it.\n            // By applying the replacements in right-to-left order, I avoid having\n            // to recalculate all the indices when a replacement changes the length\n            // of the replaced substring.\n            replacements.sortInPlace({\n                (lhs, rhs) -> Bool in\n                let (leftRange, _) = lhs\n                let (rightRange, _) = rhs\n                \n                return leftRange.location < rightRange.location\n            })\n            replacements = Array(replacements.reverse())\n            \n            var retval = string\n            for pair in replacements {\n                let (range, substring) = pair\n                retval.replaceRange(convertRange(range, relativeToString: retval), with: substring)\n            }\n            \n            return retval\n        } else {\n            return nil\n        }\n    }\n}\n\nextension Regex: StringLiteralConvertible {\n    public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType\n    public typealias UnicodeScalarLiteralType = UnicodeScalar\n    \n    public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {\n        self.pattern = \"\\(value)\"\n        self.options = []\n    }\n    \n    public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {\n        self.pattern = value\n        self.options = []\n    }\n    \n    public init(stringLiteral value: StringLiteralType) {\n        self.pattern = value\n        self.options = []\n    }\n}\n"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/UIViewController+URLManage.h",
    "content": "//\n//  UIViewController+URLManage.h\n//  rssreader\n//\n//  Created by zhuchao on 15/2/11.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface UIViewController (URLManage)\n@property(nonatomic,retain)NSURL *originUrl;\n@property(nonatomic,retain)NSString *path;\n@property(nonatomic,retain)NSDictionary *params;\n@property(nonatomic,retain)NSDictionary *dictQuery;\n\n+ (UIViewController *)initFromString:(NSString *)aString fromConfig:(NSDictionary *)config;\n+ (UIViewController *)initFromURL:(NSURL *)url fromConfig:(NSDictionary *)config;\n+ (UIViewController *)initFromString:(NSString *)aString withQuery:(NSDictionary *)query fromConfig:(NSDictionary *)config;\n+ (UIViewController *)initFromURL:(NSURL *)url withQuery:(NSDictionary *)query fromConfig:(NSDictionary *)config;\n@end\n\n@interface NSObject (URLManage)\n+ (Class)classFromString:(NSString *)className;\n+ (NSObject *)objectFromString:(NSString *)className;\n@end"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/UIViewController+URLManage.m",
    "content": "//\n//  UIViewController+URLManage.m\n//  rssreader\n//\n//  Created by zhuchao on 15/2/11.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import \"UIViewController+URLManage.h\"\n#import <objc/runtime.h>\n\nstatic char URLoriginUrl;\nstatic char URLpath;\nstatic char URLparams;\nstatic char URLdictQuery;\n\n\n@implementation UIViewController (URLManage)\n-(void)setOriginUrl:(NSURL *)originUrl{\n    [self willChangeValueForKey:@\"originUrl\"];\n    objc_setAssociatedObject(self, &URLoriginUrl,\n                             originUrl,\n                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);\n    [self didChangeValueForKey:@\"originUrl\"];\n}\n-(NSURL *)originUrl {\n    return objc_getAssociatedObject(self, &URLoriginUrl);\n}\n\n-(NSString *)path {\n    return objc_getAssociatedObject(self, &URLpath);\n}\n-(void)setPath:(NSURL *)path{\n    [self willChangeValueForKey:@\"path\"];\n    objc_setAssociatedObject(self, &URLpath,\n                             path,\n                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);\n    [self didChangeValueForKey:@\"path\"];\n}\n\n\n-(NSDictionary *)params {\n    return objc_getAssociatedObject(self, &URLparams);\n}\n-(void)setParams:(NSDictionary *)params{\n    [self willChangeValueForKey:@\"params\"];\n    objc_setAssociatedObject(self, &URLparams,\n                             params,\n                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);\n    [self didChangeValueForKey:@\"params\"];\n}\n\n-(NSDictionary *)dictQuery {\n    return objc_getAssociatedObject(self, &URLdictQuery);\n}\n\n-(void)setDictQuery:(NSDictionary *)dictQuery{\n    [self willChangeValueForKey:@\"dictQuery\"];\n    objc_setAssociatedObject(self, &URLdictQuery,\n                             dictQuery,\n                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);\n    [self didChangeValueForKey:@\"dictQuery\"];\n}\n\n-(void)open:(NSURL *)url withQuery:(NSDictionary *)dict{\n    self.path = [url path];\n    self.originUrl = url;\n    self.dictQuery = dict;\n    \n    NSArray *components = [[url query] componentsSeparatedByString:@\"&\"];\n    NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];\n    for (NSString *component in components) {\n        NSArray *subcomponents = [component componentsSeparatedByString:@\"=\"];\n        [parameters setObject:[[subcomponents objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]\n                       forKey:[[subcomponents objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];\n    }\n    self.params = parameters;\n}\n\n+ (UIViewController *)initFromString:(NSString *)aString fromConfig:(NSDictionary *)config{\n    return [UIViewController initFromURL:[NSURL URLWithString:aString] withQuery:nil fromConfig:config];\n}\n\n+ (UIViewController *)initFromURL:(NSURL *)url fromConfig:(NSDictionary *)config{\n    return [UIViewController initFromURL:url withQuery:nil fromConfig:config];\n}\n\n+ (UIViewController *)initFromString:(NSString *)aString withQuery:(NSDictionary *)query fromConfig:(NSDictionary *)config{\n    return [UIViewController initFromURL:[NSURL URLWithString:aString] withQuery:query fromConfig:config] ;\n}\n\n+ (UIViewController *)initFromURL:(NSURL *)url withQuery:(NSDictionary *)query fromConfig:(NSDictionary *)config\n{\n    UIViewController* scene = nil;\n    NSString *home;\n    if(url.path ==nil){\n        home = [NSString stringWithFormat:@\"%@://%@\", url.scheme, url.host];\n    }else{\n        home = [NSString stringWithFormat:@\"%@://%@%@\", url.scheme, url.host,url.path];\n    }\n    if([config.allKeys containsObject:url.scheme]){\n        id cgf = [config objectForKey:url.scheme];\n        Class class = nil;\n        if([cgf isKindOfClass:[NSString class]]){\n            \n            class =  [NSObject classFromString:cgf];\n        }else if([cgf isKindOfClass:[NSDictionary class]]){\n            NSDictionary *dict = (NSDictionary *)cgf;\n            if([dict.allKeys containsObject:home]){\n                class =  [NSObject classFromString:[dict objectForKey:home]];\n            }else{\n                class =  [NSObject classFromString:url.host];\n            }\n        }\n        if(class !=nil){\n            scene = [[class alloc]init];\n            if([scene  respondsToSelector:@selector(open:withQuery:)]){\n                [scene open:url withQuery:query];\n            }\n        }\n    }else if([query objectForKey:@\"openURL\"] || [url.scheme hasPrefix:@\"http\"]){\n        [[UIApplication sharedApplication] openURL:url];\n    }\n    return scene;\n}\n\n\n@end\n\n@implementation NSObject (URLManage)\n+ (Class)classFromString:(NSString *)className {\n    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"CFBundleName\"];\n    NSString *classStringName = [NSString stringWithFormat:@\"%@.%@\",appName, className];\n    return NSClassFromString(classStringName);\n}\n+ (NSObject *)objectFromString:(NSString *)className{\n    Class clazz = [NSObject classFromString:className];\n    return [[clazz alloc]init];\n}\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/URLManager.h",
    "content": "//\n//  URLManager.h\n//  rssreader\n//\n//  Created by zhuchao on 15/3/6.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import \"URLNavigation.h\"\n#import \"UIViewController+URLManage.h\"\n\n@interface URLManager : NSObject\n@property(nonatomic,retain)NSDictionary *config;\n+ (URLManager *)shareInstance;\n+ (void)loadConfigFromPlist:(NSString *)plistPath;\n\n+ (void)pushURLString:(NSString *)urlString animated:(BOOL)animated;\n+ (void)pushURLString:(NSString *)urlString animated:(BOOL)animated replace:(BOOL)replace;\n\n+ (void)pushURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated;\n+ (void)pushURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated replace:(BOOL)replace;\n\n+ (void)pushURL:(NSURL *)url animated:(BOOL)animated;\n+ (void)pushURL:(NSURL *)url animated:(BOOL)animated replace:(BOOL)replace;\n\n+ (void)pushURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated;\n+ (void)pushURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated replace:(BOOL)replace;\n\n+ (void)presentURL:(NSURL *)url animated:(BOOL)animated;\n+ (void)presentURLString:(NSString *)urlString animated:(BOOL)animated;\n\n+ (void)presentURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated;\n+ (void)presentURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated;\n\n+ (void)presentURL:(NSURL *)url animated:(BOOL)animated withNavigationClass:(Class)clazz;\n+ (void)presentURLString:(NSString *)urlString animated:(BOOL)animated withNavigationClass:(Class)clazz;\n\n+ (void)presentURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated withNavigationClass:(Class)clazz;\n+ (void)presentURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated withNavigationClass:(Class)clazz;\n\n@end\n\n\n"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/URLManager.m",
    "content": "//\n//  URLManager.m\n//  rssreader\n//\n//  Created by zhuchao on 15/3/6.\n//  Copyright (c) 2015年 zhuchao. All rights reserved.\n//\n\n#import \"URLManager.h\"\n\n@implementation URLManager\n+ (URLManager *)shareInstance{\n    static dispatch_once_t predicate = 0;\n    static id sharedInstance = nil;\n    dispatch_once(&predicate, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n+(void)loadConfigFromPlist:(NSString *)plistPath{\n    [URLManager shareInstance].config = [NSDictionary dictionaryWithContentsOfFile:plistPath];\n}\n\n+ (void)pushURLString:(NSString *)urlString animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromString:urlString fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated];\n}\n\n+ (void)pushURL:(NSURL *)url animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromURL:url fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated];\n}\n\n+ (void)pushURLString:(NSString *)urlString animated:(BOOL)animated replace:(BOOL)replace{\n    UIViewController *viewController = [UIViewController initFromString:urlString fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:YES replace:replace];\n}\n\n+ (void)pushURL:(NSURL *)url animated:(BOOL)animated replace:(BOOL)replace{\n    UIViewController *viewController = [UIViewController initFromURL:url fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated replace:replace];\n}\n\n+ (void)presentURLString:(NSString *)urlString animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromString:urlString fromConfig:[URLManager shareInstance].config];\n    [URLNavigation presentViewController:viewController animated:animated];\n}\n\n+ (void)presentURL:(NSURL *)url animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromURL:url fromConfig:[URLManager shareInstance].config];\n    [URLNavigation presentViewController:viewController animated:animated];\n}\n\n+ (void)presentURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromString:urlString withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation presentViewController:viewController animated:animated];\n}\n\n+ (void)presentURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromURL:url withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation presentViewController:viewController animated:animated];\n}\n\n+ (void)pushURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromURL:url withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated];\n}\n\n+ (void)pushURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated replace:(BOOL)replace{\n    UIViewController *viewController = [UIViewController initFromURL:url withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated replace:replace];\n}\n\n+ (void)pushURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated{\n    UIViewController *viewController = [UIViewController initFromString:urlString withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated];\n}\n\n+ (void)pushURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated replace:(BOOL)replace{\n    UIViewController *viewController = [UIViewController initFromString:urlString withQuery:query fromConfig:[URLManager shareInstance].config];\n    [URLNavigation pushViewController:viewController animated:animated replace:replace];\n}\n\n+ (void)presentURL:(NSURL *)url animated:(BOOL)animated withNavigationClass:(Class)clazz{\n    UIViewController *viewController = [UIViewController initFromURL:url fromConfig:[URLManager shareInstance].config];\n    UINavigationController *nav =  [[clazz alloc]initWithRootViewController:viewController];\n    [URLNavigation presentViewController:nav animated:animated];\n}\n\n+ (void)presentURL:(NSURL *)url query:(NSDictionary *)query animated:(BOOL)animated withNavigationClass:(Class)clazz{\n    UIViewController *viewController = [UIViewController initFromURL:url withQuery:query fromConfig:[URLManager shareInstance].config];\n    UINavigationController *nav =  [[clazz alloc]initWithRootViewController:viewController];\n    [URLNavigation presentViewController:nav animated:animated];\n}\n\n+ (void)presentURLString:(NSString *)urlString animated:(BOOL)animated withNavigationClass:(Class)clazz{\n    \n    UIViewController *viewController = [UIViewController initFromString:urlString fromConfig:[URLManager shareInstance].config];\n    if ([clazz isSubclassOfClass:[UINavigationController class]]) {\n        UINavigationController *nav =  [[clazz alloc]initWithRootViewController:viewController];\n        [URLNavigation presentViewController:nav animated:animated];\n    }\n}\n\n+ (void)presentURLString:(NSString *)urlString query:(NSDictionary *)query animated:(BOOL)animated withNavigationClass:(Class)clazz{\n    UIViewController *viewController = [UIViewController initFromString:urlString withQuery:query fromConfig:[URLManager shareInstance].config];\n    if ([clazz isSubclassOfClass:[UINavigationController class]]) {\n        UINavigationController *nav =  [[clazz alloc]initWithRootViewController:viewController];\n        [URLNavigation presentViewController:nav animated:animated];\n    }\n}\n@end"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/URLNavigation.h",
    "content": "//\n//  HKNavigation.h\n//  Hoko\n//\n//  Created by Hoko, S.A. on 23/07/14.\n//  Copyright (c) 2015 Hoko, S.A. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n/**\n *  HKNavigation is a helper class which allows you to push, present and set view\n *  controllers taking basis on your view controller hierararchy. This only takes\n *  account UITabBarControllers, UINavigationControllers and Modal View Controllers\n *  in order to traverse the hierarchy. \n *\n *  WARNING: If you have custom navigation you should use your own methods to push and present\n *  view controllers, this is only a helper class for common navigation based on Apple's default\n *  view controller hierarchies.\n *\n */\n@interface URLNavigation : NSObject\n/**\n *  setRootViewController: changes the root view controller of the AppDelegate's window.\n *\n *  @param viewController Your view controller (or hierarchy of).\n */\n+ (void)setRootViewController:(UIViewController *)viewController;\n\n/**\n *  pushViewController:animated: pushes a view controller inside a navigation controller.\n *  If your viewController is a navigation controller it replaces the rootViewController,\n *  otherwise it tries to push the viewController if the current view controller is a \n *  UINavigationController, otherwise it creates it before pushing.\n *\n *  @param viewController Your view controller.\n *  @param animated       If you choose to animate the pushing of the viewController.\n */\n+ (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;\n\n/**\n *  pushViewController:animated:replace: pushes a view controller inside a navigation controller.\n *  If your viewController is a navigation controller it replaces the rootViewController,\n *  otherwise it tries to push the viewController if the current view controller is a\n *  UINavigationController, otherwise it creates it before pushing.\n *  The replace parameter locates the current view controller and replaces it if it is of\n *  the same class as the viewController parameter being passed, this exists to avoid\n *  two of the same view controller in a row.\n *\n *  @param viewController Your view controller.\n *  @param animated       If you choose to animate the pushing of the viewController.\n */\n+ (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated replace:(BOOL)replace;\n\n/**\n *  presentViewController:animated: presents a view controller as a modal view controller,\n *  taking basis on the current view controller to present from.\n *\n *  @param viewController Your view controller.\n *  @param animated       If you choose to animate the presenting of the viewController.\n */\n+ (void)presentViewController:(UIViewController *)viewController animated:(BOOL)animated;\n\n+(void)dismissCurrentAnimated:(BOOL)animated;\n+(UIViewController*)currentViewController;\n+(UINavigationController*)currentNavigationViewController;\n@end\n"
  },
  {
    "path": "Pod/Classes/Extend/URLManager/URLNavigation.m",
    "content": "//\n//  HKObserver.m\n//  Hoko\n//\n//  Created by Hoko, S.A. on 23/07/14.\n//  Copyright (c) 2015 Hoko, S.A. All rights reserved.\n//\n\n#import \"URLNavigation.h\"\n@implementation URLNavigation\n\n#pragma mark - Singleton\n+ (instancetype)shareInstance{\n    static dispatch_once_t predicate = 0;\n    static id sharedInstance = nil;\n    dispatch_once(&predicate, ^{\n        sharedInstance = [[self alloc] init];\n    });\n    return sharedInstance;\n}\n\n#pragma mark - Public Method\n+ (void)setRootViewController:(UIViewController *)viewController\n{\n  [URLNavigation shareInstance].applicationDelegate.window.rootViewController = viewController;\n}\n\n+ (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated\n{\n  [self pushViewController:viewController animated:animated replace:NO];\n}\n\n+ (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated replace:(BOOL)replace\n{\n  // Check if viewController is a UINavigationController\n  if([viewController isKindOfClass:[UINavigationController class]])\n    [URLNavigation setRootViewController:viewController];\n  else {\n    // Check if a UINavigationController exists in the view controllers stack.\n    UINavigationController *navigationController = [URLNavigation shareInstance].currentNavigationViewController;\n    if (navigationController) {\n      // In case it should replace, look for the last UIViewController on the UINavigationController, if it's of the same class, replace it with a new one.\n      if (replace && [navigationController.viewControllers.lastObject isKindOfClass:[viewController class]]) {\n        NSArray *viewControllers = [navigationController.viewControllers subarrayWithRange:NSMakeRange(0, navigationController.viewControllers.count-1)];\n        [navigationController setViewControllers:[viewControllers arrayByAddingObject:viewController] animated:animated];\n      } else {\n        // Otherwise just push the new viewController\n        [navigationController pushViewController:viewController animated:animated];\n      }\n    } else {\n      // Create a new UINavigationController to use with the viewController\n      navigationController = [[UINavigationController alloc]initWithRootViewController:viewController];\n      [URLNavigation shareInstance].applicationDelegate.window.rootViewController = navigationController;\n    }\n  }\n}\n\n+ (void)presentViewController:(UIViewController *)viewController animated:(BOOL)animated\n{\n  // Look for the currentViewController\n  UIViewController *currentViewController = [[URLNavigation shareInstance] currentViewController];\n  if (currentViewController) {\n    // Present viewController from currentViewcontroller\n    [currentViewController presentViewController:viewController animated:animated completion:nil];\n  } else {\n    // Otherwise set the window rootViewController\n    [URLNavigation shareInstance].applicationDelegate.window.rootViewController = viewController;\n  }\n}\n\n\n+(void)dismissCurrentAnimated:(BOOL)animated{\n  UIViewController *currentViewController = [[URLNavigation shareInstance] currentViewController];\n  if(currentViewController){\n      if(currentViewController.navigationController){\n          if(currentViewController.navigationController.viewControllers.count == 1){\n              if(currentViewController.presentingViewController){\n                  [currentViewController dismissViewControllerAnimated:animated completion:nil];\n              }\n          }else{\n              [currentViewController.navigationController popViewControllerAnimated:animated];\n          }\n      }else if(currentViewController.presentingViewController){\n          [currentViewController dismissViewControllerAnimated:animated completion:nil];\n      }\n  }\n}\n\n#pragma mark - Private Methods\n- (id<UIApplicationDelegate>)applicationDelegate\n{\n  return [UIApplication sharedApplication].delegate;\n}\n\n+(UIViewController*)currentViewController{\n    return [[URLNavigation shareInstance] currentViewController];\n}\n\n- (UIViewController*)currentViewController\n{\n  UIViewController* rootViewController = self.applicationDelegate.window.rootViewController;\n  return [self currentViewControllerFrom:rootViewController];\n}\n\n+(UIViewController*)currentNavigationViewController{\n    return [[URLNavigation shareInstance] currentNavigationViewController];\n}\n\n- (UINavigationController*)currentNavigationViewController\n{\n  UIViewController* currentViewController = self.currentViewController;\n  return currentViewController.navigationController;\n}\n\n- (UIViewController*)currentViewControllerFrom:(UIViewController*)viewController\n{\n  if ([viewController isKindOfClass:[UINavigationController class]]) {\n    UINavigationController* navigationController = (UINavigationController *)viewController;\n    return [self currentViewControllerFrom:navigationController.viewControllers.lastObject];\n  } else if([viewController isKindOfClass:[UITabBarController class]]) {\n    UITabBarController* tabBarController = (UITabBarController *)viewController;\n    return [self currentViewControllerFrom:tabBarController.selectedViewController];\n  } else if(viewController.presentedViewController != nil) {\n    return [self currentViewControllerFrom:viewController.presentedViewController];\n  } else {\n    return viewController;\n  }\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/attribute.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"attribute.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n\n#include \"util.h\"\n\nstruct GumboInternalParser;\n\nGumboAttribute* gumbo_get_attribute(\n    const GumboVector* attributes, const char* name) {\n  for (int i = 0; i < attributes->length; ++i) {\n    GumboAttribute* attr = attributes->data[i];\n    if (!strcasecmp(attr->name, name)) {\n      return attr;\n    }\n  }\n  return NULL;\n}\n\nvoid gumbo_destroy_attribute(\n    struct GumboInternalParser* parser, GumboAttribute* attribute) {\n  gumbo_parser_deallocate(parser, (void*) attribute->name);\n  gumbo_parser_deallocate(parser, (void*) attribute->value);\n  gumbo_parser_deallocate(parser, (void*) attribute);\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/attribute.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#ifndef GUMBO_ATTRIBUTE_H_\n#define GUMBO_ATTRIBUTE_H_\n\n#include \"gumbo.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\n\n// Release the memory used for an GumboAttribute, including the attribute\n// itself.\nvoid gumbo_destroy_attribute(\n    struct GumboInternalParser* parser, GumboAttribute* attribute);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_ATTRIBUTE_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/char_ref.c",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"char_ref.h\"\n\n#include <assert.h>\n#include <ctype.h>\n#include <stddef.h>\n#include <string.h>     // Only for debug assertions at present.\n\n#include \"error.h\"\n#include \"string_piece.h\"\n#include \"utf8.h\"\n#include \"util.h\"\n\nstruct GumboInternalParser;\n\nconst int kGumboNoChar = -1;\n\n// Table of named character entities, and functions for looking them up.\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html\n//\n// TODO(jdtang): I'd thought of using more efficient means of this, eg. binary\n// searching the table (which can only be done if we know for sure that there's\n// enough room in the buffer for our memcmps, otherwise we need to fall back on\n// linear search) or compiling the list of named entities to a Ragel state\n// machine.  But I'll start with the simple approach and optimize only if\n// profiling calls for it.  The one concession to efficiency is to store the\n// length of the entity with it, so that we don't need to run a strlen to detect\n// potential buffer overflows.\ntypedef struct {\n  const char* name;\n  size_t length;\n  OneOrTwoCodepoints codepoints;\n} NamedCharRef;\n\n#define CHAR_REF(name, codepoint) { name, sizeof(name) - 1, { codepoint, -1 } }\n#define MULTI_CHAR_REF(name, code_point, code_point2) \\\n    { name, sizeof(name) - 1, { code_point, code_point2 } }\n\n// Versions with the semicolon must come before versions without the semicolon,\n// otherwise they'll match the invalid name first and record a parse error.\n// TODO(jdtang): Replace with a FSM that'll do longest-match-first and probably\n// give better performance besides.\nstatic const NamedCharRef kNamedEntities[] = {\n  CHAR_REF(\"AElig\", 0xc6),\n  CHAR_REF(\"AMP;\", 0x26),\n  CHAR_REF(\"AMP\", 0x26),\n  CHAR_REF(\"Aacute;\", 0xc1),\n  CHAR_REF(\"Aacute\", 0xc1),\n  CHAR_REF(\"Abreve;\", 0x0102),\n  CHAR_REF(\"Acirc;\", 0xc2),\n  CHAR_REF(\"Acirc\", 0xc2),\n  CHAR_REF(\"Acy;\", 0x0410),\n  CHAR_REF(\"Afr;\", 0x0001d504),\n  CHAR_REF(\"Agrave\", 0xc0),\n  CHAR_REF(\"Agrave;\", 0xc0),\n  CHAR_REF(\"Alpha;\", 0x0391),\n  CHAR_REF(\"Amacr;\", 0x0100),\n  CHAR_REF(\"And;\", 0x2a53),\n  CHAR_REF(\"Aogon;\", 0x0104),\n  CHAR_REF(\"Aopf;\", 0x0001d538),\n  CHAR_REF(\"ApplyFunction;\", 0x2061),\n  CHAR_REF(\"Aring;\", 0xc5),\n  CHAR_REF(\"Aring\", 0xc5),\n  CHAR_REF(\"Ascr;\", 0x0001d49c),\n  CHAR_REF(\"Assign;\", 0x2254),\n  CHAR_REF(\"Atilde;\", 0xc3),\n  CHAR_REF(\"Atilde\", 0xc3),\n  CHAR_REF(\"Auml;\", 0xc4),\n  CHAR_REF(\"Auml\", 0xc4),\n  CHAR_REF(\"Backslash;\", 0x2216),\n  CHAR_REF(\"Barv;\", 0x2ae7),\n  CHAR_REF(\"Barwed;\", 0x2306),\n  CHAR_REF(\"Bcy;\", 0x0411),\n  CHAR_REF(\"Because;\", 0x2235),\n  CHAR_REF(\"Bernoullis;\", 0x212c),\n  CHAR_REF(\"Beta;\", 0x0392),\n  CHAR_REF(\"Bfr;\", 0x0001d505),\n  CHAR_REF(\"Bopf;\", 0x0001d539),\n  CHAR_REF(\"Breve;\", 0x02d8),\n  CHAR_REF(\"Bscr;\", 0x212c),\n  CHAR_REF(\"Bumpeq;\", 0x224e),\n  CHAR_REF(\"CHcy;\", 0x0427),\n  CHAR_REF(\"COPY;\", 0xa9),\n  CHAR_REF(\"COPY\", 0xa9),\n  CHAR_REF(\"Cacute;\", 0x0106),\n  CHAR_REF(\"Cap;\", 0x22d2),\n  CHAR_REF(\"CapitalDifferentialD;\", 0x2145),\n  CHAR_REF(\"Cayleys;\", 0x212d),\n  CHAR_REF(\"Ccaron;\", 0x010c),\n  CHAR_REF(\"Ccedil;\", 0xc7),\n  CHAR_REF(\"Ccedil\", 0xc7),\n  CHAR_REF(\"Ccirc;\", 0x0108),\n  CHAR_REF(\"Cconint;\", 0x2230),\n  CHAR_REF(\"Cdot;\", 0x010a),\n  CHAR_REF(\"Cedilla;\", 0xb8),\n  CHAR_REF(\"CenterDot;\", 0xb7),\n  CHAR_REF(\"Cfr;\", 0x212d),\n  CHAR_REF(\"Chi;\", 0x03a7),\n  CHAR_REF(\"CircleDot;\", 0x2299),\n  CHAR_REF(\"CircleMinus;\", 0x2296),\n  CHAR_REF(\"CirclePlus;\", 0x2295),\n  CHAR_REF(\"CircleTimes;\", 0x2297),\n  CHAR_REF(\"ClockwiseContourIntegral;\", 0x2232),\n  CHAR_REF(\"CloseCurlyDoubleQuote;\", 0x201d),\n  CHAR_REF(\"CloseCurlyQuote;\", 0x2019),\n  CHAR_REF(\"Colon;\", 0x2237),\n  CHAR_REF(\"Colone;\", 0x2a74),\n  CHAR_REF(\"Congruent;\", 0x2261),\n  CHAR_REF(\"Conint;\", 0x222f),\n  CHAR_REF(\"ContourIntegral;\", 0x222e),\n  CHAR_REF(\"Copf;\", 0x2102),\n  CHAR_REF(\"Coproduct;\", 0x2210),\n  CHAR_REF(\"CounterClockwiseContourIntegral;\", 0x2233),\n  CHAR_REF(\"Cross;\", 0x2a2f),\n  CHAR_REF(\"Cscr;\", 0x0001d49e),\n  CHAR_REF(\"Cup;\", 0x22d3),\n  CHAR_REF(\"CupCap;\", 0x224d),\n  CHAR_REF(\"DD;\", 0x2145),\n  CHAR_REF(\"DDotrahd;\", 0x2911),\n  CHAR_REF(\"DJcy;\", 0x0402),\n  CHAR_REF(\"DScy;\", 0x0405),\n  CHAR_REF(\"DZcy;\", 0x040f),\n  CHAR_REF(\"Dagger;\", 0x2021),\n  CHAR_REF(\"Darr;\", 0x21a1),\n  CHAR_REF(\"Dashv;\", 0x2ae4),\n  CHAR_REF(\"Dcaron;\", 0x010e),\n  CHAR_REF(\"Dcy;\", 0x0414),\n  CHAR_REF(\"Del;\", 0x2207),\n  CHAR_REF(\"Delta;\", 0x0394),\n  CHAR_REF(\"Dfr;\", 0x0001d507),\n  CHAR_REF(\"DiacriticalAcute;\", 0xb4),\n  CHAR_REF(\"DiacriticalDot;\", 0x02d9),\n  CHAR_REF(\"DiacriticalDoubleAcute;\", 0x02dd),\n  CHAR_REF(\"DiacriticalGrave;\", 0x60),\n  CHAR_REF(\"DiacriticalTilde;\", 0x02dc),\n  CHAR_REF(\"Diamond;\", 0x22c4),\n  CHAR_REF(\"DifferentialD;\", 0x2146),\n  CHAR_REF(\"Dopf;\", 0x0001d53b),\n  CHAR_REF(\"Dot;\", 0xa8),\n  CHAR_REF(\"DotDot;\", 0x20dc),\n  CHAR_REF(\"DotEqual;\", 0x2250),\n  CHAR_REF(\"DoubleContourIntegral;\", 0x222f),\n  CHAR_REF(\"DoubleDot;\", 0xa8),\n  CHAR_REF(\"DoubleDownArrow;\", 0x21d3),\n  CHAR_REF(\"DoubleLeftArrow;\", 0x21d0),\n  CHAR_REF(\"DoubleLeftRightArrow;\", 0x21d4),\n  CHAR_REF(\"DoubleLeftTee;\", 0x2ae4),\n  CHAR_REF(\"DoubleLongLeftArrow;\", 0x27f8),\n  CHAR_REF(\"DoubleLongLeftRightArrow;\", 0x27fa),\n  CHAR_REF(\"DoubleLongRightArrow;\", 0x27f9),\n  CHAR_REF(\"DoubleRightArrow;\", 0x21d2),\n  CHAR_REF(\"DoubleRightTee;\", 0x22a8),\n  CHAR_REF(\"DoubleUpArrow;\", 0x21d1),\n  CHAR_REF(\"DoubleUpDownArrow;\", 0x21d5),\n  CHAR_REF(\"DoubleVerticalBar;\", 0x2225),\n  CHAR_REF(\"DownArrow;\", 0x2193),\n  CHAR_REF(\"DownArrowBar;\", 0x2913),\n  CHAR_REF(\"DownArrowUpArrow;\", 0x21f5),\n  CHAR_REF(\"DownBreve;\", 0x0311),\n  CHAR_REF(\"DownLeftRightVector;\", 0x2950),\n  CHAR_REF(\"DownLeftTeeVector;\", 0x295e),\n  CHAR_REF(\"DownLeftVector;\", 0x21bd),\n  CHAR_REF(\"DownLeftVectorBar;\", 0x2956),\n  CHAR_REF(\"DownRightTeeVector;\", 0x295f),\n  CHAR_REF(\"DownRightVector;\", 0x21c1),\n  CHAR_REF(\"DownRightVectorBar;\", 0x2957),\n  CHAR_REF(\"DownTee;\", 0x22a4),\n  CHAR_REF(\"DownTeeArrow;\", 0x21a7),\n  CHAR_REF(\"Downarrow;\", 0x21d3),\n  CHAR_REF(\"Dscr;\", 0x0001d49f),\n  CHAR_REF(\"Dstrok;\", 0x0110),\n  CHAR_REF(\"ENG;\", 0x014a),\n  CHAR_REF(\"ETH;\", 0xd0),\n  CHAR_REF(\"ETH\", 0xd0),\n  CHAR_REF(\"Eacute;\", 0xc9),\n  CHAR_REF(\"Eacute\", 0xc9),\n  CHAR_REF(\"Ecaron;\", 0x011a),\n  CHAR_REF(\"Ecirc;\", 0xca),\n  CHAR_REF(\"Ecirc\", 0xca),\n  CHAR_REF(\"Ecy;\", 0x042d),\n  CHAR_REF(\"Edot;\", 0x0116),\n  CHAR_REF(\"Efr;\", 0x0001d508),\n  CHAR_REF(\"Egrave;\", 0xc8),\n  CHAR_REF(\"Egrave\", 0xc8),\n  CHAR_REF(\"Element;\", 0x2208),\n  CHAR_REF(\"Emacr;\", 0x0112),\n  CHAR_REF(\"EmptySmallSquare;\", 0x25fb),\n  CHAR_REF(\"EmptyVerySmallSquare;\", 0x25ab),\n  CHAR_REF(\"Eogon;\", 0x0118),\n  CHAR_REF(\"Eopf;\", 0x0001d53c),\n  CHAR_REF(\"Epsilon;\", 0x0395),\n  CHAR_REF(\"Equal;\", 0x2a75),\n  CHAR_REF(\"EqualTilde;\", 0x2242),\n  CHAR_REF(\"Equilibrium;\", 0x21cc),\n  CHAR_REF(\"Escr;\", 0x2130),\n  CHAR_REF(\"Esim;\", 0x2a73),\n  CHAR_REF(\"Eta;\", 0x0397),\n  CHAR_REF(\"Euml;\", 0xcb),\n  CHAR_REF(\"Euml\", 0xcb),\n  CHAR_REF(\"Exists;\", 0x2203),\n  CHAR_REF(\"ExponentialE;\", 0x2147),\n  CHAR_REF(\"Fcy;\", 0x0424),\n  CHAR_REF(\"Ffr;\", 0x0001d509),\n  CHAR_REF(\"FilledSmallSquare;\", 0x25fc),\n  CHAR_REF(\"FilledVerySmallSquare;\", 0x25aa),\n  CHAR_REF(\"Fopf;\", 0x0001d53d),\n  CHAR_REF(\"ForAll;\", 0x2200),\n  CHAR_REF(\"Fouriertrf;\", 0x2131),\n  CHAR_REF(\"Fscr;\", 0x2131),\n  CHAR_REF(\"GJcy;\", 0x0403),\n  CHAR_REF(\"GT;\", 0x3e),\n  CHAR_REF(\"GT\", 0x3e),\n  CHAR_REF(\"Gamma;\", 0x0393),\n  CHAR_REF(\"Gammad;\", 0x03dc),\n  CHAR_REF(\"Gbreve;\", 0x011e),\n  CHAR_REF(\"Gcedil;\", 0x0122),\n  CHAR_REF(\"Gcirc;\", 0x011c),\n  CHAR_REF(\"Gcy;\", 0x0413),\n  CHAR_REF(\"Gdot;\", 0x0120),\n  CHAR_REF(\"Gfr;\", 0x0001d50a),\n  CHAR_REF(\"Gg;\", 0x22d9),\n  CHAR_REF(\"Gopf;\", 0x0001d53e),\n  CHAR_REF(\"GreaterEqual;\", 0x2265),\n  CHAR_REF(\"GreaterEqualLess;\", 0x22db),\n  CHAR_REF(\"GreaterFullEqual;\", 0x2267),\n  CHAR_REF(\"GreaterGreater;\", 0x2aa2),\n  CHAR_REF(\"GreaterLess;\", 0x2277),\n  CHAR_REF(\"GreaterSlantEqual;\", 0x2a7e),\n  CHAR_REF(\"GreaterTilde;\", 0x2273),\n  CHAR_REF(\"Gscr;\", 0x0001d4a2),\n  CHAR_REF(\"Gt;\", 0x226b),\n  CHAR_REF(\"HARDcy;\", 0x042a),\n  CHAR_REF(\"Hacek;\", 0x02c7),\n  CHAR_REF(\"Hat;\", 0x5e),\n  CHAR_REF(\"Hcirc;\", 0x0124),\n  CHAR_REF(\"Hfr;\", 0x210c),\n  CHAR_REF(\"HilbertSpace;\", 0x210b),\n  CHAR_REF(\"Hopf;\", 0x210d),\n  CHAR_REF(\"HorizontalLine;\", 0x2500),\n  CHAR_REF(\"Hscr;\", 0x210b),\n  CHAR_REF(\"Hstrok;\", 0x0126),\n  CHAR_REF(\"HumpDownHump;\", 0x224e),\n  CHAR_REF(\"HumpEqual;\", 0x224f),\n  CHAR_REF(\"IEcy;\", 0x0415),\n  CHAR_REF(\"IJlig;\", 0x0132),\n  CHAR_REF(\"IOcy;\", 0x0401),\n  CHAR_REF(\"Iacute;\", 0xcd),\n  CHAR_REF(\"Iacute\", 0xcd),\n  CHAR_REF(\"Icirc;\", 0xce),\n  CHAR_REF(\"Icirc\", 0xce),\n  CHAR_REF(\"Icy;\", 0x0418),\n  CHAR_REF(\"Idot;\", 0x0130),\n  CHAR_REF(\"Ifr;\", 0x2111),\n  CHAR_REF(\"Igrave;\", 0xcc),\n  CHAR_REF(\"Igrave\", 0xcc),\n  CHAR_REF(\"Im;\", 0x2111),\n  CHAR_REF(\"Imacr;\", 0x012a),\n  CHAR_REF(\"ImaginaryI;\", 0x2148),\n  CHAR_REF(\"Implies;\", 0x21d2),\n  CHAR_REF(\"Int;\", 0x222c),\n  CHAR_REF(\"Integral;\", 0x222b),\n  CHAR_REF(\"Intersection;\", 0x22c2),\n  CHAR_REF(\"InvisibleComma;\", 0x2063),\n  CHAR_REF(\"InvisibleTimes;\", 0x2062),\n  CHAR_REF(\"Iogon;\", 0x012e),\n  CHAR_REF(\"Iopf;\", 0x0001d540),\n  CHAR_REF(\"Iota;\", 0x0399),\n  CHAR_REF(\"Iscr;\", 0x2110),\n  CHAR_REF(\"Itilde;\", 0x0128),\n  CHAR_REF(\"Iukcy;\", 0x0406),\n  CHAR_REF(\"Iuml;\", 0xcf),\n  CHAR_REF(\"Iuml\", 0xcf),\n  CHAR_REF(\"Jcirc;\", 0x0134),\n  CHAR_REF(\"Jcy;\", 0x0419),\n  CHAR_REF(\"Jfr;\", 0x0001d50d),\n  CHAR_REF(\"Jopf;\", 0x0001d541),\n  CHAR_REF(\"Jscr;\", 0x0001d4a5),\n  CHAR_REF(\"Jsercy;\", 0x0408),\n  CHAR_REF(\"Jukcy;\", 0x0404),\n  CHAR_REF(\"KHcy;\", 0x0425),\n  CHAR_REF(\"KJcy;\", 0x040c),\n  CHAR_REF(\"Kappa;\", 0x039a),\n  CHAR_REF(\"Kcedil;\", 0x0136),\n  CHAR_REF(\"Kcy;\", 0x041a),\n  CHAR_REF(\"Kfr;\", 0x0001d50e),\n  CHAR_REF(\"Kopf;\", 0x0001d542),\n  CHAR_REF(\"Kscr;\", 0x0001d4a6),\n  CHAR_REF(\"LJcy;\", 0x0409),\n  CHAR_REF(\"LT;\", 0x3c),\n  CHAR_REF(\"LT\", 0x3c),\n  CHAR_REF(\"Lacute;\", 0x0139),\n  CHAR_REF(\"Lambda;\", 0x039b),\n  CHAR_REF(\"Lang;\", 0x27ea),\n  CHAR_REF(\"Laplacetrf;\", 0x2112),\n  CHAR_REF(\"Larr;\", 0x219e),\n  CHAR_REF(\"Lcaron;\", 0x013d),\n  CHAR_REF(\"Lcedil;\", 0x013b),\n  CHAR_REF(\"Lcy;\", 0x041b),\n  CHAR_REF(\"LeftAngleBracket;\", 0x27e8),\n  CHAR_REF(\"LeftArrow;\", 0x2190),\n  CHAR_REF(\"LeftArrowBar;\", 0x21e4),\n  CHAR_REF(\"LeftArrowRightArrow;\", 0x21c6),\n  CHAR_REF(\"LeftCeiling;\", 0x2308),\n  CHAR_REF(\"LeftDoubleBracket;\", 0x27e6),\n  CHAR_REF(\"LeftDownTeeVector;\", 0x2961),\n  CHAR_REF(\"LeftDownVector;\", 0x21c3),\n  CHAR_REF(\"LeftDownVectorBar;\", 0x2959),\n  CHAR_REF(\"LeftFloor;\", 0x230a),\n  CHAR_REF(\"LeftRightArrow;\", 0x2194),\n  CHAR_REF(\"LeftRightVector;\", 0x294e),\n  CHAR_REF(\"LeftTee;\", 0x22a3),\n  CHAR_REF(\"LeftTeeArrow;\", 0x21a4),\n  CHAR_REF(\"LeftTeeVector;\", 0x295a),\n  CHAR_REF(\"LeftTriangle;\", 0x22b2),\n  CHAR_REF(\"LeftTriangleBar;\", 0x29cf),\n  CHAR_REF(\"LeftTriangleEqual;\", 0x22b4),\n  CHAR_REF(\"LeftUpDownVector;\", 0x2951),\n  CHAR_REF(\"LeftUpTeeVector;\", 0x2960),\n  CHAR_REF(\"LeftUpVector;\", 0x21bf),\n  CHAR_REF(\"LeftUpVectorBar;\", 0x2958),\n  CHAR_REF(\"LeftVector;\", 0x21bc),\n  CHAR_REF(\"LeftVectorBar;\", 0x2952),\n  CHAR_REF(\"Leftarrow;\", 0x21d0),\n  CHAR_REF(\"Leftrightarrow;\", 0x21d4),\n  CHAR_REF(\"LessEqualGreater;\", 0x22da),\n  CHAR_REF(\"LessFullEqual;\", 0x2266),\n  CHAR_REF(\"LessGreater;\", 0x2276),\n  CHAR_REF(\"LessLess;\", 0x2aa1),\n  CHAR_REF(\"LessSlantEqual;\", 0x2a7d),\n  CHAR_REF(\"LessTilde;\", 0x2272),\n  CHAR_REF(\"Lfr;\", 0x0001d50f),\n  CHAR_REF(\"Ll;\", 0x22d8),\n  CHAR_REF(\"Lleftarrow;\", 0x21da),\n  CHAR_REF(\"Lmidot;\", 0x013f),\n  CHAR_REF(\"LongLeftArrow;\", 0x27f5),\n  CHAR_REF(\"LongLeftRightArrow;\", 0x27f7),\n  CHAR_REF(\"LongRightArrow;\", 0x27f6),\n  CHAR_REF(\"Longleftarrow;\", 0x27f8),\n  CHAR_REF(\"Longleftrightarrow;\", 0x27fa),\n  CHAR_REF(\"Longrightarrow;\", 0x27f9),\n  CHAR_REF(\"Lopf;\", 0x0001d543),\n  CHAR_REF(\"LowerLeftArrow;\", 0x2199),\n  CHAR_REF(\"LowerRightArrow;\", 0x2198),\n  CHAR_REF(\"Lscr;\", 0x2112),\n  CHAR_REF(\"Lsh;\", 0x21b0),\n  CHAR_REF(\"Lstrok;\", 0x0141),\n  CHAR_REF(\"Lt;\", 0x226a),\n  CHAR_REF(\"Map;\", 0x2905),\n  CHAR_REF(\"Mcy;\", 0x041c),\n  CHAR_REF(\"MediumSpace;\", 0x205f),\n  CHAR_REF(\"Mellintrf;\", 0x2133),\n  CHAR_REF(\"Mfr;\", 0x0001d510),\n  CHAR_REF(\"MinusPlus;\", 0x2213),\n  CHAR_REF(\"Mopf;\", 0x0001d544),\n  CHAR_REF(\"Mscr;\", 0x2133),\n  CHAR_REF(\"Mu;\", 0x039c),\n  CHAR_REF(\"NJcy;\", 0x040a),\n  CHAR_REF(\"Nacute;\", 0x0143),\n  CHAR_REF(\"Ncaron;\", 0x0147),\n  CHAR_REF(\"Ncedil;\", 0x0145),\n  CHAR_REF(\"Ncy;\", 0x041d),\n  CHAR_REF(\"NegativeMediumSpace;\", 0x200b),\n  CHAR_REF(\"NegativeThickSpace;\", 0x200b),\n  CHAR_REF(\"NegativeThinSpace;\", 0x200b),\n  CHAR_REF(\"NegativeVeryThinSpace;\", 0x200b),\n  CHAR_REF(\"NestedGreaterGreater;\", 0x226b),\n  CHAR_REF(\"NestedLessLess;\", 0x226a),\n  CHAR_REF(\"NewLine;\", 0x0a),\n  CHAR_REF(\"Nfr;\", 0x0001d511),\n  CHAR_REF(\"NoBreak;\", 0x2060),\n  CHAR_REF(\"NonBreakingSpace;\", 0xa0),\n  CHAR_REF(\"Nopf;\", 0x2115),\n  CHAR_REF(\"Not;\", 0x2aec),\n  CHAR_REF(\"NotCongruent;\", 0x2262),\n  CHAR_REF(\"NotCupCap;\", 0x226d),\n  CHAR_REF(\"NotDoubleVerticalBar;\", 0x2226),\n  CHAR_REF(\"NotElement;\", 0x2209),\n  CHAR_REF(\"NotEqual;\", 0x2260),\n  MULTI_CHAR_REF(\"NotEqualTilde;\", 0x2242, 0x0338),\n  CHAR_REF(\"NotExists;\", 0x2204),\n  CHAR_REF(\"NotGreater;\", 0x226f),\n  CHAR_REF(\"NotGreaterEqual;\", 0x2271),\n  MULTI_CHAR_REF(\"NotGreaterFullEqual;\", 0x2267, 0x0338),\n  MULTI_CHAR_REF(\"NotGreaterGreater;\", 0x226b, 0x0338),\n  CHAR_REF(\"NotGreaterLess;\", 0x2279),\n  MULTI_CHAR_REF(\"NotGreaterSlantEqual;\", 0x2a7e, 0x0338),\n  CHAR_REF(\"NotGreaterTilde;\", 0x2275),\n  MULTI_CHAR_REF(\"NotHumpDownHump;\", 0x224e, 0x0338),\n  MULTI_CHAR_REF(\"NotHumpEqual;\", 0x224f, 0x0338),\n  CHAR_REF(\"NotLeftTriangle;\", 0x22ea),\n  MULTI_CHAR_REF(\"NotLeftTriangleBar;\", 0x29cf, 0x0338),\n  CHAR_REF(\"NotLeftTriangleEqual;\", 0x22ec),\n  CHAR_REF(\"NotLess;\", 0x226e),\n  CHAR_REF(\"NotLessEqual;\", 0x2270),\n  CHAR_REF(\"NotLessGreater;\", 0x2278),\n  MULTI_CHAR_REF(\"NotLessLess;\", 0x226a, 0x0338),\n  MULTI_CHAR_REF(\"NotLessSlantEqual;\", 0x2a7d, 0x0338),\n  CHAR_REF(\"NotLessTilde;\", 0x2274),\n  MULTI_CHAR_REF(\"NotNestedGreaterGreater;\", 0x2aa2, 0x0338),\n  MULTI_CHAR_REF(\"NotNestedLessLess;\", 0x2aa1, 0x0338),\n  CHAR_REF(\"NotPrecedes;\", 0x2280),\n  MULTI_CHAR_REF(\"NotPrecedesEqual;\", 0x2aaf, 0x0338),\n  CHAR_REF(\"NotPrecedesSlantEqual;\", 0x22e0),\n  CHAR_REF(\"NotReverseElement;\", 0x220c),\n  CHAR_REF(\"NotRightTriangle;\", 0x22eb),\n  MULTI_CHAR_REF(\"NotRightTriangleBar;\", 0x29d0, 0x0338),\n  CHAR_REF(\"NotRightTriangleEqual;\", 0x22ed),\n  MULTI_CHAR_REF(\"NotSquareSubset;\", 0x228f, 0x0338),\n  CHAR_REF(\"NotSquareSubsetEqual;\", 0x22e2),\n  MULTI_CHAR_REF(\"NotSquareSuperset;\", 0x2290, 0x0338),\n  CHAR_REF(\"NotSquareSupersetEqual;\", 0x22e3),\n  MULTI_CHAR_REF(\"NotSubset;\", 0x2282, 0x20d2),\n  CHAR_REF(\"NotSubsetEqual;\", 0x2288),\n  CHAR_REF(\"NotSucceeds;\", 0x2281),\n  MULTI_CHAR_REF(\"NotSucceedsEqual;\", 0x2ab0, 0x0338),\n  CHAR_REF(\"NotSucceedsSlantEqual;\", 0x22e1),\n  MULTI_CHAR_REF(\"NotSucceedsTilde;\", 0x227f, 0x0338),\n  MULTI_CHAR_REF(\"NotSuperset;\", 0x2283, 0x20d2),\n  CHAR_REF(\"NotSupersetEqual;\", 0x2289),\n  CHAR_REF(\"NotTilde;\", 0x2241),\n  CHAR_REF(\"NotTildeEqual;\", 0x2244),\n  CHAR_REF(\"NotTildeFullEqual;\", 0x2247),\n  CHAR_REF(\"NotTildeTilde;\", 0x2249),\n  CHAR_REF(\"NotVerticalBar;\", 0x2224),\n  CHAR_REF(\"Nscr;\", 0x0001d4a9),\n  CHAR_REF(\"Ntilde;\", 0xd1),\n  CHAR_REF(\"Ntilde\", 0xd1),\n  CHAR_REF(\"Nu;\", 0x039d),\n  CHAR_REF(\"OElig;\", 0x0152),\n  CHAR_REF(\"Oacute;\", 0xd3),\n  CHAR_REF(\"Oacute\", 0xd3),\n  CHAR_REF(\"Ocirc;\", 0xd4),\n  CHAR_REF(\"Ocirc\", 0xd4),\n  CHAR_REF(\"Ocy;\", 0x041e),\n  CHAR_REF(\"Odblac;\", 0x0150),\n  CHAR_REF(\"Ofr;\", 0x0001d512),\n  CHAR_REF(\"Ograve;\", 0xd2),\n  CHAR_REF(\"Ograve\", 0xd2),\n  CHAR_REF(\"Omacr;\", 0x014c),\n  CHAR_REF(\"Omega;\", 0x03a9),\n  CHAR_REF(\"Omicron;\", 0x039f),\n  CHAR_REF(\"Oopf;\", 0x0001d546),\n  CHAR_REF(\"OpenCurlyDoubleQuote;\", 0x201c),\n  CHAR_REF(\"OpenCurlyQuote;\", 0x2018),\n  CHAR_REF(\"Or;\", 0x2a54),\n  CHAR_REF(\"Oscr;\", 0x0001d4aa),\n  CHAR_REF(\"Oslash;\", 0xd8),\n  CHAR_REF(\"Oslash\", 0xd8),\n  CHAR_REF(\"Otilde;\", 0xd5),\n  CHAR_REF(\"Otilde\", 0xd5),\n  CHAR_REF(\"Otimes;\", 0x2a37),\n  CHAR_REF(\"Ouml\", 0xd6),\n  CHAR_REF(\"Ouml;\", 0xd6),\n  CHAR_REF(\"OverBar;\", 0x203e),\n  CHAR_REF(\"OverBrace;\", 0x23de),\n  CHAR_REF(\"OverBracket;\", 0x23b4),\n  CHAR_REF(\"OverParenthesis;\", 0x23dc),\n  CHAR_REF(\"PartialD;\", 0x2202),\n  CHAR_REF(\"Pcy;\", 0x041f),\n  CHAR_REF(\"Pfr;\", 0x0001d513),\n  CHAR_REF(\"Phi;\", 0x03a6),\n  CHAR_REF(\"Pi;\", 0x03a0),\n  CHAR_REF(\"PlusMinus;\", 0xb1),\n  CHAR_REF(\"Poincareplane;\", 0x210c),\n  CHAR_REF(\"Popf;\", 0x2119),\n  CHAR_REF(\"Pr;\", 0x2abb),\n  CHAR_REF(\"Precedes;\", 0x227a),\n  CHAR_REF(\"PrecedesEqual;\", 0x2aaf),\n  CHAR_REF(\"PrecedesSlantEqual;\", 0x227c),\n  CHAR_REF(\"PrecedesTilde;\", 0x227e),\n  CHAR_REF(\"Prime;\", 0x2033),\n  CHAR_REF(\"Product;\", 0x220f),\n  CHAR_REF(\"Proportion;\", 0x2237),\n  CHAR_REF(\"Proportional;\", 0x221d),\n  CHAR_REF(\"Pscr;\", 0x0001d4ab),\n  CHAR_REF(\"Psi;\", 0x03a8),\n  CHAR_REF(\"QUOT;\", 0x22),\n  CHAR_REF(\"QUOT\", 0x22),\n  CHAR_REF(\"Qfr;\", 0x0001d514),\n  CHAR_REF(\"Qopf;\", 0x211a),\n  CHAR_REF(\"Qscr;\", 0x0001d4ac),\n  CHAR_REF(\"RBarr;\", 0x2910),\n  CHAR_REF(\"REG;\", 0xae),\n  CHAR_REF(\"REG\", 0xae),\n  CHAR_REF(\"Racute;\", 0x0154),\n  CHAR_REF(\"Rang;\", 0x27eb),\n  CHAR_REF(\"Rarr;\", 0x21a0),\n  CHAR_REF(\"Rarrtl;\", 0x2916),\n  CHAR_REF(\"Rcaron;\", 0x0158),\n  CHAR_REF(\"Rcedil;\", 0x0156),\n  CHAR_REF(\"Rcy;\", 0x0420),\n  CHAR_REF(\"Re;\", 0x211c),\n  CHAR_REF(\"ReverseElement;\", 0x220b),\n  CHAR_REF(\"ReverseEquilibrium;\", 0x21cb),\n  CHAR_REF(\"ReverseUpEquilibrium;\", 0x296f),\n  CHAR_REF(\"Rfr;\", 0x211c),\n  CHAR_REF(\"Rho;\", 0x03a1),\n  CHAR_REF(\"RightAngleBracket;\", 0x27e9),\n  CHAR_REF(\"RightArrow;\", 0x2192),\n  CHAR_REF(\"RightArrowBar;\", 0x21e5),\n  CHAR_REF(\"RightArrowLeftArrow;\", 0x21c4),\n  CHAR_REF(\"RightCeiling;\", 0x2309),\n  CHAR_REF(\"RightDoubleBracket;\", 0x27e7),\n  CHAR_REF(\"RightDownTeeVector;\", 0x295d),\n  CHAR_REF(\"RightDownVector;\", 0x21c2),\n  CHAR_REF(\"RightDownVectorBar;\", 0x2955),\n  CHAR_REF(\"RightFloor;\", 0x230b),\n  CHAR_REF(\"RightTee;\", 0x22a2),\n  CHAR_REF(\"RightTeeArrow;\", 0x21a6),\n  CHAR_REF(\"RightTeeVector;\", 0x295b),\n  CHAR_REF(\"RightTriangle;\", 0x22b3),\n  CHAR_REF(\"RightTriangleBar;\", 0x29d0),\n  CHAR_REF(\"RightTriangleEqual;\", 0x22b5),\n  CHAR_REF(\"RightUpDownVector;\", 0x294f),\n  CHAR_REF(\"RightUpTeeVector;\", 0x295c),\n  CHAR_REF(\"RightUpVector;\", 0x21be),\n  CHAR_REF(\"RightUpVectorBar;\", 0x2954),\n  CHAR_REF(\"RightVector;\", 0x21c0),\n  CHAR_REF(\"RightVectorBar;\", 0x2953),\n  CHAR_REF(\"Rightarrow;\", 0x21d2),\n  CHAR_REF(\"Ropf;\", 0x211d),\n  CHAR_REF(\"RoundImplies;\", 0x2970),\n  CHAR_REF(\"Rrightarrow;\", 0x21db),\n  CHAR_REF(\"Rscr;\", 0x211b),\n  CHAR_REF(\"Rsh;\", 0x21b1),\n  CHAR_REF(\"RuleDelayed;\", 0x29f4),\n  CHAR_REF(\"SHCHcy;\", 0x0429),\n  CHAR_REF(\"SHcy;\", 0x0428),\n  CHAR_REF(\"SOFTcy;\", 0x042c),\n  CHAR_REF(\"Sacute;\", 0x015a),\n  CHAR_REF(\"Sc;\", 0x2abc),\n  CHAR_REF(\"Scaron;\", 0x0160),\n  CHAR_REF(\"Scedil;\", 0x015e),\n  CHAR_REF(\"Scirc;\", 0x015c),\n  CHAR_REF(\"Scy;\", 0x0421),\n  CHAR_REF(\"Sfr;\", 0x0001d516),\n  CHAR_REF(\"ShortDownArrow;\", 0x2193),\n  CHAR_REF(\"ShortLeftArrow;\", 0x2190),\n  CHAR_REF(\"ShortRightArrow;\", 0x2192),\n  CHAR_REF(\"ShortUpArrow;\", 0x2191),\n  CHAR_REF(\"Sigma;\", 0x03a3),\n  CHAR_REF(\"SmallCircle;\", 0x2218),\n  CHAR_REF(\"Sopf;\", 0x0001d54a),\n  CHAR_REF(\"Sqrt;\", 0x221a),\n  CHAR_REF(\"Square;\", 0x25a1),\n  CHAR_REF(\"SquareIntersection;\", 0x2293),\n  CHAR_REF(\"SquareSubset;\", 0x228f),\n  CHAR_REF(\"SquareSubsetEqual;\", 0x2291),\n  CHAR_REF(\"SquareSuperset;\", 0x2290),\n  CHAR_REF(\"SquareSupersetEqual;\", 0x2292),\n  CHAR_REF(\"SquareUnion;\", 0x2294),\n  CHAR_REF(\"Sscr;\", 0x0001d4ae),\n  CHAR_REF(\"Star;\", 0x22c6),\n  CHAR_REF(\"Sub;\", 0x22d0),\n  CHAR_REF(\"Subset;\", 0x22d0),\n  CHAR_REF(\"SubsetEqual;\", 0x2286),\n  CHAR_REF(\"Succeeds;\", 0x227b),\n  CHAR_REF(\"SucceedsEqual;\", 0x2ab0),\n  CHAR_REF(\"SucceedsSlantEqual;\", 0x227d),\n  CHAR_REF(\"SucceedsTilde;\", 0x227f),\n  CHAR_REF(\"SuchThat;\", 0x220b),\n  CHAR_REF(\"Sum;\", 0x2211),\n  CHAR_REF(\"Sup;\", 0x22d1),\n  CHAR_REF(\"Superset;\", 0x2283),\n  CHAR_REF(\"SupersetEqual;\", 0x2287),\n  CHAR_REF(\"Supset;\", 0x22d1),\n  CHAR_REF(\"THORN;\", 0xde),\n  CHAR_REF(\"THORN\", 0xde),\n  CHAR_REF(\"TRADE;\", 0x2122),\n  CHAR_REF(\"TSHcy;\", 0x040b),\n  CHAR_REF(\"TScy;\", 0x0426),\n  CHAR_REF(\"Tab;\", 0x09),\n  CHAR_REF(\"Tau;\", 0x03a4),\n  CHAR_REF(\"Tcaron;\", 0x0164),\n  CHAR_REF(\"Tcedil;\", 0x0162),\n  CHAR_REF(\"Tcy;\", 0x0422),\n  CHAR_REF(\"Tfr;\", 0x0001d517),\n  CHAR_REF(\"Therefore;\", 0x2234),\n  CHAR_REF(\"Theta;\", 0x0398),\n  MULTI_CHAR_REF(\"ThickSpace;\", 0x205f, 0x200a),\n  CHAR_REF(\"ThinSpace;\", 0x2009),\n  CHAR_REF(\"Tilde;\", 0x223c),\n  CHAR_REF(\"TildeEqual;\", 0x2243),\n  CHAR_REF(\"TildeFullEqual;\", 0x2245),\n  CHAR_REF(\"TildeTilde;\", 0x2248),\n  CHAR_REF(\"Topf;\", 0x0001d54b),\n  CHAR_REF(\"TripleDot;\", 0x20db),\n  CHAR_REF(\"Tscr;\", 0x0001d4af),\n  CHAR_REF(\"Tstrok;\", 0x0166),\n  CHAR_REF(\"Uacute;\", 0xda),\n  CHAR_REF(\"Uacute\", 0xda),\n  CHAR_REF(\"Uarr;\", 0x219f),\n  CHAR_REF(\"Uarrocir;\", 0x2949),\n  CHAR_REF(\"Ubrcy;\", 0x040e),\n  CHAR_REF(\"Ubreve;\", 0x016c),\n  CHAR_REF(\"Ucirc;\", 0xdb),\n  CHAR_REF(\"Ucirc\", 0xdb),\n  CHAR_REF(\"Ucy;\", 0x0423),\n  CHAR_REF(\"Udblac;\", 0x0170),\n  CHAR_REF(\"Ufr;\", 0x0001d518),\n  CHAR_REF(\"Ugrave;\", 0xd9),\n  CHAR_REF(\"Ugrave\", 0xd9),\n  CHAR_REF(\"Umacr;\", 0x016a),\n  CHAR_REF(\"UnderBar;\", 0x5f),\n  CHAR_REF(\"UnderBrace;\", 0x23df),\n  CHAR_REF(\"UnderBracket;\", 0x23b5),\n  CHAR_REF(\"UnderParenthesis;\", 0x23dd),\n  CHAR_REF(\"Union;\", 0x22c3),\n  CHAR_REF(\"UnionPlus;\", 0x228e),\n  CHAR_REF(\"Uogon;\", 0x0172),\n  CHAR_REF(\"Uopf;\", 0x0001d54c),\n  CHAR_REF(\"UpArrow;\", 0x2191),\n  CHAR_REF(\"UpArrowBar;\", 0x2912),\n  CHAR_REF(\"UpArrowDownArrow;\", 0x21c5),\n  CHAR_REF(\"UpDownArrow;\", 0x2195),\n  CHAR_REF(\"UpEquilibrium;\", 0x296e),\n  CHAR_REF(\"UpTee;\", 0x22a5),\n  CHAR_REF(\"UpTeeArrow;\", 0x21a5),\n  CHAR_REF(\"Uparrow;\", 0x21d1),\n  CHAR_REF(\"Updownarrow;\", 0x21d5),\n  CHAR_REF(\"UpperLeftArrow;\", 0x2196),\n  CHAR_REF(\"UpperRightArrow;\", 0x2197),\n  CHAR_REF(\"Upsi;\", 0x03d2),\n  CHAR_REF(\"Upsilon;\", 0x03a5),\n  CHAR_REF(\"Uring;\", 0x016e),\n  CHAR_REF(\"Uscr;\", 0x0001d4b0),\n  CHAR_REF(\"Utilde;\", 0x0168),\n  CHAR_REF(\"Uuml;\", 0xdc),\n  CHAR_REF(\"Uuml\", 0xdc),\n  CHAR_REF(\"VDash;\", 0x22ab),\n  CHAR_REF(\"Vbar;\", 0x2aeb),\n  CHAR_REF(\"Vcy;\", 0x0412),\n  CHAR_REF(\"Vdash;\", 0x22a9),\n  CHAR_REF(\"Vdashl;\", 0x2ae6),\n  CHAR_REF(\"Vee;\", 0x22c1),\n  CHAR_REF(\"Verbar;\", 0x2016),\n  CHAR_REF(\"Vert;\", 0x2016),\n  CHAR_REF(\"VerticalBar;\", 0x2223),\n  CHAR_REF(\"VerticalLine;\", 0x7c),\n  CHAR_REF(\"VerticalSeparator;\", 0x2758),\n  CHAR_REF(\"VerticalTilde;\", 0x2240),\n  CHAR_REF(\"VeryThinSpace;\", 0x200a),\n  CHAR_REF(\"Vfr;\", 0x0001d519),\n  CHAR_REF(\"Vopf;\", 0x0001d54d),\n  CHAR_REF(\"Vscr;\", 0x0001d4b1),\n  CHAR_REF(\"Vvdash;\", 0x22aa),\n  CHAR_REF(\"Wcirc;\", 0x0174),\n  CHAR_REF(\"Wedge;\", 0x22c0),\n  CHAR_REF(\"Wfr;\", 0x0001d51a),\n  CHAR_REF(\"Wopf;\", 0x0001d54e),\n  CHAR_REF(\"Wscr;\", 0x0001d4b2),\n  CHAR_REF(\"Xfr;\", 0x0001d51b),\n  CHAR_REF(\"Xi;\", 0x039e),\n  CHAR_REF(\"Xopf;\", 0x0001d54f),\n  CHAR_REF(\"Xscr;\", 0x0001d4b3),\n  CHAR_REF(\"YAcy;\", 0x042f),\n  CHAR_REF(\"YIcy;\", 0x0407),\n  CHAR_REF(\"YUcy;\", 0x042e),\n  CHAR_REF(\"Yacute\", 0xdd),\n  CHAR_REF(\"Yacute;\", 0xdd),\n  CHAR_REF(\"Ycirc;\", 0x0176),\n  CHAR_REF(\"Ycy;\", 0x042b),\n  CHAR_REF(\"Yfr;\", 0x0001d51c),\n  CHAR_REF(\"Yopf;\", 0x0001d550),\n  CHAR_REF(\"Yscr;\", 0x0001d4b4),\n  CHAR_REF(\"Yuml;\", 0x0178),\n  CHAR_REF(\"ZHcy;\", 0x0416),\n  CHAR_REF(\"Zacute;\", 0x0179),\n  CHAR_REF(\"Zcaron;\", 0x017d),\n  CHAR_REF(\"Zcy;\", 0x0417),\n  CHAR_REF(\"Zdot;\", 0x017b),\n  CHAR_REF(\"ZeroWidthSpace;\", 0x200b),\n  CHAR_REF(\"Zeta;\", 0x0396),\n  CHAR_REF(\"Zfr;\", 0x2128),\n  CHAR_REF(\"Zopf;\", 0x2124),\n  CHAR_REF(\"Zscr;\", 0x0001d4b5),\n  CHAR_REF(\"aacute;\", 0xe1),\n  CHAR_REF(\"aacute\", 0xe1),\n  CHAR_REF(\"abreve;\", 0x0103),\n  CHAR_REF(\"ac;\", 0x223e),\n  MULTI_CHAR_REF(\"acE;\", 0x223e, 0x0333),\n  CHAR_REF(\"acd;\", 0x223f),\n  CHAR_REF(\"acirc;\", 0xe2),\n  CHAR_REF(\"acirc\", 0xe2),\n  CHAR_REF(\"acute;\", 0xb4),\n  CHAR_REF(\"acute\", 0xb4),\n  CHAR_REF(\"acy;\", 0x0430),\n  CHAR_REF(\"aelig;\", 0xe6),\n  CHAR_REF(\"aelig\", 0xe6),\n  CHAR_REF(\"af;\", 0x2061),\n  CHAR_REF(\"afr;\", 0x0001d51e),\n  CHAR_REF(\"agrave;\", 0xe0),\n  CHAR_REF(\"agrave\", 0xe0),\n  CHAR_REF(\"alefsym;\", 0x2135),\n  CHAR_REF(\"aleph;\", 0x2135),\n  CHAR_REF(\"alpha;\", 0x03b1),\n  CHAR_REF(\"amacr;\", 0x0101),\n  CHAR_REF(\"amalg;\", 0x2a3f),\n  CHAR_REF(\"amp;\", 0x26),\n  CHAR_REF(\"amp\", 0x26),\n  CHAR_REF(\"and;\", 0x2227),\n  CHAR_REF(\"andand;\", 0x2a55),\n  CHAR_REF(\"andd;\", 0x2a5c),\n  CHAR_REF(\"andslope;\", 0x2a58),\n  CHAR_REF(\"andv;\", 0x2a5a),\n  CHAR_REF(\"ang;\", 0x2220),\n  CHAR_REF(\"ange;\", 0x29a4),\n  CHAR_REF(\"angle;\", 0x2220),\n  CHAR_REF(\"angmsd;\", 0x2221),\n  CHAR_REF(\"angmsdaa;\", 0x29a8),\n  CHAR_REF(\"angmsdab;\", 0x29a9),\n  CHAR_REF(\"angmsdac;\", 0x29aa),\n  CHAR_REF(\"angmsdad;\", 0x29ab),\n  CHAR_REF(\"angmsdae;\", 0x29ac),\n  CHAR_REF(\"angmsdaf;\", 0x29ad),\n  CHAR_REF(\"angmsdag;\", 0x29ae),\n  CHAR_REF(\"angmsdah;\", 0x29af),\n  CHAR_REF(\"angrt;\", 0x221f),\n  CHAR_REF(\"angrtvb;\", 0x22be),\n  CHAR_REF(\"angrtvbd;\", 0x299d),\n  CHAR_REF(\"angsph;\", 0x2222),\n  CHAR_REF(\"angst;\", 0xc5),\n  CHAR_REF(\"angzarr;\", 0x237c),\n  CHAR_REF(\"aogon;\", 0x0105),\n  CHAR_REF(\"aopf;\", 0x0001d552),\n  CHAR_REF(\"ap;\", 0x2248),\n  CHAR_REF(\"apE;\", 0x2a70),\n  CHAR_REF(\"apacir;\", 0x2a6f),\n  CHAR_REF(\"ape;\", 0x224a),\n  CHAR_REF(\"apid;\", 0x224b),\n  CHAR_REF(\"apos;\", 0x27),\n  CHAR_REF(\"approx;\", 0x2248),\n  CHAR_REF(\"approxeq;\", 0x224a),\n  CHAR_REF(\"aring;\", 0xe5),\n  CHAR_REF(\"aring\", 0xe5),\n  CHAR_REF(\"ascr;\", 0x0001d4b6),\n  CHAR_REF(\"ast;\", 0x2a),\n  CHAR_REF(\"asymp;\", 0x2248),\n  CHAR_REF(\"asympeq;\", 0x224d),\n  CHAR_REF(\"atilde;\", 0xe3),\n  CHAR_REF(\"atilde\", 0xe3),\n  CHAR_REF(\"auml;\", 0xe4),\n  CHAR_REF(\"auml\", 0xe4),\n  CHAR_REF(\"awconint;\", 0x2233),\n  CHAR_REF(\"awint;\", 0x2a11),\n  CHAR_REF(\"bNot;\", 0x2aed),\n  CHAR_REF(\"backcong;\", 0x224c),\n  CHAR_REF(\"backepsilon;\", 0x03f6),\n  CHAR_REF(\"backprime;\", 0x2035),\n  CHAR_REF(\"backsim;\", 0x223d),\n  CHAR_REF(\"backsimeq;\", 0x22cd),\n  CHAR_REF(\"barvee;\", 0x22bd),\n  CHAR_REF(\"barwed;\", 0x2305),\n  CHAR_REF(\"barwedge;\", 0x2305),\n  CHAR_REF(\"bbrk;\", 0x23b5),\n  CHAR_REF(\"bbrktbrk;\", 0x23b6),\n  CHAR_REF(\"bcong;\", 0x224c),\n  CHAR_REF(\"bcy;\", 0x0431),\n  CHAR_REF(\"bdquo;\", 0x201e),\n  CHAR_REF(\"becaus;\", 0x2235),\n  CHAR_REF(\"because;\", 0x2235),\n  CHAR_REF(\"bemptyv;\", 0x29b0),\n  CHAR_REF(\"bepsi;\", 0x03f6),\n  CHAR_REF(\"bernou;\", 0x212c),\n  CHAR_REF(\"beta;\", 0x03b2),\n  CHAR_REF(\"beth;\", 0x2136),\n  CHAR_REF(\"between;\", 0x226c),\n  CHAR_REF(\"bfr;\", 0x0001d51f),\n  CHAR_REF(\"bigcap;\", 0x22c2),\n  CHAR_REF(\"bigcirc;\", 0x25ef),\n  CHAR_REF(\"bigcup;\", 0x22c3),\n  CHAR_REF(\"bigodot;\", 0x2a00),\n  CHAR_REF(\"bigoplus;\", 0x2a01),\n  CHAR_REF(\"bigotimes;\", 0x2a02),\n  CHAR_REF(\"bigsqcup;\", 0x2a06),\n  CHAR_REF(\"bigstar;\", 0x2605),\n  CHAR_REF(\"bigtriangledown;\", 0x25bd),\n  CHAR_REF(\"bigtriangleup;\", 0x25b3),\n  CHAR_REF(\"biguplus;\", 0x2a04),\n  CHAR_REF(\"bigvee;\", 0x22c1),\n  CHAR_REF(\"bigwedge;\", 0x22c0),\n  CHAR_REF(\"bkarow;\", 0x290d),\n  CHAR_REF(\"blacklozenge;\", 0x29eb),\n  CHAR_REF(\"blacksquare;\", 0x25aa),\n  CHAR_REF(\"blacktriangle;\", 0x25b4),\n  CHAR_REF(\"blacktriangledown;\", 0x25be),\n  CHAR_REF(\"blacktriangleleft;\", 0x25c2),\n  CHAR_REF(\"blacktriangleright;\", 0x25b8),\n  CHAR_REF(\"blank;\", 0x2423),\n  CHAR_REF(\"blk12;\", 0x2592),\n  CHAR_REF(\"blk14;\", 0x2591),\n  CHAR_REF(\"blk34;\", 0x2593),\n  CHAR_REF(\"block;\", 0x2588),\n  MULTI_CHAR_REF(\"bne;\", 0x3d, 0x20e5),\n  MULTI_CHAR_REF(\"bnequiv;\", 0x2261, 0x20e5),\n  CHAR_REF(\"bnot;\", 0x2310),\n  CHAR_REF(\"bopf;\", 0x0001d553),\n  CHAR_REF(\"bot;\", 0x22a5),\n  CHAR_REF(\"bottom;\", 0x22a5),\n  CHAR_REF(\"bowtie;\", 0x22c8),\n  CHAR_REF(\"boxDL;\", 0x2557),\n  CHAR_REF(\"boxDR;\", 0x2554),\n  CHAR_REF(\"boxDl;\", 0x2556),\n  CHAR_REF(\"boxDr;\", 0x2553),\n  CHAR_REF(\"boxH;\", 0x2550),\n  CHAR_REF(\"boxHD;\", 0x2566),\n  CHAR_REF(\"boxHU;\", 0x2569),\n  CHAR_REF(\"boxHd;\", 0x2564),\n  CHAR_REF(\"boxHu;\", 0x2567),\n  CHAR_REF(\"boxUL;\", 0x255d),\n  CHAR_REF(\"boxUR;\", 0x255a),\n  CHAR_REF(\"boxUl;\", 0x255c),\n  CHAR_REF(\"boxUr;\", 0x2559),\n  CHAR_REF(\"boxV;\", 0x2551),\n  CHAR_REF(\"boxVH;\", 0x256c),\n  CHAR_REF(\"boxVL;\", 0x2563),\n  CHAR_REF(\"boxVR;\", 0x2560),\n  CHAR_REF(\"boxVh;\", 0x256b),\n  CHAR_REF(\"boxVl;\", 0x2562),\n  CHAR_REF(\"boxVr;\", 0x255f),\n  CHAR_REF(\"boxbox;\", 0x29c9),\n  CHAR_REF(\"boxdL;\", 0x2555),\n  CHAR_REF(\"boxdR;\", 0x2552),\n  CHAR_REF(\"boxdl;\", 0x2510),\n  CHAR_REF(\"boxdr;\", 0x250c),\n  CHAR_REF(\"boxh;\", 0x2500),\n  CHAR_REF(\"boxhD;\", 0x2565),\n  CHAR_REF(\"boxhU;\", 0x2568),\n  CHAR_REF(\"boxhd;\", 0x252c),\n  CHAR_REF(\"boxhu;\", 0x2534),\n  CHAR_REF(\"boxminus;\", 0x229f),\n  CHAR_REF(\"boxplus;\", 0x229e),\n  CHAR_REF(\"boxtimes;\", 0x22a0),\n  CHAR_REF(\"boxuL;\", 0x255b),\n  CHAR_REF(\"boxuR;\", 0x2558),\n  CHAR_REF(\"boxul;\", 0x2518),\n  CHAR_REF(\"boxur;\", 0x2514),\n  CHAR_REF(\"boxv;\", 0x2502),\n  CHAR_REF(\"boxvH;\", 0x256a),\n  CHAR_REF(\"boxvL;\", 0x2561),\n  CHAR_REF(\"boxvR;\", 0x255e),\n  CHAR_REF(\"boxvh;\", 0x253c),\n  CHAR_REF(\"boxvl;\", 0x2524),\n  CHAR_REF(\"boxvr;\", 0x251c),\n  CHAR_REF(\"bprime;\", 0x2035),\n  CHAR_REF(\"breve;\", 0x02d8),\n  CHAR_REF(\"brvbar;\", 0xa6),\n  CHAR_REF(\"brvbar\", 0xa6),\n  CHAR_REF(\"bscr;\", 0x0001d4b7),\n  CHAR_REF(\"bsemi;\", 0x204f),\n  CHAR_REF(\"bsim;\", 0x223d),\n  CHAR_REF(\"bsime;\", 0x22cd),\n  CHAR_REF(\"bsol;\", 0x5c),\n  CHAR_REF(\"bsolb;\", 0x29c5),\n  CHAR_REF(\"bsolhsub;\", 0x27c8),\n  CHAR_REF(\"bull;\", 0x2022),\n  CHAR_REF(\"bullet;\", 0x2022),\n  CHAR_REF(\"bump;\", 0x224e),\n  CHAR_REF(\"bumpE;\", 0x2aae),\n  CHAR_REF(\"bumpe;\", 0x224f),\n  CHAR_REF(\"bumpeq;\", 0x224f),\n  CHAR_REF(\"cacute;\", 0x0107),\n  CHAR_REF(\"cap;\", 0x2229),\n  CHAR_REF(\"capand;\", 0x2a44),\n  CHAR_REF(\"capbrcup;\", 0x2a49),\n  CHAR_REF(\"capcap;\", 0x2a4b),\n  CHAR_REF(\"capcup;\", 0x2a47),\n  CHAR_REF(\"capdot;\", 0x2a40),\n  MULTI_CHAR_REF(\"caps;\", 0x2229, 0xfe00),\n  CHAR_REF(\"caret;\", 0x2041),\n  CHAR_REF(\"caron;\", 0x02c7),\n  CHAR_REF(\"ccaps;\", 0x2a4d),\n  CHAR_REF(\"ccaron;\", 0x010d),\n  CHAR_REF(\"ccedil;\", 0xe7),\n  CHAR_REF(\"ccedil\", 0xe7),\n  CHAR_REF(\"ccirc;\", 0x0109),\n  CHAR_REF(\"ccups;\", 0x2a4c),\n  CHAR_REF(\"ccupssm;\", 0x2a50),\n  CHAR_REF(\"cdot;\", 0x010b),\n  CHAR_REF(\"cedil;\", 0xb8),\n  CHAR_REF(\"cedil\", 0xb8),\n  CHAR_REF(\"cemptyv;\", 0x29b2),\n  CHAR_REF(\"cent;\", 0xa2),\n  CHAR_REF(\"cent\", 0xa2),\n  CHAR_REF(\"centerdot;\", 0xb7),\n  CHAR_REF(\"cfr;\", 0x0001d520),\n  CHAR_REF(\"chcy;\", 0x0447),\n  CHAR_REF(\"check;\", 0x2713),\n  CHAR_REF(\"checkmark;\", 0x2713),\n  CHAR_REF(\"chi;\", 0x03c7),\n  CHAR_REF(\"cir;\", 0x25cb),\n  CHAR_REF(\"cirE;\", 0x29c3),\n  CHAR_REF(\"circ;\", 0x02c6),\n  CHAR_REF(\"circeq;\", 0x2257),\n  CHAR_REF(\"circlearrowleft;\", 0x21ba),\n  CHAR_REF(\"circlearrowright;\", 0x21bb),\n  CHAR_REF(\"circledR;\", 0xae),\n  CHAR_REF(\"circledS;\", 0x24c8),\n  CHAR_REF(\"circledast;\", 0x229b),\n  CHAR_REF(\"circledcirc;\", 0x229a),\n  CHAR_REF(\"circleddash;\", 0x229d),\n  CHAR_REF(\"cire;\", 0x2257),\n  CHAR_REF(\"cirfnint;\", 0x2a10),\n  CHAR_REF(\"cirmid;\", 0x2aef),\n  CHAR_REF(\"cirscir;\", 0x29c2),\n  CHAR_REF(\"clubs;\", 0x2663),\n  CHAR_REF(\"clubsuit;\", 0x2663),\n  CHAR_REF(\"colon;\", 0x3a),\n  CHAR_REF(\"colone;\", 0x2254),\n  CHAR_REF(\"coloneq;\", 0x2254),\n  CHAR_REF(\"comma;\", 0x2c),\n  CHAR_REF(\"commat;\", 0x40),\n  CHAR_REF(\"comp;\", 0x2201),\n  CHAR_REF(\"compfn;\", 0x2218),\n  CHAR_REF(\"complement;\", 0x2201),\n  CHAR_REF(\"complexes;\", 0x2102),\n  CHAR_REF(\"cong;\", 0x2245),\n  CHAR_REF(\"congdot;\", 0x2a6d),\n  CHAR_REF(\"conint;\", 0x222e),\n  CHAR_REF(\"copf;\", 0x0001d554),\n  CHAR_REF(\"coprod;\", 0x2210),\n  CHAR_REF(\"copy;\", 0xa9),\n  CHAR_REF(\"copy\", 0xa9),\n  CHAR_REF(\"copysr;\", 0x2117),\n  CHAR_REF(\"crarr;\", 0x21b5),\n  CHAR_REF(\"cross;\", 0x2717),\n  CHAR_REF(\"cscr;\", 0x0001d4b8),\n  CHAR_REF(\"csub;\", 0x2acf),\n  CHAR_REF(\"csube;\", 0x2ad1),\n  CHAR_REF(\"csup;\", 0x2ad0),\n  CHAR_REF(\"csupe;\", 0x2ad2),\n  CHAR_REF(\"ctdot;\", 0x22ef),\n  CHAR_REF(\"cudarrl;\", 0x2938),\n  CHAR_REF(\"cudarrr;\", 0x2935),\n  CHAR_REF(\"cuepr;\", 0x22de),\n  CHAR_REF(\"cuesc;\", 0x22df),\n  CHAR_REF(\"cularr;\", 0x21b6),\n  CHAR_REF(\"cularrp;\", 0x293d),\n  CHAR_REF(\"cup;\", 0x222a),\n  CHAR_REF(\"cupbrcap;\", 0x2a48),\n  CHAR_REF(\"cupcap;\", 0x2a46),\n  CHAR_REF(\"cupcup;\", 0x2a4a),\n  CHAR_REF(\"cupdot;\", 0x228d),\n  CHAR_REF(\"cupor;\", 0x2a45),\n  MULTI_CHAR_REF(\"cups;\", 0x222a, 0xfe00),\n  CHAR_REF(\"curarr;\", 0x21b7),\n  CHAR_REF(\"curarrm;\", 0x293c),\n  CHAR_REF(\"curlyeqprec;\", 0x22de),\n  CHAR_REF(\"curlyeqsucc;\", 0x22df),\n  CHAR_REF(\"curlyvee;\", 0x22ce),\n  CHAR_REF(\"curlywedge;\", 0x22cf),\n  CHAR_REF(\"curren;\", 0xa4),\n  CHAR_REF(\"curren\", 0xa4),\n  CHAR_REF(\"curvearrowleft;\", 0x21b6),\n  CHAR_REF(\"curvearrowright;\", 0x21b7),\n  CHAR_REF(\"cuvee;\", 0x22ce),\n  CHAR_REF(\"cuwed;\", 0x22cf),\n  CHAR_REF(\"cwconint;\", 0x2232),\n  CHAR_REF(\"cwint;\", 0x2231),\n  CHAR_REF(\"cylcty;\", 0x232d),\n  CHAR_REF(\"dArr;\", 0x21d3),\n  CHAR_REF(\"dHar;\", 0x2965),\n  CHAR_REF(\"dagger;\", 0x2020),\n  CHAR_REF(\"daleth;\", 0x2138),\n  CHAR_REF(\"darr;\", 0x2193),\n  CHAR_REF(\"dash;\", 0x2010),\n  CHAR_REF(\"dashv;\", 0x22a3),\n  CHAR_REF(\"dbkarow;\", 0x290f),\n  CHAR_REF(\"dblac;\", 0x02dd),\n  CHAR_REF(\"dcaron;\", 0x010f),\n  CHAR_REF(\"dcy;\", 0x0434),\n  CHAR_REF(\"dd;\", 0x2146),\n  CHAR_REF(\"ddagger;\", 0x2021),\n  CHAR_REF(\"ddarr;\", 0x21ca),\n  CHAR_REF(\"ddotseq;\", 0x2a77),\n  CHAR_REF(\"deg;\", 0xb0),\n  CHAR_REF(\"deg\", 0xb0),\n  CHAR_REF(\"delta;\", 0x03b4),\n  CHAR_REF(\"demptyv;\", 0x29b1),\n  CHAR_REF(\"dfisht;\", 0x297f),\n  CHAR_REF(\"dfr;\", 0x0001d521),\n  CHAR_REF(\"dharl;\", 0x21c3),\n  CHAR_REF(\"dharr;\", 0x21c2),\n  CHAR_REF(\"diam;\", 0x22c4),\n  CHAR_REF(\"diamond;\", 0x22c4),\n  CHAR_REF(\"diamondsuit;\", 0x2666),\n  CHAR_REF(\"diams;\", 0x2666),\n  CHAR_REF(\"die;\", 0xa8),\n  CHAR_REF(\"digamma;\", 0x03dd),\n  CHAR_REF(\"disin;\", 0x22f2),\n  CHAR_REF(\"div;\", 0xf7),\n  CHAR_REF(\"divide;\", 0xf7),\n  CHAR_REF(\"divide\", 0xf7),\n  CHAR_REF(\"divideontimes;\", 0x22c7),\n  CHAR_REF(\"divonx;\", 0x22c7),\n  CHAR_REF(\"djcy;\", 0x0452),\n  CHAR_REF(\"dlcorn;\", 0x231e),\n  CHAR_REF(\"dlcrop;\", 0x230d),\n  CHAR_REF(\"dollar;\", 0x24),\n  CHAR_REF(\"dopf;\", 0x0001d555),\n  CHAR_REF(\"dot;\", 0x02d9),\n  CHAR_REF(\"doteq;\", 0x2250),\n  CHAR_REF(\"doteqdot;\", 0x2251),\n  CHAR_REF(\"dotminus;\", 0x2238),\n  CHAR_REF(\"dotplus;\", 0x2214),\n  CHAR_REF(\"dotsquare;\", 0x22a1),\n  CHAR_REF(\"doublebarwedge;\", 0x2306),\n  CHAR_REF(\"downarrow;\", 0x2193),\n  CHAR_REF(\"downdownarrows;\", 0x21ca),\n  CHAR_REF(\"downharpoonleft;\", 0x21c3),\n  CHAR_REF(\"downharpoonright;\", 0x21c2),\n  CHAR_REF(\"drbkarow;\", 0x2910),\n  CHAR_REF(\"drcorn;\", 0x231f),\n  CHAR_REF(\"drcrop;\", 0x230c),\n  CHAR_REF(\"dscr;\", 0x0001d4b9),\n  CHAR_REF(\"dscy;\", 0x0455),\n  CHAR_REF(\"dsol;\", 0x29f6),\n  CHAR_REF(\"dstrok;\", 0x0111),\n  CHAR_REF(\"dtdot;\", 0x22f1),\n  CHAR_REF(\"dtri;\", 0x25bf),\n  CHAR_REF(\"dtrif;\", 0x25be),\n  CHAR_REF(\"duarr;\", 0x21f5),\n  CHAR_REF(\"duhar;\", 0x296f),\n  CHAR_REF(\"dwangle;\", 0x29a6),\n  CHAR_REF(\"dzcy;\", 0x045f),\n  CHAR_REF(\"dzigrarr;\", 0x27ff),\n  CHAR_REF(\"eDDot;\", 0x2a77),\n  CHAR_REF(\"eDot;\", 0x2251),\n  CHAR_REF(\"eacute;\", 0xe9),\n  CHAR_REF(\"eacute\", 0xe9),\n  CHAR_REF(\"easter;\", 0x2a6e),\n  CHAR_REF(\"ecaron;\", 0x011b),\n  CHAR_REF(\"ecir;\", 0x2256),\n  CHAR_REF(\"ecirc;\", 0xea),\n  CHAR_REF(\"ecirc\", 0xea),\n  CHAR_REF(\"ecolon;\", 0x2255),\n  CHAR_REF(\"ecy;\", 0x044d),\n  CHAR_REF(\"edot;\", 0x0117),\n  CHAR_REF(\"ee;\", 0x2147),\n  CHAR_REF(\"efDot;\", 0x2252),\n  CHAR_REF(\"efr;\", 0x0001d522),\n  CHAR_REF(\"eg;\", 0x2a9a),\n  CHAR_REF(\"egrave;\", 0xe8),\n  CHAR_REF(\"egrave\", 0xe8),\n  CHAR_REF(\"egs;\", 0x2a96),\n  CHAR_REF(\"egsdot;\", 0x2a98),\n  CHAR_REF(\"el;\", 0x2a99),\n  CHAR_REF(\"elinters;\", 0x23e7),\n  CHAR_REF(\"ell;\", 0x2113),\n  CHAR_REF(\"els;\", 0x2a95),\n  CHAR_REF(\"elsdot;\", 0x2a97),\n  CHAR_REF(\"emacr;\", 0x0113),\n  CHAR_REF(\"empty;\", 0x2205),\n  CHAR_REF(\"emptyset;\", 0x2205),\n  CHAR_REF(\"emptyv;\", 0x2205),\n  CHAR_REF(\"emsp13;\", 0x2004),\n  CHAR_REF(\"emsp14;\", 0x2005),\n  CHAR_REF(\"emsp;\", 0x2003),\n  CHAR_REF(\"eng;\", 0x014b),\n  CHAR_REF(\"ensp;\", 0x2002),\n  CHAR_REF(\"eogon;\", 0x0119),\n  CHAR_REF(\"eopf;\", 0x0001d556),\n  CHAR_REF(\"epar;\", 0x22d5),\n  CHAR_REF(\"eparsl;\", 0x29e3),\n  CHAR_REF(\"eplus;\", 0x2a71),\n  CHAR_REF(\"epsi;\", 0x03b5),\n  CHAR_REF(\"epsilon;\", 0x03b5),\n  CHAR_REF(\"epsiv;\", 0x03f5),\n  CHAR_REF(\"eqcirc;\", 0x2256),\n  CHAR_REF(\"eqcolon;\", 0x2255),\n  CHAR_REF(\"eqsim;\", 0x2242),\n  CHAR_REF(\"eqslantgtr;\", 0x2a96),\n  CHAR_REF(\"eqslantless;\", 0x2a95),\n  CHAR_REF(\"equals;\", 0x3d),\n  CHAR_REF(\"equest;\", 0x225f),\n  CHAR_REF(\"equiv;\", 0x2261),\n  CHAR_REF(\"equivDD;\", 0x2a78),\n  CHAR_REF(\"eqvparsl;\", 0x29e5),\n  CHAR_REF(\"erDot;\", 0x2253),\n  CHAR_REF(\"erarr;\", 0x2971),\n  CHAR_REF(\"escr;\", 0x212f),\n  CHAR_REF(\"esdot;\", 0x2250),\n  CHAR_REF(\"esim;\", 0x2242),\n  CHAR_REF(\"eta;\", 0x03b7),\n  CHAR_REF(\"eth;\", 0xf0),\n  CHAR_REF(\"eth\", 0xf0),\n  CHAR_REF(\"euml;\", 0xeb),\n  CHAR_REF(\"euml\", 0xeb),\n  CHAR_REF(\"euro;\", 0x20ac),\n  CHAR_REF(\"excl;\", 0x21),\n  CHAR_REF(\"exist;\", 0x2203),\n  CHAR_REF(\"expectation;\", 0x2130),\n  CHAR_REF(\"exponentiale;\", 0x2147),\n  CHAR_REF(\"fallingdotseq;\", 0x2252),\n  CHAR_REF(\"fcy;\", 0x0444),\n  CHAR_REF(\"female;\", 0x2640),\n  CHAR_REF(\"ffilig;\", 0xfb03),\n  CHAR_REF(\"fflig;\", 0xfb00),\n  CHAR_REF(\"ffllig;\", 0xfb04),\n  CHAR_REF(\"ffr;\", 0x0001d523),\n  CHAR_REF(\"filig;\", 0xfb01),\n  MULTI_CHAR_REF(\"fjlig;\", 0x66, 0x6a),\n  CHAR_REF(\"flat;\", 0x266d),\n  CHAR_REF(\"fllig;\", 0xfb02),\n  CHAR_REF(\"fltns;\", 0x25b1),\n  CHAR_REF(\"fnof;\", 0x0192),\n  CHAR_REF(\"fopf;\", 0x0001d557),\n  CHAR_REF(\"forall;\", 0x2200),\n  CHAR_REF(\"fork;\", 0x22d4),\n  CHAR_REF(\"forkv;\", 0x2ad9),\n  CHAR_REF(\"fpartint;\", 0x2a0d),\n  CHAR_REF(\"frac12\", 0xbd),\n  CHAR_REF(\"frac12;\", 0xbd),\n  CHAR_REF(\"frac13;\", 0x2153),\n  CHAR_REF(\"frac14\", 0xbc),\n  CHAR_REF(\"frac14;\", 0xbc),\n  CHAR_REF(\"frac15;\", 0x2155),\n  CHAR_REF(\"frac16;\", 0x2159),\n  CHAR_REF(\"frac18;\", 0x215b),\n  CHAR_REF(\"frac23;\", 0x2154),\n  CHAR_REF(\"frac25;\", 0x2156),\n  CHAR_REF(\"frac34\", 0xbe),\n  CHAR_REF(\"frac34;\", 0xbe),\n  CHAR_REF(\"frac35;\", 0x2157),\n  CHAR_REF(\"frac38;\", 0x215c),\n  CHAR_REF(\"frac45;\", 0x2158),\n  CHAR_REF(\"frac56;\", 0x215a),\n  CHAR_REF(\"frac58;\", 0x215d),\n  CHAR_REF(\"frac78;\", 0x215e),\n  CHAR_REF(\"frasl;\", 0x2044),\n  CHAR_REF(\"frown;\", 0x2322),\n  CHAR_REF(\"fscr;\", 0x0001d4bb),\n  CHAR_REF(\"gE;\", 0x2267),\n  CHAR_REF(\"gEl;\", 0x2a8c),\n  CHAR_REF(\"gacute;\", 0x01f5),\n  CHAR_REF(\"gamma;\", 0x03b3),\n  CHAR_REF(\"gammad;\", 0x03dd),\n  CHAR_REF(\"gap;\", 0x2a86),\n  CHAR_REF(\"gbreve;\", 0x011f),\n  CHAR_REF(\"gcirc;\", 0x011d),\n  CHAR_REF(\"gcy;\", 0x0433),\n  CHAR_REF(\"gdot;\", 0x0121),\n  CHAR_REF(\"ge;\", 0x2265),\n  CHAR_REF(\"gel;\", 0x22db),\n  CHAR_REF(\"geq;\", 0x2265),\n  CHAR_REF(\"geqq;\", 0x2267),\n  CHAR_REF(\"geqslant;\", 0x2a7e),\n  CHAR_REF(\"ges;\", 0x2a7e),\n  CHAR_REF(\"gescc;\", 0x2aa9),\n  CHAR_REF(\"gesdot;\", 0x2a80),\n  CHAR_REF(\"gesdoto;\", 0x2a82),\n  CHAR_REF(\"gesdotol;\", 0x2a84),\n  MULTI_CHAR_REF(\"gesl;\", 0x22db, 0xfe00),\n  CHAR_REF(\"gesles;\", 0x2a94),\n  CHAR_REF(\"gfr;\", 0x0001d524),\n  CHAR_REF(\"gg;\", 0x226b),\n  CHAR_REF(\"ggg;\", 0x22d9),\n  CHAR_REF(\"gimel;\", 0x2137),\n  CHAR_REF(\"gjcy;\", 0x0453),\n  CHAR_REF(\"gl;\", 0x2277),\n  CHAR_REF(\"glE;\", 0x2a92),\n  CHAR_REF(\"gla;\", 0x2aa5),\n  CHAR_REF(\"glj;\", 0x2aa4),\n  CHAR_REF(\"gnE;\", 0x2269),\n  CHAR_REF(\"gnap;\", 0x2a8a),\n  CHAR_REF(\"gnapprox;\", 0x2a8a),\n  CHAR_REF(\"gne;\", 0x2a88),\n  CHAR_REF(\"gneq;\", 0x2a88),\n  CHAR_REF(\"gneqq;\", 0x2269),\n  CHAR_REF(\"gnsim;\", 0x22e7),\n  CHAR_REF(\"gopf;\", 0x0001d558),\n  CHAR_REF(\"grave;\", 0x60),\n  CHAR_REF(\"gscr;\", 0x210a),\n  CHAR_REF(\"gsim;\", 0x2273),\n  CHAR_REF(\"gsime;\", 0x2a8e),\n  CHAR_REF(\"gsiml;\", 0x2a90),\n  CHAR_REF(\"gt;\", 0x3e),\n  CHAR_REF(\"gt\", 0x3e),\n  CHAR_REF(\"gtcc;\", 0x2aa7),\n  CHAR_REF(\"gtcir;\", 0x2a7a),\n  CHAR_REF(\"gtdot;\", 0x22d7),\n  CHAR_REF(\"gtlPar;\", 0x2995),\n  CHAR_REF(\"gtquest;\", 0x2a7c),\n  CHAR_REF(\"gtrapprox;\", 0x2a86),\n  CHAR_REF(\"gtrarr;\", 0x2978),\n  CHAR_REF(\"gtrdot;\", 0x22d7),\n  CHAR_REF(\"gtreqless;\", 0x22db),\n  CHAR_REF(\"gtreqqless;\", 0x2a8c),\n  CHAR_REF(\"gtrless;\", 0x2277),\n  CHAR_REF(\"gtrsim;\", 0x2273),\n  MULTI_CHAR_REF(\"gvertneqq;\", 0x2269, 0xfe00),\n  MULTI_CHAR_REF(\"gvnE;\", 0x2269, 0xfe00),\n  CHAR_REF(\"hArr;\", 0x21d4),\n  CHAR_REF(\"hairsp;\", 0x200a),\n  CHAR_REF(\"half;\", 0xbd),\n  CHAR_REF(\"hamilt;\", 0x210b),\n  CHAR_REF(\"hardcy;\", 0x044a),\n  CHAR_REF(\"harr;\", 0x2194),\n  CHAR_REF(\"harrcir;\", 0x2948),\n  CHAR_REF(\"harrw;\", 0x21ad),\n  CHAR_REF(\"hbar;\", 0x210f),\n  CHAR_REF(\"hcirc;\", 0x0125),\n  CHAR_REF(\"hearts;\", 0x2665),\n  CHAR_REF(\"heartsuit;\", 0x2665),\n  CHAR_REF(\"hellip;\", 0x2026),\n  CHAR_REF(\"hercon;\", 0x22b9),\n  CHAR_REF(\"hfr;\", 0x0001d525),\n  CHAR_REF(\"hksearow;\", 0x2925),\n  CHAR_REF(\"hkswarow;\", 0x2926),\n  CHAR_REF(\"hoarr;\", 0x21ff),\n  CHAR_REF(\"homtht;\", 0x223b),\n  CHAR_REF(\"hookleftarrow;\", 0x21a9),\n  CHAR_REF(\"hookrightarrow;\", 0x21aa),\n  CHAR_REF(\"hopf;\", 0x0001d559),\n  CHAR_REF(\"horbar;\", 0x2015),\n  CHAR_REF(\"hscr;\", 0x0001d4bd),\n  CHAR_REF(\"hslash;\", 0x210f),\n  CHAR_REF(\"hstrok;\", 0x0127),\n  CHAR_REF(\"hybull;\", 0x2043),\n  CHAR_REF(\"hyphen;\", 0x2010),\n  CHAR_REF(\"iacute;\", 0xed),\n  CHAR_REF(\"iacute\", 0xed),\n  CHAR_REF(\"ic;\", 0x2063),\n  CHAR_REF(\"icirc;\", 0xee),\n  CHAR_REF(\"icirc\", 0xee),\n  CHAR_REF(\"icy;\", 0x0438),\n  CHAR_REF(\"iecy;\", 0x0435),\n  CHAR_REF(\"iexcl;\", 0xa1),\n  CHAR_REF(\"iexcl\", 0xa1),\n  CHAR_REF(\"iff;\", 0x21d4),\n  CHAR_REF(\"ifr;\", 0x0001d526),\n  CHAR_REF(\"igrave;\", 0xec),\n  CHAR_REF(\"igrave\", 0xec),\n  CHAR_REF(\"ii;\", 0x2148),\n  CHAR_REF(\"iiiint;\", 0x2a0c),\n  CHAR_REF(\"iiint;\", 0x222d),\n  CHAR_REF(\"iinfin;\", 0x29dc),\n  CHAR_REF(\"iiota;\", 0x2129),\n  CHAR_REF(\"ijlig;\", 0x0133),\n  CHAR_REF(\"imacr;\", 0x012b),\n  CHAR_REF(\"image;\", 0x2111),\n  CHAR_REF(\"imagline;\", 0x2110),\n  CHAR_REF(\"imagpart;\", 0x2111),\n  CHAR_REF(\"imath;\", 0x0131),\n  CHAR_REF(\"imof;\", 0x22b7),\n  CHAR_REF(\"imped;\", 0x01b5),\n  CHAR_REF(\"in;\", 0x2208),\n  CHAR_REF(\"incare;\", 0x2105),\n  CHAR_REF(\"infin;\", 0x221e),\n  CHAR_REF(\"infintie;\", 0x29dd),\n  CHAR_REF(\"inodot;\", 0x0131),\n  CHAR_REF(\"int;\", 0x222b),\n  CHAR_REF(\"intcal;\", 0x22ba),\n  CHAR_REF(\"integers;\", 0x2124),\n  CHAR_REF(\"intercal;\", 0x22ba),\n  CHAR_REF(\"intlarhk;\", 0x2a17),\n  CHAR_REF(\"intprod;\", 0x2a3c),\n  CHAR_REF(\"iocy;\", 0x0451),\n  CHAR_REF(\"iogon;\", 0x012f),\n  CHAR_REF(\"iopf;\", 0x0001d55a),\n  CHAR_REF(\"iota;\", 0x03b9),\n  CHAR_REF(\"iprod;\", 0x2a3c),\n  CHAR_REF(\"iquest;\", 0xbf),\n  CHAR_REF(\"iquest\", 0xbf),\n  CHAR_REF(\"iscr;\", 0x0001d4be),\n  CHAR_REF(\"isin;\", 0x2208),\n  CHAR_REF(\"isinE;\", 0x22f9),\n  CHAR_REF(\"isindot;\", 0x22f5),\n  CHAR_REF(\"isins;\", 0x22f4),\n  CHAR_REF(\"isinsv;\", 0x22f3),\n  CHAR_REF(\"isinv;\", 0x2208),\n  CHAR_REF(\"it;\", 0x2062),\n  CHAR_REF(\"itilde;\", 0x0129),\n  CHAR_REF(\"iukcy;\", 0x0456),\n  CHAR_REF(\"iuml;\", 0xef),\n  CHAR_REF(\"iuml\", 0xef),\n  CHAR_REF(\"jcirc;\", 0x0135),\n  CHAR_REF(\"jcy;\", 0x0439),\n  CHAR_REF(\"jfr;\", 0x0001d527),\n  CHAR_REF(\"jmath;\", 0x0237),\n  CHAR_REF(\"jopf;\", 0x0001d55b),\n  CHAR_REF(\"jscr;\", 0x0001d4bf),\n  CHAR_REF(\"jsercy;\", 0x0458),\n  CHAR_REF(\"jukcy;\", 0x0454),\n  CHAR_REF(\"kappa;\", 0x03ba),\n  CHAR_REF(\"kappav;\", 0x03f0),\n  CHAR_REF(\"kcedil;\", 0x0137),\n  CHAR_REF(\"kcy;\", 0x043a),\n  CHAR_REF(\"kfr;\", 0x0001d528),\n  CHAR_REF(\"kgreen;\", 0x0138),\n  CHAR_REF(\"khcy;\", 0x0445),\n  CHAR_REF(\"kjcy;\", 0x045c),\n  CHAR_REF(\"kopf;\", 0x0001d55c),\n  CHAR_REF(\"kscr;\", 0x0001d4c0),\n  CHAR_REF(\"lAarr;\", 0x21da),\n  CHAR_REF(\"lArr;\", 0x21d0),\n  CHAR_REF(\"lAtail;\", 0x291b),\n  CHAR_REF(\"lBarr;\", 0x290e),\n  CHAR_REF(\"lE;\", 0x2266),\n  CHAR_REF(\"lEg;\", 0x2a8b),\n  CHAR_REF(\"lHar;\", 0x2962),\n  CHAR_REF(\"lacute;\", 0x013a),\n  CHAR_REF(\"laemptyv;\", 0x29b4),\n  CHAR_REF(\"lagran;\", 0x2112),\n  CHAR_REF(\"lambda;\", 0x03bb),\n  CHAR_REF(\"lang;\", 0x27e8),\n  CHAR_REF(\"langd;\", 0x2991),\n  CHAR_REF(\"langle;\", 0x27e8),\n  CHAR_REF(\"lap;\", 0x2a85),\n  CHAR_REF(\"laquo;\", 0xab),\n  CHAR_REF(\"laquo\", 0xab),\n  CHAR_REF(\"larr;\", 0x2190),\n  CHAR_REF(\"larrb;\", 0x21e4),\n  CHAR_REF(\"larrbfs;\", 0x291f),\n  CHAR_REF(\"larrfs;\", 0x291d),\n  CHAR_REF(\"larrhk;\", 0x21a9),\n  CHAR_REF(\"larrlp;\", 0x21ab),\n  CHAR_REF(\"larrpl;\", 0x2939),\n  CHAR_REF(\"larrsim;\", 0x2973),\n  CHAR_REF(\"larrtl;\", 0x21a2),\n  CHAR_REF(\"lat;\", 0x2aab),\n  CHAR_REF(\"latail;\", 0x2919),\n  CHAR_REF(\"late;\", 0x2aad),\n  MULTI_CHAR_REF(\"lates;\", 0x2aad, 0xfe00),\n  CHAR_REF(\"lbarr;\", 0x290c),\n  CHAR_REF(\"lbbrk;\", 0x2772),\n  CHAR_REF(\"lbrace;\", 0x7b),\n  CHAR_REF(\"lbrack;\", 0x5b),\n  CHAR_REF(\"lbrke;\", 0x298b),\n  CHAR_REF(\"lbrksld;\", 0x298f),\n  CHAR_REF(\"lbrkslu;\", 0x298d),\n  CHAR_REF(\"lcaron;\", 0x013e),\n  CHAR_REF(\"lcedil;\", 0x013c),\n  CHAR_REF(\"lceil;\", 0x2308),\n  CHAR_REF(\"lcub;\", 0x7b),\n  CHAR_REF(\"lcy;\", 0x043b),\n  CHAR_REF(\"ldca;\", 0x2936),\n  CHAR_REF(\"ldquo;\", 0x201c),\n  CHAR_REF(\"ldquor;\", 0x201e),\n  CHAR_REF(\"ldrdhar;\", 0x2967),\n  CHAR_REF(\"ldrushar;\", 0x294b),\n  CHAR_REF(\"ldsh;\", 0x21b2),\n  CHAR_REF(\"le;\", 0x2264),\n  CHAR_REF(\"leftarrow;\", 0x2190),\n  CHAR_REF(\"leftarrowtail;\", 0x21a2),\n  CHAR_REF(\"leftharpoondown;\", 0x21bd),\n  CHAR_REF(\"leftharpoonup;\", 0x21bc),\n  CHAR_REF(\"leftleftarrows;\", 0x21c7),\n  CHAR_REF(\"leftrightarrow;\", 0x2194),\n  CHAR_REF(\"leftrightarrows;\", 0x21c6),\n  CHAR_REF(\"leftrightharpoons;\", 0x21cb),\n  CHAR_REF(\"leftrightsquigarrow;\", 0x21ad),\n  CHAR_REF(\"leftthreetimes;\", 0x22cb),\n  CHAR_REF(\"leg;\", 0x22da),\n  CHAR_REF(\"leq;\", 0x2264),\n  CHAR_REF(\"leqq;\", 0x2266),\n  CHAR_REF(\"leqslant;\", 0x2a7d),\n  CHAR_REF(\"les;\", 0x2a7d),\n  CHAR_REF(\"lescc;\", 0x2aa8),\n  CHAR_REF(\"lesdot;\", 0x2a7f),\n  CHAR_REF(\"lesdoto;\", 0x2a81),\n  CHAR_REF(\"lesdotor;\", 0x2a83),\n  MULTI_CHAR_REF(\"lesg;\", 0x22da, 0xfe00),\n  CHAR_REF(\"lesges;\", 0x2a93),\n  CHAR_REF(\"lessapprox;\", 0x2a85),\n  CHAR_REF(\"lessdot;\", 0x22d6),\n  CHAR_REF(\"lesseqgtr;\", 0x22da),\n  CHAR_REF(\"lesseqqgtr;\", 0x2a8b),\n  CHAR_REF(\"lessgtr;\", 0x2276),\n  CHAR_REF(\"lesssim;\", 0x2272),\n  CHAR_REF(\"lfisht;\", 0x297c),\n  CHAR_REF(\"lfloor;\", 0x230a),\n  CHAR_REF(\"lfr;\", 0x0001d529),\n  CHAR_REF(\"lg;\", 0x2276),\n  CHAR_REF(\"lgE;\", 0x2a91),\n  CHAR_REF(\"lhard;\", 0x21bd),\n  CHAR_REF(\"lharu;\", 0x21bc),\n  CHAR_REF(\"lharul;\", 0x296a),\n  CHAR_REF(\"lhblk;\", 0x2584),\n  CHAR_REF(\"ljcy;\", 0x0459),\n  CHAR_REF(\"ll;\", 0x226a),\n  CHAR_REF(\"llarr;\", 0x21c7),\n  CHAR_REF(\"llcorner;\", 0x231e),\n  CHAR_REF(\"llhard;\", 0x296b),\n  CHAR_REF(\"lltri;\", 0x25fa),\n  CHAR_REF(\"lmidot;\", 0x0140),\n  CHAR_REF(\"lmoust;\", 0x23b0),\n  CHAR_REF(\"lmoustache;\", 0x23b0),\n  CHAR_REF(\"lnE;\", 0x2268),\n  CHAR_REF(\"lnap;\", 0x2a89),\n  CHAR_REF(\"lnapprox;\", 0x2a89),\n  CHAR_REF(\"lne;\", 0x2a87),\n  CHAR_REF(\"lneq;\", 0x2a87),\n  CHAR_REF(\"lneqq;\", 0x2268),\n  CHAR_REF(\"lnsim;\", 0x22e6),\n  CHAR_REF(\"loang;\", 0x27ec),\n  CHAR_REF(\"loarr;\", 0x21fd),\n  CHAR_REF(\"lobrk;\", 0x27e6),\n  CHAR_REF(\"longleftarrow;\", 0x27f5),\n  CHAR_REF(\"longleftrightarrow;\", 0x27f7),\n  CHAR_REF(\"longmapsto;\", 0x27fc),\n  CHAR_REF(\"longrightarrow;\", 0x27f6),\n  CHAR_REF(\"looparrowleft;\", 0x21ab),\n  CHAR_REF(\"looparrowright;\", 0x21ac),\n  CHAR_REF(\"lopar;\", 0x2985),\n  CHAR_REF(\"lopf;\", 0x0001d55d),\n  CHAR_REF(\"loplus;\", 0x2a2d),\n  CHAR_REF(\"lotimes;\", 0x2a34),\n  CHAR_REF(\"lowast;\", 0x2217),\n  CHAR_REF(\"lowbar;\", 0x5f),\n  CHAR_REF(\"loz;\", 0x25ca),\n  CHAR_REF(\"lozenge;\", 0x25ca),\n  CHAR_REF(\"lozf;\", 0x29eb),\n  CHAR_REF(\"lpar;\", 0x28),\n  CHAR_REF(\"lparlt;\", 0x2993),\n  CHAR_REF(\"lrarr;\", 0x21c6),\n  CHAR_REF(\"lrcorner;\", 0x231f),\n  CHAR_REF(\"lrhar;\", 0x21cb),\n  CHAR_REF(\"lrhard;\", 0x296d),\n  CHAR_REF(\"lrm;\", 0x200e),\n  CHAR_REF(\"lrtri;\", 0x22bf),\n  CHAR_REF(\"lsaquo;\", 0x2039),\n  CHAR_REF(\"lscr;\", 0x0001d4c1),\n  CHAR_REF(\"lsh;\", 0x21b0),\n  CHAR_REF(\"lsim;\", 0x2272),\n  CHAR_REF(\"lsime;\", 0x2a8d),\n  CHAR_REF(\"lsimg;\", 0x2a8f),\n  CHAR_REF(\"lsqb;\", 0x5b),\n  CHAR_REF(\"lsquo;\", 0x2018),\n  CHAR_REF(\"lsquor;\", 0x201a),\n  CHAR_REF(\"lstrok;\", 0x0142),\n  CHAR_REF(\"lt;\", 0x3c),\n  CHAR_REF(\"lt\", 0x3c),\n  CHAR_REF(\"ltcc;\", 0x2aa6),\n  CHAR_REF(\"ltcir;\", 0x2a79),\n  CHAR_REF(\"ltdot;\", 0x22d6),\n  CHAR_REF(\"lthree;\", 0x22cb),\n  CHAR_REF(\"ltimes;\", 0x22c9),\n  CHAR_REF(\"ltlarr;\", 0x2976),\n  CHAR_REF(\"ltquest;\", 0x2a7b),\n  CHAR_REF(\"ltrPar;\", 0x2996),\n  CHAR_REF(\"ltri;\", 0x25c3),\n  CHAR_REF(\"ltrie;\", 0x22b4),\n  CHAR_REF(\"ltrif;\", 0x25c2),\n  CHAR_REF(\"lurdshar;\", 0x294a),\n  CHAR_REF(\"luruhar;\", 0x2966),\n  MULTI_CHAR_REF(\"lvertneqq;\", 0x2268, 0xfe00),\n  MULTI_CHAR_REF(\"lvnE;\", 0x2268, 0xfe00),\n  CHAR_REF(\"mDDot;\", 0x223a),\n  CHAR_REF(\"macr;\", 0xaf),\n  CHAR_REF(\"macr\", 0xaf),\n  CHAR_REF(\"male;\", 0x2642),\n  CHAR_REF(\"malt;\", 0x2720),\n  CHAR_REF(\"maltese;\", 0x2720),\n  CHAR_REF(\"map;\", 0x21a6),\n  CHAR_REF(\"mapsto;\", 0x21a6),\n  CHAR_REF(\"mapstodown;\", 0x21a7),\n  CHAR_REF(\"mapstoleft;\", 0x21a4),\n  CHAR_REF(\"mapstoup;\", 0x21a5),\n  CHAR_REF(\"marker;\", 0x25ae),\n  CHAR_REF(\"mcomma;\", 0x2a29),\n  CHAR_REF(\"mcy;\", 0x043c),\n  CHAR_REF(\"mdash;\", 0x2014),\n  CHAR_REF(\"measuredangle;\", 0x2221),\n  CHAR_REF(\"mfr;\", 0x0001d52a),\n  CHAR_REF(\"mho;\", 0x2127),\n  CHAR_REF(\"micro;\", 0xb5),\n  CHAR_REF(\"micro\", 0xb5),\n  CHAR_REF(\"mid;\", 0x2223),\n  CHAR_REF(\"midast;\", 0x2a),\n  CHAR_REF(\"midcir;\", 0x2af0),\n  CHAR_REF(\"middot;\", 0xb7),\n  CHAR_REF(\"middot\", 0xb7),\n  CHAR_REF(\"minus;\", 0x2212),\n  CHAR_REF(\"minusb;\", 0x229f),\n  CHAR_REF(\"minusd;\", 0x2238),\n  CHAR_REF(\"minusdu;\", 0x2a2a),\n  CHAR_REF(\"mlcp;\", 0x2adb),\n  CHAR_REF(\"mldr;\", 0x2026),\n  CHAR_REF(\"mnplus;\", 0x2213),\n  CHAR_REF(\"models;\", 0x22a7),\n  CHAR_REF(\"mopf;\", 0x0001d55e),\n  CHAR_REF(\"mp;\", 0x2213),\n  CHAR_REF(\"mscr;\", 0x0001d4c2),\n  CHAR_REF(\"mstpos;\", 0x223e),\n  CHAR_REF(\"mu;\", 0x03bc),\n  CHAR_REF(\"multimap;\", 0x22b8),\n  CHAR_REF(\"mumap;\", 0x22b8),\n  MULTI_CHAR_REF(\"nGg;\", 0x22d9, 0x0338),\n  MULTI_CHAR_REF(\"nGt;\", 0x226b, 0x20d2),\n  MULTI_CHAR_REF(\"nGtv;\", 0x226b, 0x0338),\n  CHAR_REF(\"nLeftarrow;\", 0x21cd),\n  CHAR_REF(\"nLeftrightarrow;\", 0x21ce),\n  MULTI_CHAR_REF(\"nLl;\", 0x22d8, 0x0338),\n  MULTI_CHAR_REF(\"nLt;\", 0x226a, 0x20d2),\n  MULTI_CHAR_REF(\"nLtv;\", 0x226a, 0x0338),\n  CHAR_REF(\"nRightarrow;\", 0x21cf),\n  CHAR_REF(\"nVDash;\", 0x22af),\n  CHAR_REF(\"nVdash;\", 0x22ae),\n  CHAR_REF(\"nabla;\", 0x2207),\n  CHAR_REF(\"nacute;\", 0x0144),\n  MULTI_CHAR_REF(\"nang;\", 0x2220, 0x20d2),\n  CHAR_REF(\"nap;\", 0x2249),\n  MULTI_CHAR_REF(\"napE;\", 0x2a70, 0x0338),\n  MULTI_CHAR_REF(\"napid;\", 0x224b, 0x0338),\n  CHAR_REF(\"napos;\", 0x0149),\n  CHAR_REF(\"napprox;\", 0x2249),\n  CHAR_REF(\"natur;\", 0x266e),\n  CHAR_REF(\"natural;\", 0x266e),\n  CHAR_REF(\"naturals;\", 0x2115),\n  CHAR_REF(\"nbsp;\", 0xa0),\n  CHAR_REF(\"nbsp\", 0xa0),\n  MULTI_CHAR_REF(\"nbump;\", 0x224e, 0x0338),\n  MULTI_CHAR_REF(\"nbumpe;\", 0x224f, 0x0338),\n  CHAR_REF(\"ncap;\", 0x2a43),\n  CHAR_REF(\"ncaron;\", 0x0148),\n  CHAR_REF(\"ncedil;\", 0x0146),\n  CHAR_REF(\"ncong;\", 0x2247),\n  MULTI_CHAR_REF(\"ncongdot;\", 0x2a6d, 0x0338),\n  CHAR_REF(\"ncup;\", 0x2a42),\n  CHAR_REF(\"ncy;\", 0x043d),\n  CHAR_REF(\"ndash;\", 0x2013),\n  CHAR_REF(\"ne;\", 0x2260),\n  CHAR_REF(\"neArr;\", 0x21d7),\n  CHAR_REF(\"nearhk;\", 0x2924),\n  CHAR_REF(\"nearr;\", 0x2197),\n  CHAR_REF(\"nearrow;\", 0x2197),\n  MULTI_CHAR_REF(\"nedot;\", 0x2250, 0x0338),\n  CHAR_REF(\"nequiv;\", 0x2262),\n  CHAR_REF(\"nesear;\", 0x2928),\n  MULTI_CHAR_REF(\"nesim;\", 0x2242, 0x0338),\n  CHAR_REF(\"nexist;\", 0x2204),\n  CHAR_REF(\"nexists;\", 0x2204),\n  CHAR_REF(\"nfr;\", 0x0001d52b),\n  MULTI_CHAR_REF(\"ngE;\", 0x2267, 0x0338),\n  CHAR_REF(\"nge;\", 0x2271),\n  CHAR_REF(\"ngeq;\", 0x2271),\n  MULTI_CHAR_REF(\"ngeqq;\", 0x2267, 0x0338),\n  MULTI_CHAR_REF(\"ngeqslant;\", 0x2a7e, 0x0338),\n  MULTI_CHAR_REF(\"nges;\", 0x2a7e, 0x0338),\n  CHAR_REF(\"ngsim;\", 0x2275),\n  CHAR_REF(\"ngt;\", 0x226f),\n  CHAR_REF(\"ngtr;\", 0x226f),\n  CHAR_REF(\"nhArr;\", 0x21ce),\n  CHAR_REF(\"nharr;\", 0x21ae),\n  CHAR_REF(\"nhpar;\", 0x2af2),\n  CHAR_REF(\"ni;\", 0x220b),\n  CHAR_REF(\"nis;\", 0x22fc),\n  CHAR_REF(\"nisd;\", 0x22fa),\n  CHAR_REF(\"niv;\", 0x220b),\n  CHAR_REF(\"njcy;\", 0x045a),\n  CHAR_REF(\"nlArr;\", 0x21cd),\n  MULTI_CHAR_REF(\"nlE;\", 0x2266, 0x0338),\n  CHAR_REF(\"nlarr;\", 0x219a),\n  CHAR_REF(\"nldr;\", 0x2025),\n  CHAR_REF(\"nle;\", 0x2270),\n  CHAR_REF(\"nleftarrow;\", 0x219a),\n  CHAR_REF(\"nleftrightarrow;\", 0x21ae),\n  CHAR_REF(\"nleq;\", 0x2270),\n  MULTI_CHAR_REF(\"nleqq;\", 0x2266, 0x0338),\n  MULTI_CHAR_REF(\"nleqslant;\", 0x2a7d, 0x0338),\n  MULTI_CHAR_REF(\"nles;\", 0x2a7d, 0x0338),\n  CHAR_REF(\"nless;\", 0x226e),\n  CHAR_REF(\"nlsim;\", 0x2274),\n  CHAR_REF(\"nlt;\", 0x226e),\n  CHAR_REF(\"nltri;\", 0x22ea),\n  CHAR_REF(\"nltrie;\", 0x22ec),\n  CHAR_REF(\"nmid;\", 0x2224),\n  CHAR_REF(\"nopf;\", 0x0001d55f),\n  CHAR_REF(\"not;\", 0xac),\n  CHAR_REF(\"notin;\", 0x2209),\n  MULTI_CHAR_REF(\"notinE;\", 0x22f9, 0x0338),\n  MULTI_CHAR_REF(\"notindot;\", 0x22f5, 0x0338),\n  CHAR_REF(\"notinva;\", 0x2209),\n  CHAR_REF(\"notinvb;\", 0x22f7),\n  CHAR_REF(\"notinvc;\", 0x22f6),\n  CHAR_REF(\"notni;\", 0x220c),\n  CHAR_REF(\"notniva;\", 0x220c),\n  CHAR_REF(\"notnivb;\", 0x22fe),\n  CHAR_REF(\"notnivc;\", 0x22fd),\n  CHAR_REF(\"not\", 0xac),\n  CHAR_REF(\"npar;\", 0x2226),\n  CHAR_REF(\"nparallel;\", 0x2226),\n  MULTI_CHAR_REF(\"nparsl;\", 0x2afd, 0x20e5),\n  MULTI_CHAR_REF(\"npart;\", 0x2202, 0x0338),\n  CHAR_REF(\"npolint;\", 0x2a14),\n  CHAR_REF(\"npr;\", 0x2280),\n  CHAR_REF(\"nprcue;\", 0x22e0),\n  MULTI_CHAR_REF(\"npre;\", 0x2aaf, 0x0338),\n  CHAR_REF(\"nprec;\", 0x2280),\n  MULTI_CHAR_REF(\"npreceq;\", 0x2aaf, 0x0338),\n  CHAR_REF(\"nrArr;\", 0x21cf),\n  CHAR_REF(\"nrarr;\", 0x219b),\n  MULTI_CHAR_REF(\"nrarrc;\", 0x2933, 0x0338),\n  MULTI_CHAR_REF(\"nrarrw;\", 0x219d, 0x0338),\n  CHAR_REF(\"nrightarrow;\", 0x219b),\n  CHAR_REF(\"nrtri;\", 0x22eb),\n  CHAR_REF(\"nrtrie;\", 0x22ed),\n  CHAR_REF(\"nsc;\", 0x2281),\n  CHAR_REF(\"nsccue;\", 0x22e1),\n  MULTI_CHAR_REF(\"nsce;\", 0x2ab0, 0x0338),\n  CHAR_REF(\"nscr;\", 0x0001d4c3),\n  CHAR_REF(\"nshortmid;\", 0x2224),\n  CHAR_REF(\"nshortparallel;\", 0x2226),\n  CHAR_REF(\"nsim;\", 0x2241),\n  CHAR_REF(\"nsime;\", 0x2244),\n  CHAR_REF(\"nsimeq;\", 0x2244),\n  CHAR_REF(\"nsmid;\", 0x2224),\n  CHAR_REF(\"nspar;\", 0x2226),\n  CHAR_REF(\"nsqsube;\", 0x22e2),\n  CHAR_REF(\"nsqsupe;\", 0x22e3),\n  CHAR_REF(\"nsub;\", 0x2284),\n  MULTI_CHAR_REF(\"nsubE;\", 0x2ac5, 0x0338),\n  CHAR_REF(\"nsube;\", 0x2288),\n  MULTI_CHAR_REF(\"nsubset;\", 0x2282, 0x20d2),\n  CHAR_REF(\"nsubseteq;\", 0x2288),\n  MULTI_CHAR_REF(\"nsubseteqq;\", 0x2ac5, 0x0338),\n  CHAR_REF(\"nsucc;\", 0x2281),\n  MULTI_CHAR_REF(\"nsucceq;\", 0x2ab0, 0x0338),\n  CHAR_REF(\"nsup;\", 0x2285),\n  MULTI_CHAR_REF(\"nsupE;\", 0x2ac6, 0x0338),\n  CHAR_REF(\"nsupe;\", 0x2289),\n  MULTI_CHAR_REF(\"nsupset;\", 0x2283, 0x20d2),\n  CHAR_REF(\"nsupseteq;\", 0x2289),\n  MULTI_CHAR_REF(\"nsupseteqq;\", 0x2ac6, 0x0338),\n  CHAR_REF(\"ntgl;\", 0x2279),\n  CHAR_REF(\"ntilde;\", 0xf1),\n  CHAR_REF(\"ntilde\", 0xf1),\n  CHAR_REF(\"ntlg;\", 0x2278),\n  CHAR_REF(\"ntriangleleft;\", 0x22ea),\n  CHAR_REF(\"ntrianglelefteq;\", 0x22ec),\n  CHAR_REF(\"ntriangleright;\", 0x22eb),\n  CHAR_REF(\"ntrianglerighteq;\", 0x22ed),\n  CHAR_REF(\"nu;\", 0x03bd),\n  CHAR_REF(\"num;\", 0x23),\n  CHAR_REF(\"numero;\", 0x2116),\n  CHAR_REF(\"numsp;\", 0x2007),\n  CHAR_REF(\"nvDash;\", 0x22ad),\n  CHAR_REF(\"nvHarr;\", 0x2904),\n  MULTI_CHAR_REF(\"nvap;\", 0x224d, 0x20d2),\n  CHAR_REF(\"nvdash;\", 0x22ac),\n  MULTI_CHAR_REF(\"nvge;\", 0x2265, 0x20d2),\n  MULTI_CHAR_REF(\"nvgt;\", 0x3e, 0x20d2),\n  CHAR_REF(\"nvinfin;\", 0x29de),\n  CHAR_REF(\"nvlArr;\", 0x2902),\n  MULTI_CHAR_REF(\"nvle;\", 0x2264, 0x20d2),\n  MULTI_CHAR_REF(\"nvlt;\", 0x3c, 0x20d2),\n  MULTI_CHAR_REF(\"nvltrie;\", 0x22b4, 0x20d2),\n  CHAR_REF(\"nvrArr;\", 0x2903),\n  MULTI_CHAR_REF(\"nvrtrie;\", 0x22b5, 0x20d2),\n  MULTI_CHAR_REF(\"nvsim;\", 0x223c, 0x20d2),\n  CHAR_REF(\"nwArr;\", 0x21d6),\n  CHAR_REF(\"nwarhk;\", 0x2923),\n  CHAR_REF(\"nwarr;\", 0x2196),\n  CHAR_REF(\"nwarrow;\", 0x2196),\n  CHAR_REF(\"nwnear;\", 0x2927),\n  CHAR_REF(\"oS;\", 0x24c8),\n  CHAR_REF(\"oacute;\", 0xf3),\n  CHAR_REF(\"oacute\", 0xf3),\n  CHAR_REF(\"oast;\", 0x229b),\n  CHAR_REF(\"ocir;\", 0x229a),\n  CHAR_REF(\"ocirc;\", 0xf4),\n  CHAR_REF(\"ocirc\", 0xf4),\n  CHAR_REF(\"ocy;\", 0x043e),\n  CHAR_REF(\"odash;\", 0x229d),\n  CHAR_REF(\"odblac;\", 0x0151),\n  CHAR_REF(\"odiv;\", 0x2a38),\n  CHAR_REF(\"odot;\", 0x2299),\n  CHAR_REF(\"odsold;\", 0x29bc),\n  CHAR_REF(\"oelig;\", 0x0153),\n  CHAR_REF(\"ofcir;\", 0x29bf),\n  CHAR_REF(\"ofr;\", 0x0001d52c),\n  CHAR_REF(\"ogon;\", 0x02db),\n  CHAR_REF(\"ograve;\", 0xf2),\n  CHAR_REF(\"ograve\", 0xf2),\n  CHAR_REF(\"ogt;\", 0x29c1),\n  CHAR_REF(\"ohbar;\", 0x29b5),\n  CHAR_REF(\"ohm;\", 0x03a9),\n  CHAR_REF(\"oint;\", 0x222e),\n  CHAR_REF(\"olarr;\", 0x21ba),\n  CHAR_REF(\"olcir;\", 0x29be),\n  CHAR_REF(\"olcross;\", 0x29bb),\n  CHAR_REF(\"oline;\", 0x203e),\n  CHAR_REF(\"olt;\", 0x29c0),\n  CHAR_REF(\"omacr;\", 0x014d),\n  CHAR_REF(\"omega;\", 0x03c9),\n  CHAR_REF(\"omicron;\", 0x03bf),\n  CHAR_REF(\"omid;\", 0x29b6),\n  CHAR_REF(\"ominus;\", 0x2296),\n  CHAR_REF(\"oopf;\", 0x0001d560),\n  CHAR_REF(\"opar;\", 0x29b7),\n  CHAR_REF(\"operp;\", 0x29b9),\n  CHAR_REF(\"oplus;\", 0x2295),\n  CHAR_REF(\"or;\", 0x2228),\n  CHAR_REF(\"orarr;\", 0x21bb),\n  CHAR_REF(\"ord;\", 0x2a5d),\n  CHAR_REF(\"order;\", 0x2134),\n  CHAR_REF(\"orderof;\", 0x2134),\n  CHAR_REF(\"ordf;\", 0xaa),\n  CHAR_REF(\"ordf\", 0xaa),\n  CHAR_REF(\"ordm;\", 0xba),\n  CHAR_REF(\"ordm\", 0xba),\n  CHAR_REF(\"origof;\", 0x22b6),\n  CHAR_REF(\"oror;\", 0x2a56),\n  CHAR_REF(\"orslope;\", 0x2a57),\n  CHAR_REF(\"orv;\", 0x2a5b),\n  CHAR_REF(\"oscr;\", 0x2134),\n  CHAR_REF(\"oslash;\", 0xf8),\n  CHAR_REF(\"oslash\", 0xf8),\n  CHAR_REF(\"osol;\", 0x2298),\n  CHAR_REF(\"otilde;\", 0xf5),\n  CHAR_REF(\"otilde\", 0xf5),\n  CHAR_REF(\"otimes;\", 0x2297),\n  CHAR_REF(\"otimesas;\", 0x2a36),\n  CHAR_REF(\"ouml;\", 0xf6),\n  CHAR_REF(\"ouml\", 0xf6),\n  CHAR_REF(\"ovbar;\", 0x233d),\n  CHAR_REF(\"par;\", 0x2225),\n  CHAR_REF(\"para;\", 0xb6),\n  CHAR_REF(\"para\", 0xb6),\n  CHAR_REF(\"parallel;\", 0x2225),\n  CHAR_REF(\"parsim;\", 0x2af3),\n  CHAR_REF(\"parsl;\", 0x2afd),\n  CHAR_REF(\"part;\", 0x2202),\n  CHAR_REF(\"pcy;\", 0x043f),\n  CHAR_REF(\"percnt;\", 0x25),\n  CHAR_REF(\"period;\", 0x2e),\n  CHAR_REF(\"permil;\", 0x2030),\n  CHAR_REF(\"perp;\", 0x22a5),\n  CHAR_REF(\"pertenk;\", 0x2031),\n  CHAR_REF(\"pfr;\", 0x0001d52d),\n  CHAR_REF(\"phi;\", 0x03c6),\n  CHAR_REF(\"phiv;\", 0x03d5),\n  CHAR_REF(\"phmmat;\", 0x2133),\n  CHAR_REF(\"phone;\", 0x260e),\n  CHAR_REF(\"pi;\", 0x03c0),\n  CHAR_REF(\"pitchfork;\", 0x22d4),\n  CHAR_REF(\"piv;\", 0x03d6),\n  CHAR_REF(\"planck;\", 0x210f),\n  CHAR_REF(\"planckh;\", 0x210e),\n  CHAR_REF(\"plankv;\", 0x210f),\n  CHAR_REF(\"plus;\", 0x2b),\n  CHAR_REF(\"plusacir;\", 0x2a23),\n  CHAR_REF(\"plusb;\", 0x229e),\n  CHAR_REF(\"pluscir;\", 0x2a22),\n  CHAR_REF(\"plusdo;\", 0x2214),\n  CHAR_REF(\"plusdu;\", 0x2a25),\n  CHAR_REF(\"pluse;\", 0x2a72),\n  CHAR_REF(\"plusmn;\", 0xb1),\n  CHAR_REF(\"plusmn\", 0xb1),\n  CHAR_REF(\"plussim;\", 0x2a26),\n  CHAR_REF(\"plustwo;\", 0x2a27),\n  CHAR_REF(\"pm;\", 0xb1),\n  CHAR_REF(\"pointint;\", 0x2a15),\n  CHAR_REF(\"popf;\", 0x0001d561),\n  CHAR_REF(\"pound;\", 0xa3),\n  CHAR_REF(\"pound\", 0xa3),\n  CHAR_REF(\"pr;\", 0x227a),\n  CHAR_REF(\"prE;\", 0x2ab3),\n  CHAR_REF(\"prap;\", 0x2ab7),\n  CHAR_REF(\"prcue;\", 0x227c),\n  CHAR_REF(\"pre;\", 0x2aaf),\n  CHAR_REF(\"prec;\", 0x227a),\n  CHAR_REF(\"precapprox;\", 0x2ab7),\n  CHAR_REF(\"preccurlyeq;\", 0x227c),\n  CHAR_REF(\"preceq;\", 0x2aaf),\n  CHAR_REF(\"precnapprox;\", 0x2ab9),\n  CHAR_REF(\"precneqq;\", 0x2ab5),\n  CHAR_REF(\"precnsim;\", 0x22e8),\n  CHAR_REF(\"precsim;\", 0x227e),\n  CHAR_REF(\"prime;\", 0x2032),\n  CHAR_REF(\"primes;\", 0x2119),\n  CHAR_REF(\"prnE;\", 0x2ab5),\n  CHAR_REF(\"prnap;\", 0x2ab9),\n  CHAR_REF(\"prnsim;\", 0x22e8),\n  CHAR_REF(\"prod;\", 0x220f),\n  CHAR_REF(\"profalar;\", 0x232e),\n  CHAR_REF(\"profline;\", 0x2312),\n  CHAR_REF(\"profsurf;\", 0x2313),\n  CHAR_REF(\"prop;\", 0x221d),\n  CHAR_REF(\"propto;\", 0x221d),\n  CHAR_REF(\"prsim;\", 0x227e),\n  CHAR_REF(\"prurel;\", 0x22b0),\n  CHAR_REF(\"pscr;\", 0x0001d4c5),\n  CHAR_REF(\"psi;\", 0x03c8),\n  CHAR_REF(\"puncsp;\", 0x2008),\n  CHAR_REF(\"qfr;\", 0x0001d52e),\n  CHAR_REF(\"qint;\", 0x2a0c),\n  CHAR_REF(\"qopf;\", 0x0001d562),\n  CHAR_REF(\"qprime;\", 0x2057),\n  CHAR_REF(\"qscr;\", 0x0001d4c6),\n  CHAR_REF(\"quaternions;\", 0x210d),\n  CHAR_REF(\"quatint;\", 0x2a16),\n  CHAR_REF(\"quest;\", 0x3f),\n  CHAR_REF(\"questeq;\", 0x225f),\n  CHAR_REF(\"quot;\", 0x22),\n  CHAR_REF(\"quot\", 0x22),\n  CHAR_REF(\"rAarr;\", 0x21db),\n  CHAR_REF(\"rArr;\", 0x21d2),\n  CHAR_REF(\"rAtail;\", 0x291c),\n  CHAR_REF(\"rBarr;\", 0x290f),\n  CHAR_REF(\"rHar;\", 0x2964),\n  MULTI_CHAR_REF(\"race;\", 0x223d, 0x0331),\n  CHAR_REF(\"racute;\", 0x0155),\n  CHAR_REF(\"radic;\", 0x221a),\n  CHAR_REF(\"raemptyv;\", 0x29b3),\n  CHAR_REF(\"rang;\", 0x27e9),\n  CHAR_REF(\"rangd;\", 0x2992),\n  CHAR_REF(\"range;\", 0x29a5),\n  CHAR_REF(\"rangle;\", 0x27e9),\n  CHAR_REF(\"raquo;\", 0xbb),\n  CHAR_REF(\"raquo\", 0xbb),\n  CHAR_REF(\"rarr;\", 0x2192),\n  CHAR_REF(\"rarrap;\", 0x2975),\n  CHAR_REF(\"rarrb;\", 0x21e5),\n  CHAR_REF(\"rarrbfs;\", 0x2920),\n  CHAR_REF(\"rarrc;\", 0x2933),\n  CHAR_REF(\"rarrfs;\", 0x291e),\n  CHAR_REF(\"rarrhk;\", 0x21aa),\n  CHAR_REF(\"rarrlp;\", 0x21ac),\n  CHAR_REF(\"rarrpl;\", 0x2945),\n  CHAR_REF(\"rarrsim;\", 0x2974),\n  CHAR_REF(\"rarrtl;\", 0x21a3),\n  CHAR_REF(\"rarrw;\", 0x219d),\n  CHAR_REF(\"ratail;\", 0x291a),\n  CHAR_REF(\"ratio;\", 0x2236),\n  CHAR_REF(\"rationals;\", 0x211a),\n  CHAR_REF(\"rbarr;\", 0x290d),\n  CHAR_REF(\"rbbrk;\", 0x2773),\n  CHAR_REF(\"rbrace;\", 0x7d),\n  CHAR_REF(\"rbrack;\", 0x5d),\n  CHAR_REF(\"rbrke;\", 0x298c),\n  CHAR_REF(\"rbrksld;\", 0x298e),\n  CHAR_REF(\"rbrkslu;\", 0x2990),\n  CHAR_REF(\"rcaron;\", 0x0159),\n  CHAR_REF(\"rcedil;\", 0x0157),\n  CHAR_REF(\"rceil;\", 0x2309),\n  CHAR_REF(\"rcub;\", 0x7d),\n  CHAR_REF(\"rcy;\", 0x0440),\n  CHAR_REF(\"rdca;\", 0x2937),\n  CHAR_REF(\"rdldhar;\", 0x2969),\n  CHAR_REF(\"rdquo;\", 0x201d),\n  CHAR_REF(\"rdquor;\", 0x201d),\n  CHAR_REF(\"rdsh;\", 0x21b3),\n  CHAR_REF(\"real;\", 0x211c),\n  CHAR_REF(\"realine;\", 0x211b),\n  CHAR_REF(\"realpart;\", 0x211c),\n  CHAR_REF(\"reals;\", 0x211d),\n  CHAR_REF(\"rect;\", 0x25ad),\n  CHAR_REF(\"reg;\", 0xae),\n  CHAR_REF(\"reg\", 0xae),\n  CHAR_REF(\"rfisht;\", 0x297d),\n  CHAR_REF(\"rfloor;\", 0x230b),\n  CHAR_REF(\"rfr;\", 0x0001d52f),\n  CHAR_REF(\"rhard;\", 0x21c1),\n  CHAR_REF(\"rharu;\", 0x21c0),\n  CHAR_REF(\"rharul;\", 0x296c),\n  CHAR_REF(\"rho;\", 0x03c1),\n  CHAR_REF(\"rhov;\", 0x03f1),\n  CHAR_REF(\"rightarrow;\", 0x2192),\n  CHAR_REF(\"rightarrowtail;\", 0x21a3),\n  CHAR_REF(\"rightharpoondown;\", 0x21c1),\n  CHAR_REF(\"rightharpoonup;\", 0x21c0),\n  CHAR_REF(\"rightleftarrows;\", 0x21c4),\n  CHAR_REF(\"rightleftharpoons;\", 0x21cc),\n  CHAR_REF(\"rightrightarrows;\", 0x21c9),\n  CHAR_REF(\"rightsquigarrow;\", 0x219d),\n  CHAR_REF(\"rightthreetimes;\", 0x22cc),\n  CHAR_REF(\"ring;\", 0x02da),\n  CHAR_REF(\"risingdotseq;\", 0x2253),\n  CHAR_REF(\"rlarr;\", 0x21c4),\n  CHAR_REF(\"rlhar;\", 0x21cc),\n  CHAR_REF(\"rlm;\", 0x200f),\n  CHAR_REF(\"rmoust;\", 0x23b1),\n  CHAR_REF(\"rmoustache;\", 0x23b1),\n  CHAR_REF(\"rnmid;\", 0x2aee),\n  CHAR_REF(\"roang;\", 0x27ed),\n  CHAR_REF(\"roarr;\", 0x21fe),\n  CHAR_REF(\"robrk;\", 0x27e7),\n  CHAR_REF(\"ropar;\", 0x2986),\n  CHAR_REF(\"ropf;\", 0x0001d563),\n  CHAR_REF(\"roplus;\", 0x2a2e),\n  CHAR_REF(\"rotimes;\", 0x2a35),\n  CHAR_REF(\"rpar;\", 0x29),\n  CHAR_REF(\"rpargt;\", 0x2994),\n  CHAR_REF(\"rppolint;\", 0x2a12),\n  CHAR_REF(\"rrarr;\", 0x21c9),\n  CHAR_REF(\"rsaquo;\", 0x203a),\n  CHAR_REF(\"rscr;\", 0x0001d4c7),\n  CHAR_REF(\"rsh;\", 0x21b1),\n  CHAR_REF(\"rsqb;\", 0x5d),\n  CHAR_REF(\"rsquo;\", 0x2019),\n  CHAR_REF(\"rsquor;\", 0x2019),\n  CHAR_REF(\"rthree;\", 0x22cc),\n  CHAR_REF(\"rtimes;\", 0x22ca),\n  CHAR_REF(\"rtri;\", 0x25b9),\n  CHAR_REF(\"rtrie;\", 0x22b5),\n  CHAR_REF(\"rtrif;\", 0x25b8),\n  CHAR_REF(\"rtriltri;\", 0x29ce),\n  CHAR_REF(\"ruluhar;\", 0x2968),\n  CHAR_REF(\"rx;\", 0x211e),\n  CHAR_REF(\"sacute;\", 0x015b),\n  CHAR_REF(\"sbquo;\", 0x201a),\n  CHAR_REF(\"sc;\", 0x227b),\n  CHAR_REF(\"scE;\", 0x2ab4),\n  CHAR_REF(\"scap;\", 0x2ab8),\n  CHAR_REF(\"scaron;\", 0x0161),\n  CHAR_REF(\"sccue;\", 0x227d),\n  CHAR_REF(\"sce;\", 0x2ab0),\n  CHAR_REF(\"scedil;\", 0x015f),\n  CHAR_REF(\"scirc;\", 0x015d),\n  CHAR_REF(\"scnE;\", 0x2ab6),\n  CHAR_REF(\"scnap;\", 0x2aba),\n  CHAR_REF(\"scnsim;\", 0x22e9),\n  CHAR_REF(\"scpolint;\", 0x2a13),\n  CHAR_REF(\"scsim;\", 0x227f),\n  CHAR_REF(\"scy;\", 0x0441),\n  CHAR_REF(\"sdot;\", 0x22c5),\n  CHAR_REF(\"sdotb;\", 0x22a1),\n  CHAR_REF(\"sdote;\", 0x2a66),\n  CHAR_REF(\"seArr;\", 0x21d8),\n  CHAR_REF(\"searhk;\", 0x2925),\n  CHAR_REF(\"searr;\", 0x2198),\n  CHAR_REF(\"searrow;\", 0x2198),\n  CHAR_REF(\"sect;\", 0xa7),\n  CHAR_REF(\"sect\", 0xa7),\n  CHAR_REF(\"semi;\", 0x3b),\n  CHAR_REF(\"seswar;\", 0x2929),\n  CHAR_REF(\"setminus;\", 0x2216),\n  CHAR_REF(\"setmn;\", 0x2216),\n  CHAR_REF(\"sext;\", 0x2736),\n  CHAR_REF(\"sfr;\", 0x0001d530),\n  CHAR_REF(\"sfrown;\", 0x2322),\n  CHAR_REF(\"sharp;\", 0x266f),\n  CHAR_REF(\"shchcy;\", 0x0449),\n  CHAR_REF(\"shcy;\", 0x0448),\n  CHAR_REF(\"shortmid;\", 0x2223),\n  CHAR_REF(\"shortparallel;\", 0x2225),\n  CHAR_REF(\"shy;\", 0xad),\n  CHAR_REF(\"shy\", 0xad),\n  CHAR_REF(\"sigma;\", 0x03c3),\n  CHAR_REF(\"sigmaf;\", 0x03c2),\n  CHAR_REF(\"sigmav;\", 0x03c2),\n  CHAR_REF(\"sim;\", 0x223c),\n  CHAR_REF(\"simdot;\", 0x2a6a),\n  CHAR_REF(\"sime;\", 0x2243),\n  CHAR_REF(\"simeq;\", 0x2243),\n  CHAR_REF(\"simg;\", 0x2a9e),\n  CHAR_REF(\"simgE;\", 0x2aa0),\n  CHAR_REF(\"siml;\", 0x2a9d),\n  CHAR_REF(\"simlE;\", 0x2a9f),\n  CHAR_REF(\"simne;\", 0x2246),\n  CHAR_REF(\"simplus;\", 0x2a24),\n  CHAR_REF(\"simrarr;\", 0x2972),\n  CHAR_REF(\"slarr;\", 0x2190),\n  CHAR_REF(\"smallsetminus;\", 0x2216),\n  CHAR_REF(\"smashp;\", 0x2a33),\n  CHAR_REF(\"smeparsl;\", 0x29e4),\n  CHAR_REF(\"smid;\", 0x2223),\n  CHAR_REF(\"smile;\", 0x2323),\n  CHAR_REF(\"smt;\", 0x2aaa),\n  CHAR_REF(\"smte;\", 0x2aac),\n  MULTI_CHAR_REF(\"smtes;\", 0x2aac, 0xfe00),\n  CHAR_REF(\"softcy;\", 0x044c),\n  CHAR_REF(\"sol;\", 0x2f),\n  CHAR_REF(\"solb;\", 0x29c4),\n  CHAR_REF(\"solbar;\", 0x233f),\n  CHAR_REF(\"sopf;\", 0x0001d564),\n  CHAR_REF(\"spades;\", 0x2660),\n  CHAR_REF(\"spadesuit;\", 0x2660),\n  CHAR_REF(\"spar;\", 0x2225),\n  CHAR_REF(\"sqcap;\", 0x2293),\n  MULTI_CHAR_REF(\"sqcaps;\", 0x2293, 0xfe00),\n  CHAR_REF(\"sqcup;\", 0x2294),\n  MULTI_CHAR_REF(\"sqcups;\", 0x2294, 0xfe00),\n  CHAR_REF(\"sqsub;\", 0x228f),\n  CHAR_REF(\"sqsube;\", 0x2291),\n  CHAR_REF(\"sqsubset;\", 0x228f),\n  CHAR_REF(\"sqsubseteq;\", 0x2291),\n  CHAR_REF(\"sqsup;\", 0x2290),\n  CHAR_REF(\"sqsupe;\", 0x2292),\n  CHAR_REF(\"sqsupset;\", 0x2290),\n  CHAR_REF(\"sqsupseteq;\", 0x2292),\n  CHAR_REF(\"squ;\", 0x25a1),\n  CHAR_REF(\"square;\", 0x25a1),\n  CHAR_REF(\"squarf;\", 0x25aa),\n  CHAR_REF(\"squf;\", 0x25aa),\n  CHAR_REF(\"srarr;\", 0x2192),\n  CHAR_REF(\"sscr;\", 0x0001d4c8),\n  CHAR_REF(\"ssetmn;\", 0x2216),\n  CHAR_REF(\"ssmile;\", 0x2323),\n  CHAR_REF(\"sstarf;\", 0x22c6),\n  CHAR_REF(\"star;\", 0x2606),\n  CHAR_REF(\"starf;\", 0x2605),\n  CHAR_REF(\"straightepsilon;\", 0x03f5),\n  CHAR_REF(\"straightphi;\", 0x03d5),\n  CHAR_REF(\"strns;\", 0xaf),\n  CHAR_REF(\"sub;\", 0x2282),\n  CHAR_REF(\"subE;\", 0x2ac5),\n  CHAR_REF(\"subdot;\", 0x2abd),\n  CHAR_REF(\"sube;\", 0x2286),\n  CHAR_REF(\"subedot;\", 0x2ac3),\n  CHAR_REF(\"submult;\", 0x2ac1),\n  CHAR_REF(\"subnE;\", 0x2acb),\n  CHAR_REF(\"subne;\", 0x228a),\n  CHAR_REF(\"subplus;\", 0x2abf),\n  CHAR_REF(\"subrarr;\", 0x2979),\n  CHAR_REF(\"subset;\", 0x2282),\n  CHAR_REF(\"subseteq;\", 0x2286),\n  CHAR_REF(\"subseteqq;\", 0x2ac5),\n  CHAR_REF(\"subsetneq;\", 0x228a),\n  CHAR_REF(\"subsetneqq;\", 0x2acb),\n  CHAR_REF(\"subsim;\", 0x2ac7),\n  CHAR_REF(\"subsub;\", 0x2ad5),\n  CHAR_REF(\"subsup;\", 0x2ad3),\n  CHAR_REF(\"succ;\", 0x227b),\n  CHAR_REF(\"succapprox;\", 0x2ab8),\n  CHAR_REF(\"succcurlyeq;\", 0x227d),\n  CHAR_REF(\"succeq;\", 0x2ab0),\n  CHAR_REF(\"succnapprox;\", 0x2aba),\n  CHAR_REF(\"succneqq;\", 0x2ab6),\n  CHAR_REF(\"succnsim;\", 0x22e9),\n  CHAR_REF(\"succsim;\", 0x227f),\n  CHAR_REF(\"sum;\", 0x2211),\n  CHAR_REF(\"sung;\", 0x266a),\n  CHAR_REF(\"sup1;\", 0xb9),\n  CHAR_REF(\"sup1\", 0xb9),\n  CHAR_REF(\"sup2;\", 0xb2),\n  CHAR_REF(\"sup2\", 0xb2),\n  CHAR_REF(\"sup3;\", 0xb3),\n  CHAR_REF(\"sup3\", 0xb3),\n  CHAR_REF(\"sup;\", 0x2283),\n  CHAR_REF(\"supE;\", 0x2ac6),\n  CHAR_REF(\"supdot;\", 0x2abe),\n  CHAR_REF(\"supdsub;\", 0x2ad8),\n  CHAR_REF(\"supe;\", 0x2287),\n  CHAR_REF(\"supedot;\", 0x2ac4),\n  CHAR_REF(\"suphsol;\", 0x27c9),\n  CHAR_REF(\"suphsub;\", 0x2ad7),\n  CHAR_REF(\"suplarr;\", 0x297b),\n  CHAR_REF(\"supmult;\", 0x2ac2),\n  CHAR_REF(\"supnE;\", 0x2acc),\n  CHAR_REF(\"supne;\", 0x228b),\n  CHAR_REF(\"supplus;\", 0x2ac0),\n  CHAR_REF(\"supset;\", 0x2283),\n  CHAR_REF(\"supseteq;\", 0x2287),\n  CHAR_REF(\"supseteqq;\", 0x2ac6),\n  CHAR_REF(\"supsetneq;\", 0x228b),\n  CHAR_REF(\"supsetneqq;\", 0x2acc),\n  CHAR_REF(\"supsim;\", 0x2ac8),\n  CHAR_REF(\"supsub;\", 0x2ad4),\n  CHAR_REF(\"supsup;\", 0x2ad6),\n  CHAR_REF(\"swArr;\", 0x21d9),\n  CHAR_REF(\"swarhk;\", 0x2926),\n  CHAR_REF(\"swarr;\", 0x2199),\n  CHAR_REF(\"swarrow;\", 0x2199),\n  CHAR_REF(\"swnwar;\", 0x292a),\n  CHAR_REF(\"szlig;\", 0xdf),\n  CHAR_REF(\"szlig\", 0xdf),\n  CHAR_REF(\"target;\", 0x2316),\n  CHAR_REF(\"tau;\", 0x03c4),\n  CHAR_REF(\"tbrk;\", 0x23b4),\n  CHAR_REF(\"tcaron;\", 0x0165),\n  CHAR_REF(\"tcedil;\", 0x0163),\n  CHAR_REF(\"tcy;\", 0x0442),\n  CHAR_REF(\"tdot;\", 0x20db),\n  CHAR_REF(\"telrec;\", 0x2315),\n  CHAR_REF(\"tfr;\", 0x0001d531),\n  CHAR_REF(\"there4;\", 0x2234),\n  CHAR_REF(\"therefore;\", 0x2234),\n  CHAR_REF(\"theta;\", 0x03b8),\n  CHAR_REF(\"thetasym;\", 0x03d1),\n  CHAR_REF(\"thetav;\", 0x03d1),\n  CHAR_REF(\"thickapprox;\", 0x2248),\n  CHAR_REF(\"thicksim;\", 0x223c),\n  CHAR_REF(\"thinsp;\", 0x2009),\n  CHAR_REF(\"thkap;\", 0x2248),\n  CHAR_REF(\"thksim;\", 0x223c),\n  CHAR_REF(\"thorn;\", 0xfe),\n  CHAR_REF(\"thorn\", 0xfe),\n  CHAR_REF(\"tilde;\", 0x02dc),\n  CHAR_REF(\"times;\", 0xd7),\n  CHAR_REF(\"times\", 0xd7),\n  CHAR_REF(\"timesb;\", 0x22a0),\n  CHAR_REF(\"timesbar;\", 0x2a31),\n  CHAR_REF(\"timesd;\", 0x2a30),\n  CHAR_REF(\"tint;\", 0x222d),\n  CHAR_REF(\"toea;\", 0x2928),\n  CHAR_REF(\"top;\", 0x22a4),\n  CHAR_REF(\"topbot;\", 0x2336),\n  CHAR_REF(\"topcir;\", 0x2af1),\n  CHAR_REF(\"topf;\", 0x0001d565),\n  CHAR_REF(\"topfork;\", 0x2ada),\n  CHAR_REF(\"tosa;\", 0x2929),\n  CHAR_REF(\"tprime;\", 0x2034),\n  CHAR_REF(\"trade;\", 0x2122),\n  CHAR_REF(\"triangle;\", 0x25b5),\n  CHAR_REF(\"triangledown;\", 0x25bf),\n  CHAR_REF(\"triangleleft;\", 0x25c3),\n  CHAR_REF(\"trianglelefteq;\", 0x22b4),\n  CHAR_REF(\"triangleq;\", 0x225c),\n  CHAR_REF(\"triangleright;\", 0x25b9),\n  CHAR_REF(\"trianglerighteq;\", 0x22b5),\n  CHAR_REF(\"tridot;\", 0x25ec),\n  CHAR_REF(\"trie;\", 0x225c),\n  CHAR_REF(\"triminus;\", 0x2a3a),\n  CHAR_REF(\"triplus;\", 0x2a39),\n  CHAR_REF(\"trisb;\", 0x29cd),\n  CHAR_REF(\"tritime;\", 0x2a3b),\n  CHAR_REF(\"trpezium;\", 0x23e2),\n  CHAR_REF(\"tscr;\", 0x0001d4c9),\n  CHAR_REF(\"tscy;\", 0x0446),\n  CHAR_REF(\"tshcy;\", 0x045b),\n  CHAR_REF(\"tstrok;\", 0x0167),\n  CHAR_REF(\"twixt;\", 0x226c),\n  CHAR_REF(\"twoheadleftarrow;\", 0x219e),\n  CHAR_REF(\"twoheadrightarrow;\", 0x21a0),\n  CHAR_REF(\"uArr;\", 0x21d1),\n  CHAR_REF(\"uHar;\", 0x2963),\n  CHAR_REF(\"uacute;\", 0xfa),\n  CHAR_REF(\"uacute\", 0xfa),\n  CHAR_REF(\"uarr;\", 0x2191),\n  CHAR_REF(\"ubrcy;\", 0x045e),\n  CHAR_REF(\"ubreve;\", 0x016d),\n  CHAR_REF(\"ucirc;\", 0xfb),\n  CHAR_REF(\"ucirc\", 0xfb),\n  CHAR_REF(\"ucy;\", 0x0443),\n  CHAR_REF(\"udarr;\", 0x21c5),\n  CHAR_REF(\"udblac;\", 0x0171),\n  CHAR_REF(\"udhar;\", 0x296e),\n  CHAR_REF(\"ufisht;\", 0x297e),\n  CHAR_REF(\"ufr;\", 0x0001d532),\n  CHAR_REF(\"ugrave;\", 0xf9),\n  CHAR_REF(\"ugrave\", 0xf9),\n  CHAR_REF(\"uharl;\", 0x21bf),\n  CHAR_REF(\"uharr;\", 0x21be),\n  CHAR_REF(\"uhblk;\", 0x2580),\n  CHAR_REF(\"ulcorn;\", 0x231c),\n  CHAR_REF(\"ulcorner;\", 0x231c),\n  CHAR_REF(\"ulcrop;\", 0x230f),\n  CHAR_REF(\"ultri;\", 0x25f8),\n  CHAR_REF(\"umacr;\", 0x016b),\n  CHAR_REF(\"uml;\", 0xa8),\n  CHAR_REF(\"uml\", 0xa8),\n  CHAR_REF(\"uogon;\", 0x0173),\n  CHAR_REF(\"uopf;\", 0x0001d566),\n  CHAR_REF(\"uparrow;\", 0x2191),\n  CHAR_REF(\"updownarrow;\", 0x2195),\n  CHAR_REF(\"upharpoonleft;\", 0x21bf),\n  CHAR_REF(\"upharpoonright;\", 0x21be),\n  CHAR_REF(\"uplus;\", 0x228e),\n  CHAR_REF(\"upsi;\", 0x03c5),\n  CHAR_REF(\"upsih;\", 0x03d2),\n  CHAR_REF(\"upsilon;\", 0x03c5),\n  CHAR_REF(\"upuparrows;\", 0x21c8),\n  CHAR_REF(\"urcorn;\", 0x231d),\n  CHAR_REF(\"urcorner;\", 0x231d),\n  CHAR_REF(\"urcrop;\", 0x230e),\n  CHAR_REF(\"uring;\", 0x016f),\n  CHAR_REF(\"urtri;\", 0x25f9),\n  CHAR_REF(\"uscr;\", 0x0001d4ca),\n  CHAR_REF(\"utdot;\", 0x22f0),\n  CHAR_REF(\"utilde;\", 0x0169),\n  CHAR_REF(\"utri;\", 0x25b5),\n  CHAR_REF(\"utrif;\", 0x25b4),\n  CHAR_REF(\"uuarr;\", 0x21c8),\n  CHAR_REF(\"uuml;\", 0xfc),\n  CHAR_REF(\"uuml\", 0xfc),\n  CHAR_REF(\"uwangle;\", 0x29a7),\n  CHAR_REF(\"vArr;\", 0x21d5),\n  CHAR_REF(\"vBar;\", 0x2ae8),\n  CHAR_REF(\"vBarv;\", 0x2ae9),\n  CHAR_REF(\"vDash;\", 0x22a8),\n  CHAR_REF(\"vangrt;\", 0x299c),\n  CHAR_REF(\"varepsilon;\", 0x03f5),\n  CHAR_REF(\"varkappa;\", 0x03f0),\n  CHAR_REF(\"varnothing;\", 0x2205),\n  CHAR_REF(\"varphi;\", 0x03d5),\n  CHAR_REF(\"varpi;\", 0x03d6),\n  CHAR_REF(\"varpropto;\", 0x221d),\n  CHAR_REF(\"varr;\", 0x2195),\n  CHAR_REF(\"varrho;\", 0x03f1),\n  CHAR_REF(\"varsigma;\", 0x03c2),\n  MULTI_CHAR_REF(\"varsubsetneq;\", 0x228a, 0xfe00),\n  MULTI_CHAR_REF(\"varsubsetneqq;\", 0x2acb, 0xfe00),\n  MULTI_CHAR_REF(\"varsupsetneq;\", 0x228b, 0xfe00),\n  MULTI_CHAR_REF(\"varsupsetneqq;\", 0x2acc, 0xfe00),\n  CHAR_REF(\"vartheta;\", 0x03d1),\n  CHAR_REF(\"vartriangleleft;\", 0x22b2),\n  CHAR_REF(\"vartriangleright;\", 0x22b3),\n  CHAR_REF(\"vcy;\", 0x0432),\n  CHAR_REF(\"vdash;\", 0x22a2),\n  CHAR_REF(\"vee;\", 0x2228),\n  CHAR_REF(\"veebar;\", 0x22bb),\n  CHAR_REF(\"veeeq;\", 0x225a),\n  CHAR_REF(\"vellip;\", 0x22ee),\n  CHAR_REF(\"verbar;\", 0x7c),\n  CHAR_REF(\"vert;\", 0x7c),\n  CHAR_REF(\"vfr;\", 0x0001d533),\n  CHAR_REF(\"vltri;\", 0x22b2),\n  MULTI_CHAR_REF(\"vnsub;\", 0x2282, 0x20d2),\n  MULTI_CHAR_REF(\"vnsup;\", 0x2283, 0x20d2),\n  CHAR_REF(\"vopf;\", 0x0001d567),\n  CHAR_REF(\"vprop;\", 0x221d),\n  CHAR_REF(\"vrtri;\", 0x22b3),\n  CHAR_REF(\"vscr;\", 0x0001d4cb),\n  MULTI_CHAR_REF(\"vsubnE;\", 0x2acb, 0xfe00),\n  MULTI_CHAR_REF(\"vsubne;\", 0x228a, 0xfe00),\n  MULTI_CHAR_REF(\"vsupnE;\", 0x2acc, 0xfe00),\n  MULTI_CHAR_REF(\"vsupne;\", 0x228b, 0xfe00),\n  CHAR_REF(\"vzigzag;\", 0x299a),\n  CHAR_REF(\"wcirc;\", 0x0175),\n  CHAR_REF(\"wedbar;\", 0x2a5f),\n  CHAR_REF(\"wedge;\", 0x2227),\n  CHAR_REF(\"wedgeq;\", 0x2259),\n  CHAR_REF(\"weierp;\", 0x2118),\n  CHAR_REF(\"wfr;\", 0x0001d534),\n  CHAR_REF(\"wopf;\", 0x0001d568),\n  CHAR_REF(\"wp;\", 0x2118),\n  CHAR_REF(\"wr;\", 0x2240),\n  CHAR_REF(\"wreath;\", 0x2240),\n  CHAR_REF(\"wscr;\", 0x0001d4cc),\n  CHAR_REF(\"xcap;\", 0x22c2),\n  CHAR_REF(\"xcirc;\", 0x25ef),\n  CHAR_REF(\"xcup;\", 0x22c3),\n  CHAR_REF(\"xdtri;\", 0x25bd),\n  CHAR_REF(\"xfr;\", 0x0001d535),\n  CHAR_REF(\"xhArr;\", 0x27fa),\n  CHAR_REF(\"xharr;\", 0x27f7),\n  CHAR_REF(\"xi;\", 0x03be),\n  CHAR_REF(\"xlArr;\", 0x27f8),\n  CHAR_REF(\"xlarr;\", 0x27f5),\n  CHAR_REF(\"xmap;\", 0x27fc),\n  CHAR_REF(\"xnis;\", 0x22fb),\n  CHAR_REF(\"xodot;\", 0x2a00),\n  CHAR_REF(\"xopf;\", 0x0001d569),\n  CHAR_REF(\"xoplus;\", 0x2a01),\n  CHAR_REF(\"xotime;\", 0x2a02),\n  CHAR_REF(\"xrArr;\", 0x27f9),\n  CHAR_REF(\"xrarr;\", 0x27f6),\n  CHAR_REF(\"xscr;\", 0x0001d4cd),\n  CHAR_REF(\"xsqcup;\", 0x2a06),\n  CHAR_REF(\"xuplus;\", 0x2a04),\n  CHAR_REF(\"xutri;\", 0x25b3),\n  CHAR_REF(\"xvee;\", 0x22c1),\n  CHAR_REF(\"xwedge;\", 0x22c0),\n  CHAR_REF(\"yacute;\", 0xfd),\n  CHAR_REF(\"yacute\", 0xfd),\n  CHAR_REF(\"yacy;\", 0x044f),\n  CHAR_REF(\"ycirc;\", 0x0177),\n  CHAR_REF(\"ycy;\", 0x044b),\n  CHAR_REF(\"yen;\", 0xa5),\n  CHAR_REF(\"yen\", 0xa5),\n  CHAR_REF(\"yfr;\", 0x0001d536),\n  CHAR_REF(\"yicy;\", 0x0457),\n  CHAR_REF(\"yopf;\", 0x0001d56a),\n  CHAR_REF(\"yscr;\", 0x0001d4ce),\n  CHAR_REF(\"yucy;\", 0x044e),\n  CHAR_REF(\"yuml;\", 0xff),\n  CHAR_REF(\"yuml\", 0xff),\n  CHAR_REF(\"zacute;\", 0x017a),\n  CHAR_REF(\"zcaron;\", 0x017e),\n  CHAR_REF(\"zcy;\", 0x0437),\n  CHAR_REF(\"zdot;\", 0x017c),\n  CHAR_REF(\"zeetrf;\", 0x2128),\n  CHAR_REF(\"zeta;\", 0x03b6),\n  CHAR_REF(\"zfr;\", 0x0001d537),\n  CHAR_REF(\"zhcy;\", 0x0436),\n  CHAR_REF(\"zigrarr;\", 0x21dd),\n  CHAR_REF(\"zopf;\", 0x0001d56b),\n  CHAR_REF(\"zscr;\", 0x0001d4cf),\n  CHAR_REF(\"zwj;\", 0x200d),\n  CHAR_REF(\"zwnj;\", 0x200c),\n  // Terminator.\n  CHAR_REF(\"\", -1)\n};\n\n// Table of replacement characters.  The spec specifies that any occurrence of\n// the first character should be replaced by the second character, and a parse\n// error recorded.\ntypedef struct {\n  int from_char;\n  int to_char;\n} CharReplacement;\n\nstatic const CharReplacement kCharReplacements[] = {\n  { 0x00, 0xfffd },\n  { 0x0d, 0x000d },\n  { 0x80, 0x20ac },\n  { 0x81, 0x0081 },\n  { 0x82, 0x201A },\n  { 0x83, 0x0192 },\n  { 0x84, 0x201E },\n  { 0x85, 0x2026 },\n  { 0x86, 0x2020 },\n  { 0x87, 0x2021 },\n  { 0x88, 0x02C6 },\n  { 0x89, 0x2030 },\n  { 0x8A, 0x0160 },\n  { 0x8B, 0x2039 },\n  { 0x8C, 0x0152 },\n  { 0x8D, 0x008D },\n  { 0x8E, 0x017D },\n  { 0x8F, 0x008F },\n  { 0x90, 0x0090 },\n  { 0x91, 0x2018 },\n  { 0x92, 0x2019 },\n  { 0x93, 0x201C },\n  { 0x94, 0x201D },\n  { 0x95, 0x2022 },\n  { 0x96, 0x2013 },\n  { 0x97, 0x2014 },\n  { 0x98, 0x02DC },\n  { 0x99, 0x2122 },\n  { 0x9A, 0x0161 },\n  { 0x9B, 0x203A },\n  { 0x9C, 0x0153 },\n  { 0x9D, 0x009D },\n  { 0x9E, 0x017E },\n  { 0x9F, 0x0178 },\n  // Terminator.\n  { -1, -1 }\n};\n\nstatic int parse_digit(int c, bool allow_hex) {\n  if (c >= '0' && c <= '9') {\n    return c - '0';\n  }\n  if (allow_hex && c >= 'a' && c <= 'f') {\n    return c - 'a' + 10;\n  }\n  if (allow_hex && c >= 'A' && c <= 'F') {\n    return c - 'A' + 10;\n  }\n  return -1;\n}\n\nstatic void add_no_digit_error(\n    struct GumboInternalParser* parser, Utf8Iterator* input) {\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  utf8iterator_fill_error_at_mark(input, error);\n  error->type = GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS;\n}\n\nstatic void add_codepoint_error(\n    struct GumboInternalParser* parser, Utf8Iterator* input,\n    GumboErrorType type, int codepoint) {\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  utf8iterator_fill_error_at_mark(input, error);\n  error->type = type;\n  error->v.codepoint = codepoint;\n}\n\nstatic void add_named_reference_error(\n    struct GumboInternalParser* parser, Utf8Iterator* input,\n    GumboErrorType type, GumboStringPiece text) {\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  utf8iterator_fill_error_at_mark(input, error);\n  error->type = type;\n  error->v.text = text;\n}\n\nstatic int maybe_replace_codepoint(int codepoint) {\n  for (int i = 0; kCharReplacements[i].from_char != -1; ++i) {\n    if (kCharReplacements[i].from_char == codepoint) {\n      return kCharReplacements[i].to_char;\n    }\n  }\n  return -1;\n}\n\nstatic bool consume_numeric_ref(\n    struct GumboInternalParser* parser, Utf8Iterator* input, int* output) {\n  utf8iterator_next(input);\n  bool is_hex = false;\n  int c = utf8iterator_current(input);\n  if (c == 'x' || c == 'X') {\n    is_hex = true;\n    utf8iterator_next(input);\n    c = utf8iterator_current(input);\n  }\n\n  int digit = parse_digit(c, is_hex);\n  if (digit == -1) {\n    // First digit was invalid; add a parse error and return.\n    add_no_digit_error(parser, input);\n    utf8iterator_reset(input);\n    *output = kGumboNoChar;\n    return false;\n  }\n\n  int codepoint = 0;\n  bool status = true;\n  do {\n    codepoint = (codepoint * (is_hex ? 16 : 10)) + digit;\n    utf8iterator_next(input);\n    digit = parse_digit(utf8iterator_current(input), is_hex);\n  } while (digit != -1);\n\n  if (utf8iterator_current(input) != ';') {\n    add_codepoint_error(\n        parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON, codepoint);\n    status = false;\n  } else {\n    utf8iterator_next(input);\n  }\n\n  int replacement = maybe_replace_codepoint(codepoint);\n  if (replacement != -1) {\n    add_codepoint_error(\n        parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint);\n    *output = replacement;\n    return false;\n  }\n\n  if ((codepoint >= 0xd800 && codepoint <= 0xdfff) || codepoint > 0x10ffff) {\n    add_codepoint_error(\n        parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint);\n    *output = 0xfffd;\n    return false;\n  }\n\n  if (utf8_is_invalid_code_point(codepoint) || codepoint == 0xb) {\n    add_codepoint_error(\n        parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint);\n    status = false;\n    // But return it anyway, per spec.\n  }\n  *output = codepoint;\n  return status;\n}\n\nstatic const NamedCharRef* find_named_char_ref(Utf8Iterator* input) {\n  for (int i = 0; kNamedEntities[i].codepoints.first != -1; ++i) {\n    const NamedCharRef* current = &kNamedEntities[i];\n    assert(strlen(current->name) == current->length);\n    if (utf8iterator_maybe_consume_match(\n        input, current->name, current->length, true)) {\n      assert(current->name != NULL);\n      assert(current->length > 0);\n      assert(current->codepoints.first != kGumboNoChar);\n      return current;\n    }\n  }\n  return NULL;\n}\n\nstatic bool is_legal_attribute_char_next(Utf8Iterator* input) {\n  int c = utf8iterator_current(input);\n  return c == '=' || isalnum(c);\n}\n\nstatic bool maybe_add_invalid_named_reference(\n    struct GumboInternalParser* parser, Utf8Iterator* input) {\n  // The iterator will always be reset in this code path, so we don't need to\n  // worry about consuming characters.\n  const char* start = utf8iterator_get_char_pointer(input);\n  int c = utf8iterator_current(input);\n  while ((c >= 'a' && c <= 'z') ||\n         (c >= 'A' && c <= 'Z') ||\n         (c >= '0' && c <= '9')) {\n    utf8iterator_next(input);\n    c = utf8iterator_current(input);\n  }\n  if (c == ';') {\n    GumboStringPiece bad_ref;\n    bad_ref.data = start;\n    bad_ref.length = utf8iterator_get_char_pointer(input) - start;\n    add_named_reference_error(\n        parser, input, GUMBO_ERR_NAMED_CHAR_REF_INVALID, bad_ref);\n    return false;\n  }\n  return true;\n}\n\nstatic bool consume_named_ref(\n    struct GumboInternalParser* parser, Utf8Iterator* input, bool is_in_attribute,\n    OneOrTwoCodepoints* output) {\n  assert(output->first == kGumboNoChar);\n  const NamedCharRef* char_ref = find_named_char_ref(input);\n  if (char_ref) {\n    assert(char_ref->length == strlen(char_ref->name));\n    char last_char = char_ref->name[char_ref->length - 1];\n    if (last_char == ';') {\n      *output = char_ref->codepoints;\n      assert(output->first != kGumboNoChar);\n      return true;\n    } else if (is_in_attribute && is_legal_attribute_char_next(input)) {\n      utf8iterator_reset(input);\n      return true;\n    } else {\n      GumboStringPiece bad_ref;\n      bad_ref.data = char_ref->name;\n      bad_ref.length = char_ref->length;\n      add_named_reference_error(\n          parser, input, GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON, bad_ref);\n      *output = char_ref->codepoints;\n      assert(output->first != kGumboNoChar);\n      return false;\n    }\n  } else {\n    bool status = maybe_add_invalid_named_reference(parser, input);\n    utf8iterator_reset(input);\n    return status;\n  }\n}\n\nbool consume_char_ref(\n    struct GumboInternalParser* parser, struct GumboInternalUtf8Iterator* input,\n    int additional_allowed_char, bool is_in_attribute,\n    OneOrTwoCodepoints* output) {\n  utf8iterator_mark(input);\n  utf8iterator_next(input);\n  int c = utf8iterator_current(input);\n  output->first = kGumboNoChar;\n  output->second = kGumboNoChar;\n  if (c == additional_allowed_char) {\n    utf8iterator_reset(input);\n    output->first = kGumboNoChar;\n    return true;\n  }\n  switch (utf8iterator_current(input)) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n    case '<':\n    case '&':\n    case -1:\n      utf8iterator_reset(input);\n      return true;\n    case '#':\n      return consume_numeric_ref(parser, input, &output->first);\n    default:\n      return consume_named_ref(parser, input, is_in_attribute, output);\n  }\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/char_ref.h",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// Internal header for character reference handling; this should not be exposed\n// transitively by any public API header.  This is why the functions aren't\n// namespaced.\n\n#ifndef GUMBO_CHAR_REF_H_\n#define GUMBO_CHAR_REF_H_\n\n#include <stdbool.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\nstruct GumboInternalUtf8Iterator;\n\n// Value that indicates no character was produced.\nextern const int kGumboNoChar;\n\n// Certain named character references generate two codepoints, not one, and so\n// the consume_char_ref subroutine needs to return this instead of an int.  The\n// first field will be kGumboNoChar if no character reference was found; the\n// second field will be kGumboNoChar if that is the case or if the character\n// reference returns only a single codepoint.\ntypedef struct {\n  int first;\n  int second;\n} OneOrTwoCodepoints;\n\n// Implements the \"consume a character reference\" section of the spec.\n// This reads in characters from the input as necessary, and fills in a\n// OneOrTwoCodepoints struct containing the characters read.  It may add parse\n// errors to the GumboParser's errors vector, if the spec calls for it.  Pass a\n// space for the \"additional allowed char\" when the spec says \"with no\n// additional allowed char\".  Returns false on parse error, true otherwise.\nbool consume_char_ref(\n    struct GumboInternalParser* parser, struct GumboInternalUtf8Iterator* input,\n    int additional_allowed_char, bool is_in_attribute,\n    OneOrTwoCodepoints* output);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_CHAR_REF_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/error.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"error.h\"\n\n#include <assert.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"gumbo.h\"\n#include \"parser.h\"\n#include \"string_buffer.h\"\n#include \"util.h\"\n#include \"vector.h\"\n\n//static const size_t kMessageBufferSize = 256;\n\n// Prints a formatted message to a StringBuffer.  This automatically resizes the\n// StringBuffer as necessary to fit the message.  Returns the number of bytes\n// written.\nstatic int print_message(GumboParser* parser, GumboStringBuffer* output,\n                         const char* format, ...) {\n  va_list args;\n  va_start(args, format);\n  unsigned long remaining_capacity = output->capacity - output->length;\n  int bytes_written = vsnprintf(output->data + output->length,\n                                remaining_capacity, format, args);\n  if (bytes_written > remaining_capacity) {\n    gumbo_string_buffer_reserve(\n        parser, output->capacity + bytes_written, output);\n    remaining_capacity = output->capacity - output->length;\n    bytes_written = vsnprintf(output->data + output->length,\n                              remaining_capacity, format, args);\n  }\n  output->length += bytes_written;\n  va_end(args);\n  return bytes_written;\n}\n\nstatic void print_tag_stack(\n    GumboParser* parser, const GumboParserError* error,\n    GumboStringBuffer* output) {\n  print_message(parser, output, \"  Currently open tags: \");\n  for (int i = 0; i < error->tag_stack.length; ++i) {\n    if (i) {\n      print_message(parser, output, \", \");\n    }\n    GumboTag tag = (GumboTag) error->tag_stack.data[i];\n    print_message(parser, output, gumbo_normalized_tagname(tag));\n  }\n  gumbo_string_buffer_append_codepoint(parser, '.', output);\n}\n\nstatic void handle_parser_error(GumboParser* parser,\n                                const GumboParserError* error,\n                                GumboStringBuffer* output) {\n  if (error->parser_state == GUMBO_INSERTION_MODE_INITIAL &&\n      error->input_type != GUMBO_TOKEN_DOCTYPE) {\n    print_message(parser, output,\n                  \"The doctype must be the first token in the document\");\n    return;\n  }\n\n  switch (error->input_type) {\n    case GUMBO_TOKEN_DOCTYPE:\n      print_message(parser, output, \"This is not a legal doctype\");\n      return;\n    case GUMBO_TOKEN_COMMENT:\n      // Should never happen; comments are always legal.\n      assert(0);\n      // But just in case...\n      print_message(parser, output, \"Comments aren't legal here\");\n      return;\n    case GUMBO_TOKEN_WHITESPACE:\n    case GUMBO_TOKEN_CHARACTER:\n      print_message(parser, output, \"Character tokens aren't legal here\");\n      return;\n    case GUMBO_TOKEN_NULL:\n      print_message(parser, output, \"Null bytes are not allowed in HTML5\");\n      return;\n    case GUMBO_TOKEN_EOF:\n      if (error->parser_state == GUMBO_INSERTION_MODE_INITIAL) {\n        print_message(parser, output, \"You must provide a doctype\");\n      } else {\n        print_message(parser, output, \"Premature end of file\");\n        print_tag_stack(parser, error, output);\n      }\n      return;\n    case GUMBO_TOKEN_START_TAG:\n    case GUMBO_TOKEN_END_TAG:\n      print_message(parser, output, \"That tag isn't allowed here\");\n      print_tag_stack(parser, error, output);\n      // TODO(jdtang): Give more specific messaging.\n      return;\n  }\n}\n\n// Finds the preceding newline in an original source buffer from a given byte\n// location.  Returns a character pointer to the character after that, or a\n// pointer to the beginning of the string if this is the first line.\nstatic const char* find_last_newline(\n    const char* original_text, const char* error_location) {\n  assert(error_location >= original_text);\n  const char* c = error_location;\n  for (; c != original_text && *c != '\\n'; --c) {\n    // There may be an error at EOF, which would be a nul byte.\n    assert(*c || c == error_location);\n  }\n  return c == original_text ? c : c + 1;\n}\n\n// Finds the next newline in the original source buffer from a given byte\n// location.  Returns a character pointer to that newline, or a pointer to the\n// terminating null byte if this is the last line.\nstatic const char* find_next_newline(\n    const char* original_text, const char* error_location) {\n  const char* c = error_location;\n  for (; *c && *c != '\\n'; ++c);\n  return c;\n}\n\nGumboError* gumbo_add_error(GumboParser* parser) {\n  int max_errors = parser->_options->max_errors;\n  if (max_errors < 0 && parser->_output->errors.length >= max_errors) {\n    return NULL;\n  }\n  GumboError* error = gumbo_parser_allocate(parser, sizeof(GumboError));\n  gumbo_vector_add(parser, error, &parser->_output->errors);\n  return error;\n}\n\nvoid gumbo_error_to_string(\n    GumboParser* parser, const GumboError* error, GumboStringBuffer* output) {\n  print_message(parser, output, \"@%d:%d: \",\n                error->position.line, error->position.column);\n  switch (error->type) {\n    case GUMBO_ERR_UTF8_INVALID:\n      print_message(parser, output, \"Invalid UTF8 character 0x%x\",\n               error->v.codepoint);\n      break;\n    case GUMBO_ERR_UTF8_TRUNCATED:\n      print_message(parser, output,\n               \"Input stream ends with a truncated UTF8 character 0x%x\",\n               error->v.codepoint);\n      break;\n    case GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS:\n      print_message(parser, output,\n               \"No digits after &# in numeric character reference\");\n      break;\n    case GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON:\n      print_message(parser, output,\n               \"The numeric character reference &#%d should be followed \"\n               \"by a semicolon\", error->v.codepoint);\n      break;\n    case GUMBO_ERR_NUMERIC_CHAR_REF_INVALID:\n      print_message(parser, output,\n               \"The numeric character reference &#%d; encodes an invalid \"\n               \"unicode codepoint\", error->v.codepoint);\n      break;\n    case GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON:\n      // The textual data came from one of the literal strings in the table, and\n      // so it'll be null-terminated.\n      print_message(parser, output,\n               \"The named character reference &%.*s should be followed by a \"\n               \"semicolon\", (int) error->v.text.length, error->v.text.data);\n      break;\n    case GUMBO_ERR_NAMED_CHAR_REF_INVALID:\n      print_message(parser, output,\n               \"The named character reference &%.*s; is not a valid entity name\",\n               (int) error->v.text.length, error->v.text.data);\n      break;\n    case GUMBO_ERR_DUPLICATE_ATTR:\n      print_message(parser, output,\n               \"Attribute %s occurs multiple times, at positions %d and %d\",\n               error->v.duplicate_attr.name,\n               error->v.duplicate_attr.original_index,\n               error->v.duplicate_attr.new_index);\n      break;\n    case GUMBO_ERR_PARSER:\n    case GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG:\n      handle_parser_error(parser, &error->v.parser, output);\n      break;\n    default:\n      print_message(parser, output,\n               \"Tokenizer error with an unimplemented error message\");\n      break;\n  }\n  gumbo_string_buffer_append_codepoint(parser, '.', output);\n}\n\nvoid gumbo_caret_diagnostic_to_string(\n    GumboParser* parser, const GumboError* error,\n    const char* source_text, GumboStringBuffer* output) {\n  gumbo_error_to_string(parser, error, output);\n\n  const char* line_start =\n      find_last_newline(source_text, error->original_text);\n  const char* line_end =\n      find_next_newline(source_text, error->original_text);\n  GumboStringPiece original_line;\n  original_line.data = line_start;\n  original_line.length = line_end - line_start;\n\n  gumbo_string_buffer_append_codepoint(parser, '\\n', output);\n  gumbo_string_buffer_append_string(parser, &original_line, output);\n  gumbo_string_buffer_append_codepoint(parser, '\\n', output);\n  gumbo_string_buffer_reserve(\n      parser, output->length + error->position.column, output);\n  int num_spaces = error->position.column - 1;\n  memset(output->data + output->length, ' ', num_spaces);\n  output->length += num_spaces;\n  gumbo_string_buffer_append_codepoint(parser, '^', output);\n  gumbo_string_buffer_append_codepoint(parser, '\\n', output);\n}\n\nvoid gumbo_print_caret_diagnostic(\n    GumboParser* parser, const GumboError* error, const char* source_text) {\n  GumboStringBuffer text;\n  gumbo_string_buffer_init(parser, &text);\n  gumbo_caret_diagnostic_to_string(parser, error, source_text, &text);\n  printf(\"%.*s\", (int) text.length, text.data);\n  gumbo_string_buffer_destroy(parser, &text);\n}\n\nvoid gumbo_error_destroy(GumboParser* parser, GumboError* error) {\n  if (error->type == GUMBO_ERR_PARSER ||\n      error->type == GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG) {\n    gumbo_vector_destroy(parser, &error->v.parser.tag_stack);\n  } else if (error->type == GUMBO_ERR_DUPLICATE_ATTR) {\n    gumbo_parser_deallocate(parser, (void*) error->v.duplicate_attr.name);\n  }\n  gumbo_parser_deallocate(parser, error);\n}\n\nvoid gumbo_init_errors(GumboParser* parser) {\n  gumbo_vector_init(parser, 5, &parser->_output->errors);\n}\n\nvoid gumbo_destroy_errors(GumboParser* parser) {\n  for (int i = 0; i < parser->_output->errors.length; ++i) {\n    gumbo_error_destroy(parser, parser->_output->errors.data[i]);\n  }\n  gumbo_vector_destroy(parser, &parser->_output->errors);\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/error.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// Error types, enums, and handling functions.\n\n#ifndef GUMBO_ERROR_H_\n#define GUMBO_ERROR_H_\n\n#include <stdint.h>\n\n#include \"gumbo.h\"\n#include \"insertion_mode.h\"\n#include \"string_buffer.h\"\n#include \"token_type.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\n\ntypedef enum {\n  GUMBO_ERR_UTF8_INVALID,\n  GUMBO_ERR_UTF8_TRUNCATED,\n  GUMBO_ERR_UTF8_NULL,\n  GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS,\n  GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON,\n  GUMBO_ERR_NUMERIC_CHAR_REF_INVALID,\n  GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON,\n  GUMBO_ERR_NAMED_CHAR_REF_INVALID,\n  GUMBO_ERR_TAG_STARTS_WITH_QUESTION,\n  GUMBO_ERR_TAG_EOF,\n  GUMBO_ERR_TAG_INVALID,\n  GUMBO_ERR_CLOSE_TAG_EMPTY,\n  GUMBO_ERR_CLOSE_TAG_EOF,\n  GUMBO_ERR_CLOSE_TAG_INVALID,\n  GUMBO_ERR_SCRIPT_EOF,\n  GUMBO_ERR_ATTR_NAME_EOF,\n  GUMBO_ERR_ATTR_NAME_INVALID,\n  GUMBO_ERR_ATTR_DOUBLE_QUOTE_EOF,\n  GUMBO_ERR_ATTR_SINGLE_QUOTE_EOF,\n  GUMBO_ERR_ATTR_UNQUOTED_EOF,\n  GUMBO_ERR_ATTR_UNQUOTED_RIGHT_BRACKET,\n  GUMBO_ERR_ATTR_UNQUOTED_EQUALS,\n  GUMBO_ERR_ATTR_AFTER_EOF,\n  GUMBO_ERR_ATTR_AFTER_INVALID,\n  GUMBO_ERR_DUPLICATE_ATTR,\n  GUMBO_ERR_SOLIDUS_EOF,\n  GUMBO_ERR_SOLIDUS_INVALID,\n  GUMBO_ERR_DASHES_OR_DOCTYPE,\n  GUMBO_ERR_COMMENT_EOF,\n  GUMBO_ERR_COMMENT_INVALID,\n  GUMBO_ERR_COMMENT_BANG_AFTER_DOUBLE_DASH,\n  GUMBO_ERR_COMMENT_DASH_AFTER_DOUBLE_DASH,\n  GUMBO_ERR_COMMENT_SPACE_AFTER_DOUBLE_DASH,\n  GUMBO_ERR_COMMENT_END_BANG_EOF,\n  GUMBO_ERR_DOCTYPE_EOF,\n  GUMBO_ERR_DOCTYPE_INVALID,\n  GUMBO_ERR_DOCTYPE_SPACE,\n  GUMBO_ERR_DOCTYPE_RIGHT_BRACKET,\n  GUMBO_ERR_DOCTYPE_SPACE_OR_RIGHT_BRACKET,\n  GUMBO_ERR_DOCTYPE_END,\n  GUMBO_ERR_PARSER,\n  GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG,\n} GumboErrorType;\n\n// Additional data for duplicated attributes.\ntypedef struct GumboInternalDuplicateAttrError {\n  // The name of the attribute.  Owned by this struct.\n  const char* name;\n\n  // The (0-based) index within the attributes vector of the original\n  // occurrence.\n  unsigned int original_index;\n\n  // The (0-based) index where the new occurrence would be.\n  unsigned int new_index;\n} GumboDuplicateAttrError;\n\n// A simplified representation of the tokenizer state, designed to be more\n// useful to clients of this library than the internal representation.  This\n// condenses the actual states used in the tokenizer state machine into a few\n// values that will be familiar to users of HTML.\ntypedef enum {\n  GUMBO_ERR_TOKENIZER_DATA,\n  GUMBO_ERR_TOKENIZER_CHAR_REF,\n  GUMBO_ERR_TOKENIZER_RCDATA,\n  GUMBO_ERR_TOKENIZER_RAWTEXT,\n  GUMBO_ERR_TOKENIZER_PLAINTEXT,\n  GUMBO_ERR_TOKENIZER_SCRIPT,\n  GUMBO_ERR_TOKENIZER_TAG,\n  GUMBO_ERR_TOKENIZER_SELF_CLOSING_TAG,\n  GUMBO_ERR_TOKENIZER_ATTR_NAME,\n  GUMBO_ERR_TOKENIZER_ATTR_VALUE,\n  GUMBO_ERR_TOKENIZER_MARKUP_DECLARATION,\n  GUMBO_ERR_TOKENIZER_COMMENT,\n  GUMBO_ERR_TOKENIZER_DOCTYPE,\n  GUMBO_ERR_TOKENIZER_CDATA,\n} GumboTokenizerErrorState;\n\n// Additional data for tokenizer errors.\n// This records the current state and codepoint encountered - this is usually\n// enough to reconstruct what went wrong and provide a friendly error message.\ntypedef struct GumboInternalTokenizerError {\n  // The bad codepoint encountered.\n  int codepoint;\n\n  // The state that the tokenizer was in at the time.\n  GumboTokenizerErrorState state;\n} GumboTokenizerError;\n\n// Additional data for parse errors.\ntypedef struct GumboInternalParserError {\n  // The type of input token that resulted in this error.\n  GumboTokenType input_type;\n\n  // The HTML tag of the input token.  TAG_UNKNOWN if this was not a tag token.\n  GumboTag input_tag;\n\n  // The insertion mode that the parser was in at the time.\n  GumboInsertionMode parser_state;\n\n  // The tag stack at the point of the error.  Note that this is an GumboVector\n  // of GumboTag's *stored by value* - cast the void* to an GumboTag directly to\n  // get at the tag.\n  GumboVector /* GumboTag */ tag_stack;\n} GumboParserError;\n\n// The overall error struct representing an error in decoding/tokenizing/parsing\n// the HTML.  This contains an enumerated type flag, a source position, and then\n// a union of fields containing data specific to the error.\ntypedef struct GumboInternalError {\n  // The type of error.\n  GumboErrorType type;\n\n  // The position within the source file where the error occurred.\n  GumboSourcePosition position;\n\n  // A pointer to the byte within the original source file text where the error\n  // occurred (note that this is not the same as position.offset, as that gives\n  // character-based instead of byte-based offsets).\n  const char* original_text;\n\n  // Type-specific error information.\n  union {\n    // The code point we encountered, for:\n    // * GUMBO_ERR_UTF8_INVALID\n    // * GUMBO_ERR_UTF8_TRUNCATED\n    // * GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON\n    // * GUMBO_ERR_NUMERIC_CHAR_REF_INVALID\n    uint64_t codepoint;\n\n    // Tokenizer errors.\n    GumboTokenizerError tokenizer;\n\n    // Short textual data, for:\n    // * GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON\n    // * GUMBO_ERR_NAMED_CHAR_REF_INVALID\n    GumboStringPiece text;\n\n    // Duplicate attribute data, for GUMBO_ERR_DUPLICATE_ATTR.\n    GumboDuplicateAttrError duplicate_attr;\n\n    // Parser state, for GUMBO_ERR_PARSER and\n    // GUMBO_ERR_UNACKNOWLEDGE_SELF_CLOSING_TAG.\n    struct GumboInternalParserError parser;\n  } v;\n} GumboError;\n\n// Adds a new error to the parser's error list, and returns a pointer to it so\n// that clients can fill out the rest of its fields.  May return NULL if we're\n// already over the max_errors field specified in GumboOptions.\nGumboError* gumbo_add_error(struct GumboInternalParser* parser);\n\n// Initializes the errors vector in the parser.\nvoid gumbo_init_errors(struct GumboInternalParser* errors);\n\n// Frees all the errors in the 'errors_' field of the parser.\nvoid gumbo_destroy_errors(struct GumboInternalParser* errors);\n\n// Frees the memory used for a single GumboError.\nvoid gumbo_error_destroy(struct GumboInternalParser* parser, GumboError* error);\n\n// Prints an error to a string.  This fills an empty GumboStringBuffer with a\n// freshly-allocated buffer containing the error message text.  The caller is\n// responsible for deleting the buffer.  (Note that the buffer is allocated with\n// the allocator specified in the GumboParser config and hence should be freed\n// by gumbo_parser_deallocate().)\nvoid gumbo_error_to_string(\n    struct GumboInternalParser* parser, const GumboError* error,\n    GumboStringBuffer* output);\n\n// Prints a caret diagnostic to a string.  This fills an empty GumboStringBuffer\n// with a freshly-allocated buffer containing the error message text.  The\n// caller is responsible for deleting the buffer.  (Note that the buffer is\n// allocated with the allocator specified in the GumboParser config and hence\n// should be freed by gumbo_parser_deallocate().)\nvoid gumbo_caret_diagnostic_to_string(\n    struct GumboInternalParser* parser, const GumboError* error,\n    const char* source_text, GumboStringBuffer* output);\n\n// Like gumbo_caret_diagnostic_to_string, but prints the text to stdout instead\n// of writing to a string.\nvoid gumbo_print_caret_diagnostic(\n    struct GumboInternalParser* parser, const GumboError* error,\n    const char* source_text);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_ERROR_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/gumbo.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// We use Gumbo as a prefix for types, gumbo_ as a prefix for functions, and\n// GUMBO_ as a prefix for enum constants (static constants get the Google-style\n// kGumbo prefix).\n\n/**\n * @file\n * @mainpage Gumbo HTML Parser\n *\n * This provides a conformant, no-dependencies implementation of the HTML5\n * parsing algorithm.  It supports only UTF8; if you need to parse a different\n * encoding, run a preprocessing step to convert to UTF8.  It returns a parse\n * tree made of the structs in this file.\n *\n * Example:\n * @code\n *    GumboOutput* output = gumbo_parse(input);\n *    do_something_with_doctype(output->document);\n *    do_something_with_html_tree(output->root);\n *    gumbo_destroy_output(&options, output);\n * @endcode\n * HTML5 Spec:\n *\n * http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html\n */\n\n#ifndef GUMBO_GUMBO_H_\n#define GUMBO_GUMBO_H_\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * A struct representing a character position within the original text buffer.\n * Line and column numbers are 1-based and offsets are 0-based, which matches\n * how most editors and command-line tools work.  Also, columns measure\n * positions in terms of characters while offsets measure by bytes; this is\n * because the offset field is often used to pull out a particular region of\n * text (which in most languages that bind to C implies pointer arithmetic on a\n * buffer of bytes), while the column field is often used to reference a\n * particular column on a printable display, which nowadays is usually UTF-8.\n */\ntypedef struct {\n  unsigned int line;\n  unsigned int column;\n  unsigned int offset;\n} GumboSourcePosition;\n\n/**\n * A SourcePosition used for elements that have no source position, i.e.\n * parser-inserted elements.\n */\nextern const GumboSourcePosition kGumboEmptySourcePosition;\n\n\n/**\n * A struct representing a string or part of a string.  Strings within the\n * parser are represented by a char* and a length; the char* points into\n * an existing data buffer owned by some other code (often the original input).\n * GumboStringPieces are assumed (by convention) to be immutable, because they\n * may share data.  Use GumboStringBuffer if you need to construct a string.\n * Clients should assume that it is not NUL-terminated, and should always use\n * explicit lengths when manipulating them.\n */\ntypedef struct {\n  /** A pointer to the beginning of the string.  NULL iff length == 0. */\n  const char* data;\n\n  /** The length of the string fragment, in bytes.  May be zero. */\n  size_t length;\n} GumboStringPiece;\n\n/** A constant to represent a 0-length null string. */\nextern const GumboStringPiece kGumboEmptyString;\n\n/**\n * Compares two GumboStringPieces, and returns true if they're equal or false\n * otherwise.\n */\nbool gumbo_string_equals(\n    const GumboStringPiece* str1, const GumboStringPiece* str2);\n\n/**\n * Compares two GumboStringPieces ignoring case, and returns true if they're\n * equal or false otherwise.\n */\nbool gumbo_string_equals_ignore_case(\n    const GumboStringPiece* str1, const GumboStringPiece* str2);\n\n\n/**\n * A simple vector implementation.  This stores a pointer to a data array and a\n * length.  All elements are stored as void*; client code must cast to the\n * appropriate type.  Overflows upon addition result in reallocation of the data\n * array, with the size doubling to maintain O(1) amortized cost.  There is no\n * removal function, as this isn't needed for any of the operations within this\n * library.  Iteration can be done through inspecting the structure directly in\n * a for-loop.\n */\ntypedef struct {\n  /** Data elements.  This points to a dynamically-allocated array of capacity\n   * elements, each a void* to the element itself.\n   */\n  void** data;\n\n  /** Number of elements currently in the vector. */\n  unsigned int length;\n\n  /** Current array capacity. */\n  unsigned int capacity;\n} GumboVector;\n\n/** An empty (0-length, 0-capacity) GumboVector. */\nextern const GumboVector kGumboEmptyVector;\n\n/**\n * Returns the first index at which an element appears in this vector (testing\n * by pointer equality), or -1 if it never does.\n */\nint gumbo_vector_index_of(GumboVector* vector, void* element);\n\n\n/**\n * An enum for all the tags defined in the HTML5 standard.  These correspond to\n * the tag names themselves.  Enum constants exist only for tags which appear in\n * the spec itself (or for tags with special handling in the SVG and MathML\n * namespaces); any other tags appear as GUMBO_TAG_UNKNOWN and the actual tag\n * name can be obtained through original_tag.\n *\n * This is mostly for API convenience, so that clients of this library don't\n * need to perform a strcasecmp to find the normalized tag name.  It also has\n * efficiency benefits, by letting the parser work with enums instead of\n * strings.\n */\ntypedef enum {\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#the-root-element\n  GUMBO_TAG_HTML,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#document-metadata\n  GUMBO_TAG_HEAD,\n  GUMBO_TAG_TITLE,\n  GUMBO_TAG_BASE,\n  GUMBO_TAG_LINK,\n  GUMBO_TAG_META,\n  GUMBO_TAG_STYLE,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#scripting-1\n  GUMBO_TAG_SCRIPT,\n  GUMBO_TAG_NOSCRIPT,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/sections.html#sections\n  GUMBO_TAG_BODY,\n  GUMBO_TAG_SECTION,\n  GUMBO_TAG_NAV,\n  GUMBO_TAG_ARTICLE,\n  GUMBO_TAG_ASIDE,\n  GUMBO_TAG_H1,\n  GUMBO_TAG_H2,\n  GUMBO_TAG_H3,\n  GUMBO_TAG_H4,\n  GUMBO_TAG_H5,\n  GUMBO_TAG_H6,\n  GUMBO_TAG_HGROUP,\n  GUMBO_TAG_HEADER,\n  GUMBO_TAG_FOOTER,\n  GUMBO_TAG_ADDRESS,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/grouping-content.html#grouping-content\n  GUMBO_TAG_P,\n  GUMBO_TAG_HR,\n  GUMBO_TAG_PRE,\n  GUMBO_TAG_BLOCKQUOTE,\n  GUMBO_TAG_OL,\n  GUMBO_TAG_UL,\n  GUMBO_TAG_LI,\n  GUMBO_TAG_DL,\n  GUMBO_TAG_DT,\n  GUMBO_TAG_DD,\n  GUMBO_TAG_FIGURE,\n  GUMBO_TAG_FIGCAPTION,\n  GUMBO_TAG_DIV,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#text-level-semantics\n  GUMBO_TAG_A,\n  GUMBO_TAG_EM,\n  GUMBO_TAG_STRONG,\n  GUMBO_TAG_SMALL,\n  GUMBO_TAG_S,\n  GUMBO_TAG_CITE,\n  GUMBO_TAG_Q,\n  GUMBO_TAG_DFN,\n  GUMBO_TAG_ABBR,\n  GUMBO_TAG_TIME,\n  GUMBO_TAG_CODE,\n  GUMBO_TAG_VAR,\n  GUMBO_TAG_SAMP,\n  GUMBO_TAG_KBD,\n  GUMBO_TAG_SUB,\n  GUMBO_TAG_SUP,\n  GUMBO_TAG_I,\n  GUMBO_TAG_B,\n  GUMBO_TAG_MARK,\n  GUMBO_TAG_RUBY,\n  GUMBO_TAG_RT,\n  GUMBO_TAG_RP,\n  GUMBO_TAG_BDI,\n  GUMBO_TAG_BDO,\n  GUMBO_TAG_SPAN,\n  GUMBO_TAG_BR,\n  GUMBO_TAG_WBR,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#edits\n  GUMBO_TAG_INS,\n  GUMBO_TAG_DEL,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#embedded-content-1\n  GUMBO_TAG_IMAGE,\n  GUMBO_TAG_IMG,\n  GUMBO_TAG_IFRAME,\n  GUMBO_TAG_EMBED,\n  GUMBO_TAG_OBJECT,\n  GUMBO_TAG_PARAM,\n  GUMBO_TAG_VIDEO,\n  GUMBO_TAG_AUDIO,\n  GUMBO_TAG_SOURCE,\n  GUMBO_TAG_TRACK,\n  GUMBO_TAG_CANVAS,\n  GUMBO_TAG_MAP,\n  GUMBO_TAG_AREA,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-map-element.html#mathml\n  GUMBO_TAG_MATH,\n  GUMBO_TAG_MI,\n  GUMBO_TAG_MO,\n  GUMBO_TAG_MN,\n  GUMBO_TAG_MS,\n  GUMBO_TAG_MTEXT,\n  GUMBO_TAG_MGLYPH,\n  GUMBO_TAG_MALIGNMARK,\n  GUMBO_TAG_ANNOTATION_XML,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-map-element.html#svg-0\n  GUMBO_TAG_SVG,\n  GUMBO_TAG_FOREIGNOBJECT,\n  GUMBO_TAG_DESC,\n  // SVG title tags will have GUMBO_TAG_TITLE as with HTML.\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/tabular-data.html#tabular-data\n  GUMBO_TAG_TABLE,\n  GUMBO_TAG_CAPTION,\n  GUMBO_TAG_COLGROUP,\n  GUMBO_TAG_COL,\n  GUMBO_TAG_TBODY,\n  GUMBO_TAG_THEAD,\n  GUMBO_TAG_TFOOT,\n  GUMBO_TAG_TR,\n  GUMBO_TAG_TD,\n  GUMBO_TAG_TH,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms\n  GUMBO_TAG_FORM,\n  GUMBO_TAG_FIELDSET,\n  GUMBO_TAG_LEGEND,\n  GUMBO_TAG_LABEL,\n  GUMBO_TAG_INPUT,\n  GUMBO_TAG_BUTTON,\n  GUMBO_TAG_SELECT,\n  GUMBO_TAG_DATALIST,\n  GUMBO_TAG_OPTGROUP,\n  GUMBO_TAG_OPTION,\n  GUMBO_TAG_TEXTAREA,\n  GUMBO_TAG_KEYGEN,\n  GUMBO_TAG_OUTPUT,\n  GUMBO_TAG_PROGRESS,\n  GUMBO_TAG_METER,\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#interactive-elements\n  GUMBO_TAG_DETAILS,\n  GUMBO_TAG_SUMMARY,\n  GUMBO_TAG_COMMAND,\n  GUMBO_TAG_MENU,\n  // Non-conforming elements that nonetheless appear in the HTML5 spec.\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#non-conforming-features\n  GUMBO_TAG_APPLET,\n  GUMBO_TAG_ACRONYM,\n  GUMBO_TAG_BGSOUND,\n  GUMBO_TAG_DIR,\n  GUMBO_TAG_FRAME,\n  GUMBO_TAG_FRAMESET,\n  GUMBO_TAG_NOFRAMES,\n  GUMBO_TAG_ISINDEX,\n  GUMBO_TAG_LISTING,\n  GUMBO_TAG_XMP,\n  GUMBO_TAG_NEXTID,\n  GUMBO_TAG_NOEMBED,\n  GUMBO_TAG_PLAINTEXT,\n  GUMBO_TAG_RB,\n  GUMBO_TAG_STRIKE,\n  GUMBO_TAG_BASEFONT,\n  GUMBO_TAG_BIG,\n  GUMBO_TAG_BLINK,\n  GUMBO_TAG_CENTER,\n  GUMBO_TAG_FONT,\n  GUMBO_TAG_MARQUEE,\n  GUMBO_TAG_MULTICOL,\n  GUMBO_TAG_NOBR,\n  GUMBO_TAG_SPACER,\n  GUMBO_TAG_TT,\n  GUMBO_TAG_U,\n  // Used for all tags that don't have special handling in HTML.\n  GUMBO_TAG_UNKNOWN,\n  // A marker value to indicate the end of the enum, for iterating over it.\n  // Also used as the terminator for varargs functions that take tags.\n  GUMBO_TAG_LAST,\n} GumboTag;\n\n/**\n * Returns the normalized (usually all-lowercased, except for foreign content)\n * tag name for an GumboTag enum.  Return value is static data owned by the\n * library.\n */\nconst char* gumbo_normalized_tagname(GumboTag tag);\n\n/**\n * Extracts the tag name from the original_text field of an element or token by\n * stripping off </> characters and attributes and adjusting the passed-in\n * GumboStringPiece appropriately.  The tag name is in the original case and\n * shares a buffer with the original text, to simplify memory management.\n * Behavior is undefined if a string-piece that doesn't represent an HTML tag\n * (<tagname> or </tagname>) is passed in.  If the string piece is completely\n * empty (NULL data pointer), then this function will exit successfully as a\n * no-op.\n */\nvoid gumbo_tag_from_original_text(GumboStringPiece* text);\n\n/**\n * Fixes the case of SVG elements that are not all lowercase.\n * http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inforeign\n * This is not done at parse time because there's no place to store a mutated\n * tag name.  tag_name is an enum (which will be TAG_UNKNOWN for most SVG tags\n * without special handling), while original_tag_name is a pointer into the\n * original buffer.  Instead, we provide this helper function that clients can\n * use to rename SVG tags as appropriate.\n * Returns the case-normalized SVG tagname if a replacement is found, or NULL if\n * no normalization is called for.  The return value is static data and owned by\n * the library.\n */\nconst char* gumbo_normalize_svg_tagname(const GumboStringPiece* tagname);\n\n/**\n * Converts a tag name string (which may be in upper or mixed case) to a tag\n * enum.\n */\nGumboTag gumbo_tag_enum(const char* tagname);\n\n/**\n * Attribute namespaces.\n * HTML includes special handling for XLink, XML, and XMLNS namespaces on\n * attributes.  Everything else goes in the generatic \"NONE\" namespace.\n */\ntypedef enum {\n  GUMBO_ATTR_NAMESPACE_NONE,\n  GUMBO_ATTR_NAMESPACE_XLINK,\n  GUMBO_ATTR_NAMESPACE_XML,\n  GUMBO_ATTR_NAMESPACE_XMLNS,\n} GumboAttributeNamespaceEnum;\n\n/**\n * A struct representing a single attribute on an HTML tag.  This is a\n * name-value pair, but also includes information about source locations and\n * original source text.\n */\ntypedef struct {\n  /**\n   * The namespace for the attribute.  This will usually be\n   * GUMBO_ATTR_NAMESPACE_NONE, but some XLink/XMLNS/XML attributes take special\n   * values, per:\n   * http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adjust-foreign-attributes\n   */\n  GumboAttributeNamespaceEnum attr_namespace;\n\n  /**\n   * The name of the attribute.  This is in a freshly-allocated buffer to deal\n   * with case-normalization, and is null-terminated.\n   */\n  const char* name;\n\n  /**\n   * The original text of the attribute name, as a pointer into the original\n   * source buffer.\n   */\n  GumboStringPiece original_name;\n\n  /**\n   * The value of the attribute.  This is in a freshly-allocated buffer to deal\n   * with unescaping, and is null-terminated.  It does not include any quotes\n   * that surround the attribute.  If the attribute has no value (for example,\n   * 'selected' on a checkbox), this will be an empty string.\n   */\n  const char* value;\n\n  /**\n   * The original text of the value of the attribute.  This points into the\n   * original source buffer.  It includes any quotes that surround the\n   * attribute, and you can look at original_value.data[0] and\n   * original_value.data[original_value.length - 1] to determine what the quote\n   * characters were.  If the attribute has no value, this will be a 0-length\n   * string.\n   */\n  GumboStringPiece original_value;\n\n  /** The starting position of the attribute name. */\n  GumboSourcePosition name_start;\n\n  /**\n   * The ending position of the attribute name.  This is not always derivable\n   * from the starting position of the value because of the possibility of\n   * whitespace around the = sign.\n   */\n  GumboSourcePosition name_end;\n\n  /** The starting position of the attribute value. */\n  GumboSourcePosition value_start;\n\n  /** The ending position of the attribute value. */\n  GumboSourcePosition value_end;\n} GumboAttribute;\n\n/**\n * Given a vector of GumboAttributes, look up the one with the specified name\n * and return it, or NULL if no such attribute exists.  This uses a\n * case-insensitive match, as HTML is case-insensitive.\n */\nGumboAttribute* gumbo_get_attribute(const GumboVector* attrs, const char* name);\n\n/**\n * Enum denoting the type of node.  This determines the type of the node.v\n * union.\n */\ntypedef enum {\n  /** Document node.  v will be a GumboDocument. */\n  GUMBO_NODE_DOCUMENT,\n  /** Element node.  v will be a GumboElement. */\n  GUMBO_NODE_ELEMENT,\n  /** Text node.  v will be a GumboText. */\n  GUMBO_NODE_TEXT,\n  /** CDATA node. v will be a GumboText. */\n  GUMBO_NODE_CDATA,\n  /** Comment node.  v. will be a GumboText, excluding comment delimiters. */\n  GUMBO_NODE_COMMENT,\n  /** Text node, where all contents is whitespace.  v will be a GumboText. */\n  GUMBO_NODE_WHITESPACE\n} GumboNodeType;\n\n/**\n * Forward declaration of GumboNode so it can be used recursively in\n * GumboNode.parent.\n */\ntypedef struct GumboInternalNode GumboNode;\n\n/** http://www.whatwg.org/specs/web-apps/current-work/complete/dom.html#quirks-mode */\ntypedef enum {\n  GUMBO_DOCTYPE_NO_QUIRKS,\n  GUMBO_DOCTYPE_QUIRKS,\n  GUMBO_DOCTYPE_LIMITED_QUIRKS\n} GumboQuirksModeEnum;\n\n/**\n * Namespaces.\n * Unlike in X(HT)ML, namespaces in HTML5 are not denoted by a prefix.  Rather,\n * anything inside an <svg> tag is in the SVG namespace, anything inside the\n * <math> tag is in the MathML namespace, and anything else is inside the HTML\n * namespace.  No other namespaces are supported, so this can be an enum only.\n */\ntypedef enum {\n  GUMBO_NAMESPACE_HTML,\n  GUMBO_NAMESPACE_SVG,\n  GUMBO_NAMESPACE_MATHML\n} GumboNamespaceEnum;\n\n/**\n * Parse flags.\n * We track the reasons for parser insertion of nodes and store them in a\n * bitvector in the node itself.  This lets client code optimize out nodes that\n * are implied by the HTML structure of the document, or flag constructs that\n * may not be allowed by a style guide, or track the prevalence of incorrect or\n * tricky HTML code.\n */\ntypedef enum {\n  /**\n   * A normal node - both start and end tags appear in the source, nothing has\n   * been reparented.\n   */\n  GUMBO_INSERTION_NORMAL = 0,\n\n  /**\n   * A node inserted by the parser to fulfill some implicit insertion rule.\n   * This is usually set in addition to some other flag giving a more specific\n   * insertion reason; it's a generic catch-all term meaning \"The start tag for\n   * this node did not appear in the document source\".\n   */\n  GUMBO_INSERTION_BY_PARSER = 1 << 0,\n\n  /**\n   * A flag indicating that the end tag for this node did not appear in the\n   * document source.  Note that in some cases, you can still have\n   * parser-inserted nodes with an explicit end tag: for example, \"Text</html>\"\n   * has GUMBO_INSERTED_BY_PARSER set on the <html> node, but\n   * GUMBO_INSERTED_END_TAG_IMPLICITLY is unset, as the </html> tag actually\n   * exists.  This flag will be set only if the end tag is completely missing;\n   * in some cases, the end tag may be misplaced (eg. a </body> tag with text\n   * afterwards), which will leave this flag unset and require clients to\n   * inspect the parse errors for that case.\n   */\n  GUMBO_INSERTION_IMPLICIT_END_TAG = 1 << 1,\n\n  // Value 1 << 2 was for a flag that has since been removed.\n\n  /**\n   * A flag for nodes that are inserted because their presence is implied by\n   * other tags, eg. <html>, <head>, <body>, <tbody>, etc.\n   */\n  GUMBO_INSERTION_IMPLIED = 1 << 3,\n\n  /**\n   * A flag for nodes that are converted from their end tag equivalents.  For\n   * example, </p> when no paragraph is open implies that the parser should\n   * create a <p> tag and immediately close it, while </br> means the same thing\n   * as <br>.\n   */\n  GUMBO_INSERTION_CONVERTED_FROM_END_TAG = 1 << 4,\n\n  /** A flag for nodes that are converted from the parse of an <isindex> tag. */\n  GUMBO_INSERTION_FROM_ISINDEX = 1 << 5,\n\n  /** A flag for <image> tags that are rewritten as <img>. */\n  GUMBO_INSERTION_FROM_IMAGE = 1 << 6,\n\n  /**\n   * A flag for nodes that are cloned as a result of the reconstruction of\n   * active formatting elements.  This is set only on the clone; the initial\n   * portion of the formatting run is a NORMAL node with an IMPLICIT_END_TAG.\n   */\n  GUMBO_INSERTION_RECONSTRUCTED_FORMATTING_ELEMENT = 1 << 7,\n\n  /** A flag for nodes that are cloned by the adoption agency algorithm. */\n  GUMBO_INSERTION_ADOPTION_AGENCY_CLONED = 1 << 8,\n\n  /** A flag for nodes that are moved by the adoption agency algorithm. */\n  GUMBO_INSERTION_ADOPTION_AGENCY_MOVED = 1 << 9,\n\n  /**\n   * A flag for nodes that have been foster-parented out of a table (or\n   * should've been foster-parented, if verbatim mode is set).\n   */\n  GUMBO_INSERTION_FOSTER_PARENTED = 1 << 10,\n} GumboParseFlags;\n\n\n/**\n * Information specific to document nodes.\n */\ntypedef struct {\n  /**\n   * An array of GumboNodes, containing the children of this element.  This will\n   * normally consist of the <html> element and any comment nodes found.\n   * Pointers are owned.\n   */\n  GumboVector /* GumboNode* */ children;\n\n  // True if there was an explicit doctype token as opposed to it being omitted.\n  bool has_doctype;\n\n  // Fields from the doctype token, copied verbatim.\n  const char* name;\n  const char* public_identifier;\n  const char* system_identifier;\n\n  /**\n   * Whether or not the document is in QuirksMode, as determined by the values\n   * in the GumboTokenDocType template.\n   */\n  GumboQuirksModeEnum doc_type_quirks_mode;\n} GumboDocument;\n\n/**\n * The struct used to represent TEXT, CDATA, COMMENT, and WHITESPACE elements.\n * This contains just a block of text and its position.\n */\ntypedef struct {\n  /**\n   * The text of this node, after entities have been parsed and decoded.  For\n   * comment/cdata nodes, this does not include the comment delimiters.\n   */\n  const char* text;\n\n  /**\n   * The original text of this node, as a pointer into the original buffer.  For\n   * comment/cdata nodes, this includes the comment delimiters.\n   */\n  GumboStringPiece original_text;\n\n  /**\n   * The starting position of this node.  This corresponds to the position of\n   * original_text, before entities are decoded.\n   * */\n  GumboSourcePosition start_pos;\n} GumboText;\n\n/**\n * The struct used to represent all HTML elements.  This contains information\n * about the tag, attributes, and child nodes.\n */\ntypedef struct {\n  /**\n   * An array of GumboNodes, containing the children of this element.  Pointers\n   * are owned.\n   */\n  GumboVector /* GumboNode* */ children;\n\n  /** The GumboTag enum for this element. */\n  GumboTag tag;\n\n  /** The GumboNamespaceEnum for this element. */\n  GumboNamespaceEnum tag_namespace;\n\n  /**\n   * A GumboStringPiece pointing to the original tag text for this element,\n   * pointing directly into the source buffer.  If the tag was inserted\n   * algorithmically (for example, <head> or <tbody> insertion), this will be a\n   * zero-length string.\n   */\n  GumboStringPiece original_tag;\n\n  /**\n   * A GumboStringPiece pointing to the original end tag text for this element.\n   * If the end tag was inserted algorithmically, (for example, closing a\n   * self-closing tag), this will be a zero-length string.\n   */\n  GumboStringPiece original_end_tag;\n\n  /** The source position for the start of the start tag. */\n  GumboSourcePosition start_pos;\n\n  /** The source position for the start of the end tag. */\n  GumboSourcePosition end_pos;\n\n  /**\n   * An array of GumboAttributes, containing the attributes for this tag in the\n   * order that they were parsed.  Pointers are owned.\n   */\n  GumboVector /* GumboAttribute* */ attributes;\n} GumboElement;\n\n/**\n * A supertype for GumboElement and GumboText, so that we can include one\n * generic type in lists of children and cast as necessary to subtypes.\n */\nstruct GumboInternalNode {\n  /** The type of node that this is. */\n  GumboNodeType type;\n\n  /** Pointer back to parent node.  Not owned. */\n  GumboNode* parent;\n\n  /** The index within the parent's children vector of this node. */\n  size_t index_within_parent;\n\n  /**\n   * A bitvector of flags containing information about why this element was\n   * inserted into the parse tree, including a variety of special parse\n   * situations.\n   */\n  GumboParseFlags parse_flags;\n\n  /** The actual node data. */\n  union {\n    GumboDocument document;      // For GUMBO_NODE_DOCUMENT.\n    GumboElement element;        // For GUMBO_NODE_ELEMENT.\n    GumboText text;              // For everything else.\n  } v;\n};\n\n/**\n * The type for an allocator function.  Takes the 'userdata' member of the\n * GumboParser struct as its first argument.  Semantics should be the same as\n * malloc, i.e. return a block of size_t bytes on success or NULL on failure.\n * Allocating a block of 0 bytes behaves as per malloc.\n */\n// TODO(jdtang): Add checks throughout the codebase for out-of-memory condition.\ntypedef void* (*GumboAllocatorFunction)(void* userdata, size_t size);\n\n/**\n * The type for a deallocator function.  Takes the 'userdata' member of the\n * GumboParser struct as its first argument.\n */\ntypedef void (*GumboDeallocatorFunction)(void* userdata, void* ptr);\n\n/**\n * Input struct containing configuration options for the parser.\n * These let you specify alternate memory managers, provide different error\n * handling, etc.\n * Use kGumboDefaultOptions for sensible defaults, and only set what you need.\n */\ntypedef struct GumboInternalOptions {\n  /** A memory allocator function.  Default: malloc. */\n  GumboAllocatorFunction allocator;\n\n  /** A memory deallocator function. Default: free. */\n  GumboDeallocatorFunction deallocator;\n\n  /**\n   * An opaque object that's passed in as the first argument to all callbacks\n   * used by this library.  Default: NULL.\n   */\n  void* userdata;\n\n  /**\n   * The tab-stop size, for computing positions in source code that uses tabs.\n   * Default: 8.\n   */\n  int tab_stop;\n\n  /**\n   * Whether or not to stop parsing when the first error is encountered.\n   * Default: false.\n   */\n  bool stop_on_first_error;\n\n  /**\n   * The maximum number of errors before the parser stops recording them.  This\n   * is provided so that if the page is totally borked, we don't completely fill\n   * up the errors vector and exhaust memory with useless redundant errors.  Set\n   * to -1 to disable the limit.\n   * Default: -1\n   */\n  int max_errors;\n} GumboOptions;\n\n/** Default options struct; use this with gumbo_parse_with_options. */\nextern const GumboOptions kGumboDefaultOptions;\n\n/** The output struct containing the results of the parse. */\ntypedef struct GumboInternalOutput {\n  /**\n   * Pointer to the document node.  This is a GumboNode of type NODE_DOCUMENT\n   * that contains the entire document as its child.\n   */\n  GumboNode* document;\n\n  /**\n   * Pointer to the root node.  This the <html> tag that forms the root of the\n   * document.\n   */\n  GumboNode* root;\n\n  /**\n   * A list of errors that occurred during the parse.\n   * NOTE: In version 1.0 of this library, the API for errors hasn't been fully\n   * fleshed out and may change in the future.  For this reason, the GumboError\n   * header isn't part of the public API.  Contact us if you need errors\n   * reported so we can work out something appropriate for your use-case.\n   */\n  GumboVector /* GumboError */ errors;\n} GumboOutput;\n\n/**\n * Parses a buffer of UTF8 text into an GumboNode parse tree.  The buffer must\n * live at least as long as the parse tree, as some fields (eg. original_text)\n * point directly into the original buffer.\n *\n * This doesn't support buffers longer than 4 gigabytes.\n */\nGumboOutput* gumbo_parse(const char* buffer);\n\n/**\n * Extended version of gumbo_parse that takes an explicit options structure,\n * buffer, and length.\n */\nGumboOutput* gumbo_parse_with_options(\n    const GumboOptions* options, const char* buffer, size_t buffer_length);\n\n/** Release the memory used for the parse tree & parse errors. */\nvoid gumbo_destroy_output(\n    const GumboOptions* options, GumboOutput* output);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_GUMBO_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/insertion_mode.h",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#ifndef GUMBO_INSERTION_MODE_H_\n#define GUMBO_INSERTION_MODE_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#insertion-mode\ntypedef enum {\n  GUMBO_INSERTION_MODE_INITIAL,\n  GUMBO_INSERTION_MODE_BEFORE_HTML,\n  GUMBO_INSERTION_MODE_BEFORE_HEAD,\n  GUMBO_INSERTION_MODE_IN_HEAD,\n  GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT,\n  GUMBO_INSERTION_MODE_AFTER_HEAD,\n  GUMBO_INSERTION_MODE_IN_BODY,\n  GUMBO_INSERTION_MODE_TEXT,\n  GUMBO_INSERTION_MODE_IN_TABLE,\n  GUMBO_INSERTION_MODE_IN_TABLE_TEXT,\n  GUMBO_INSERTION_MODE_IN_CAPTION,\n  GUMBO_INSERTION_MODE_IN_COLUMN_GROUP,\n  GUMBO_INSERTION_MODE_IN_TABLE_BODY,\n  GUMBO_INSERTION_MODE_IN_ROW,\n  GUMBO_INSERTION_MODE_IN_CELL,\n  GUMBO_INSERTION_MODE_IN_SELECT,\n  GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE,\n  GUMBO_INSERTION_MODE_AFTER_BODY,\n  GUMBO_INSERTION_MODE_IN_FRAMESET,\n  GUMBO_INSERTION_MODE_AFTER_FRAMESET,\n  GUMBO_INSERTION_MODE_AFTER_AFTER_BODY,\n  GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET\n} GumboInsertionMode;\n\n#ifdef __cplusplus\n}  // extern C\n#endif\n\n#endif  // GUMBO_INSERTION_MODE_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/parser.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include <assert.h>\n#include <ctype.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n\n#include \"attribute.h\"\n#include \"error.h\"\n#include \"gumbo.h\"\n#include \"insertion_mode.h\"\n#include \"parser.h\"\n#include \"tokenizer.h\"\n#include \"tokenizer_states.h\"\n#include \"utf8.h\"\n#include \"util.h\"\n#include \"vector.h\"\n\n\n#define AVOID_UNUSED_VARIABLE_WARNING(i) (void)(i)\n\n#define GUMBO_STRING(literal) { literal, sizeof(literal) - 1 }\n#define TERMINATOR { \"\", 0 }\n\nstatic void* malloc_wrapper(void* unused, size_t size) {\n  return malloc(size);\n}\n\nstatic void free_wrapper(void* unused, void* ptr) {\n  return free(ptr);\n}\n\nconst GumboOptions kGumboDefaultOptions = {\n  &malloc_wrapper,\n  &free_wrapper,\n  NULL,\n  8,\n  false,\n  -1,\n};\n\nstatic const GumboStringPiece kDoctypeHtml = GUMBO_STRING(\"html\");\nstatic const GumboStringPiece kPublicIdHtml4_0 = GUMBO_STRING(\n    \"-//W3C//DTD HTML 4.0//EN\");\nstatic const GumboStringPiece kPublicIdHtml4_01 = GUMBO_STRING(\n    \"-//W3C//DTD HTML 4.01//EN\");\nstatic const GumboStringPiece kPublicIdXhtml1_0 = GUMBO_STRING(\n    \"-//W3C//DTD XHTML 1.0 Strict//EN\");\nstatic const GumboStringPiece kPublicIdXhtml1_1 = GUMBO_STRING(\n    \"-//W3C//DTD XHTML 1.1//EN\");\nstatic const GumboStringPiece kSystemIdRecHtml4_0 = GUMBO_STRING(\n    \"http://www.w3.org/TR/REC-html40/strict.dtd\");\nstatic const GumboStringPiece kSystemIdHtml4 = GUMBO_STRING(\n    \"http://www.w3.org/TR/html4/strict.dtd\");\nstatic const GumboStringPiece kSystemIdXhtmlStrict1_1 = GUMBO_STRING(\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\");\nstatic const GumboStringPiece kSystemIdXhtml1_1 = GUMBO_STRING(\n    \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\");\nstatic const GumboStringPiece kSystemIdLegacyCompat = GUMBO_STRING(\n    \"about:legacy-compat\");\n\n// The doctype arrays have an explicit terminator because we want to pass them\n// to a helper function, and passing them as a pointer discards sizeof\n// information.  The SVG arrays are used only by one-off functions, and so loops\n// over them use sizeof directly instead of a terminator.\n\nstatic const GumboStringPiece kQuirksModePublicIdPrefixes[] = {\n  GUMBO_STRING(\"+//Silmaril//dtd html Pro v0r11 19970101//\"),\n  GUMBO_STRING(\"-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//\"),\n  GUMBO_STRING(\"-//AS//DTD HTML 3.0 asWedit + extensions//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0 Level 1//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0 Level 2//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0 Strict Level 1//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0 Strict Level 2//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0 Strict//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.0//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 2.1E//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 3.0//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 3.2 Final//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 3.2//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML 3//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Level 0//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Level 1//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Level 2//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Level 3//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Strict Level 0//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Strict Level 1//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Strict Level 2//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Strict Level 3//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML Strict//\"),\n  GUMBO_STRING(\"-//IETF//DTD HTML//\"),\n  GUMBO_STRING(\"-//Metrius//DTD Metrius Presentational//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 2.0 HTML//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 2.0 Tables//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 3.0 HTML//\"),\n  GUMBO_STRING(\"-//Microsoft//DTD Internet Explorer 3.0 Tables//\"),\n  GUMBO_STRING(\"-//Netscape Comm. Corp.//DTD HTML//\"),\n  GUMBO_STRING(\"-//Netscape Comm. Corp.//DTD Strict HTML//\"),\n  GUMBO_STRING(\"-//O'Reilly and Associates//DTD HTML 2.0//\"),\n  GUMBO_STRING(\"-//O'Reilly and Associates//DTD HTML Extended 1.0//\"),\n  GUMBO_STRING(\"-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//\"),\n  GUMBO_STRING(\"-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::)\"\n      \"extensions to HTML 4.0//\"),\n  GUMBO_STRING(\"-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::\"\n      \"extensions to HTML 4.0//\"),\n  GUMBO_STRING(\"-//Spyglass//DTD HTML 2.0 Extended//\"),\n  GUMBO_STRING(\"-//SQ//DTD HTML 2.0 HoTMetaL + extensions//\"),\n  GUMBO_STRING(\"-//Sun Microsystems Corp.//DTD HotJava HTML//\"),\n  GUMBO_STRING(\"-//Sun Microsystems Corp.//DTD HotJava Strict HTML//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 3 1995-03-24//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 3.2 Draft//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 3.2 Final//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 3.2//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 3.2S Draft//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 4.0 Frameset//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 4.0 Transitional//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML Experimental 19960712//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML Experimental 970421//\"),\n  GUMBO_STRING(\"-//W3C//DTD W3 HTML//\"),\n  GUMBO_STRING(\"-//W3O//DTD W3 HTML 3.0//\"),\n  GUMBO_STRING(\"-//WebTechs//DTD Mozilla HTML 2.0//\"),\n  GUMBO_STRING(\"-//WebTechs//DTD Mozilla HTML//\"),\n  TERMINATOR\n};\n\nstatic const GumboStringPiece kQuirksModePublicIdExactMatches[] = {\n  GUMBO_STRING(\"-//W3O//DTD W3 HTML Strict 3.0//EN//\"),\n  GUMBO_STRING(\"-/W3C/DTD HTML 4.0 Transitional/EN\"),\n  GUMBO_STRING(\"HTML\"),\n  TERMINATOR\n};\n\nstatic const GumboStringPiece kQuirksModeSystemIdExactMatches[] = {\n  GUMBO_STRING(\"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd\"),\n  TERMINATOR\n};\n\nstatic const GumboStringPiece kLimitedQuirksPublicIdPrefixes[] = {\n  GUMBO_STRING(\"-//W3C//DTD XHTML 1.0 Frameset//\"),\n  GUMBO_STRING(\"-//W3C//DTD XHTML 1.0 Transitional//\"),\n  TERMINATOR\n};\n\nstatic const GumboStringPiece kLimitedQuirksRequiresSystemIdPublicIdPrefixes[] = {\n  GUMBO_STRING(\"-//W3C//DTD HTML 4.01 Frameset//\"),\n  GUMBO_STRING(\"-//W3C//DTD HTML 4.01 Transitional//\"),\n  TERMINATOR\n};\n\n// Indexed by GumboNamespaceEnum; keep in sync with that.\nstatic const char* kLegalXmlns[] = {\n  \"http://www.w3.org/1999/xhtml\",\n  \"http://www.w3.org/2000/svg\",\n  \"http://www.w3.org/1998/Math/MathML\"\n};\n\ntypedef struct _ReplacementEntry {\n  const GumboStringPiece from;\n  const GumboStringPiece to;\n} ReplacementEntry;\n\n#define REPLACEMENT_ENTRY(from, to) \\\n    { GUMBO_STRING(from), GUMBO_STRING(to) }\n\n// Static data for SVG attribute replacements.\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adjust-svg-attributes\nstatic const ReplacementEntry kSvgAttributeReplacements[] = {\n  REPLACEMENT_ENTRY(\"attributename\", \"attributeName\"),\n  REPLACEMENT_ENTRY(\"attributetype\", \"attributeType\"),\n  REPLACEMENT_ENTRY(\"basefrequency\", \"baseFrequency\"),\n  REPLACEMENT_ENTRY(\"baseprofile\", \"baseProfile\"),\n  REPLACEMENT_ENTRY(\"calcmode\", \"calcMode\"),\n  REPLACEMENT_ENTRY(\"clippathunits\", \"clipPathUnits\"),\n  REPLACEMENT_ENTRY(\"contentscripttype\", \"contentScriptType\"),\n  REPLACEMENT_ENTRY(\"contentstyletype\", \"contentStyleType\"),\n  REPLACEMENT_ENTRY(\"diffuseconstant\", \"diffuseConstant\"),\n  REPLACEMENT_ENTRY(\"edgemode\", \"edgeMode\"),\n  REPLACEMENT_ENTRY(\"externalresourcesrequired\", \"externalResourcesRequired\"),\n  REPLACEMENT_ENTRY(\"filterres\", \"filterRes\"),\n  REPLACEMENT_ENTRY(\"filterunits\", \"filterUnits\"),\n  REPLACEMENT_ENTRY(\"glyphref\", \"glyphRef\"),\n  REPLACEMENT_ENTRY(\"gradienttransform\", \"gradientTransform\"),\n  REPLACEMENT_ENTRY(\"gradientunits\", \"gradientUnits\"),\n  REPLACEMENT_ENTRY(\"kernelmatrix\", \"kernelMatrix\"),\n  REPLACEMENT_ENTRY(\"kernelunitlength\", \"kernelUnitLength\"),\n  REPLACEMENT_ENTRY(\"keypoints\", \"keyPoints\"),\n  REPLACEMENT_ENTRY(\"keysplines\", \"keySplines\"),\n  REPLACEMENT_ENTRY(\"keytimes\", \"keyTimes\"),\n  REPLACEMENT_ENTRY(\"lengthadjust\", \"lengthAdjust\"),\n  REPLACEMENT_ENTRY(\"limitingconeangle\", \"limitingConeAngle\"),\n  REPLACEMENT_ENTRY(\"markerheight\", \"markerHeight\"),\n  REPLACEMENT_ENTRY(\"markerunits\", \"markerUnits\"),\n  REPLACEMENT_ENTRY(\"markerwidth\", \"markerWidth\"),\n  REPLACEMENT_ENTRY(\"maskcontentunits\", \"maskContentUnits\"),\n  REPLACEMENT_ENTRY(\"maskunits\", \"maskUnits\"),\n  REPLACEMENT_ENTRY(\"numoctaves\", \"numOctaves\"),\n  REPLACEMENT_ENTRY(\"pathlength\", \"pathLength\"),\n  REPLACEMENT_ENTRY(\"patterncontentunits\", \"patternContentUnits\"),\n  REPLACEMENT_ENTRY(\"patterntransform\", \"patternTransform\"),\n  REPLACEMENT_ENTRY(\"patternunits\", \"patternUnits\"),\n  REPLACEMENT_ENTRY(\"pointsatx\", \"pointsAtX\"),\n  REPLACEMENT_ENTRY(\"pointsaty\", \"pointsAtY\"),\n  REPLACEMENT_ENTRY(\"pointsatz\", \"pointsAtZ\"),\n  REPLACEMENT_ENTRY(\"preservealpha\", \"preserveAlpha\"),\n  REPLACEMENT_ENTRY(\"preserveaspectratio\", \"preserveAspectRatio\"),\n  REPLACEMENT_ENTRY(\"primitiveunits\", \"primitiveUnits\"),\n  REPLACEMENT_ENTRY(\"refx\", \"refX\"),\n  REPLACEMENT_ENTRY(\"refy\", \"refY\"),\n  REPLACEMENT_ENTRY(\"repeatcount\", \"repeatCount\"),\n  REPLACEMENT_ENTRY(\"repeatdur\", \"repeatDur\"),\n  REPLACEMENT_ENTRY(\"requiredextensions\", \"requiredExtensions\"),\n  REPLACEMENT_ENTRY(\"requiredfeatures\", \"requiredFeatures\"),\n  REPLACEMENT_ENTRY(\"specularconstant\", \"specularConstant\"),\n  REPLACEMENT_ENTRY(\"specularexponent\", \"specularExponent\"),\n  REPLACEMENT_ENTRY(\"spreadmethod\", \"spreadMethod\"),\n  REPLACEMENT_ENTRY(\"startoffset\", \"startOffset\"),\n  REPLACEMENT_ENTRY(\"stddeviation\", \"stdDeviation\"),\n  REPLACEMENT_ENTRY(\"stitchtiles\", \"stitchTiles\"),\n  REPLACEMENT_ENTRY(\"surfacescale\", \"surfaceScale\"),\n  REPLACEMENT_ENTRY(\"systemlanguage\", \"systemLanguage\"),\n  REPLACEMENT_ENTRY(\"tablevalues\", \"tableValues\"),\n  REPLACEMENT_ENTRY(\"targetx\", \"targetX\"),\n  REPLACEMENT_ENTRY(\"targety\", \"targetY\"),\n  REPLACEMENT_ENTRY(\"textlength\", \"textLength\"),\n  REPLACEMENT_ENTRY(\"viewbox\", \"viewBox\"),\n  REPLACEMENT_ENTRY(\"viewtarget\", \"viewTarget\"),\n  REPLACEMENT_ENTRY(\"xchannelselector\", \"xChannelSelector\"),\n  REPLACEMENT_ENTRY(\"ychannelselector\", \"yChannelSelector\"),\n  REPLACEMENT_ENTRY(\"zoomandpan\", \"zoomAndPan\"),\n};\n\nstatic const ReplacementEntry kSvgTagReplacements[] = {\n  REPLACEMENT_ENTRY(\"altglyph\", \"altGlyph\"),\n  REPLACEMENT_ENTRY(\"altglyphdef\", \"altGlyphDef\"),\n  REPLACEMENT_ENTRY(\"altglyphitem\", \"altGlyphItem\"),\n  REPLACEMENT_ENTRY(\"animatecolor\", \"animateColor\"),\n  REPLACEMENT_ENTRY(\"animatemotion\", \"animateMotion\"),\n  REPLACEMENT_ENTRY(\"animatetransform\", \"animateTransform\"),\n  REPLACEMENT_ENTRY(\"clippath\", \"clipPath\"),\n  REPLACEMENT_ENTRY(\"feblend\", \"feBlend\"),\n  REPLACEMENT_ENTRY(\"fecolormatrix\", \"feColorMatrix\"),\n  REPLACEMENT_ENTRY(\"fecomponenttransfer\", \"feComponentTransfer\"),\n  REPLACEMENT_ENTRY(\"fecomposite\", \"feComposite\"),\n  REPLACEMENT_ENTRY(\"feconvolvematrix\", \"feConvolveMatrix\"),\n  REPLACEMENT_ENTRY(\"fediffuselighting\", \"feDiffuseLighting\"),\n  REPLACEMENT_ENTRY(\"fedisplacementmap\", \"feDisplacementMap\"),\n  REPLACEMENT_ENTRY(\"fedistantlight\", \"feDistantLight\"),\n  REPLACEMENT_ENTRY(\"feflood\", \"feFlood\"),\n  REPLACEMENT_ENTRY(\"fefunca\", \"feFuncA\"),\n  REPLACEMENT_ENTRY(\"fefuncb\", \"feFuncB\"),\n  REPLACEMENT_ENTRY(\"fefuncg\", \"feFuncG\"),\n  REPLACEMENT_ENTRY(\"fefuncr\", \"feFuncR\"),\n  REPLACEMENT_ENTRY(\"fegaussianblur\", \"feGaussianBlur\"),\n  REPLACEMENT_ENTRY(\"feimage\", \"feImage\"),\n  REPLACEMENT_ENTRY(\"femerge\", \"feMerge\"),\n  REPLACEMENT_ENTRY(\"femergenode\", \"feMergeNode\"),\n  REPLACEMENT_ENTRY(\"femorphology\", \"feMorphology\"),\n  REPLACEMENT_ENTRY(\"feoffset\", \"feOffset\"),\n  REPLACEMENT_ENTRY(\"fepointlight\", \"fePointLight\"),\n  REPLACEMENT_ENTRY(\"fespecularlighting\", \"feSpecularLighting\"),\n  REPLACEMENT_ENTRY(\"fespotlight\", \"feSpotLight\"),\n  REPLACEMENT_ENTRY(\"fetile\", \"feTile\"),\n  REPLACEMENT_ENTRY(\"feturbulence\", \"feTurbulence\"),\n  REPLACEMENT_ENTRY(\"foreignobject\", \"foreignObject\"),\n  REPLACEMENT_ENTRY(\"glyphref\", \"glyphRef\"),\n  REPLACEMENT_ENTRY(\"lineargradient\", \"linearGradient\"),\n  REPLACEMENT_ENTRY(\"radialgradient\", \"radialGradient\"),\n  REPLACEMENT_ENTRY(\"textpath\", \"textPath\"),\n};\n\ntypedef struct _NamespacedAttributeReplacement {\n  const char* from;\n  const char* local_name;\n  const GumboAttributeNamespaceEnum attr_namespace;\n} NamespacedAttributeReplacement;\n\nstatic const NamespacedAttributeReplacement kForeignAttributeReplacements[] = {\n  { \"xlink:actuate\", \"actuate\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:actuate\", \"actuate\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:href\", \"href\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:role\", \"role\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:show\", \"show\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:title\", \"title\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xlink:type\", \"type\", GUMBO_ATTR_NAMESPACE_XLINK },\n  { \"xml:base\", \"base\", GUMBO_ATTR_NAMESPACE_XML },\n  { \"xml:lang\", \"lang\", GUMBO_ATTR_NAMESPACE_XML },\n  { \"xml:space\", \"space\", GUMBO_ATTR_NAMESPACE_XML },\n  { \"xmlns\", \"xmlns\", GUMBO_ATTR_NAMESPACE_XMLNS },\n  { \"xmlns:xlink\", \"xlink\", GUMBO_ATTR_NAMESPACE_XMLNS },\n};\n\n// The \"scope marker\" for the list of active formatting elements.  We use a\n// pointer to this as a generic marker element, since the particular element\n// scope doesn't matter.\nstatic const GumboNode kActiveFormattingScopeMarker;\n\n// The tag_is and tag_in function use true & false to denote start & end tags,\n// but for readability, we define constants for them here.\nstatic const bool kStartTag = true;\nstatic const bool kEndTag = false;\n\n// Because GumboStringPieces are immutable, we can't insert a character directly\n// into a text node.  Instead, we accumulate all pending characters here and\n// flush them out to a text node whenever a new element is inserted.\n//\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#insert-a-character\ntypedef struct _TextNodeBufferState {\n  // The accumulated text to be inserted into the current text node.\n  GumboStringBuffer _buffer;\n\n  // A pointer to the original text represented by this text node.  Note that\n  // because of foster parenting and other strange DOM manipulations, this may\n  // include other non-text HTML tags in it; it is defined as the span of\n  // original text from the first character in this text node to the last\n  // character in this text node.\n  const char* _start_original_text;\n\n  // The source position of the start of this text node.\n  GumboSourcePosition _start_position;\n\n  // The type of node that will be inserted (TEXT or WHITESPACE).\n  GumboNodeType _type;\n} TextNodeBufferState;\n\ntypedef struct GumboInternalParserState {\n  // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#insertion-mode\n  GumboInsertionMode _insertion_mode;\n\n  // Used for run_generic_parsing_algorithm, which needs to switch back to the\n  // original insertion mode at its conclusion.\n  GumboInsertionMode _original_insertion_mode;\n\n  // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-stack-of-open-elements\n  GumboVector /*GumboNode*/ _open_elements;\n\n  // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-list-of-active-formatting-elements\n  GumboVector /*GumboNode*/ _active_formatting_elements;\n\n  // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-element-pointers\n  GumboNode* _head_element;\n  GumboNode* _form_element;\n\n  // The flag for when the spec says \"Reprocess the current token in...\"\n  bool _reprocess_current_token;\n\n  // The flag for \"acknowledge the token's self-closing flag\".\n  bool _self_closing_flag_acknowledged;\n\n  // The \"frameset-ok\" flag from the spec.\n  bool _frameset_ok;\n\n  // The flag for \"If the next token is a LINE FEED, ignore that token...\".\n  bool _ignore_next_linefeed;\n\n  // The flag for \"whenever a node would be inserted into the current node, it\n  // must instead be foster parented\".  This is used for misnested table\n  // content, which needs to be handled according to \"in body\" rules yet foster\n  // parented outside of the table.\n  // It would perhaps be more explicit to have this as a parameter to\n  // handle_in_body and insert_element, but given how special-purpose this is\n  // and the number of call-sites that would need to take the extra parameter,\n  // it's easier just to have a state flag.\n  bool _foster_parent_insertions;\n\n  // The accumulated text node buffer state.\n  TextNodeBufferState _text_node;\n\n  // The current token.\n  GumboToken* _current_token;\n\n  // The way that the spec is written, the </body> and </html> tags are *always*\n  // implicit, because encountering one of those tokens merely switches the\n  // insertion mode out of \"in body\".  So we have individual state flags for\n  // those end tags that are then inspected by pop_current_node when the <body>\n  // and <html> nodes are popped to set the GUMBO_INSERTION_IMPLICIT_END_TAG\n  // flag appropriately.\n  bool _closed_body_tag;\n  bool _closed_html_tag;\n} GumboParserState;\n\nstatic bool token_has_attribute(const GumboToken* token, const char* name) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  return gumbo_get_attribute(&token->v.start_tag.attributes, name) != NULL;\n}\n\n// Checks if the value of the specified attribute is a case-insensitive match\n// for the specified string.\nstatic bool attribute_matches(\n    const GumboVector* attributes, const char* name, const char* value) {\n  const GumboAttribute* attr = gumbo_get_attribute(attributes, name);\n  return attr ? strcasecmp(value, attr->value) == 0 : false;\n}\n\n// Checks if the value of the specified attribute is a case-sensitive match\n// for the specified string.\nstatic bool attribute_matches_case_sensitive(\n    const GumboVector* attributes, const char* name, const char* value) {\n  const GumboAttribute* attr = gumbo_get_attribute(attributes, name);\n  return attr ?  strcmp(value, attr->value) == 0 : false;\n}\n\n// Checks if the specified attribute vectors are identical.\nstatic bool all_attributes_match(\n    const GumboVector* attr1, const GumboVector* attr2) {\n  int num_unmatched_attr2_elements = attr2->length;\n  for (int i = 0; i < attr1->length; ++i) {\n    const GumboAttribute* attr = attr1->data[i];\n    if (attribute_matches_case_sensitive(attr2, attr->name, attr->value)) {\n      --num_unmatched_attr2_elements;\n    } else {\n      return false;\n    }\n  }\n  return num_unmatched_attr2_elements == 0;\n}\n\nstatic void set_frameset_not_ok(GumboParser* parser) {\n  gumbo_debug(\"Setting frameset_ok to false.\\n\");\n  parser->_parser_state->_frameset_ok = false;\n}\n\nstatic GumboNode* create_node(GumboParser* parser, GumboNodeType type) {\n  GumboNode* node = gumbo_parser_allocate(parser, sizeof(GumboNode));\n  node->parent = NULL;\n  node->index_within_parent = -1;\n  node->type = type;\n  node->parse_flags = GUMBO_INSERTION_NORMAL;\n  return node;\n}\n\nstatic GumboNode* new_document_node(GumboParser* parser) {\n  GumboNode* document_node = create_node(parser, GUMBO_NODE_DOCUMENT);\n  document_node->parse_flags = GUMBO_INSERTION_BY_PARSER;\n  gumbo_vector_init(\n      parser, 1, &document_node->v.document.children);\n\n  // Must be initialized explicitly, as there's no guarantee that we'll see a\n  // doc type token.\n  GumboDocument* document = &document_node->v.document;\n  document->has_doctype = false;\n  document->name = NULL;\n  document->public_identifier = NULL;\n  document->system_identifier = NULL;\n  return document_node;\n}\n\nstatic void output_init(GumboParser* parser) {\n  GumboOutput* output = gumbo_parser_allocate(parser, sizeof(GumboOutput));\n  output->root = NULL;\n  output->document = new_document_node(parser);\n  parser->_output = output;\n  gumbo_init_errors(parser);\n}\n\nstatic void parser_state_init(GumboParser* parser) {\n  GumboParserState* parser_state =\n      gumbo_parser_allocate(parser, sizeof(GumboParserState));\n  parser_state->_insertion_mode = GUMBO_INSERTION_MODE_INITIAL;\n  parser_state->_reprocess_current_token = false;\n  parser_state->_frameset_ok = true;\n  parser_state->_ignore_next_linefeed = false;\n  parser_state->_foster_parent_insertions = false;\n  parser_state->_text_node._type = GUMBO_NODE_WHITESPACE;\n  gumbo_string_buffer_init(parser, &parser_state->_text_node._buffer);\n  gumbo_vector_init(parser, 10, &parser_state->_open_elements);\n  gumbo_vector_init(parser, 5, &parser_state->_active_formatting_elements);\n  parser_state->_head_element = NULL;\n  parser_state->_form_element = NULL;\n  parser_state->_current_token = NULL;\n  parser_state->_closed_body_tag = false;\n  parser_state->_closed_html_tag = false;\n  parser->_parser_state = parser_state;\n}\n\nstatic void parser_state_destroy(GumboParser* parser) {\n  GumboParserState* state = parser->_parser_state;\n  gumbo_vector_destroy(parser, &state->_active_formatting_elements);\n  gumbo_vector_destroy(parser, &state->_open_elements);\n  gumbo_string_buffer_destroy(parser, &state->_text_node._buffer);\n  gumbo_parser_deallocate(parser, state);\n}\n\nstatic GumboNode* get_document_node(GumboParser* parser) {\n  return parser->_output->document;\n}\n\n// Returns the node at the bottom of the stack of open elements, or NULL if no\n// elements have been added yet.\nstatic GumboNode* get_current_node(GumboParser* parser) {\n  GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  if (open_elements->length == 0) {\n    assert(!parser->_output->root);\n    return NULL;\n  }\n  assert(open_elements->length > 0);\n  assert(open_elements->data != NULL);\n  return open_elements->data[open_elements->length - 1];\n}\n\n// Returns true if the given needle is in the given array of literal\n// GumboStringPieces.  If exact_match is true, this requires that they match\n// exactly; otherwise, this performs a prefix match to check if any of the\n// elements in haystack start with needle.  This always performs a\n// case-insensitive match.\nstatic bool is_in_static_list(\n    const char* needle, const GumboStringPiece* haystack, bool exact_match) {\n  for (int i = 0; haystack[i].length > 0; ++i) {\n    if ((exact_match && !strcmp(needle, haystack[i].data)) ||\n        (!exact_match && !strcasecmp(needle, haystack[i].data))) {\n      return true;\n    }\n  }\n  return false;\n}\n\nstatic void set_insertion_mode(GumboParser* parser, GumboInsertionMode mode) {\n  parser->_parser_state->_insertion_mode = mode;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#reset-the-insertion-mode-appropriately\n// This is a helper function that returns the appropriate insertion mode instead\n// of setting it.  Returns GUMBO_INSERTION_MODE_INITIAL as a sentinel value to\n// indicate that there is no appropriate insertion mode, and the loop should\n// continue.\nstatic GumboInsertionMode get_appropriate_insertion_mode(\n    const GumboNode* node, bool is_last) {\n  assert(node->type == GUMBO_NODE_ELEMENT);\n  switch (node->v.element.tag) {\n    case GUMBO_TAG_SELECT:\n      return GUMBO_INSERTION_MODE_IN_SELECT;\n    case GUMBO_TAG_TD:\n    case GUMBO_TAG_TH:\n      return is_last ?\n          GUMBO_INSERTION_MODE_IN_BODY : GUMBO_INSERTION_MODE_IN_CELL;\n    case GUMBO_TAG_TR:\n      return GUMBO_INSERTION_MODE_IN_ROW;\n    case GUMBO_TAG_TBODY:\n    case GUMBO_TAG_THEAD:\n    case GUMBO_TAG_TFOOT:\n      return GUMBO_INSERTION_MODE_IN_TABLE_BODY;\n    case GUMBO_TAG_CAPTION:\n      return GUMBO_INSERTION_MODE_IN_CAPTION;\n    case GUMBO_TAG_COLGROUP:\n      return GUMBO_INSERTION_MODE_IN_COLUMN_GROUP;\n    case GUMBO_TAG_TABLE:\n      return GUMBO_INSERTION_MODE_IN_TABLE;\n    case GUMBO_TAG_HEAD:\n    case GUMBO_TAG_BODY:\n      return GUMBO_INSERTION_MODE_IN_BODY;\n    case GUMBO_TAG_FRAMESET:\n      return GUMBO_INSERTION_MODE_IN_FRAMESET;\n    case GUMBO_TAG_HTML:\n      return GUMBO_INSERTION_MODE_BEFORE_HEAD;\n    default:\n      return is_last ?\n          GUMBO_INSERTION_MODE_IN_BODY : GUMBO_INSERTION_MODE_INITIAL;\n  }\n}\n\n// This performs the actual \"reset the insertion mode\" loop.\nstatic void reset_insertion_mode_appropriately(GumboParser* parser) {\n  const GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  for (int i = open_elements->length; --i >= 0; ) {\n    GumboInsertionMode mode =\n        get_appropriate_insertion_mode(open_elements->data[i], i == 0);\n    if (mode != GUMBO_INSERTION_MODE_INITIAL) {\n      set_insertion_mode(parser, mode);\n      return;\n    }\n  }\n  // Should never get here, because is_last will be set on the last iteration\n  // and will force GUMBO_INSERTION_MODE_IN_BODY.\n  assert(0);\n}\n\nstatic GumboError* add_parse_error(GumboParser* parser, const GumboToken* token) {\n  gumbo_debug(\"Adding parse error.\\n\");\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return NULL;\n  }\n  error->type = GUMBO_ERR_PARSER;\n  error->position = token->position;\n  error->original_text = token->original_text.data;\n  GumboParserError* extra_data = &error->v.parser;\n  extra_data->input_type = token->type;\n  extra_data->input_tag = GUMBO_TAG_UNKNOWN;\n  if (token->type == GUMBO_TOKEN_START_TAG) {\n    extra_data->input_tag = token->v.start_tag.tag;\n  } else if (token->type == GUMBO_TOKEN_END_TAG) {\n    extra_data->input_tag = token->v.end_tag;\n  }\n  GumboParserState* state = parser->_parser_state;\n  extra_data->parser_state = state->_insertion_mode;\n  gumbo_vector_init(parser, state->_open_elements.length,\n                   &extra_data->tag_stack);\n  for (int i = 0; i < state->_open_elements.length; ++i) {\n    const GumboNode* node = state->_open_elements.data[i];\n    assert(node->type == GUMBO_NODE_ELEMENT);\n    gumbo_vector_add(parser, (void*) node->v.element.tag,\n                    &extra_data->tag_stack);\n  }\n  return error;\n}\n\n// Returns true if the specified token is either a start or end tag (specified\n// by is_start) with one of the tag types in the varargs list.  Terminate the\n// list with GUMBO_TAG_LAST; this functions as a sentinel since no portion of\n// the spec references tags that are not in the spec.\n// TODO(jdtang): A lot of the tag lists for this function are repeated in many\n// places in the code.  This is how it's written in the spec (and it's done this\n// way so it's easy to verify the code against the spec), but it may be worth\n// coming up with a notion of a \"tag set\" that includes a list of tags, and\n// using that in many places.  It'd probably also help performance, but I want\n// to profile before optimizing.\nstatic bool tag_in(const GumboToken* token, bool is_start, ...) {\n  GumboTag token_tag;\n  if (is_start && token->type == GUMBO_TOKEN_START_TAG) {\n    token_tag = token->v.start_tag.tag;\n  } else if (!is_start && token->type == GUMBO_TOKEN_END_TAG) {\n    token_tag = token->v.end_tag;\n  } else {\n    return false;\n  }\n\n  va_list tags;\n  va_start(tags, is_start);\n  bool result = false;\n  for (GumboTag tag = va_arg(tags, GumboTag); tag != GUMBO_TAG_LAST;\n       tag = va_arg(tags, GumboTag)) {\n    if (tag == token_tag) {\n      result = true;\n      break;\n    }\n  }\n  va_end(tags);\n  return result;\n}\n\n// Like tag_in, but for the single-tag case.\nstatic bool tag_is(const GumboToken* token, bool is_start, GumboTag tag) {\n  if (is_start && token->type == GUMBO_TOKEN_START_TAG) {\n    return token->v.start_tag.tag == tag;\n  } else if (!is_start && token->type == GUMBO_TOKEN_END_TAG) {\n    return token->v.end_tag == tag;\n  } else {\n    return false;\n  }\n}\n\n// Like tag_in, but checks for the tag of a node, rather than a token.\nstatic bool node_tag_in(const GumboNode* node, ...) {\n  assert(node != NULL);\n  if (node->type != GUMBO_NODE_ELEMENT) {\n    return false;\n  }\n  GumboTag node_tag = node->v.element.tag;\n\n  va_list tags;\n  va_start(tags, node);\n  bool result = false;\n  for (GumboTag tag = va_arg(tags, GumboTag); tag != GUMBO_TAG_LAST;\n       tag = va_arg(tags, GumboTag)) {\n    assert(tag <= GUMBO_TAG_LAST);\n    if (tag == node_tag) {\n      result = true;\n      break;\n    }\n  }\n  va_end(tags);\n  return result;\n}\n\n// Like node_tag_in, but for the single-tag case.\nstatic bool node_tag_is(const GumboNode* node, GumboTag tag) {\n  return node->type == GUMBO_NODE_ELEMENT && node->v.element.tag == tag;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#mathml-text-integration-point\nstatic bool is_mathml_integration_point(const GumboNode* node) {\n  return node_tag_in(node, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN,\n                     GUMBO_TAG_MS, GUMBO_TAG_MTEXT, GUMBO_TAG_LAST) &&\n      node->v.element.tag_namespace == GUMBO_NAMESPACE_MATHML;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#html-integration-point\nstatic bool is_html_integration_point(const GumboNode* node) {\n  return (node_tag_in(node, GUMBO_TAG_FOREIGNOBJECT, GUMBO_TAG_DESC,\n                      GUMBO_TAG_TITLE, GUMBO_TAG_LAST) &&\n      node->v.element.tag_namespace == GUMBO_NAMESPACE_SVG) ||\n      (node_tag_is(node, GUMBO_TAG_ANNOTATION_XML) && (\n          attribute_matches(&node->v.element.attributes,\n                            \"encoding\", \"text/html\") ||\n          attribute_matches(&node->v.element.attributes,\n                            \"encoding\", \"application/xhtml+xml\")));\n}\n\n// Appends a node to the end of its parent, setting the \"parent\" and\n// \"index_within_parent\" fields appropriately.\nstatic void append_node(\n    GumboParser* parser, GumboNode* parent, GumboNode* node) {\n  assert(node->parent == NULL);\n  assert(node->index_within_parent = -1);\n  GumboVector* children;\n  if (parent->type == GUMBO_NODE_ELEMENT) {\n    children = &parent->v.element.children;\n  } else {\n    assert(parent->type == GUMBO_NODE_DOCUMENT);\n    children = &parent->v.document.children;\n  }\n  node->parent = parent;\n  node->index_within_parent = children->length;\n  gumbo_vector_add(parser, (void*) node, children);\n  assert(node->index_within_parent < children->length);\n}\n\n// Inserts a node at the specified index within its parent, updating the\n// \"parent\" and \"index_within_parent\" fields of it and all its siblings.\nstatic void insert_node(\n    GumboParser* parser, GumboNode* parent, int index, GumboNode* node) {\n  assert(node->parent == NULL);\n  assert(node->index_within_parent = -1);\n  assert(parent->type == GUMBO_NODE_ELEMENT);\n  GumboVector* children = &parent->v.element.children;\n  assert(index >= 0);\n  assert(index < children->length);\n  node->parent = parent;\n  node->index_within_parent = index;\n  gumbo_vector_insert_at(parser, (void*) node, index, children);\n  assert(node->index_within_parent < children->length);\n  for (int i = index + 1; i < children->length; ++i) {\n    GumboNode* sibling = children->data[i];\n    sibling->index_within_parent = i;\n    assert(sibling->index_within_parent < children->length);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#foster-parenting\nstatic void foster_parent_element(GumboParser* parser, GumboNode* node) {\n  GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  assert(open_elements->length > 2);\n\n  node->parse_flags |= GUMBO_INSERTION_FOSTER_PARENTED;\n  GumboNode* foster_parent_element = open_elements->data[0];\n  assert(foster_parent_element->type == GUMBO_NODE_ELEMENT);\n  assert(node_tag_is(foster_parent_element, GUMBO_TAG_HTML));\n  for (int i = open_elements->length; --i > 1; ) {\n    GumboNode* table_element = open_elements->data[i];\n    if (node_tag_is(table_element, GUMBO_TAG_TABLE)) {\n      foster_parent_element = table_element->parent;\n      if (!foster_parent_element ||\n          foster_parent_element->type != GUMBO_NODE_ELEMENT) {\n        // Table has no parent; spec says it's possible if a script manipulated\n        // the DOM, although I don't think we have to worry about this case.\n        gumbo_debug(\"Table has no parent.\\n\");\n        foster_parent_element = open_elements->data[i - 1];\n        break;\n      }\n      assert(foster_parent_element->type == GUMBO_NODE_ELEMENT);\n      gumbo_debug(\"Found enclosing table (%x) at %d; parent=%s, index=%d.\\n\",\n                 table_element, i, gumbo_normalized_tagname(\n                     foster_parent_element->v.element.tag),\n                 table_element->index_within_parent);\n      assert(foster_parent_element->v.element.children.data[\n             table_element->index_within_parent] == table_element);\n      insert_node(parser, foster_parent_element,\n                  (int)table_element->index_within_parent, node);\n      return;\n    }\n  }\n  if (node->type == GUMBO_NODE_ELEMENT) {\n    gumbo_vector_add(parser, (void*) node, open_elements);\n  }\n  append_node(parser, foster_parent_element, node);\n}\n\nstatic void maybe_flush_text_node_buffer(GumboParser* parser) {\n  GumboParserState* state = parser->_parser_state;\n  TextNodeBufferState* buffer_state = &state->_text_node;\n  if (buffer_state->_buffer.length == 0) {\n    return;\n  }\n\n  assert(buffer_state->_type == GUMBO_NODE_WHITESPACE ||\n         buffer_state->_type == GUMBO_NODE_TEXT);\n  GumboNode* text_node = create_node(parser, buffer_state->_type);\n  GumboText* text_node_data = &text_node->v.text;\n  text_node_data->text = gumbo_string_buffer_to_string(\n      parser, &buffer_state->_buffer);\n  text_node_data->original_text.data = buffer_state->_start_original_text;\n  text_node_data->original_text.length =\n      state->_current_token->original_text.data -\n      buffer_state->_start_original_text;\n  text_node_data->start_pos = buffer_state->_start_position;\n  if (state->_foster_parent_insertions && node_tag_in(\n      get_current_node(parser), GUMBO_TAG_TABLE, GUMBO_TAG_TBODY,\n      GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD, GUMBO_TAG_TR, GUMBO_TAG_LAST)) {\n    foster_parent_element(parser, text_node);\n  } else {\n    append_node(\n        parser, parser->_output->root ?\n        get_current_node(parser) : parser->_output->document, text_node);\n  }\n  gumbo_debug(\"Flushing text node buffer of %.*s.\\n\",\n             (int) buffer_state->_buffer.length, buffer_state->_buffer.data);\n\n  gumbo_string_buffer_destroy(parser, &buffer_state->_buffer);\n  gumbo_string_buffer_init(parser, &buffer_state->_buffer);\n  buffer_state->_type = GUMBO_NODE_WHITESPACE;\n  assert(buffer_state->_buffer.length == 0);\n}\n\nstatic void record_end_of_element(\n    GumboToken* current_token, GumboElement* element) {\n  element->end_pos = current_token->position;\n  element->original_end_tag =\n      current_token->type == GUMBO_TOKEN_END_TAG ?\n      current_token->original_text : kGumboEmptyString;\n}\n\nstatic GumboNode* pop_current_node(GumboParser* parser) {\n  GumboParserState* state = parser->_parser_state;\n  maybe_flush_text_node_buffer(parser);\n  if (state->_open_elements.length > 0) {\n    assert(node_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML));\n    gumbo_debug(\n        \"Popping %s node.\\n\",\n        gumbo_normalized_tagname(get_current_node(parser)->v.element.tag));\n  }\n  GumboNode* current_node = gumbo_vector_pop(parser, &state->_open_elements);\n  if (!current_node) {\n    assert(state->_open_elements.length == 0);\n    return NULL;\n  }\n  assert(current_node->type == GUMBO_NODE_ELEMENT);\n  bool is_closed_body_or_html_tag =\n      (node_tag_is(current_node, GUMBO_TAG_BODY) && state->_closed_body_tag) ||\n      (node_tag_is(current_node, GUMBO_TAG_HTML) && state->_closed_html_tag);\n  if ((state->_current_token->type != GUMBO_TOKEN_END_TAG ||\n       !node_tag_is(current_node, state->_current_token->v.end_tag)) &&\n       !is_closed_body_or_html_tag) {\n    current_node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG;\n  }\n  if (!is_closed_body_or_html_tag) {\n    record_end_of_element(state->_current_token, &current_node->v.element);\n  }\n  return current_node;\n}\n\nstatic void append_comment_node(\n    GumboParser* parser, GumboNode* node, const GumboToken* token) {\n  maybe_flush_text_node_buffer(parser);\n  GumboNode* comment = create_node(parser, GUMBO_NODE_COMMENT);\n  comment->type = GUMBO_NODE_COMMENT;\n  comment->parse_flags = GUMBO_INSERTION_NORMAL;\n  comment->v.text.text = token->v.text;\n  comment->v.text.original_text = token->original_text;\n  comment->v.text.start_pos = token->position;\n  append_node(parser, node, comment);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-row-context\nstatic void clear_stack_to_table_row_context(GumboParser* parser) {\n  while (!node_tag_in(get_current_node(parser),\n                      GUMBO_TAG_HTML, GUMBO_TAG_TR, GUMBO_TAG_LAST)) {\n    pop_current_node(parser);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-context\nstatic void clear_stack_to_table_context(GumboParser* parser) {\n  while (!node_tag_in(get_current_node(parser),\n                      GUMBO_TAG_HTML, GUMBO_TAG_TABLE, GUMBO_TAG_LAST)) {\n    pop_current_node(parser);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-body-context\nvoid clear_stack_to_table_body_context(GumboParser* parser) {\n  while (!node_tag_in(get_current_node(parser), GUMBO_TAG_HTML,\n                      GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD,\n                      GUMBO_TAG_LAST)) {\n    pop_current_node(parser);\n  }\n}\n\n// Creates a parser-inserted element in the HTML namespace and returns it.\nstatic GumboNode* create_element(GumboParser* parser, GumboTag tag) {\n  GumboNode* node = create_node(parser, GUMBO_NODE_ELEMENT);\n  GumboElement* element = &node->v.element;\n  gumbo_vector_init(parser, 1, &element->children);\n  gumbo_vector_init(parser, 0, &element->attributes);\n  element->tag = tag;\n  element->tag_namespace = GUMBO_NAMESPACE_HTML;\n  element->original_tag = kGumboEmptyString;\n  element->original_end_tag = kGumboEmptyString;\n  element->start_pos = parser->_parser_state->_current_token->position;\n  element->end_pos = kGumboEmptySourcePosition;\n  return node;\n}\n\n// Constructs an element from the given start tag token.\nstatic GumboNode* create_element_from_token(\n    GumboParser* parser, GumboToken* token, GumboNamespaceEnum tag_namespace) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  GumboTokenStartTag* start_tag = &token->v.start_tag;\n\n  GumboNode* node = create_node(parser, GUMBO_NODE_ELEMENT);\n  GumboElement* element = &node->v.element;\n  gumbo_vector_init(parser, 1, &element->children);\n  element->attributes = start_tag->attributes;\n  element->tag = start_tag->tag;\n  element->tag_namespace = tag_namespace;\n\n  assert(token->original_text.length >= 2);\n  assert(token->original_text.data[0] == '<');\n  assert(token->original_text.data[token->original_text.length - 1] == '>');\n  element->original_tag = token->original_text;\n  element->start_pos = token->position;\n  element->original_end_tag = kGumboEmptyString;\n  element->end_pos = kGumboEmptySourcePosition;\n\n  // The element takes ownership of the attributes from the token, so any\n  // allocated-memory fields should be nulled out.\n  start_tag->attributes = kGumboEmptyVector;\n  return node;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#insert-an-html-element\nstatic void insert_element(GumboParser* parser, GumboNode* node,\n                           bool is_reconstructing_formatting_elements) {\n  GumboParserState* state = parser->_parser_state;\n  // NOTE(jdtang): The text node buffer must always be flushed before inserting\n  // a node, otherwise we're handling nodes in a different order than the spec\n  // mandated.  However, one clause of the spec (character tokens in the body)\n  // requires that we reconstruct the active formatting elements *before* adding\n  // the character, and reconstructing the active formatting elements may itself\n  // result in the insertion of new elements (which should be pushed onto the\n  // stack of open elements before the buffer is flushed).  We solve this (for\n  // the time being, the spec has been rewritten for <template> and the new\n  // version may be simpler here) with a boolean flag to this method.\n  if (!is_reconstructing_formatting_elements) {\n    maybe_flush_text_node_buffer(parser);\n  }\n  if (state->_foster_parent_insertions && node_tag_in(\n      get_current_node(parser), GUMBO_TAG_TABLE, GUMBO_TAG_TBODY,\n      GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD, GUMBO_TAG_TR, GUMBO_TAG_LAST)) {\n    foster_parent_element(parser, node);\n    gumbo_vector_add(parser, (void*) node, &state->_open_elements);\n    return;\n  }\n\n  // This is called to insert the root HTML element, but get_current_node\n  // assumes the stack of open elements is non-empty, so we need special\n  // handling for this case.\n  append_node(\n      parser, parser->_output->root ?\n      get_current_node(parser) : parser->_output->document, node);\n  gumbo_vector_add(parser, (void*) node, &state->_open_elements);\n}\n\n// Convenience method that combines create_element_from_token and\n// insert_element, inserting the generated element directly into the current\n// node.  Returns the node inserted.\nstatic GumboNode* insert_element_from_token(\n    GumboParser* parser, GumboToken* token) {\n  GumboNode* element =\n      create_element_from_token(parser, token, GUMBO_NAMESPACE_HTML);\n  insert_element(parser, element, false);\n  gumbo_debug(\"Inserting <%s> element (@%x) from token.\\n\",\n             gumbo_normalized_tagname(element->v.element.tag), element);\n  return element;\n}\n\n// Convenience method that combines create_element and insert_element, inserting\n// a parser-generated element of a specific tag type.  Returns the node\n// inserted.\nstatic GumboNode* insert_element_of_tag_type(\n    GumboParser* parser, GumboTag tag, GumboParseFlags reason) {\n  GumboNode* element = create_element(parser, tag);\n  element->parse_flags |= GUMBO_INSERTION_BY_PARSER | reason;\n  insert_element(parser, element, false);\n  gumbo_debug(\"Inserting %s element (@%x) from tag type.\\n\",\n             gumbo_normalized_tagname(tag), element);\n  return element;\n}\n\n// Convenience method for creating foreign namespaced element.  Returns the node\n// inserted.\nstatic GumboNode* insert_foreign_element(\n    GumboParser* parser, GumboToken* token, GumboNamespaceEnum tag_namespace) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  GumboNode* element = create_element_from_token(parser, token, tag_namespace);\n  insert_element(parser, element, false);\n  if (token_has_attribute(token, \"xmlns\") &&\n      !attribute_matches_case_sensitive(\n          &token->v.start_tag.attributes, \"xmlns\",\n          kLegalXmlns[tag_namespace])) {\n    // TODO(jdtang): Since there're multiple possible error codes here, we\n    // eventually need reason codes to differentiate them.\n    add_parse_error(parser, token);\n  }\n  if (token_has_attribute(token, \"xmlns:xlink\") &&\n      !attribute_matches_case_sensitive(\n          &token->v.start_tag.attributes,\n          \"xmlns:xlink\", \"http://www.w3.org/1999/xlink\")) {\n    add_parse_error(parser, token);\n  }\n  return element;\n}\n\nstatic void insert_text_token(GumboParser* parser, GumboToken* token) {\n  assert(token->type == GUMBO_TOKEN_WHITESPACE ||\n         token->type == GUMBO_TOKEN_CHARACTER);\n  TextNodeBufferState* buffer_state = &parser->_parser_state->_text_node;\n  if (buffer_state->_buffer.length == 0) {\n    // Initialize position fields.\n    buffer_state->_start_original_text = token->original_text.data;\n    buffer_state->_start_position = token->position;\n  }\n  gumbo_string_buffer_append_codepoint(\n      parser, token->v.character, &buffer_state->_buffer);\n  if (token->type == GUMBO_TOKEN_CHARACTER) {\n    buffer_state->_type = GUMBO_NODE_TEXT;\n  }\n  gumbo_debug(\"Inserting text token '%c'.\\n\", token->v.character);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#generic-rcdata-element-parsing-algorithm\nstatic void run_generic_parsing_algorithm(\n    GumboParser* parser, GumboToken* token, GumboTokenizerEnum lexer_state) {\n  insert_element_from_token(parser, token);\n  gumbo_tokenizer_set_state(parser, lexer_state);\n  parser->_parser_state->_original_insertion_mode =\n      parser->_parser_state->_insertion_mode;\n  parser->_parser_state->_insertion_mode = GUMBO_INSERTION_MODE_TEXT;\n}\n\nstatic void acknowledge_self_closing_tag(GumboParser* parser) {\n  parser->_parser_state->_self_closing_flag_acknowledged = true;\n}\n\n// Returns true if there's an anchor tag in the list of active formatting\n// elements, and fills in its index if so.\nstatic bool find_last_anchor_index(GumboParser* parser, int* anchor_index) {\n  GumboVector* elements = &parser->_parser_state->_active_formatting_elements;\n  for (int i = elements->length; --i >= 0; ) {\n    GumboNode* node = elements->data[i];\n    if (node == &kActiveFormattingScopeMarker) {\n      return false;\n    }\n    if (node_tag_is(node, GUMBO_TAG_A)) {\n      *anchor_index = i;\n      return true;\n    }\n  }\n  return false;\n}\n\n// Counts the number of open formatting elements in the list of active\n// formatting elements (after the last active scope marker) that have a specific\n// tag.  If this is > 0, then earliest_matching_index will be filled in with the\n// index of the first such element.\nstatic int count_formatting_elements_of_tag(\n    GumboParser* parser, const GumboNode* desired_node,\n    int* earliest_matching_index) {\n  const GumboElement* desired_element = &desired_node->v.element;\n  GumboVector* elements = &parser->_parser_state->_active_formatting_elements;\n  int num_identical_elements = 0;\n  for (int i = elements->length; --i >= 0; ) {\n    GumboNode* node = elements->data[i];\n    if (node == &kActiveFormattingScopeMarker) {\n      break;\n    }\n    assert(node->type == GUMBO_NODE_ELEMENT);\n    GumboElement* element = &node->v.element;\n    if (node_tag_is(node, desired_element->tag) &&\n        element->tag_namespace == desired_element->tag_namespace &&\n        all_attributes_match(&element->attributes,\n                             &desired_element->attributes)) {\n      num_identical_elements++;\n      *earliest_matching_index = i;\n    }\n  }\n  return num_identical_elements;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#reconstruct-the-active-formatting-elements\nstatic void add_formatting_element(GumboParser* parser, const GumboNode* node) {\n  assert(node == &kActiveFormattingScopeMarker ||\n         node->type == GUMBO_NODE_ELEMENT);\n  GumboVector* elements = &parser->_parser_state->_active_formatting_elements;\n  if (node == &kActiveFormattingScopeMarker) {\n    gumbo_debug(\"Adding a scope marker.\\n\");\n  } else {\n    gumbo_debug(\"Adding a formatting element.\\n\");\n  }\n\n  // Hunt for identical elements.\n  int earliest_identical_element = elements->length;\n  int num_identical_elements = count_formatting_elements_of_tag(\n      parser, node, &earliest_identical_element);\n\n  // Noah's Ark clause: if there're at least 3, remove the earliest.\n  if (num_identical_elements >= 3) {\n    gumbo_debug(\"Noah's ark clause: removing element at %d.\\n\",\n                earliest_identical_element);\n    gumbo_vector_remove_at(parser, earliest_identical_element, elements);\n  }\n\n  gumbo_vector_add(parser, (void*) node, elements);\n}\n\nstatic bool is_open_element(GumboParser* parser, const GumboNode* node) {\n  GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  for (int i = 0; i < open_elements->length; ++i) {\n    if (open_elements->data[i] == node) {\n      return true;\n    }\n  }\n  return false;\n}\n\n// Clones attributes, tags, etc. of a node, but does not copy the content.  The\n// clone shares no structure with the original node: all owned strings and\n// values are fresh copies.\nGumboNode* clone_node(\n    GumboParser* parser, const GumboNode* node, GumboParseFlags reason) {\n  assert(node->type == GUMBO_NODE_ELEMENT);\n  GumboNode* new_node = gumbo_parser_allocate(parser, sizeof(GumboNode));\n  *new_node = *node;\n  new_node->parent = NULL;\n  new_node->index_within_parent = -1;\n  // Clear the GUMBO_INSERTION_IMPLICIT_END_TAG flag, as the cloned node may\n  // have a separate end tag.\n  new_node->parse_flags &= ~GUMBO_INSERTION_IMPLICIT_END_TAG;\n  new_node->parse_flags |= reason | GUMBO_INSERTION_BY_PARSER;\n  GumboElement* element = &new_node->v.element;\n  gumbo_vector_init(parser, 1, &element->children);\n\n  const GumboVector* old_attributes = &node->v.element.attributes;\n  gumbo_vector_init(parser, old_attributes->length, &element->attributes);\n  for (int i = 0; i < old_attributes->length; ++i) {\n    const GumboAttribute* old_attr = old_attributes->data[i];\n    GumboAttribute* attr =\n        gumbo_parser_allocate(parser, sizeof(GumboAttribute));\n    *attr = *old_attr;\n    attr->name = gumbo_copy_stringz(parser, old_attr->name);\n    attr->value = gumbo_copy_stringz(parser, old_attr->value);\n    gumbo_vector_add(parser, attr, &element->attributes);\n  }\n  return new_node;\n}\n\n// \"Reconstruct active formatting elements\" part of the spec.\n// This implementation is based on the html5lib translation from the mess of\n// GOTOs in the spec to reasonably structured programming.\n// http://code.google.com/p/html5lib/source/browse/python/html5lib/treebuilders/_base.py\nstatic void reconstruct_active_formatting_elements(GumboParser* parser) {\n  GumboVector* elements = &parser->_parser_state->_active_formatting_elements;\n  // Step 1\n  if (elements->length == 0) {\n    return;\n  }\n\n  // Step 2 & 3\n  int i = elements->length - 1;\n  const GumboNode* element = elements->data[i];\n  if (element == &kActiveFormattingScopeMarker ||\n      is_open_element(parser, element)) {\n    return;\n  }\n\n  // Step 6\n  do {\n    if (i == 0) {\n      // Step 4\n      i = -1;   // Incremented to 0 below.\n      break;\n    }\n    // Step 5\n    element = elements->data[--i];\n  } while (element != &kActiveFormattingScopeMarker &&\n           !is_open_element(parser, element));\n\n  ++i;\n  gumbo_debug(\"Reconstructing elements from %d on %s parent.\\n\", i,\n              gumbo_normalized_tagname(\n                  get_current_node(parser)->v.element.tag));\n  for(; i < elements->length; ++i) {\n    // Step 7 & 8.\n    assert(elements->length > 0);\n    assert(i < elements->length);\n    element = elements->data[i];\n    assert(element != &kActiveFormattingScopeMarker);\n    GumboNode* clone = clone_node(\n        parser, element, GUMBO_INSERTION_RECONSTRUCTED_FORMATTING_ELEMENT);\n    // Step 9.\n    insert_element(parser, clone, true);\n    // Step 10.\n    elements->data[i] = clone;\n    gumbo_debug(\"Reconstructed %s element at %d.\\n\",\n               gumbo_normalized_tagname(clone->v.element.tag), i);\n  }\n}\n\nstatic void clear_active_formatting_elements(GumboParser* parser) {\n  GumboVector* elements = &parser->_parser_state->_active_formatting_elements;\n  int num_elements_cleared = 0;\n  const GumboNode* node;\n  do {\n    node = gumbo_vector_pop(parser, elements);\n    ++num_elements_cleared;\n  } while(node && node != &kActiveFormattingScopeMarker);\n  gumbo_debug(\"Cleared %d elements from active formatting list.\\n\",\n              num_elements_cleared);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-initial-insertion-mode\nstatic GumboQuirksModeEnum compute_quirks_mode(\n    const GumboTokenDocType* doctype) {\n  if (doctype->force_quirks ||\n      strcmp(doctype->name, kDoctypeHtml.data) ||\n      is_in_static_list(doctype->public_identifier,\n                        kQuirksModePublicIdPrefixes, false) ||\n      is_in_static_list(doctype->public_identifier,\n                        kQuirksModePublicIdExactMatches, true) ||\n      is_in_static_list(doctype->system_identifier,\n                        kQuirksModeSystemIdExactMatches, true) ||\n      (is_in_static_list(doctype->public_identifier,\n                         kLimitedQuirksRequiresSystemIdPublicIdPrefixes, false)\n       && !doctype->has_system_identifier)) {\n    return GUMBO_DOCTYPE_QUIRKS;\n  } else if (\n      is_in_static_list(doctype->public_identifier,\n                        kLimitedQuirksPublicIdPrefixes, false) ||\n      (is_in_static_list(doctype->public_identifier,\n                         kLimitedQuirksRequiresSystemIdPublicIdPrefixes, false)\n       && doctype->has_system_identifier)) {\n    return GUMBO_DOCTYPE_LIMITED_QUIRKS;\n  }\n  return GUMBO_DOCTYPE_NO_QUIRKS;\n}\n\n// The following functions are all defined by the \"has an element in __ scope\"\n// sections of the HTML5 spec:\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-the-specific-scope\n// The basic idea behind them is that they check for an element of the given tag\n// name, contained within a scope formed by a set of other tag names.  For\n// example, \"has an element in list scope\" looks for an element of the given tag\n// within the nearest enclosing <ol> or <ul>, along with a bunch of generic\n// element types that serve to \"firewall\" their content from the rest of the\n// document.\nstatic bool has_an_element_in_specific_scope(\n    GumboParser* parser, GumboVector* /* GumboTag */ expected, bool negate, ...) {\n  GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  va_list args;\n  va_start(args, negate);\n  // va_arg can only run through the list once, so we copy it to an GumboVector\n  // here.  I wonder if it'd make more sense to make tags the GumboVector*\n  // parameter and 'expected' a vararg list, but that'd require changing a lot\n  // of code for unknown benefit.  We may want to change the representation of\n  // these tag sets anyway, to something more efficient.\n  GumboVector tags;\n  gumbo_vector_init(parser, 10, &tags);\n  for (GumboTag tag = va_arg(args, GumboTag); tag != GUMBO_TAG_LAST;\n       tag = va_arg(args, GumboTag)) {\n    // We store the tags inline instead of storing pointers to them.\n    gumbo_vector_add(parser, (void*) tag, &tags);\n  }\n  va_end(args);\n\n  bool result = false;\n  for (int i = open_elements->length; --i >= 0; ) {\n    const GumboNode* node = open_elements->data[i];\n    if (node->type != GUMBO_NODE_ELEMENT) {\n      continue;\n    }\n    GumboTag node_tag = node->v.element.tag;\n    for (int j = 0; j < expected->length; ++j) {\n      GumboTag expected_tag = (GumboTag) expected->data[j];\n      if (node_tag == expected_tag) {\n        result = true;\n        goto cleanup;\n      }\n    }\n\n    bool found_tag = false;\n    for (int j = 0; j < tags.length; ++j) {\n      GumboTag tag = (GumboTag) tags.data[j];\n      if (tag == node_tag) {\n        found_tag = true;\n        break;\n      }\n    }\n    if (negate != found_tag) {\n      result = false;\n      goto cleanup;\n    }\n  }\ncleanup:\n  gumbo_vector_destroy(parser, &tags);\n  return result;\n}\n\n// This is a bit of a hack to stack-allocate a one-element GumboVector name\n// 'varname' containing the 'from_var' variable, since it's used in nearly all\n// the subsequent helper functions.  Note the use of void* and casts instead of\n// GumboTag; this is so the alignment requirements are the same as GumboVector\n// and the data inside it can be freely accessed as if it were a normal\n// GumboVector.\n#define DECLARE_ONE_ELEMENT_GUMBO_VECTOR(varname, from_var) \\\n    void* varname ## _tmp_array[1] = { (void*) from_var }; \\\n    GumboVector varname = { varname ## _tmp_array, 1, 1 }\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-scope\nstatic bool has_an_element_in_scope(GumboParser* parser, GumboTag tag) {\n  DECLARE_ONE_ELEMENT_GUMBO_VECTOR(tags, tag);\n  return has_an_element_in_specific_scope(\n      parser, &tags, false, GUMBO_TAG_APPLET, GUMBO_TAG_CAPTION, GUMBO_TAG_HTML,\n      GUMBO_TAG_TABLE, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_MARQUEE,\n      GUMBO_TAG_OBJECT, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN, GUMBO_TAG_MS,\n      GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML, GUMBO_TAG_FOREIGNOBJECT,\n      GUMBO_TAG_DESC, GUMBO_TAG_TITLE, GUMBO_TAG_LAST);\n}\n\n// Like \"has an element in scope\", but for the specific case of looking for a\n// unique target node, not for any node with a given tag name.  This duplicates\n// much of the algorithm from has_an_element_in_specific_scope because the\n// predicate is different when checking for an exact node, and it's easier &\n// faster just to duplicate the code for this one case than to try and\n// parameterize it.\nstatic bool has_node_in_scope(GumboParser* parser, const GumboNode* node) {\n  GumboVector* open_elements = &parser->_parser_state->_open_elements;\n  for (int i = open_elements->length; --i >= 0; ) {\n    const GumboNode* current = open_elements->data[i];\n    if (current == node) {\n      return true;\n    }\n    if (current->type != GUMBO_NODE_ELEMENT) {\n      continue;\n    }\n    if (node_tag_in(\n        current, GUMBO_TAG_APPLET, GUMBO_TAG_CAPTION, GUMBO_TAG_HTML,\n        GUMBO_TAG_TABLE, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_MARQUEE,\n        GUMBO_TAG_OBJECT, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN,\n        GUMBO_TAG_MS, GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML,\n        GUMBO_TAG_FOREIGNOBJECT, GUMBO_TAG_DESC, GUMBO_TAG_TITLE,\n        GUMBO_TAG_LAST)) {\n      return false;\n    }\n  }\n  assert(false);\n  return false;\n}\n\n// Like has_an_element_in_scope, but restricts the expected tag to a range of\n// possible tag names instead of just a single one.\nstatic bool has_an_element_in_scope_with_tagname(GumboParser* parser, ...) {\n  GumboVector tags;\n  // 6 = arbitrary initial size for vector, chosen because the major use-case\n  // for this method is heading tags, of which there are 6.\n  gumbo_vector_init(parser, 6, &tags);\n  va_list args;\n  va_start(args, parser);\n  for (GumboTag tag = va_arg(args, GumboTag); tag != GUMBO_TAG_LAST;\n       tag = va_arg(args, GumboTag)) {\n    gumbo_vector_add(parser, (void*) tag, &tags);\n  }\n  bool found = has_an_element_in_specific_scope(\n      parser, &tags, false, GUMBO_TAG_APPLET, GUMBO_TAG_CAPTION, GUMBO_TAG_HTML,\n      GUMBO_TAG_TABLE, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_MARQUEE,\n      GUMBO_TAG_OBJECT, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN, GUMBO_TAG_MS,\n      GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML, GUMBO_TAG_FOREIGNOBJECT,\n      GUMBO_TAG_DESC, GUMBO_TAG_TITLE, GUMBO_TAG_LAST);\n  gumbo_vector_destroy(parser, &tags);\n  va_end(args);\n  return found;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-list-item-scope\nstatic bool has_an_element_in_list_scope(GumboParser* parser, GumboTag tag) {\n  DECLARE_ONE_ELEMENT_GUMBO_VECTOR(tags, tag);\n  return has_an_element_in_specific_scope(\n      parser, &tags, false, GUMBO_TAG_APPLET, GUMBO_TAG_CAPTION, GUMBO_TAG_HTML,\n      GUMBO_TAG_TABLE, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_MARQUEE,\n      GUMBO_TAG_OBJECT, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN, GUMBO_TAG_MS,\n      GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML, GUMBO_TAG_FOREIGNOBJECT,\n      GUMBO_TAG_DESC, GUMBO_TAG_TITLE, GUMBO_TAG_OL, GUMBO_TAG_UL,\n      GUMBO_TAG_LAST);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-button-scope\nstatic bool has_an_element_in_button_scope(GumboParser* parser, GumboTag tag) {\n  DECLARE_ONE_ELEMENT_GUMBO_VECTOR(tags, tag);\n  return has_an_element_in_specific_scope(\n      parser, &tags, false, GUMBO_TAG_APPLET, GUMBO_TAG_CAPTION, GUMBO_TAG_HTML,\n      GUMBO_TAG_TABLE, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_MARQUEE,\n      GUMBO_TAG_OBJECT, GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN, GUMBO_TAG_MS,\n      GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML, GUMBO_TAG_FOREIGNOBJECT,\n      GUMBO_TAG_DESC, GUMBO_TAG_TITLE, GUMBO_TAG_BUTTON, GUMBO_TAG_LAST);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-table-scope\nstatic bool has_an_element_in_table_scope(GumboParser* parser, GumboTag tag) {\n  DECLARE_ONE_ELEMENT_GUMBO_VECTOR(tags, tag);\n  return has_an_element_in_specific_scope(\n      parser, &tags, false, GUMBO_TAG_HTML, GUMBO_TAG_TABLE, GUMBO_TAG_LAST);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-select-scope\nstatic bool has_an_element_in_select_scope(GumboParser* parser, GumboTag tag) {\n  DECLARE_ONE_ELEMENT_GUMBO_VECTOR(tags, tag);\n  return has_an_element_in_specific_scope(\n      parser, &tags, true, GUMBO_TAG_OPTGROUP, GUMBO_TAG_OPTION,\n      GUMBO_TAG_LAST);\n}\n\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#generate-implied-end-tags\n// \"exception\" is the \"element to exclude from the process\" listed in the spec.\n// Pass GUMBO_TAG_LAST to not exclude any of them.\nstatic void generate_implied_end_tags(GumboParser* parser, GumboTag exception) {\n  for (;\n       node_tag_in(get_current_node(parser), GUMBO_TAG_DD, GUMBO_TAG_DT,\n                   GUMBO_TAG_LI, GUMBO_TAG_OPTION, GUMBO_TAG_OPTGROUP,\n                   GUMBO_TAG_P, GUMBO_TAG_RP, GUMBO_TAG_RT, GUMBO_TAG_LAST) &&\n       !node_tag_is(get_current_node(parser), exception);\n       pop_current_node(parser));\n}\n\n// This factors out the clauses relating to \"act as if an end tag token with tag\n// name \"table\" had been seen.  Returns true if there's a table element in table\n// scope which was successfully closed, false if not and the token should be\n// ignored.  Does not add parse errors; callers should handle that.\nstatic bool close_table(GumboParser* parser) {\n  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TABLE)) {\n    return false;\n  }\n\n  GumboNode* node = pop_current_node(parser);\n  while (!node_tag_is(node, GUMBO_TAG_TABLE)) {\n    node = pop_current_node(parser);\n  }\n  reset_insertion_mode_appropriately(parser);\n  return true;\n}\n\n// This factors out the clauses relating to \"act as if an end tag token with tag\n// name `cell_tag` had been seen\".\nstatic bool close_table_cell(GumboParser* parser, const GumboToken* token,\n                             GumboTag cell_tag) {\n  bool result = true;\n  generate_implied_end_tags(parser, GUMBO_TAG_LAST);\n  const GumboNode* node = get_current_node(parser);\n  if (!node_tag_is(node, cell_tag)) {\n    add_parse_error(parser, token);\n    result = false;\n  }\n  do {\n    node = pop_current_node(parser);\n  } while (!node_tag_is(node, cell_tag));\n\n  clear_active_formatting_elements(parser);\n  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);\n  return result;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#close-the-cell\n// This holds the logic to determine whether we should close a <td> or a <th>.\nstatic bool close_current_cell(GumboParser* parser, const GumboToken* token) {\n  if (has_an_element_in_table_scope(parser, GUMBO_TAG_TD)) {\n    assert(!has_an_element_in_table_scope(parser, GUMBO_TAG_TH));\n    return close_table_cell(parser, token, GUMBO_TAG_TD);\n  } else {\n    assert(has_an_element_in_table_scope(parser, GUMBO_TAG_TH));\n    return close_table_cell(parser, token, GUMBO_TAG_TH);\n  }\n}\n\n// This factors out the \"act as if an end tag of tag name 'select' had been\n// seen\" clause of the spec, since it's referenced in several places.  It pops\n// all nodes from the stack until the current <select> has been closed, then\n// resets the insertion mode appropriately.\nstatic void close_current_select(GumboParser* parser) {\n  GumboNode* node = pop_current_node(parser);\n  while (!node_tag_is(node, GUMBO_TAG_SELECT)) {\n    node = pop_current_node(parser);\n  }\n  reset_insertion_mode_appropriately(parser);\n}\n\n// The list of nodes in the \"special\" category:\n// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#special\nstatic bool is_special_node(const GumboNode* node) {\n  assert(node->type == GUMBO_NODE_ELEMENT);\n  switch (node->v.element.tag_namespace) {\n    case GUMBO_NAMESPACE_HTML:\n      return node_tag_in(node,\n           GUMBO_TAG_ADDRESS, GUMBO_TAG_APPLET, GUMBO_TAG_AREA,\n           GUMBO_TAG_ARTICLE, GUMBO_TAG_ASIDE, GUMBO_TAG_BASE,\n           GUMBO_TAG_BASEFONT, GUMBO_TAG_BGSOUND, GUMBO_TAG_BLOCKQUOTE,\n           GUMBO_TAG_BODY, GUMBO_TAG_BR, GUMBO_TAG_BUTTON, GUMBO_TAG_CAPTION,\n           GUMBO_TAG_CENTER, GUMBO_TAG_COL, GUMBO_TAG_COLGROUP,\n           GUMBO_TAG_COMMAND, GUMBO_TAG_DD, GUMBO_TAG_DETAILS, GUMBO_TAG_DIR,\n           GUMBO_TAG_DIV, GUMBO_TAG_DL, GUMBO_TAG_DT, GUMBO_TAG_EMBED,\n           GUMBO_TAG_FIELDSET, GUMBO_TAG_FIGCAPTION, GUMBO_TAG_FIGURE,\n           GUMBO_TAG_FOOTER, GUMBO_TAG_FORM, GUMBO_TAG_FRAME,\n           GUMBO_TAG_FRAMESET, GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3,\n           GUMBO_TAG_H4, GUMBO_TAG_H5, GUMBO_TAG_H6, GUMBO_TAG_HEAD,\n           GUMBO_TAG_HEADER, GUMBO_TAG_HGROUP, GUMBO_TAG_HR, GUMBO_TAG_HTML,\n           GUMBO_TAG_IFRAME, GUMBO_TAG_IMG, GUMBO_TAG_INPUT, GUMBO_TAG_ISINDEX,\n           GUMBO_TAG_LI, GUMBO_TAG_LINK, GUMBO_TAG_LISTING, GUMBO_TAG_MARQUEE,\n           GUMBO_TAG_MENU, GUMBO_TAG_META, GUMBO_TAG_NAV, GUMBO_TAG_NOEMBED,\n           GUMBO_TAG_NOFRAMES, GUMBO_TAG_NOSCRIPT, GUMBO_TAG_OBJECT,\n           GUMBO_TAG_OL, GUMBO_TAG_P, GUMBO_TAG_PARAM, GUMBO_TAG_PLAINTEXT,\n           GUMBO_TAG_PRE, GUMBO_TAG_SCRIPT, GUMBO_TAG_SECTION, GUMBO_TAG_SELECT,\n           GUMBO_TAG_STYLE, GUMBO_TAG_SUMMARY, GUMBO_TAG_TABLE, GUMBO_TAG_TBODY,\n           GUMBO_TAG_TD, GUMBO_TAG_TEXTAREA, GUMBO_TAG_TFOOT, GUMBO_TAG_TH,\n           GUMBO_TAG_THEAD, GUMBO_TAG_TITLE, GUMBO_TAG_TR, GUMBO_TAG_UL,\n           GUMBO_TAG_WBR, GUMBO_TAG_XMP, GUMBO_TAG_LAST);\n    case GUMBO_NAMESPACE_MATHML:\n      return node_tag_in(node,\n          GUMBO_TAG_MI, GUMBO_TAG_MO, GUMBO_TAG_MN, GUMBO_TAG_MS,\n          GUMBO_TAG_MTEXT, GUMBO_TAG_ANNOTATION_XML, GUMBO_TAG_LAST);\n    case GUMBO_NAMESPACE_SVG:\n      return node_tag_in(node,\n          GUMBO_TAG_FOREIGNOBJECT, GUMBO_TAG_DESC, GUMBO_TAG_LAST);\n  }\n  abort();\n  return false;  // Pacify compiler.\n}\n\n// Implicitly closes currently open tags until it reaches an element with the\n// specified tag name.  If the elements closed are in the set handled by\n// generate_implied_end_tags, this is normal operation and this function returns\n// true.  Otherwise, a parse error is recorded and this function returns false.\nstatic bool implicitly_close_tags(\n    GumboParser* parser, GumboToken* token, GumboTag target) {\n  bool result = true;\n  generate_implied_end_tags(parser, target);\n  if (!node_tag_is(get_current_node(parser), target)) {\n    add_parse_error(parser, token);\n    while (!node_tag_is(get_current_node(parser), target)) {\n      pop_current_node(parser);\n    }\n    result = false;\n  }\n  assert(node_tag_is(get_current_node(parser), target));\n  pop_current_node(parser);\n  return result;\n}\n\n// If the stack of open elements has a <p> tag in button scope, this acts as if\n// a </p> tag was encountered, implicitly closing tags.  Returns false if a\n// parse error occurs.  This is a convenience function because this particular\n// clause appears several times in the spec.\nstatic bool maybe_implicitly_close_p_tag(GumboParser* parser, GumboToken* token) {\n  if (has_an_element_in_button_scope(parser, GUMBO_TAG_P)) {\n    return implicitly_close_tags(parser, token, GUMBO_TAG_P);\n  }\n  return true;\n}\n\n// Convenience function to encapsulate the logic for closing <li> or <dd>/<dt>\n// tags.  Pass true to is_li for handling <li> tags, false for <dd> and <dt>.\nstatic void maybe_implicitly_close_list_tag(\n    GumboParser* parser, GumboToken* token, bool is_li) {\n  GumboParserState* state = parser->_parser_state;\n  state->_frameset_ok = false;\n  for (int i = state->_open_elements.length; --i >= 0; ) {\n    const GumboNode* node = state->_open_elements.data[i];\n    bool is_list_tag = is_li ?\n        node_tag_is(node, GUMBO_TAG_LI) :\n        node_tag_in(node, GUMBO_TAG_DD, GUMBO_TAG_DT, GUMBO_TAG_LAST);\n    if (is_list_tag) {\n      implicitly_close_tags(parser, token, node->v.element.tag);\n      return;\n    }\n    if (is_special_node(node) &&\n        !node_tag_in(node, GUMBO_TAG_ADDRESS, GUMBO_TAG_DIV, GUMBO_TAG_P,\n                     GUMBO_TAG_LAST)) {\n      return;\n    }\n  }\n}\n\nstatic void merge_attributes(\n    GumboParser* parser, GumboToken* token, GumboNode* node) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  assert(node->type == GUMBO_NODE_ELEMENT);\n  const GumboVector* token_attr = &token->v.start_tag.attributes;\n  GumboVector* node_attr = &node->v.element.attributes;\n\n  for (int i = 0; i < token_attr->length; ++i) {\n    GumboAttribute* attr = token_attr->data[i];\n    if (!gumbo_get_attribute(node_attr, attr->name)) {\n      // Ownership of the attribute is transferred by this gumbo_vector_add,\n      // so it has to be nulled out of the original token so it doesn't get\n      // double-deleted.\n      gumbo_vector_add(parser, attr, node_attr);\n      token_attr->data[i] = NULL;\n    }\n  }\n  // When attributes are merged, it means the token has been ignored and merged\n  // with another token, so we need to free its memory.  The attributes that are\n  // transferred need to be nulled-out in the vector above so that they aren't\n  // double-deleted.\n  gumbo_token_destroy(parser, token);\n\n#ifndef NDEBUG\n  // Mark this sentinel so the assertion in the main loop knows it's been\n  // destroyed.\n  token->v.start_tag.attributes = kGumboEmptyVector;\n#endif\n}\n\nconst char* gumbo_normalize_svg_tagname(const GumboStringPiece* tag) {\n  for (int i = 0;\n       i < sizeof(kSvgTagReplacements) / sizeof(ReplacementEntry); ++i) {\n    const ReplacementEntry* entry = &kSvgTagReplacements[i];\n    if (gumbo_string_equals_ignore_case(tag, &entry->from)) {\n      return entry->to.data;\n    }\n  }\n  return NULL;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adjust-foreign-attributes\n// This destructively modifies any matching attributes on the token and sets the\n// namespace appropriately.\nstatic void adjust_foreign_attributes(GumboParser* parser, GumboToken* token) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  const GumboVector* attributes = &token->v.start_tag.attributes;\n  for (int i = 0;\n       i < sizeof(kForeignAttributeReplacements) /\n       sizeof(NamespacedAttributeReplacement); ++i) {\n    const NamespacedAttributeReplacement* entry =\n        &kForeignAttributeReplacements[i];\n    GumboAttribute* attr = gumbo_get_attribute(attributes, entry->from);\n    if (!attr) {\n      continue;\n    }\n    gumbo_parser_deallocate(parser, (void*) attr->name);\n    attr->attr_namespace = entry->attr_namespace;\n    attr->name = gumbo_copy_stringz(parser, entry->local_name);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#adjust-svg-attributes\n// This destructively modifies any matching attributes on the token.\nstatic void adjust_svg_attributes(GumboParser* parser, GumboToken* token) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  const GumboVector* attributes = &token->v.start_tag.attributes;\n  for (int i = 0;\n       i < sizeof(kSvgAttributeReplacements) / sizeof(ReplacementEntry); ++i) {\n    const ReplacementEntry* entry = &kSvgAttributeReplacements[i];\n    GumboAttribute* attr = gumbo_get_attribute(attributes, entry->from.data);\n    if (!attr) {\n      continue;\n    }\n    gumbo_parser_deallocate(parser, (void*) attr->name);\n    attr->name = gumbo_copy_stringz(parser, entry->to.data);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#adjust-mathml-attributes\n// Note that this may destructively modify the token with the new attribute\n// value.\nstatic void adjust_mathml_attributes(GumboParser* parser, GumboToken* token) {\n  assert(token->type == GUMBO_TOKEN_START_TAG);\n  GumboAttribute* attr = gumbo_get_attribute(\n      &token->v.start_tag.attributes, \"definitionurl\");\n  if (!attr) {\n    return;\n  }\n  gumbo_parser_deallocate(parser, (void*) attr->name);\n  attr->name = gumbo_copy_stringz(parser, \"definitionURL\");\n}\n\nstatic bool doctype_matches(\n    const GumboTokenDocType* doctype,\n    const GumboStringPiece* public_id,\n    const GumboStringPiece* system_id,\n    bool allow_missing_system_id) {\n  return !strcmp(doctype->public_identifier, public_id->data) &&\n      (allow_missing_system_id || doctype->has_system_identifier) &&\n      !strcmp(doctype->system_identifier, system_id->data);\n}\n\nstatic bool maybe_add_doctype_error(\n    GumboParser* parser, const GumboToken* token) {\n  const GumboTokenDocType* doctype = &token->v.doc_type;\n  bool html_doctype = !strcmp(doctype->name, kDoctypeHtml.data);\n  if (!html_doctype ||\n      doctype->has_public_identifier ||\n      (doctype->has_system_identifier && !strcmp(\n          doctype->system_identifier, kSystemIdLegacyCompat.data)) ||\n      !(html_doctype && (\n          doctype_matches(doctype, &kPublicIdHtml4_0,\n                          &kSystemIdRecHtml4_0, true) ||\n          doctype_matches(doctype, &kPublicIdHtml4_01, &kSystemIdHtml4, true) ||\n          doctype_matches(doctype, &kPublicIdXhtml1_0,\n                          &kSystemIdXhtmlStrict1_1, false) ||\n          doctype_matches(doctype, &kPublicIdXhtml1_1,\n                          &kSystemIdXhtml1_1, false)))) {\n    add_parse_error(parser, token);\n    return false;\n  }\n  return true;\n}\n\nstatic void remove_from_parent(GumboParser* parser, GumboNode* node) {\n  if (!node->parent) {\n    // The node may not have a parent if, for example, it is a newly-cloned copy\n    // of an active formatting element.  DOM manipulations continue with the\n    // orphaned fragment of the DOM tree until it's appended/foster-parented to\n    // the common ancestor at the end of the adoption agency algorithm.\n    return;\n  }\n  assert(node->parent->type == GUMBO_NODE_ELEMENT);\n  GumboVector* children = &node->parent->v.element.children;\n  int index = gumbo_vector_index_of(children, node);\n  assert(index != -1);\n\n  gumbo_vector_remove_at(parser, index, children);\n  node->parent = NULL;\n  node->index_within_parent = -1;\n  for (int i = index; i < children->length; ++i) {\n    GumboNode* child = children->data[i];\n    child->index_within_parent = i;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser\n// Also described in the \"in body\" handling for end formatting tags.\nstatic bool adoption_agency_algorithm(\n    GumboParser* parser, GumboToken* token, GumboTag closing_tag) {\n  GumboParserState* state = parser->_parser_state;\n  gumbo_debug(\"Entering adoption agency algorithm.\\n\");\n  // Steps 1-3 & 16:\n  for (int i = 0; i < 8; ++i) {\n    // Step 4.\n    GumboNode* formatting_node = NULL;\n    int formatting_node_in_open_elements = -1;\n    for (int j = state->_active_formatting_elements.length; --j >= 0; ) {\n      GumboNode* current_node = state->_active_formatting_elements.data[j];\n      if (current_node == &kActiveFormattingScopeMarker) {\n        gumbo_debug(\"Broke on scope marker; aborting.\\n\");\n        // Last scope marker; abort the algorithm.\n        return false;\n      }\n      if (node_tag_is(current_node, closing_tag)) {\n        // Found it.\n        formatting_node = current_node;\n        formatting_node_in_open_elements = gumbo_vector_index_of(\n            &state->_open_elements, formatting_node);\n        gumbo_debug(\"Formatting element of tag %s at %d.\\n\",\n                    gumbo_normalized_tagname(closing_tag),\n                    formatting_node_in_open_elements);\n        break;\n      }\n    }\n    if (!formatting_node) {\n      // No matching tag; not a parse error outright, but fall through to the\n      // \"any other end tag\" clause (which may potentially add a parse error,\n      // but not always).\n      gumbo_debug(\"No active formatting elements; aborting.\\n\");\n      return false;\n    }\n\n    if (formatting_node_in_open_elements == -1) {\n      gumbo_debug(\"Formatting node not on stack of open elements.\\n\");\n      gumbo_vector_remove(parser, formatting_node,\n                          &state->_active_formatting_elements);\n      return false;\n    }\n\n    if (!has_an_element_in_scope(parser, formatting_node->v.element.tag)) {\n      add_parse_error(parser, token);\n      gumbo_debug(\"Element not in scope.\\n\");\n      return false;\n    }\n    if (formatting_node != get_current_node(parser)) {\n      add_parse_error(parser, token);  // But continue onwards.\n    }\n    assert(formatting_node);\n    assert(!node_tag_is(formatting_node, GUMBO_TAG_HTML));\n    assert(!node_tag_is(formatting_node, GUMBO_TAG_BODY));\n\n    // Step 5 & 6.\n    GumboNode* furthest_block = NULL;\n    for (int j = formatting_node_in_open_elements;\n         j < state->_open_elements.length; ++j) {\n      assert(j > 0);\n      GumboNode* current = state->_open_elements.data[j];\n      if (is_special_node(current)) {\n        // Step 5.\n        furthest_block = current;\n        break;\n      }\n    }\n    if (!furthest_block) {\n      // Step 6.\n      while (get_current_node(parser) != formatting_node) {\n        pop_current_node(parser);\n      }\n      // And the formatting element itself.\n      pop_current_node(parser);\n      gumbo_vector_remove(parser, formatting_node,\n                          &state->_active_formatting_elements);\n      return false;\n    }\n    assert(!node_tag_is(furthest_block, GUMBO_TAG_HTML));\n    assert(furthest_block);\n\n    // Step 7.\n    // Elements may be moved and reparented by this algorithm, so\n    // common_ancestor is not necessarily the same as formatting_node->parent.\n    GumboNode* common_ancestor =\n        state->_open_elements.data[gumbo_vector_index_of(\n            &state->_open_elements, formatting_node) - 1];\n    gumbo_debug(\"Common ancestor tag = %s, furthest block tag = %s.\\n\",\n                gumbo_normalized_tagname(common_ancestor->v.element.tag),\n                gumbo_normalized_tagname(furthest_block->v.element.tag));\n\n    // Step 8.\n    int bookmark = gumbo_vector_index_of(\n        &state->_active_formatting_elements, formatting_node);;\n    // Step 9.\n    GumboNode* node = furthest_block;\n    GumboNode* last_node = furthest_block;\n    // Must be stored explicitly, in case node is removed from the stack of open\n    // elements, to handle step 9.4.\n    int saved_node_index = gumbo_vector_index_of(&state->_open_elements, node);\n    assert(saved_node_index > 0);\n    // Step 9.1-9.3 & 9.11.\n    for (int j = 0; j < 3; ++j) {\n      // Step 9.4.\n      int node_index = gumbo_vector_index_of(&state->_open_elements, node);\n      gumbo_debug(\n          \"Current index: %d, last index: %d.\\n\", node_index, saved_node_index);\n      if (node_index == -1) {\n        node_index = saved_node_index;\n      }\n      saved_node_index = --node_index;\n      assert(node_index > 0);\n      assert(node_index < state->_open_elements.capacity);\n      node = state->_open_elements.data[node_index];\n      assert(node->parent);\n      // Step 9.5.\n      if (gumbo_vector_index_of(\n          &state->_active_formatting_elements, node) == -1) {\n        gumbo_vector_remove_at(parser, node_index, &state->_open_elements);\n        continue;\n      } else if (node == formatting_node) {\n        // Step 9.6.\n        break;\n      }\n      // Step 9.7.\n      int formatting_index = gumbo_vector_index_of(\n          &state->_active_formatting_elements, node);\n      node = clone_node(parser, node, GUMBO_INSERTION_ADOPTION_AGENCY_CLONED);\n      state->_active_formatting_elements.data[formatting_index] = node;\n      state->_open_elements.data[node_index] = node;\n      // Step 9.8.\n      if (last_node == furthest_block) {\n        bookmark = formatting_index + 1;\n        assert(bookmark <= state->_active_formatting_elements.length);\n      }\n      // Step 9.9.\n      last_node->parse_flags |= GUMBO_INSERTION_ADOPTION_AGENCY_MOVED;\n      remove_from_parent(parser, last_node);\n      append_node(parser, node, last_node);\n      // Step 9.10.\n      last_node = node;\n    }\n\n    // Step 10.\n    gumbo_debug(\"Removing %s node from parent \",\n                gumbo_normalized_tagname(last_node->v.element.tag));\n    remove_from_parent(parser, last_node);\n    last_node->parse_flags |= GUMBO_INSERTION_ADOPTION_AGENCY_MOVED;\n    if (node_tag_in(common_ancestor, GUMBO_TAG_TABLE, GUMBO_TAG_TBODY,\n                    GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD, GUMBO_TAG_TR,\n                    GUMBO_TAG_LAST)) {\n      gumbo_debug(\"and foster-parenting it.\\n\");\n      foster_parent_element(parser, last_node);\n    } else {\n      gumbo_debug(\"and inserting it into %s.\\n\",\n                  gumbo_normalized_tagname(common_ancestor->v.element.tag));\n      append_node(parser, common_ancestor, last_node);\n    }\n\n    // Step 11.\n    GumboNode* new_formatting_node = clone_node(\n        parser, formatting_node, GUMBO_INSERTION_ADOPTION_AGENCY_CLONED);\n    formatting_node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG;\n\n    // Step 12.  Instead of appending nodes one-by-one, we swap the children\n    // vector of furthest_block with the empty children of new_formatting_node,\n    // reducing memory traffic and allocations.  We still have to reset their\n    // parent pointers, though.\n    GumboVector temp = new_formatting_node->v.element.children;\n    new_formatting_node->v.element.children =\n        furthest_block->v.element.children;\n    furthest_block->v.element.children = temp;\n\n    temp = new_formatting_node->v.element.children;\n    for (int i = 0; i < temp.length; ++i) {\n      GumboNode* child = temp.data[i];\n      child->parent = new_formatting_node;\n    }\n\n    // Step 13.\n    append_node(parser, furthest_block, new_formatting_node);\n\n    // Step 14.\n    // If the formatting node was before the bookmark, it may shift over all\n    // indices after it, so we need to explicitly find the index and possibly\n    // adjust the bookmark.\n    int formatting_node_index = gumbo_vector_index_of(\n        &state->_active_formatting_elements, formatting_node);\n    assert(formatting_node_index != -1);\n    if (formatting_node_index < bookmark) {\n      --bookmark;\n    }\n    gumbo_vector_remove_at(\n        parser, formatting_node_index, &state->_active_formatting_elements);\n    assert(bookmark >= 0);\n    assert(bookmark <= state->_active_formatting_elements.length);\n    gumbo_vector_insert_at(parser, new_formatting_node, bookmark,\n                           &state->_active_formatting_elements);\n\n    // Step 15.\n    gumbo_vector_remove(\n        parser, formatting_node, &state->_open_elements);\n    int insert_at = gumbo_vector_index_of(\n        &state->_open_elements, furthest_block) + 1;\n    assert(insert_at >= 0);\n    assert(insert_at <= state->_open_elements.length);\n    gumbo_vector_insert_at(\n        parser, new_formatting_node, insert_at, &state->_open_elements);\n  }\n  return true;\n}\n\n// This is here to clean up memory when the spec says \"Ignore current token.\"\nstatic void ignore_token(GumboParser* parser) {\n  GumboToken* token = parser->_parser_state->_current_token;\n  // Ownership of the token's internal buffers are normally transferred to the\n  // element, but if no element is emitted (as happens in non-verbatim-mode\n  // when a token is ignored), we need to free it here to prevent a memory\n  // leak.\n  gumbo_token_destroy(parser, token);\n#ifndef NDEBUG\n  if (token->type == GUMBO_TOKEN_START_TAG) {\n    // Mark this sentinel so the assertion in the main loop knows it's been\n    // destroyed.\n    token->v.start_tag.attributes = kGumboEmptyVector;\n  }\n#endif\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/the-end.html\nstatic void finish_parsing(GumboParser* parser) {\n  maybe_flush_text_node_buffer(parser);\n  GumboParserState* state = parser->_parser_state;\n  for (GumboNode* node = pop_current_node(parser); node;\n       node = pop_current_node(parser)) {\n    if ((node_tag_is(node, GUMBO_TAG_BODY) && state->_closed_body_tag) ||\n        (node_tag_is(node, GUMBO_TAG_HTML) && state->_closed_html_tag)) {\n      continue;\n    }\n    node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG;\n  }\n  while (pop_current_node(parser));  // Pop them all.\n}\n\nstatic bool handle_initial(GumboParser* parser, GumboToken* token) {\n  GumboDocument* document = &get_document_node(parser)->v.document;\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    ignore_token(parser);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_document_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    document->has_doctype = true;\n    document->name = token->v.doc_type.name;\n    document->public_identifier = token->v.doc_type.public_identifier;\n    document->system_identifier = token->v.doc_type.system_identifier;\n    document->doc_type_quirks_mode = compute_quirks_mode(&token->v.doc_type);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML);\n    return maybe_add_doctype_error(parser, token);\n  }\n  add_parse_error(parser, token);\n  document->doc_type_quirks_mode = GUMBO_DOCTYPE_QUIRKS;\n  set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML);\n  parser->_parser_state->_reprocess_current_token = true;\n  return true;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-before-html-insertion-mode\nstatic bool handle_before_html(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_document_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    ignore_token(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    GumboNode* html_node = insert_element_from_token(parser, token);\n    parser->_output->root = html_node;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_END_TAG && !tag_in(\n      token, false, GUMBO_TAG_HEAD, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n      GUMBO_TAG_BR, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    GumboNode* html_node = insert_element_of_tag_type(\n        parser, GUMBO_TAG_HTML, GUMBO_INSERTION_IMPLIED);\n    assert(html_node);\n    parser->_output->root = html_node;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD);\n    parser->_parser_state->_reprocess_current_token = true;\n    return true;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-before-head-insertion-mode\nstatic bool handle_before_head(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    ignore_token(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD)) {\n    GumboNode* node = insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);\n    parser->_parser_state->_head_element = node;\n    return true;\n  } else if (token->type == GUMBO_TOKEN_END_TAG && !tag_in(\n      token, false, GUMBO_TAG_HEAD, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n      GUMBO_TAG_BR, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    GumboNode* node = insert_element_of_tag_type(\n        parser, GUMBO_TAG_HEAD, GUMBO_INSERTION_IMPLIED);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);\n    parser->_parser_state->_head_element = node;\n    parser->_parser_state->_reprocess_current_token = true;\n    return true;\n  }\n}\n\n// Forward declarations because of mutual dependencies.\nstatic bool handle_token(GumboParser* parser, GumboToken* token);\nstatic bool handle_in_body(GumboParser* parser, GumboToken* token);\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inhead\nstatic bool handle_in_head(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_BASE, GUMBO_TAG_BASEFONT,\n                    GUMBO_TAG_BGSOUND, GUMBO_TAG_COMMAND, GUMBO_TAG_LINK,\n                    GUMBO_TAG_LAST)) {\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_META)) {\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    // NOTE(jdtang): Gumbo handles only UTF-8, so the encoding clause of the\n    // spec doesn't apply.  If clients want to handle meta-tag re-encoding, they\n    // should specifically look for that string in the document and re-encode it\n    // before passing to Gumbo.\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_TITLE)) {\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_NOFRAMES, GUMBO_TAG_STYLE,\n                    GUMBO_TAG_LAST)) {\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOSCRIPT)) {\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_SCRIPT)) {\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_SCRIPT);\n    return true;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_HEAD)) {\n    GumboNode* head = pop_current_node(parser);\n    AVOID_UNUSED_VARIABLE_WARNING(head);\n    assert(node_tag_is(head, GUMBO_TAG_HEAD));\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD) ||\n             (token->type == GUMBO_TOKEN_END_TAG &&\n              !tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n                      GUMBO_TAG_BR, GUMBO_TAG_LAST))) {\n    add_parse_error(parser, token);\n    return false;\n  } else {\n    const GumboNode* node = pop_current_node(parser);\n    assert(node_tag_is(node, GUMBO_TAG_HEAD));\n    AVOID_UNUSED_VARIABLE_WARNING(node);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD);\n    parser->_parser_state->_reprocess_current_token = true;\n    return true;\n  }\n\n  return true;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inheadnoscript\nstatic bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_NOSCRIPT)) {\n    const GumboNode* node = pop_current_node(parser);\n    assert(node_tag_is(node, GUMBO_TAG_NOSCRIPT));\n    AVOID_UNUSED_VARIABLE_WARNING(node);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_WHITESPACE ||\n             token->type == GUMBO_TOKEN_COMMENT ||\n             tag_in(token, kStartTag, GUMBO_TAG_BASEFONT, GUMBO_TAG_BGSOUND,\n                    GUMBO_TAG_LINK, GUMBO_TAG_META, GUMBO_TAG_NOFRAMES,\n                    GUMBO_TAG_STYLE, GUMBO_TAG_LAST)) {\n    return handle_in_head(parser, token);\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_HEAD, GUMBO_TAG_NOSCRIPT,\n                    GUMBO_TAG_LAST) ||\n            (token->type == GUMBO_TOKEN_END_TAG &&\n             !tag_is(token, kEndTag, GUMBO_TAG_BR))) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    add_parse_error(parser, token);\n    const GumboNode* node = pop_current_node(parser);\n    assert(node_tag_is(node, GUMBO_TAG_NOSCRIPT));\n    AVOID_UNUSED_VARIABLE_WARNING(node);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);\n    parser->_parser_state->_reprocess_current_token = true;\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-head-insertion-mode\nstatic bool handle_after_head(GumboParser* parser, GumboToken* token) {\n  GumboParserState* state = parser->_parser_state;\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) {\n    insert_element_from_token(parser, token);\n    state->_frameset_ok = false;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_BASE, GUMBO_TAG_BASEFONT,\n                    GUMBO_TAG_BGSOUND, GUMBO_TAG_LINK, GUMBO_TAG_META,\n                    GUMBO_TAG_NOFRAMES, GUMBO_TAG_SCRIPT, GUMBO_TAG_STYLE,\n                    GUMBO_TAG_TITLE, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    assert(state->_head_element != NULL);\n    // This must be flushed before we push the head element on, as there may be\n    // pending character tokens that should be attached to the root.\n    maybe_flush_text_node_buffer(parser);\n    gumbo_vector_add(parser, state->_head_element, &state->_open_elements);\n    bool result = handle_in_head(parser, token);\n    gumbo_vector_remove(parser, state->_head_element, &state->_open_elements);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD) ||\n            (token->type == GUMBO_TOKEN_END_TAG &&\n             !tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n                     GUMBO_TAG_BR, GUMBO_TAG_LAST))) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    insert_element_of_tag_type(parser, GUMBO_TAG_BODY, GUMBO_INSERTION_IMPLIED);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);\n    state->_reprocess_current_token = true;\n    return true;\n  }\n}\n\nstatic void destroy_node(GumboParser* parser, GumboNode* node) {\n  switch (node->type) {\n    case GUMBO_NODE_DOCUMENT:\n      {\n        GumboDocument* doc = &node->v.document;\n        for (int i = 0; i < doc->children.length; ++i) {\n          destroy_node(parser, doc->children.data[i]);\n        }\n        gumbo_parser_deallocate(parser, (void*) doc->children.data);\n        gumbo_parser_deallocate(parser, (void*) doc->name);\n        gumbo_parser_deallocate(parser, (void*) doc->public_identifier);\n        gumbo_parser_deallocate(parser, (void*) doc->system_identifier);\n      }\n      break;\n    case GUMBO_NODE_ELEMENT:\n      for (int i = 0; i < node->v.element.attributes.length; ++i) {\n        gumbo_destroy_attribute(parser, node->v.element.attributes.data[i]);\n      }\n      gumbo_parser_deallocate(parser, node->v.element.attributes.data);\n      for (int i = 0; i < node->v.element.children.length; ++i) {\n        destroy_node(parser, node->v.element.children.data[i]);\n      }\n      gumbo_parser_deallocate(parser, node->v.element.children.data);\n      break;\n    case GUMBO_NODE_TEXT:\n    case GUMBO_NODE_CDATA:\n    case GUMBO_NODE_COMMENT:\n    case GUMBO_NODE_WHITESPACE:\n      gumbo_parser_deallocate(parser, (void*) node->v.text.text);\n      break;\n  }\n  gumbo_parser_deallocate(parser, node);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inbody\nstatic bool handle_in_body(GumboParser* parser, GumboToken* token) {\n  GumboParserState* state = parser->_parser_state;\n  assert(state->_open_elements.length > 0);\n  if (token->type == GUMBO_TOKEN_NULL) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    reconstruct_active_formatting_elements(parser);\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_CHARACTER) {\n    reconstruct_active_formatting_elements(parser);\n    insert_text_token(parser, token);\n    set_frameset_not_ok(parser);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    assert(parser->_output->root != NULL);\n    assert(parser->_output->root->type == GUMBO_NODE_ELEMENT);\n    add_parse_error(parser, token);\n    merge_attributes(parser, token, parser->_output->root);\n    return false;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_BASE, GUMBO_TAG_BASEFONT,\n                    GUMBO_TAG_BGSOUND, GUMBO_TAG_COMMAND, GUMBO_TAG_LINK,\n                    GUMBO_TAG_META, GUMBO_TAG_NOFRAMES, GUMBO_TAG_SCRIPT,\n                    GUMBO_TAG_STYLE, GUMBO_TAG_TITLE, GUMBO_TAG_LAST)) {\n    return handle_in_head(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) {\n    add_parse_error(parser, token);\n    if (state->_open_elements.length < 2 ||\n        !node_tag_is(state->_open_elements.data[1], GUMBO_TAG_BODY)) {\n      ignore_token(parser);\n      return false;\n    }\n    state->_frameset_ok = false;\n    merge_attributes(parser, token, state->_open_elements.data[1]);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {\n    add_parse_error(parser, token);\n    if (state->_open_elements.length < 2 ||\n        !node_tag_is(state->_open_elements.data[1], GUMBO_TAG_BODY) ||\n        !state->_frameset_ok) {\n      ignore_token(parser);\n      return false;\n    }\n    // Save the body node for later removal.\n    GumboNode* body_node = state->_open_elements.data[1];\n\n    // Pop all nodes except root HTML element.\n    GumboNode* node;\n    do {\n      node = pop_current_node(parser);\n    } while (node != state->_open_elements.data[1]);\n\n    // Remove the body node.  We may want to factor this out into a generic\n    // helper, but right now this is the only code that needs to do this.\n    GumboVector* children = &parser->_output->root->v.element.children;\n    for (int i = 0; i < children->length; ++i) {\n      if (children->data[i] == body_node) {\n        gumbo_vector_remove_at(parser, i, children);\n        break;\n      }\n    }\n    destroy_node(parser, body_node);\n\n    // Insert the <frameset>, and switch the insertion mode.\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    for (int i = 0; i < state->_open_elements.length; ++i) {\n      if (!node_tag_in(state->_open_elements.data[i], GUMBO_TAG_DD,\n                       GUMBO_TAG_DT, GUMBO_TAG_LI, GUMBO_TAG_P, GUMBO_TAG_TBODY,\n                       GUMBO_TAG_TD, GUMBO_TAG_TFOOT, GUMBO_TAG_TH,\n                       GUMBO_TAG_THEAD, GUMBO_TAG_TR, GUMBO_TAG_BODY,\n                       GUMBO_TAG_HTML, GUMBO_TAG_LAST)) {\n        add_parse_error(parser, token);\n        return false;\n      }\n    }\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n                    GUMBO_TAG_LAST)) {\n    if (!has_an_element_in_scope(parser, GUMBO_TAG_BODY)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    bool success = true;\n    for (int i = 0; i < state->_open_elements.length; ++i) {\n      if (!node_tag_in(state->_open_elements.data[i], GUMBO_TAG_DD,\n                       GUMBO_TAG_DT, GUMBO_TAG_LI, GUMBO_TAG_OPTGROUP,\n                       GUMBO_TAG_OPTION, GUMBO_TAG_P, GUMBO_TAG_RP,\n                       GUMBO_TAG_RT, GUMBO_TAG_TBODY, GUMBO_TAG_TD,\n                       GUMBO_TAG_TFOOT, GUMBO_TAG_TH, GUMBO_TAG_THEAD,\n                       GUMBO_TAG_TR, GUMBO_TAG_BODY, GUMBO_TAG_HTML,\n                       GUMBO_TAG_LAST)) {\n        add_parse_error(parser, token);\n        success = false;\n        break;\n      }\n    }\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_BODY);\n    if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {\n      parser->_parser_state->_reprocess_current_token = true;\n    } else {\n      GumboNode* body = state->_open_elements.data[1];\n      assert(node_tag_is(body, GUMBO_TAG_BODY));\n      record_end_of_element(state->_current_token, &body->v.element);\n    }\n    return success;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_ADDRESS, GUMBO_TAG_ARTICLE,\n                    GUMBO_TAG_ASIDE, GUMBO_TAG_BLOCKQUOTE, GUMBO_TAG_CENTER,\n                    GUMBO_TAG_DETAILS, GUMBO_TAG_DIR, GUMBO_TAG_DIV,\n                    GUMBO_TAG_DL, GUMBO_TAG_FIELDSET, GUMBO_TAG_FIGCAPTION,\n                    GUMBO_TAG_FIGURE, GUMBO_TAG_FOOTER, GUMBO_TAG_HEADER,\n                    GUMBO_TAG_HGROUP, GUMBO_TAG_MENU, GUMBO_TAG_NAV,\n                    GUMBO_TAG_OL, GUMBO_TAG_P, GUMBO_TAG_SECTION,\n                    GUMBO_TAG_SUMMARY, GUMBO_TAG_UL, GUMBO_TAG_LAST)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    return result;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3,\n                    GUMBO_TAG_H4, GUMBO_TAG_H5, GUMBO_TAG_H6, GUMBO_TAG_LAST)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    if (node_tag_in(get_current_node(parser), GUMBO_TAG_H1, GUMBO_TAG_H2,\n                    GUMBO_TAG_H3, GUMBO_TAG_H4, GUMBO_TAG_H5, GUMBO_TAG_H6,\n                    GUMBO_TAG_LAST)) {\n      add_parse_error(parser, token);\n      pop_current_node(parser);\n      result = false;\n    }\n    insert_element_from_token(parser, token);\n    return result;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_PRE, GUMBO_TAG_LISTING,\n                    GUMBO_TAG_LAST)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    state->_ignore_next_linefeed = true;\n    state->_frameset_ok = false;\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) {\n    if (state->_form_element != NULL) {\n      gumbo_debug(\"Ignoring nested form.\\n\");\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    state->_form_element =\n        insert_element_from_token(parser, token);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_LI)) {\n    maybe_implicitly_close_list_tag(parser, token, true);\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    return result;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_DD, GUMBO_TAG_DT,\n                    GUMBO_TAG_LAST)) {\n    maybe_implicitly_close_list_tag(parser, token, false);\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_PLAINTEXT)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_PLAINTEXT);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_BUTTON)) {\n    if (has_an_element_in_scope(parser, GUMBO_TAG_BUTTON)) {\n      add_parse_error(parser, token);\n      implicitly_close_tags(parser, token, GUMBO_TAG_BUTTON);\n      state->_reprocess_current_token = true;\n      return false;\n    }\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    state->_frameset_ok = false;\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_ADDRESS, GUMBO_TAG_ARTICLE,\n                    GUMBO_TAG_ASIDE, GUMBO_TAG_BLOCKQUOTE, GUMBO_TAG_BUTTON,\n                    GUMBO_TAG_CENTER, GUMBO_TAG_DETAILS, GUMBO_TAG_DIR,\n                    GUMBO_TAG_DIV, GUMBO_TAG_DL, GUMBO_TAG_FIELDSET,\n                    GUMBO_TAG_FIGCAPTION, GUMBO_TAG_FIGURE, GUMBO_TAG_FOOTER,\n                    GUMBO_TAG_HEADER, GUMBO_TAG_HGROUP, GUMBO_TAG_LISTING,\n                    GUMBO_TAG_MENU, GUMBO_TAG_NAV, GUMBO_TAG_OL, GUMBO_TAG_PRE,\n                    GUMBO_TAG_SECTION, GUMBO_TAG_SUMMARY, GUMBO_TAG_UL,\n                    GUMBO_TAG_LAST)) {\n    GumboTag tag = token->v.end_tag;\n    if (!has_an_element_in_scope(parser, tag)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    implicitly_close_tags(parser, token, token->v.end_tag);\n    return true;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_FORM)) {\n    bool result = true;\n    const GumboNode* node = state->_form_element;\n    assert(!node || node->type == GUMBO_NODE_ELEMENT);\n    state->_form_element = NULL;\n    if (!node || !has_node_in_scope(parser, node)) {\n      gumbo_debug(\"Closing an unopened form.\\n\");\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    // This differs from implicitly_close_tags because we remove *only* the\n    // <form> element; other nodes are left in scope.\n    generate_implied_end_tags(parser, GUMBO_TAG_LAST);\n    if (get_current_node(parser) != node) {\n      add_parse_error(parser, token);\n      result = false;\n    }\n\n    GumboVector* open_elements = &state->_open_elements;\n    int index = open_elements->length - 1;\n    for (; index >= 0 && open_elements->data[index] != node; --index);\n    assert(index >= 0);\n    gumbo_vector_remove_at(parser, index, open_elements);\n    return result;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_P)) {\n    if (!has_an_element_in_button_scope(parser, GUMBO_TAG_P)) {\n      add_parse_error(parser, token);\n      reconstruct_active_formatting_elements(parser);\n      insert_element_of_tag_type(\n          parser, GUMBO_TAG_P, GUMBO_INSERTION_CONVERTED_FROM_END_TAG);\n      state->_reprocess_current_token = true;\n      return false;\n    }\n    return implicitly_close_tags(parser, token, GUMBO_TAG_P);\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_LI)) {\n    if (!has_an_element_in_list_scope(parser, GUMBO_TAG_LI)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    return implicitly_close_tags(parser, token, GUMBO_TAG_LI);\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_DD, GUMBO_TAG_DT,\n                    GUMBO_TAG_LAST)) {\n    assert(token->type == GUMBO_TOKEN_END_TAG);\n    GumboTag token_tag = token->v.end_tag;\n    if (!has_an_element_in_scope(parser, token_tag)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    return implicitly_close_tags(parser, token, token_tag);\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3,\n                    GUMBO_TAG_H4, GUMBO_TAG_H5, GUMBO_TAG_H6, GUMBO_TAG_LAST)) {\n    if (!has_an_element_in_scope_with_tagname(\n            parser, GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3, GUMBO_TAG_H4,\n            GUMBO_TAG_H5, GUMBO_TAG_H6, GUMBO_TAG_LAST)) {\n      // No heading open; ignore the token entirely.\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    } else {\n      generate_implied_end_tags(parser, GUMBO_TAG_LAST);\n      const GumboNode* current_node = get_current_node(parser);\n      bool success = node_tag_is(current_node, token->v.end_tag);\n      if (!success) {\n        // There're children of the heading currently open; close them below and\n        // record a parse error.\n        // TODO(jdtang): Add a way to distinguish this error case from the one\n        // above.\n        add_parse_error(parser, token);\n      }\n      do {\n        current_node = pop_current_node(parser);\n      } while (!node_tag_in(current_node, GUMBO_TAG_H1, GUMBO_TAG_H2,\n                            GUMBO_TAG_H3, GUMBO_TAG_H4, GUMBO_TAG_H5,\n                            GUMBO_TAG_H6, GUMBO_TAG_LAST));\n      return success;\n    }\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_A)) {\n    bool success = true;\n    int last_a;\n    int has_matching_a = find_last_anchor_index(parser, &last_a);\n    if (has_matching_a) {\n      assert(has_matching_a == 1);\n      add_parse_error(parser, token);\n      adoption_agency_algorithm(parser, token, GUMBO_TAG_A);\n      // The adoption agency algorithm usually removes all instances of <a>\n      // from the list of active formatting elements, but in case it doesn't,\n      // we're supposed to do this.  (The conditions where it might not are\n      // listed in the spec.)\n      if (find_last_anchor_index(parser, &last_a)) {\n        void* last_element = gumbo_vector_remove_at(\n            parser, last_a, &state->_active_formatting_elements);\n        gumbo_vector_remove(\n            parser, last_element, &state->_open_elements);\n      }\n      success = false;\n    }\n    reconstruct_active_formatting_elements(parser);\n    add_formatting_element(parser, insert_element_from_token(parser, token));\n    return success;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_B, GUMBO_TAG_BIG,\n                    GUMBO_TAG_CODE, GUMBO_TAG_EM, GUMBO_TAG_FONT, GUMBO_TAG_I,\n                    GUMBO_TAG_S, GUMBO_TAG_SMALL, GUMBO_TAG_STRIKE,\n                    GUMBO_TAG_STRONG, GUMBO_TAG_TT, GUMBO_TAG_U,\n                    GUMBO_TAG_LAST)) {\n    reconstruct_active_formatting_elements(parser);\n    add_formatting_element(parser, insert_element_from_token(parser, token));\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOBR)) {\n    bool result = true;\n    reconstruct_active_formatting_elements(parser);\n    if (has_an_element_in_scope(parser, GUMBO_TAG_NOBR)) {\n      result = false;\n      add_parse_error(parser, token);\n      adoption_agency_algorithm(parser, token, GUMBO_TAG_NOBR);\n      reconstruct_active_formatting_elements(parser);\n    }\n    insert_element_from_token(parser, token);\n    add_formatting_element(parser, get_current_node(parser));\n    return result;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_A, GUMBO_TAG_B, GUMBO_TAG_BIG,\n                    GUMBO_TAG_CODE, GUMBO_TAG_EM, GUMBO_TAG_FONT, GUMBO_TAG_I,\n                    GUMBO_TAG_NOBR, GUMBO_TAG_S, GUMBO_TAG_SMALL,\n                    GUMBO_TAG_STRIKE, GUMBO_TAG_STRONG, GUMBO_TAG_TT,\n                    GUMBO_TAG_U, GUMBO_TAG_LAST)) {\n    return adoption_agency_algorithm(parser, token, token->v.end_tag);\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_APPLET, GUMBO_TAG_MARQUEE,\n                    GUMBO_TAG_OBJECT, GUMBO_TAG_LAST)) {\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    add_formatting_element(parser, &kActiveFormattingScopeMarker);\n    set_frameset_not_ok(parser);\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_APPLET, GUMBO_TAG_MARQUEE,\n                    GUMBO_TAG_OBJECT, GUMBO_TAG_LAST)) {\n    GumboTag token_tag = token->v.end_tag;\n    if (!has_an_element_in_table_scope(parser, token_tag)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    implicitly_close_tags(parser, token, token_tag);\n    clear_active_formatting_elements(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) {\n    if (get_document_node(parser)->v.document.doc_type_quirks_mode !=\n        GUMBO_DOCTYPE_QUIRKS) {\n      maybe_implicitly_close_p_tag(parser, token);\n    }\n    insert_element_from_token(parser, token);\n    set_frameset_not_ok(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_AREA, GUMBO_TAG_BR,\n                    GUMBO_TAG_EMBED, GUMBO_TAG_IMG, GUMBO_TAG_IMAGE,\n                    GUMBO_TAG_KEYGEN, GUMBO_TAG_WBR, GUMBO_TAG_LAST)) {\n    bool success = true;\n    if (tag_is(token, kStartTag, GUMBO_TAG_IMAGE)) {\n      success = false;\n      add_parse_error(parser, token);\n      token->v.start_tag.tag = GUMBO_TAG_IMG;\n    }\n    reconstruct_active_formatting_elements(parser);\n    GumboNode* node = insert_element_from_token(parser, token);\n    if (tag_is(token, kStartTag, GUMBO_TAG_IMAGE)) {\n      success = false;\n      add_parse_error(parser, token);\n      node->v.element.tag = GUMBO_TAG_IMG;\n      node->parse_flags |= GUMBO_INSERTION_FROM_IMAGE;\n    }\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    set_frameset_not_ok(parser);\n    return success;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_INPUT)) {\n    if (!attribute_matches(&token->v.start_tag.attributes, \"type\", \"hidden\")) {\n      // Must be before the element is inserted, as that takes ownership of the\n      // token's attribute vector.\n      set_frameset_not_ok(parser);\n    }\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_PARAM, GUMBO_TAG_SOURCE,\n                    GUMBO_TAG_TRACK, GUMBO_TAG_LAST)) {\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HR)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    set_frameset_not_ok(parser);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_ISINDEX)) {\n    add_parse_error(parser, token);\n    if (parser->_parser_state->_form_element != NULL) {\n      ignore_token(parser);\n      return false;\n    }\n    acknowledge_self_closing_tag(parser);\n    maybe_implicitly_close_p_tag(parser, token);\n    set_frameset_not_ok(parser);\n\n    GumboVector* token_attrs = &token->v.start_tag.attributes;\n    GumboAttribute* prompt_attr = gumbo_get_attribute(token_attrs, \"prompt\");\n    GumboAttribute* action_attr = gumbo_get_attribute(token_attrs, \"action\");\n    GumboAttribute* name_attr = gumbo_get_attribute(token_attrs, \"isindex\");\n\n    GumboNode* form = insert_element_of_tag_type(\n        parser, GUMBO_TAG_FORM, GUMBO_INSERTION_FROM_ISINDEX);\n    if (action_attr) {\n      gumbo_vector_add(parser, action_attr, &form->v.element.attributes);\n    }\n    insert_element_of_tag_type(parser, GUMBO_TAG_HR,\n                               GUMBO_INSERTION_FROM_ISINDEX);\n    pop_current_node(parser);   // <hr>\n\n    insert_element_of_tag_type(parser, GUMBO_TAG_LABEL,\n                               GUMBO_INSERTION_FROM_ISINDEX);\n    TextNodeBufferState* text_state = &parser->_parser_state->_text_node;\n    text_state->_start_original_text = token->original_text.data;\n    text_state->_start_position = token->position;\n    text_state->_type = GUMBO_NODE_TEXT;\n    if (prompt_attr) {\n      unsigned long prompt_attr_length = strlen(prompt_attr->value);\n      gumbo_string_buffer_destroy(parser, &text_state->_buffer);\n      text_state->_buffer.data = gumbo_copy_stringz(parser, prompt_attr->value);\n      text_state->_buffer.length = prompt_attr_length;\n      text_state->_buffer.capacity = prompt_attr_length + 1;\n      gumbo_destroy_attribute(parser, prompt_attr);\n    } else {\n      GumboStringPiece prompt_text = GUMBO_STRING(\n          \"This is a searchable index. Enter search keywords: \");\n      gumbo_string_buffer_append_string(\n          parser, &prompt_text, &text_state->_buffer);\n    }\n\n    GumboNode* input = insert_element_of_tag_type(\n        parser, GUMBO_TAG_INPUT, GUMBO_INSERTION_FROM_ISINDEX);\n    for (int i = 0; i < token_attrs->length; ++i) {\n      GumboAttribute* attr = token_attrs->data[i];\n      if (attr != prompt_attr && attr != action_attr && attr != name_attr) {\n        gumbo_vector_add(parser, attr, &input->v.element.attributes);\n      }\n      token_attrs->data[i] = NULL;\n    }\n\n    // All attributes have been successfully transferred and nulled out at this\n    // point, so the call to ignore_token will free the memory for it without\n    // touching the attributes.\n    ignore_token(parser);\n\n    GumboAttribute* name =\n        gumbo_parser_allocate(parser, sizeof(GumboAttribute));\n    GumboStringPiece name_str = GUMBO_STRING(\"name\");\n    GumboStringPiece isindex_str = GUMBO_STRING(\"isindex\");\n    name->attr_namespace = GUMBO_ATTR_NAMESPACE_NONE;\n    name->name = gumbo_copy_stringz(parser, \"name\");\n    name->value = gumbo_copy_stringz(parser, \"isindex\");\n    name->original_name = name_str;\n    name->original_value = isindex_str;\n    name->name_start = kGumboEmptySourcePosition;\n    name->name_end = kGumboEmptySourcePosition;\n    name->value_start = kGumboEmptySourcePosition;\n    name->value_end = kGumboEmptySourcePosition;\n    gumbo_vector_add(parser, name, &input->v.element.attributes);\n\n    pop_current_node(parser);   // <input>\n    pop_current_node(parser);   // <label>\n    insert_element_of_tag_type(\n        parser, GUMBO_TAG_HR, GUMBO_INSERTION_FROM_ISINDEX);\n    pop_current_node(parser);   // <hr>\n    pop_current_node(parser);   // <form>\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_TEXTAREA)) {\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA);\n    parser->_parser_state->_ignore_next_linefeed = true;\n    set_frameset_not_ok(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_XMP)) {\n    bool result = maybe_implicitly_close_p_tag(parser, token);\n    reconstruct_active_formatting_elements(parser);\n    set_frameset_not_ok(parser);\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);\n    return result;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_IFRAME)) {\n    set_frameset_not_ok(parser);\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOEMBED)) {\n    run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) {\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    set_frameset_not_ok(parser);\n    GumboInsertionMode state = parser->_parser_state->_insertion_mode;\n    if (state == GUMBO_INSERTION_MODE_IN_TABLE ||\n        state == GUMBO_INSERTION_MODE_IN_CAPTION ||\n        state == GUMBO_INSERTION_MODE_IN_TABLE_BODY ||\n        state == GUMBO_INSERTION_MODE_IN_ROW ||\n        state == GUMBO_INSERTION_MODE_IN_CELL) {\n      set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE);\n    } else {\n      set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_SELECT);\n    }\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_OPTION, GUMBO_TAG_OPTGROUP,\n                    GUMBO_TAG_LAST)) {\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {\n      pop_current_node(parser);\n    }\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_RP, GUMBO_TAG_RT,\n                    GUMBO_TAG_LAST)) {\n    bool success = true;\n    if (has_an_element_in_scope(parser, GUMBO_TAG_RUBY)) {\n      generate_implied_end_tags(parser, GUMBO_TAG_LAST);\n    }\n    if (!node_tag_is(get_current_node(parser), GUMBO_TAG_RUBY)) {\n      add_parse_error(parser, token);\n      success = false;\n    }\n    insert_element_from_token(parser, token);\n    return success;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_BR)) {\n    add_parse_error(parser, token);\n    reconstruct_active_formatting_elements(parser);\n    insert_element_of_tag_type(\n        parser, GUMBO_TAG_BR, GUMBO_INSERTION_CONVERTED_FROM_END_TAG);\n    pop_current_node(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_MATH)) {\n    reconstruct_active_formatting_elements(parser);\n    adjust_mathml_attributes(parser, token);\n    adjust_foreign_attributes(parser, token);\n    insert_foreign_element(parser, token, GUMBO_NAMESPACE_MATHML);\n    if (token->v.start_tag.is_self_closing) {\n      pop_current_node(parser);\n      acknowledge_self_closing_tag(parser);\n    }\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_SVG)) {\n    reconstruct_active_formatting_elements(parser);\n    adjust_svg_attributes(parser, token);\n    adjust_foreign_attributes(parser, token);\n    insert_foreign_element(parser, token, GUMBO_NAMESPACE_SVG);\n    if (token->v.start_tag.is_self_closing) {\n      pop_current_node(parser);\n      acknowledge_self_closing_tag(parser);\n    }\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_COL,\n                    GUMBO_TAG_COLGROUP, GUMBO_TAG_FRAME, GUMBO_TAG_HEAD,\n                    GUMBO_TAG_TBODY, GUMBO_TAG_TD, GUMBO_TAG_TFOOT,\n                    GUMBO_TAG_TH, GUMBO_TAG_THEAD, GUMBO_TAG_TR,\n                    GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_START_TAG) {\n    reconstruct_active_formatting_elements(parser);\n    insert_element_from_token(parser, token);\n    return true;\n  } else {\n    assert(token->type == GUMBO_TOKEN_END_TAG);\n    GumboTag end_tag = token->v.end_tag;\n    assert(state->_open_elements.length > 0);\n    assert(node_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML));\n    // Walk up the stack of open elements until we find one that either:\n    // a) Matches the tag name we saw\n    // b) Is in the \"special\" category.\n    // If we see a), implicitly close everything up to and including it.  If we\n    // see b), then record a parse error, don't close anything (except the\n    // implied end tags) and ignore the end tag token.\n    for (int i = state->_open_elements.length; --i >= 0; ) {\n      const GumboNode* node = state->_open_elements.data[i];\n      if (node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML &&\n          node_tag_is(node, end_tag)) {\n        generate_implied_end_tags(parser, end_tag);\n        // TODO(jdtang): Do I need to add a parse error here?  The condition in\n        // the spec seems like it's the inverse of the loop condition above, and\n        // so would never fire.\n        while (node != pop_current_node(parser));  // Pop everything.\n        return true;\n      } else if (is_special_node(node)) {\n        add_parse_error(parser, token);\n        ignore_token(parser);\n        return false;\n      }\n    }\n    // <html> is in the special category, so we should never get here.\n    assert(0);\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incdata\nstatic bool handle_text(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_CHARACTER || token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n  } else {\n    // We provide only bare-bones script handling that doesn't involve any of\n    // the parser-pause/already-started/script-nesting flags or re-entrant\n    // invocations of the tokenizer.  Because the intended usage of this library\n    // is mostly for templating, refactoring, and static-analysis libraries, we\n    // provide the script body as a text-node child of the <script> element.\n    // This behavior doesn't support document.write of partial HTML elements,\n    // but should be adequate for almost all other scripting support.\n    if (token->type == GUMBO_TOKEN_EOF) {\n      add_parse_error(parser, token);\n      parser->_parser_state->_reprocess_current_token = true;\n    }\n    pop_current_node(parser);\n    set_insertion_mode(parser, parser->_parser_state->_original_insertion_mode);\n  }\n  return true;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intable\nstatic bool handle_in_table(GumboParser* parser, GumboToken* token) {\n  GumboParserState* state = parser->_parser_state;\n  if (token->type == GUMBO_TOKEN_CHARACTER ||\n      token->type == GUMBO_TOKEN_WHITESPACE) {\n    // The \"pending table character tokens\" list described in the spec is\n    // nothing more than the TextNodeBufferState.  We accumulate text tokens as\n    // normal, except that when we go to flush them in the handle_in_table_text,\n    // we set _foster_parent_insertions if there're non-whitespace characters in\n    // the buffer.\n    assert(state->_text_node._buffer.length == 0);\n    state->_original_insertion_mode = state->_insertion_mode;\n    state->_reprocess_current_token = true;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_TEXT);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_CAPTION)) {\n    clear_stack_to_table_context(parser);\n    add_formatting_element(parser, &kActiveFormattingScopeMarker);\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CAPTION);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_COLGROUP)) {\n    clear_stack_to_table_context(parser);\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_COL)) {\n    clear_stack_to_table_context(parser);\n    insert_element_of_tag_type(\n        parser, GUMBO_TAG_COLGROUP, GUMBO_INSERTION_IMPLIED);\n    parser->_parser_state->_reprocess_current_token = true;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT,\n                    GUMBO_TAG_THEAD, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_TR,\n                    GUMBO_TAG_LAST)) {\n    clear_stack_to_table_context(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);\n    if (tag_in(token, kStartTag, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_TR,\n               GUMBO_TAG_LAST)) {\n      insert_element_of_tag_type(\n          parser, GUMBO_TAG_TBODY, GUMBO_INSERTION_IMPLIED);\n      state->_reprocess_current_token = true;\n    } else {\n      insert_element_from_token(parser, token);\n    }\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) {\n    add_parse_error(parser, token);\n    if (close_table(parser)) {\n      parser->_parser_state->_reprocess_current_token = true;\n    } else {\n      ignore_token(parser);\n    }\n    return false;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_TABLE)) {\n    if (!close_table(parser)) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_CAPTION,\n                    GUMBO_TAG_COL, GUMBO_TAG_COLGROUP, GUMBO_TAG_HTML,\n                    GUMBO_TAG_TBODY, GUMBO_TAG_TD, GUMBO_TAG_TFOOT,\n                    GUMBO_TAG_TH, GUMBO_TAG_THEAD, GUMBO_TAG_TR,\n                    GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_STYLE, GUMBO_TAG_SCRIPT,\n                    GUMBO_TAG_LAST)) {\n    return handle_in_head(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_INPUT) &&\n             attribute_matches(&token->v.start_tag.attributes,\n                               \"type\", \"hidden\")) {\n    add_parse_error(parser, token);\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) {\n    add_parse_error(parser, token);\n    if (state->_form_element) {\n      ignore_token(parser);\n      return false;\n    }\n    state->_form_element = insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    if (!node_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    state->_foster_parent_insertions = true;\n    bool result = handle_in_body(parser, token);\n    state->_foster_parent_insertions = false;\n    return result;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intabletext\nstatic bool handle_in_table_text(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_NULL) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_CHARACTER ||\n             token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else {\n    GumboParserState* state = parser->_parser_state;\n    GumboStringBuffer* buffer = &state->_text_node._buffer;\n    // Can't use strspn for this because GumboStringBuffers are not\n    // null-terminated.\n    // Note that TextNodeBuffer may contain UTF-8 characters, but the presence\n    // of any one byte that is not whitespace means we flip the flag, so this\n    // loop is still valid.\n    for (int i = 0; i < buffer->length; ++i) {\n      if (!isspace(buffer->data[i]) || buffer->data[i] == '\\v') {\n        state->_foster_parent_insertions = true;\n        reconstruct_active_formatting_elements(parser);\n        break;\n      }\n    }\n    maybe_flush_text_node_buffer(parser);\n    state->_foster_parent_insertions = false;\n    state->_reprocess_current_token = true;\n    state->_insertion_mode = state->_original_insertion_mode;\n    return true;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incaption\nstatic bool handle_in_caption(GumboParser* parser, GumboToken* token) {\n  if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_COL,\n                    GUMBO_TAG_COLGROUP, GUMBO_TAG_TBODY, GUMBO_TAG_TD,\n                    GUMBO_TAG_TFOOT, GUMBO_TAG_TH, GUMBO_TAG_THEAD,\n                    GUMBO_TAG_TR, GUMBO_TAG_LAST) ||\n             tag_in(token, kEndTag, GUMBO_TAG_CAPTION, GUMBO_TAG_TABLE,\n                    GUMBO_TAG_LAST)) {\n    if (!has_an_element_in_table_scope(parser, GUMBO_TAG_CAPTION)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    if (!tag_is(token, kEndTag, GUMBO_TAG_CAPTION)) {\n      add_parse_error(parser, token);\n      parser->_parser_state->_reprocess_current_token = true;\n    }\n    generate_implied_end_tags(parser, GUMBO_TAG_LAST);\n    bool result = true;\n    if (!node_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION)) {\n      add_parse_error(parser, token);\n      while (!node_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION)) {\n        pop_current_node(parser);\n      }\n      result = false;\n    }\n    pop_current_node(parser);  // The <caption> itself.\n    clear_active_formatting_elements(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);\n    return result;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_COL,\n                    GUMBO_TAG_COLGROUP, GUMBO_TAG_HTML, GUMBO_TAG_TBODY,\n                    GUMBO_TAG_TD, GUMBO_TAG_TFOOT, GUMBO_TAG_TH,\n                    GUMBO_TAG_THEAD, GUMBO_TAG_TR, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    return handle_in_body(parser, token);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incolgroup\nstatic bool handle_in_column_group(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_COL)) {\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    return true;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_COL)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_EOF &&\n             get_current_node(parser) == parser->_output->root) {\n    return true;\n  } else {\n    if (get_current_node(parser) == parser->_output->root) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    assert(node_tag_is(get_current_node(parser), GUMBO_TAG_COLGROUP));\n    pop_current_node(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);\n    if (!tag_is(token, kEndTag, GUMBO_TAG_COLGROUP)) {\n      parser->_parser_state->_reprocess_current_token = true;\n    }\n    return true;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intbody\nstatic bool handle_in_table_body(GumboParser* parser, GumboToken* token) {\n  if (tag_is(token, kStartTag, GUMBO_TAG_TR)) {\n    clear_stack_to_table_body_context(parser);\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_TD, GUMBO_TAG_TH,\n                    GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    clear_stack_to_table_body_context(parser);\n    insert_element_of_tag_type(parser, GUMBO_TAG_TR, GUMBO_INSERTION_IMPLIED);\n    parser->_parser_state->_reprocess_current_token = true;\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);\n    return false;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT,\n                    GUMBO_TAG_THEAD, GUMBO_TAG_LAST)) {\n    if (!has_an_element_in_table_scope(parser, token->v.end_tag)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    clear_stack_to_table_body_context(parser);\n    pop_current_node(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_COL,\n                    GUMBO_TAG_COLGROUP, GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT,\n                    GUMBO_TAG_THEAD, GUMBO_TAG_LAST) ||\n             tag_is(token, kEndTag, GUMBO_TAG_TABLE)) {\n    if (!(has_an_element_in_table_scope(parser, GUMBO_TAG_TBODY) ||\n          has_an_element_in_table_scope(parser, GUMBO_TAG_THEAD) ||\n          has_an_element_in_table_scope(parser, GUMBO_TAG_TFOOT))) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    clear_stack_to_table_body_context(parser);\n    pop_current_node(parser);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);\n    parser->_parser_state->_reprocess_current_token = true;\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_CAPTION,\n                    GUMBO_TAG_COL, GUMBO_TAG_TR, GUMBO_TAG_COLGROUP,\n                    GUMBO_TAG_HTML, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_LAST))\n  {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    return handle_in_table(parser, token);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intr\nstatic bool handle_in_row(GumboParser* parser, GumboToken* token) {\n  if (tag_in(token, kStartTag, GUMBO_TAG_TH, GUMBO_TAG_TD, GUMBO_TAG_LAST)) {\n    clear_stack_to_table_row_context(parser);\n    insert_element_from_token(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CELL);\n    add_formatting_element(parser, &kActiveFormattingScopeMarker);\n    return true;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_COLGROUP,\n                    GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD,\n                    GUMBO_TAG_TR, GUMBO_TAG_LAST) ||\n             tag_in(token, kEndTag, GUMBO_TAG_TR, GUMBO_TAG_TABLE,\n                    GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD,\n                    GUMBO_TAG_LAST)) {\n    // This case covers 4 clauses of the spec, each of which say \"Otherwise, act\n    // as if an end tag with the tag name \"tr\" had been seen.\"  The differences\n    // are in error handling and whether the current token is reprocessed.\n    GumboTag desired_tag =\n        tag_in(token, kEndTag, GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT,\n               GUMBO_TAG_THEAD, GUMBO_TAG_LAST)\n        ? token->v.end_tag : GUMBO_TAG_TR;\n    if (!has_an_element_in_table_scope(parser, desired_tag)) {\n      gumbo_debug(\"Bailing because there is no tag %s in table scope.\\nOpen elements:\",\n                 gumbo_normalized_tagname(desired_tag));\n      for (int i = 0; i < parser->_parser_state->_open_elements.length; ++i) {\n        const GumboNode* node = parser->_parser_state->_open_elements.data[i];\n        gumbo_debug(\"%s\\n\", gumbo_normalized_tagname(node->v.element.tag));\n      }\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    clear_stack_to_table_row_context(parser);\n    GumboNode* last_element = pop_current_node(parser);\n    assert(node_tag_is(last_element, GUMBO_TAG_TR));\n    AVOID_UNUSED_VARIABLE_WARNING(last_element);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);\n    if (!tag_is(token, kEndTag, GUMBO_TAG_TR)) {\n      parser->_parser_state->_reprocess_current_token = true;\n    }\n    return true;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_CAPTION,\n                    GUMBO_TAG_COL, GUMBO_TAG_COLGROUP, GUMBO_TAG_HTML,\n                    GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else {\n    return handle_in_table(parser, token);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intd\nstatic bool handle_in_cell(GumboParser* parser, GumboToken* token) {\n  if (tag_in(token, kEndTag, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_LAST)) {\n    GumboTag token_tag = token->v.end_tag;\n    if (!has_an_element_in_table_scope(parser, token_tag)) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    return close_table_cell(parser, token, token_tag);\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_COL,\n                    GUMBO_TAG_COLGROUP, GUMBO_TAG_TBODY, GUMBO_TAG_TD,\n                    GUMBO_TAG_TFOOT, GUMBO_TAG_TH, GUMBO_TAG_THEAD,\n                    GUMBO_TAG_TR, GUMBO_TAG_LAST)) {\n    gumbo_debug(\"Handling <td> in cell.\\n\");\n    if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TH) &&\n        !has_an_element_in_table_scope(parser, GUMBO_TAG_TD)) {\n      gumbo_debug(\"Bailing out because there's no <td> or <th> in scope.\\n\");\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    parser->_parser_state->_reprocess_current_token = true;\n    return close_current_cell(parser, token);\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_BODY, GUMBO_TAG_CAPTION,\n                    GUMBO_TAG_COL, GUMBO_TAG_COLGROUP, GUMBO_TAG_HTML,\n                    GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_TABLE, GUMBO_TAG_TBODY,\n                    GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD, GUMBO_TAG_TR,\n                    GUMBO_TAG_LAST)) {\n    if (!has_an_element_in_table_scope(parser, token->v.end_tag)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    parser->_parser_state->_reprocess_current_token = true;\n    return close_current_cell(parser, token);\n  } else {\n    return handle_in_body(parser, token);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inselect\nstatic bool handle_in_select(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_NULL) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_CHARACTER ||\n             token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_OPTION)) {\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {\n      pop_current_node(parser);\n    }\n    insert_element_from_token(parser, token);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_OPTGROUP)) {\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {\n      pop_current_node(parser);\n    }\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTGROUP)) {\n      pop_current_node(parser);\n    }\n    insert_element_from_token(parser, token);\n    return true;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_OPTGROUP)) {\n    GumboVector* open_elements = &parser->_parser_state->_open_elements;\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTION) &&\n        node_tag_is(open_elements->data[open_elements->length - 2],\n                    GUMBO_TAG_OPTGROUP)) {\n      pop_current_node(parser);\n    }\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTGROUP)) {\n      pop_current_node(parser);\n      return true;\n    } else {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_OPTION)) {\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {\n      pop_current_node(parser);\n      return true;\n    } else {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_SELECT)) {\n    if (!has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    close_current_select(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    close_current_select(parser);\n    return false;\n  } else if (tag_in(token, kStartTag, GUMBO_TAG_INPUT, GUMBO_TAG_KEYGEN,\n                    GUMBO_TAG_TEXTAREA, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    if (!has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) {\n      ignore_token(parser);\n    } else {\n      close_current_select(parser);\n      parser->_parser_state->_reprocess_current_token = true;\n    }\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_SCRIPT)) {\n    return handle_in_head(parser, token);\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    if (get_current_node(parser) != parser->_output->root) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inselectintable\nstatic bool handle_in_select_in_table(GumboParser* parser, GumboToken* token) {\n  if (tag_in(token, kStartTag, GUMBO_TAG_CAPTION, GUMBO_TAG_TABLE,\n             GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD, GUMBO_TAG_TR,\n             GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    close_current_select(parser);\n    parser->_parser_state->_reprocess_current_token = true;\n    return false;\n  } else if (tag_in(token, kEndTag, GUMBO_TAG_CAPTION, GUMBO_TAG_TABLE,\n                    GUMBO_TAG_TBODY, GUMBO_TAG_TFOOT, GUMBO_TAG_THEAD,\n                    GUMBO_TAG_TR, GUMBO_TAG_TD, GUMBO_TAG_TH, GUMBO_TAG_LAST)) {\n    add_parse_error(parser, token);\n    if (has_an_element_in_table_scope(parser, token->v.end_tag)) {\n      close_current_select(parser);\n      reset_insertion_mode_appropriately(parser);\n      parser->_parser_state->_reprocess_current_token = true;\n    } else {\n      ignore_token(parser);\n    }\n    return false;\n  } else {\n    return handle_in_select(parser, token);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-afterbody\nstatic bool handle_after_body(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_WHITESPACE ||\n      tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    GumboNode* html_node = parser->_output->root;\n    assert(html_node != NULL);\n    append_comment_node(parser, html_node, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {\n    // TODO(jdtang): Handle fragment parsing algorithm case.\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_BODY);\n    GumboNode* html = parser->_parser_state->_open_elements.data[0];\n    assert(node_tag_is(html, GUMBO_TAG_HTML));\n    record_end_of_element(\n        parser->_parser_state->_current_token, &html->v.element);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);\n    parser->_parser_state->_reprocess_current_token = true;\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inframeset\nstatic bool handle_in_frameset(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {\n    insert_element_from_token(parser, token);\n    return true;\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_FRAMESET)) {\n    if (node_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) {\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    }\n    pop_current_node(parser);\n    // TODO(jdtang): Add a condition to ignore this for the fragment parsing\n    // algorithm.\n    if (!node_tag_is(get_current_node(parser), GUMBO_TAG_FRAMESET)) {\n      set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_FRAMESET);\n    }\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAME)) {\n    insert_element_from_token(parser, token);\n    pop_current_node(parser);\n    acknowledge_self_closing_tag(parser);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {\n    return handle_in_head(parser, token);\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    if (!node_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) {\n      add_parse_error(parser, token);\n      return false;\n    }\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-afterframeset\nstatic bool handle_after_frameset(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_WHITESPACE) {\n    insert_text_token(parser, token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_current_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE) {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET);\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {\n    return handle_in_head(parser, token);\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-after-body-insertion-mode\nstatic bool handle_after_after_body(GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_document_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE ||\n             token->type == GUMBO_TOKEN_WHITESPACE ||\n             tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    return true;\n  } else {\n    add_parse_error(parser, token);\n    set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);\n    parser->_parser_state->_reprocess_current_token = true;\n    return false;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-after-frameset-insertion-mode\nstatic bool handle_after_after_frameset(\n    GumboParser* parser, GumboToken* token) {\n  if (token->type == GUMBO_TOKEN_COMMENT) {\n    append_comment_node(parser, get_document_node(parser), token);\n    return true;\n  } else if (token->type == GUMBO_TOKEN_DOCTYPE ||\n             token->type == GUMBO_TOKEN_WHITESPACE ||\n             tag_is(token, kStartTag, GUMBO_TAG_HTML)) {\n    return handle_in_body(parser, token);\n  } else if (token->type == GUMBO_TOKEN_EOF) {\n    return true;\n  } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {\n    return handle_in_head(parser, token);\n  } else {\n    add_parse_error(parser, token);\n    ignore_token(parser);\n    return false;\n  }\n}\n\n// Function pointers for each insertion mode.  Keep in sync with\n// insertion_mode.h.\ntypedef bool (*TokenHandler)(GumboParser* parser, GumboToken* token);\nstatic const TokenHandler kTokenHandlers[] = {\n  handle_initial,\n  handle_before_html,\n  handle_before_head,\n  handle_in_head,\n  handle_in_head_noscript,\n  handle_after_head,\n  handle_in_body,\n  handle_text,\n  handle_in_table,\n  handle_in_table_text,\n  handle_in_caption,\n  handle_in_column_group,\n  handle_in_table_body,\n  handle_in_row,\n  handle_in_cell,\n  handle_in_select,\n  handle_in_select_in_table,\n  handle_after_body,\n  handle_in_frameset,\n  handle_after_frameset,\n  handle_after_after_body,\n  handle_after_after_frameset\n};\n\nstatic bool handle_html_content(GumboParser* parser, GumboToken* token) {\n  return kTokenHandlers[parser->_parser_state->_insertion_mode](\n      parser, token);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inforeign\nstatic bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {\n  switch (token->type) {\n    case GUMBO_TOKEN_NULL:\n      add_parse_error(parser, token);\n      token->type = GUMBO_TOKEN_CHARACTER;\n      token->v.character = kUtf8ReplacementChar;\n      insert_text_token(parser, token);\n      return false;\n    case GUMBO_TOKEN_WHITESPACE:\n      insert_text_token(parser, token);\n      return true;\n    case GUMBO_TOKEN_CHARACTER:\n      insert_text_token(parser, token);\n      set_frameset_not_ok(parser);\n      return true;\n    case GUMBO_TOKEN_COMMENT:\n      append_comment_node(parser, get_current_node(parser), token);\n      return true;\n    case GUMBO_TOKEN_DOCTYPE:\n      add_parse_error(parser, token);\n      ignore_token(parser);\n      return false;\n    default:\n      // Fall through to the if-statements below.\n      break;\n  }\n  // Order matters for these clauses.\n  if (tag_in(token, kStartTag, GUMBO_TAG_B, GUMBO_TAG_BIG,\n             GUMBO_TAG_BLOCKQUOTE, GUMBO_TAG_BODY, GUMBO_TAG_BR,\n             GUMBO_TAG_CENTER, GUMBO_TAG_CODE, GUMBO_TAG_DD, GUMBO_TAG_DIV,\n             GUMBO_TAG_DL, GUMBO_TAG_DT, GUMBO_TAG_EM, GUMBO_TAG_EMBED,\n             GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3, GUMBO_TAG_H4,\n             GUMBO_TAG_H5, GUMBO_TAG_H6, GUMBO_TAG_HEAD, GUMBO_TAG_HR,\n             GUMBO_TAG_I, GUMBO_TAG_IMG, GUMBO_TAG_LI, GUMBO_TAG_LISTING,\n             GUMBO_TAG_MENU, GUMBO_TAG_META, GUMBO_TAG_NOBR, GUMBO_TAG_OL,\n             GUMBO_TAG_P, GUMBO_TAG_PRE, GUMBO_TAG_RUBY, GUMBO_TAG_S,\n             GUMBO_TAG_SMALL, GUMBO_TAG_SPAN, GUMBO_TAG_STRONG,\n             GUMBO_TAG_STRIKE, GUMBO_TAG_SUB, GUMBO_TAG_SUP,\n             GUMBO_TAG_TABLE, GUMBO_TAG_TT, GUMBO_TAG_U, GUMBO_TAG_UL,\n             GUMBO_TAG_VAR, GUMBO_TAG_LAST) ||\n     (tag_is(token, kStartTag, GUMBO_TAG_FONT) && (\n         token_has_attribute(token, \"color\") ||\n         token_has_attribute(token, \"face\") ||\n         token_has_attribute(token, \"size\")))) {\n    add_parse_error(parser, token);\n    do {\n      pop_current_node(parser);\n    } while(!(is_mathml_integration_point(get_current_node(parser)) ||\n              is_html_integration_point(get_current_node(parser)) ||\n              get_current_node(parser)->v.element.tag_namespace ==\n              GUMBO_NAMESPACE_HTML));\n    parser->_parser_state->_reprocess_current_token = true;\n    return false;\n  } else if (token->type == GUMBO_TOKEN_START_TAG) {\n    const GumboNamespaceEnum current_namespace =\n        get_current_node(parser)->v.element.tag_namespace;\n    if (current_namespace == GUMBO_NAMESPACE_MATHML) {\n      adjust_mathml_attributes(parser, token);\n    }\n    if (current_namespace == GUMBO_NAMESPACE_SVG) {\n      // Tag adjustment is left to the gumbo_normalize_svg_tagname helper\n      // function.\n      adjust_svg_attributes(parser, token);\n    }\n    adjust_foreign_attributes(parser, token);\n    insert_foreign_element(parser, token, current_namespace);\n    if (token->v.start_tag.is_self_closing) {\n      pop_current_node(parser);\n      acknowledge_self_closing_tag(parser);\n    }\n    return true;\n  // </script> tags are handled like any other end tag, putting the script's\n  // text into a text node child and closing the current node.\n  } else {\n    assert(token->type == GUMBO_TOKEN_END_TAG);\n    GumboNode* node = get_current_node(parser);\n    assert(node != NULL);\n    GumboStringPiece token_tagname = token->original_text;\n    GumboStringPiece node_tagname = node->v.element.original_tag;\n    gumbo_tag_from_original_text(&token_tagname);\n    gumbo_tag_from_original_text(&node_tagname);\n\n    bool is_success = true;\n    if (!gumbo_string_equals_ignore_case(&node_tagname, &token_tagname)) {\n      add_parse_error(parser, token);\n      is_success = false;\n    }\n    int i = parser->_parser_state->_open_elements.length;\n    for( --i; i > 0; ) {\n      // Here we move up the stack until we find an HTML element (in which\n      // case we do nothing) or we find the element that we're about to\n      // close (in which case we pop everything we've seen until that\n      // point.)\n      gumbo_debug(\"Foreign %.*s node at %d.\\n\", node_tagname.length,\n                  node_tagname.data, i);\n      if (gumbo_string_equals_ignore_case(&node_tagname, &token_tagname)) {\n        gumbo_debug(\"Matches.\\n\");\n        while (pop_current_node(parser) != node) {\n          // Pop all the nodes below the current one.  Node is guaranteed to\n          // be an element on the stack of open elements (set below), so\n          // this loop is guaranteed to terminate.\n        }\n        return is_success;\n      }\n      --i;\n      node = parser->_parser_state->_open_elements.data[i];\n      if (node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML) {\n        // Must break before gumbo_tag_from_original_text to avoid passing\n        // parser-inserted nodes through.\n        break;\n      }\n      node_tagname = node->v.element.original_tag;\n      gumbo_tag_from_original_text(&node_tagname);\n    }\n    assert(node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML);\n    // We can't call handle_token directly because the current node is still in\n    // the SVG namespace, so it would re-enter this and result in infinite\n    // recursion.\n    return handle_html_content(parser, token) && is_success;\n  }\n}\n\n\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction\nstatic bool handle_token(GumboParser* parser, GumboToken* token) {\n  if (parser->_parser_state->_ignore_next_linefeed &&\n      token->type == GUMBO_TOKEN_WHITESPACE && token->v.character == '\\n') {\n    parser->_parser_state->_ignore_next_linefeed = false;\n    ignore_token(parser);\n    return true;\n  }\n  // This needs to be reset both here and in the conditional above to catch both\n  // the case where the next token is not whitespace (so we don't ignore\n  // whitespace in the middle of <pre> tags) and where there are multiple\n  // whitespace tokens (so we don't ignore the second one).\n  parser->_parser_state->_ignore_next_linefeed = false;\n\n  if (tag_is(token, kEndTag, GUMBO_TAG_BODY)) {\n    parser->_parser_state->_closed_body_tag = true;\n  }\n  if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {\n    parser->_parser_state->_closed_html_tag = true;\n  }\n\n  const GumboNode* current_node = get_current_node(parser);\n  assert(!current_node || current_node->type == GUMBO_NODE_ELEMENT);\n  if (current_node) {\n    gumbo_debug(\"Current node: <%s>.\\n\",\n                gumbo_normalized_tagname(current_node->v.element.tag));\n  }\n  if (!current_node ||\n      current_node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML ||\n      (is_mathml_integration_point(current_node) &&\n       (token->type == GUMBO_TOKEN_CHARACTER ||\n        token->type == GUMBO_TOKEN_WHITESPACE ||\n        token->type == GUMBO_TOKEN_NULL ||\n        (token->type == GUMBO_TOKEN_START_TAG &&\n         !tag_in(token, kStartTag, GUMBO_TAG_MGLYPH, GUMBO_TAG_MALIGNMARK,\n                GUMBO_TAG_LAST)))) ||\n      (current_node->v.element.tag_namespace == GUMBO_NAMESPACE_MATHML &&\n       node_tag_is(current_node, GUMBO_TAG_ANNOTATION_XML) &&\n       tag_is(token, kStartTag, GUMBO_TAG_SVG)) ||\n      (is_html_integration_point(current_node) && (\n          token->type == GUMBO_TOKEN_START_TAG ||\n          token->type == GUMBO_TOKEN_CHARACTER ||\n          token->type == GUMBO_TOKEN_NULL ||\n          token->type == GUMBO_TOKEN_WHITESPACE)) ||\n      token->type == GUMBO_TOKEN_EOF) {\n    return handle_html_content(parser, token);\n  } else {\n    return handle_in_foreign_content(parser, token);\n  }\n}\n\nGumboOutput* gumbo_parse(const char* buffer) {\n  return gumbo_parse_with_options(\n      &kGumboDefaultOptions, buffer, strlen(buffer));\n}\n\nGumboOutput* gumbo_parse_with_options(\n    const GumboOptions* options, const char* buffer, size_t length) {\n  GumboParser parser;\n  parser._options = options;\n  output_init(&parser);\n  gumbo_tokenizer_state_init(&parser, buffer, length);\n  parser_state_init(&parser);\n\n  GumboParserState* state = parser._parser_state;\n  gumbo_debug(\"Parsing %.*s.\\n\", length, buffer);\n\n  // Sanity check so that infinite loops die with an assertion failure instead\n  // of hanging the process before we ever get an error.\n  int loop_count = 0;\n\n  GumboToken token;\n  bool has_error = false;\n  do {\n    if (state->_reprocess_current_token) {\n      state->_reprocess_current_token = false;\n    } else {\n      GumboNode* current_node = get_current_node(&parser);\n      gumbo_tokenizer_set_is_current_node_foreign(\n          &parser, current_node &&\n          current_node->v.element.tag_namespace != GUMBO_NAMESPACE_HTML);\n      has_error = !gumbo_lex(&parser, &token) || has_error;\n    }\n    const char* token_type = \"text\";\n    switch (token.type) {\n      case GUMBO_TOKEN_DOCTYPE:\n        token_type = \"doctype\";\n        break;\n      case GUMBO_TOKEN_START_TAG:\n        token_type = gumbo_normalized_tagname(token.v.start_tag.tag);\n        break;\n      case GUMBO_TOKEN_END_TAG:\n        token_type = gumbo_normalized_tagname(token.v.end_tag);\n        break;\n      case GUMBO_TOKEN_COMMENT:\n        token_type = \"comment\";\n        break;\n      default:\n        break;\n    }\n    gumbo_debug(\"Handling %s token @%d:%d in state %d.\\n\",\n               (char*) token_type, token.position.line, token.position.column,\n               state->_insertion_mode);\n\n    state->_current_token = &token;\n    state->_self_closing_flag_acknowledged =\n        !(token.type == GUMBO_TOKEN_START_TAG &&\n          token.v.start_tag.is_self_closing);\n\n    has_error = !handle_token(&parser, &token) || has_error;\n\n    // Check for memory leaks when ownership is transferred from start tag\n    // tokens to nodes.\n    assert(state->_reprocess_current_token ||\n           token.type != GUMBO_TOKEN_START_TAG ||\n           token.v.start_tag.attributes.data == NULL);\n\n    if (!state->_self_closing_flag_acknowledged) {\n      GumboError* error = add_parse_error(&parser, &token);\n      if (error) {\n        error->type = GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG;\n      }\n    }\n\n    ++loop_count;\n    assert(loop_count < 1000000000);\n\n  } while ((token.type != GUMBO_TOKEN_EOF || state->_reprocess_current_token) &&\n           !(options->stop_on_first_error && has_error));\n\n  finish_parsing(&parser);\n  // For API uniformity reasons, if the doctype still has nulls, convert them to\n  // empty strings.\n  GumboDocument* doc_type = &parser._output->document->v.document;\n  if (doc_type->name == NULL) {\n    doc_type->name = gumbo_copy_stringz(&parser, \"\");\n  }\n  if (doc_type->public_identifier == NULL) {\n    doc_type->public_identifier = gumbo_copy_stringz(&parser, \"\");\n  }\n  if (doc_type->system_identifier == NULL) {\n    doc_type->system_identifier = gumbo_copy_stringz(&parser, \"\");\n  }\n\n  parser_state_destroy(&parser);\n  gumbo_tokenizer_state_destroy(&parser);\n  return parser._output;\n}\n\nvoid gumbo_destroy_node(GumboOptions* options, GumboNode* node) {\n  // Need a dummy GumboParser because the allocator comes along with the\n  // options object.\n  GumboParser parser;\n  parser._options = options;\n  destroy_node(&parser, node);\n}\n\nvoid gumbo_destroy_output(const GumboOptions* options, GumboOutput* output) {\n  // Need a dummy GumboParser because the allocator comes along with the\n  // options object.\n  GumboParser parser;\n  parser._options = options;\n  destroy_node(&parser, output->document);\n  for (int i = 0; i < output->errors.length; ++i) {\n    gumbo_error_destroy(&parser, output->errors.data[i]);\n  }\n  gumbo_vector_destroy(&parser, &output->errors);\n  gumbo_parser_deallocate(&parser, output);\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/parser.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// Contains the definition of the top-level GumboParser structure that's\n// threaded through basically every internal function in the library.\n\n#ifndef GUMBO_PARSER_H_\n#define GUMBO_PARSER_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParserState;\nstruct GumboInternalOutput;\nstruct GumboInternalOptions;\nstruct GumboInternalTokenizerState;\n\n// An overarching struct that's threaded through (nearly) all functions in the\n// library, OOP-style.  This gives each function access to the options and\n// output, along with any internal state needed for the parse.\ntypedef struct GumboInternalParser {\n  // Settings for this parse run.\n  const struct GumboInternalOptions* _options;\n\n  // Output for the parse.\n  struct GumboInternalOutput* _output;\n\n  // The internal tokenizer state, defined as a pointer to avoid a cyclic\n  // dependency on html5tokenizer.h.  The main parse routine is responsible for\n  // initializing this on parse start, and destroying it on parse end.\n  // End-users will never see a non-garbage value in this pointer.\n  struct GumboInternalTokenizerState* _tokenizer_state;\n\n  // The internal parser state.  Initialized on parse start and destroyed on\n  // parse end; end-users will never see a non-garbage value in this pointer.\n  struct GumboInternalParserState* _parser_state;\n} GumboParser;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_PARSER_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/string_buffer.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"string_buffer.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n\n#include \"string_piece.h\"\n#include \"util.h\"\n\nstruct GumboInternalParser;\n\nstatic const size_t kDefaultStringBufferSize = 10;\n\nstatic void maybe_resize_string_buffer(\n    struct GumboInternalParser* parser, size_t additional_chars,\n    GumboStringBuffer* buffer) {\n  size_t new_length = buffer->length + additional_chars;\n  size_t new_capacity = buffer->capacity;\n  while (new_capacity < new_length) {\n    new_capacity *= 2;\n  }\n  if (new_capacity != buffer->capacity) {\n    char* new_data = gumbo_parser_allocate(parser, new_capacity);\n    memcpy(new_data, buffer->data, buffer->length);\n    gumbo_parser_deallocate(parser, buffer->data);\n    buffer->data = new_data;\n    buffer->capacity = new_capacity;\n  }\n}\n\nvoid gumbo_string_buffer_init(\n    struct GumboInternalParser* parser, GumboStringBuffer* output) {\n  output->data = gumbo_parser_allocate(parser, kDefaultStringBufferSize);\n  output->length = 0;\n  output->capacity = kDefaultStringBufferSize;\n}\n\nvoid gumbo_string_buffer_reserve(\n    struct GumboInternalParser* parser, size_t min_capacity,\n    GumboStringBuffer* output) {\n  maybe_resize_string_buffer(parser, min_capacity - output->length, output);\n}\n\nvoid gumbo_string_buffer_append_codepoint(\n    struct GumboInternalParser* parser, int c, GumboStringBuffer* output) {\n  // num_bytes is actually the number of continuation bytes, 1 less than the\n  // total number of bytes.  This is done to keep the loop below simple and\n  // should probably change if we unroll it.\n  int num_bytes, prefix;\n  if (c <= 0x7f) {\n    num_bytes = 0;\n    prefix = 0;\n  } else if (c <= 0x7ff) {\n    num_bytes = 1;\n    prefix = 0xc0;\n  } else if (c <= 0xffff) {\n    num_bytes = 2;\n    prefix = 0xe0;\n  } else {\n    num_bytes = 3;\n    prefix = 0xf0;\n  }\n  maybe_resize_string_buffer(parser, num_bytes + 1, output);\n  output->data[output->length++] = prefix | (c >> (num_bytes * 6));\n  for (int i = num_bytes - 1; i >= 0; --i) {\n    output->data[output->length++] = 0x80 | (0x3f & (c >> (i * 6)));\n  }\n}\n\nvoid gumbo_string_buffer_append_string(\n    struct GumboInternalParser* parser, GumboStringPiece* str,\n    GumboStringBuffer* output) {\n  maybe_resize_string_buffer(parser, str->length, output);\n  memcpy(output->data + output->length, str->data, str->length);\n  output->length += str->length;\n}\n\nchar* gumbo_string_buffer_to_string(\n    struct GumboInternalParser* parser, GumboStringBuffer* input) {\n  char* buffer = gumbo_parser_allocate(parser, input->length + 1);\n  memcpy(buffer, input->data, input->length);\n  buffer[input->length] = '\\0';\n  return buffer;\n}\n\nvoid gumbo_string_buffer_destroy(\n    struct GumboInternalParser* parser, GumboStringBuffer* buffer) {\n  gumbo_parser_deallocate(parser, buffer->data);\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/string_buffer.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n#ifndef GUMBO_STRING_BUFFER_H_\n#define GUMBO_STRING_BUFFER_H_\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"gumbo.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\n\n// A struct representing a mutable, growable string.  This consists of a\n// heap-allocated buffer that may grow (by doubling) as necessary.  When\n// converting to a string, this allocates a new buffer that is only as long as\n// it needs to be.  Note that the internal buffer here is *not* nul-terminated,\n// so be sure not to use ordinary string manipulation functions on it.\ntypedef struct {\n  // A pointer to the beginning of the string.  NULL iff length == 0.\n  char* data;\n\n  // The length of the string fragment, in bytes.  May be zero.\n  size_t length;\n\n  // The capacity of the buffer, in bytes.\n  size_t capacity;\n} GumboStringBuffer;\n\n// Initializes a new GumboStringBuffer.\nvoid gumbo_string_buffer_init(\n    struct GumboInternalParser* parser, GumboStringBuffer* output);\n\n// Ensures that the buffer contains at least a certain amount of space.  Most\n// useful with snprintf and the other length-delimited string functions, which\n// may want to write directly into the buffer.\nvoid gumbo_string_buffer_reserve(\n    struct GumboInternalParser* parser, size_t min_capacity,\n    GumboStringBuffer* output);\n\n// Appends a single Unicode codepoint onto the end of the GumboStringBuffer.\n// This is essentially a UTF-8 encoder, and may add 1-4 bytes depending on the\n// value of the codepoint.\nvoid gumbo_string_buffer_append_codepoint(\n    struct GumboInternalParser* parser, int c, GumboStringBuffer* output);\n\n// Appends a string onto the end of the GumboStringBuffer.\nvoid gumbo_string_buffer_append_string(\n    struct GumboInternalParser* parser, GumboStringPiece* str,\n    GumboStringBuffer* output);\n\n// Converts this string buffer to const char*, alloctaing a new buffer for it.\nchar* gumbo_string_buffer_to_string(\n    struct GumboInternalParser* parser, GumboStringBuffer* input);\n\n// Deallocates this GumboStringBuffer.\nvoid gumbo_string_buffer_destroy(\n    struct GumboInternalParser* parser, GumboStringBuffer* buffer);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_STRING_BUFFER_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/string_piece.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"string_piece.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n\n#include \"util.h\"\n\nstruct GumboInternalParser;\n\nconst GumboStringPiece kGumboEmptyString = { NULL, 0 };\n\nbool gumbo_string_equals(\n    const GumboStringPiece* str1, const GumboStringPiece* str2) {\n  return str1->length == str2->length &&\n      !memcmp(str1->data, str2->data, str1->length);\n}\n\nbool gumbo_string_equals_ignore_case(\n    const GumboStringPiece* str1, const GumboStringPiece* str2) {\n  return str1->length == str2->length &&\n      !strncasecmp(str1->data, str2->data, str1->length);\n}\n\nvoid gumbo_string_copy(\n    struct GumboInternalParser* parser, GumboStringPiece* dest,\n    const GumboStringPiece* source) {\n  dest->length = source->length;\n  char* buffer = gumbo_parser_allocate(parser, source->length);\n  memcpy(buffer, source->data, source->length);\n  dest->data = buffer;\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/string_piece.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#ifndef GUMBO_STRING_PIECE_H_\n#define GUMBO_STRING_PIECE_H_\n\n#include \"gumbo.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\n\n// Performs a deep-copy of an GumboStringPiece, allocating a fresh buffer in the\n// destination and copying over the characters from source.  Dest should be\n// empty, with no buffer allocated; otherwise, this leaks it.\nvoid gumbo_string_copy(\n    struct GumboInternalParser* parser, GumboStringPiece* dest,\n    const GumboStringPiece* source);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_STRING_PIECE_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/tag.c",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"gumbo.h\"\n\n#include <assert.h>\n#include <ctype.h>\n#include <strings.h>    // For strcasecmp.\n\n// NOTE(jdtang): Keep this in sync with the GumboTag enum in the header.\n// TODO(jdtang): Investigate whether there're efficiency benefits to putting the\n// most common tag names first, or to putting them in alphabetical order and\n// using a binary search.\nconst char* kGumboTagNames[] = {\n  \"html\",\n  \"head\",\n  \"title\",\n  \"base\",\n  \"link\",\n  \"meta\",\n  \"style\",\n  \"script\",\n  \"noscript\",\n  \"body\",\n  \"section\",\n  \"nav\",\n  \"article\",\n  \"aside\",\n  \"h1\",\n  \"h2\",\n  \"h3\",\n  \"h4\",\n  \"h5\",\n  \"h6\",\n  \"hgroup\",\n  \"header\",\n  \"footer\",\n  \"address\",\n  \"p\",\n  \"hr\",\n  \"pre\",\n  \"blockquote\",\n  \"ol\",\n  \"ul\",\n  \"li\",\n  \"dl\",\n  \"dt\",\n  \"dd\",\n  \"figure\",\n  \"figcaption\",\n  \"div\",\n  \"a\",\n  \"em\",\n  \"strong\",\n  \"small\",\n  \"s\",\n  \"cite\",\n  \"q\",\n  \"dfn\",\n  \"abbr\",\n  \"time\",\n  \"code\",\n  \"var\",\n  \"samp\",\n  \"kbd\",\n  \"sub\",\n  \"sup\",\n  \"i\",\n  \"b\",\n  \"mark\",\n  \"ruby\",\n  \"rt\",\n  \"rp\",\n  \"bdi\",\n  \"bdo\",\n  \"span\",\n  \"br\",\n  \"wbr\",\n  \"ins\",\n  \"del\",\n  \"image\",\n  \"img\",\n  \"iframe\",\n  \"embed\",\n  \"object\",\n  \"param\",\n  \"video\",\n  \"audio\",\n  \"source\",\n  \"track\",\n  \"canvas\",\n  \"map\",\n  \"area\",\n  \"math\",\n  \"mi\",\n  \"mo\",\n  \"mn\",\n  \"ms\",\n  \"mtext\",\n  \"mglyph\",\n  \"malignmark\",\n  \"annotation-xml\",\n  \"svg\",\n  \"foreignobject\",\n  \"desc\",\n  \"table\",\n  \"caption\",\n  \"colgroup\",\n  \"col\",\n  \"tbody\",\n  \"thead\",\n  \"tfoot\",\n  \"tr\",\n  \"td\",\n  \"th\",\n  \"form\",\n  \"fieldset\",\n  \"legend\",\n  \"label\",\n  \"input\",\n  \"button\",\n  \"select\",\n  \"datalist\",\n  \"optgroup\",\n  \"option\",\n  \"textarea\",\n  \"keygen\",\n  \"output\",\n  \"progress\",\n  \"meter\",\n  \"details\",\n  \"summary\",\n  \"command\",\n  \"menu\",\n  \"applet\",\n  \"acronym\",\n  \"bgsound\",\n  \"dir\",\n  \"frame\",\n  \"frameset\",\n  \"noframes\",\n  \"isindex\",\n  \"listing\",\n  \"xmp\",\n  \"nextid\",\n  \"noembed\",\n  \"plaintext\",\n  \"rb\",\n  \"strike\",\n  \"basefont\",\n  \"big\",\n  \"blink\",\n  \"center\",\n  \"font\",\n  \"marquee\",\n  \"multicol\",\n  \"nobr\",\n  \"spacer\",\n  \"tt\",\n  \"u\",\n  \"\",                   // TAG_UNKNOWN\n  \"\",                   // TAG_LAST\n};\n\nconst char* gumbo_normalized_tagname(GumboTag tag) {\n  assert(tag <= GUMBO_TAG_LAST);\n  return kGumboTagNames[tag];\n}\n\n// TODO(jdtang): Add test for this.\nvoid gumbo_tag_from_original_text(GumboStringPiece* text) {\n  if (text->data == NULL) {\n    return;\n  }\n\n  assert(text->length >= 2);\n  assert(text->data[0] == '<');\n  assert(text->data[text->length - 1] == '>');\n  if (text->data[1] == '/') {\n    // End tag.\n    assert(text->length >= 3);\n    text->data += 2;    // Move past </\n    text->length -= 3;\n  } else {\n    // Start tag.\n    text->data += 1;    // Move past <\n    text->length -= 2;\n    // strnchr is apparently not a standard C library function, so I loop\n    // explicitly looking for whitespace or other illegal tag characters.\n    for (const char* c = text->data; c != text->data + text->length; ++c) {\n      if (isspace(*c) || *c == '/') {\n        text->length = c - text->data;\n        break;\n      }\n    }\n  }\n}\n\nGumboTag gumbo_tag_enum(const char* tagname) {\n  for (int i = 0; i < GUMBO_TAG_LAST; ++i) {\n    // TODO(jdtang): strcasecmp is non-portable, so if we want to support\n    // non-GCC compilers, we'll need some #ifdef magic.  This source already has\n    // pretty significant issues with MSVC6 anyway.\n    if (strcasecmp(tagname, kGumboTagNames[i]) == 0) {\n      return i;\n    }\n  }\n  return GUMBO_TAG_UNKNOWN;\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/token_type.h",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#ifndef GUMBO_TOKEN_TYPE_H_\n#define GUMBO_TOKEN_TYPE_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// An enum representing the type of token.\ntypedef enum {\n  GUMBO_TOKEN_DOCTYPE,\n  GUMBO_TOKEN_START_TAG,\n  GUMBO_TOKEN_END_TAG,\n  GUMBO_TOKEN_COMMENT,\n  GUMBO_TOKEN_WHITESPACE,\n  GUMBO_TOKEN_CHARACTER,\n  GUMBO_TOKEN_NULL,\n  GUMBO_TOKEN_EOF\n} GumboTokenType;\n\n#ifdef __cplusplus\n}  // extern C\n#endif\n\n#endif  // GUMBO_TOKEN_TYPE_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/tokenizer.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// Coding conventions specific to this file:\n//\n// 1. Functions that fill in a token should be named emit_*, and should be\n// followed immediately by a return from the tokenizer (true if no error\n// occurred, false if an error occurred).  Sometimes the emit functions\n// themselves return a boolean so that they can be combined with the return\n// statement; in this case, they should match this convention.\n// 2. Functions that shuffle data from temporaries to final API structures\n// should be named finish_*, and be called just before the tokenizer exits the\n// state that accumulates the temporary.\n// 3. All internal data structures should be kept in an initialized state from\n// tokenizer creation onwards, ready to accept input.  When a buffer's flushed\n// and reset, it should be deallocated and immediately reinitialized.\n// 4. Make sure there are appropriate break statements following each state.\n// 5. Assertions on the state of the temporary and tag buffers are usually a\n// good idea, and should go at the entry point of each state when added.\n// 6. Statement order within states goes:\n//    1. Add parse errors, if appropriate.\n//    2. Call finish_* functions to build up tag state.\n//    2. Switch to new state.  Set _reconsume flag if appropriate.\n//    3. Perform any other temporary buffer manipulation.\n//    4. Emit tokens\n//    5. Return/break.\n// This order ensures that we can verify that every emit is followed by a\n// return, ensures that the correct state is recorded with any parse errors, and\n// prevents parse error position from being messed up by possible mark/resets in\n// temporary buffer manipulation.\n\n\n#include \"tokenizer.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <string.h>\n\n#include \"attribute.h\"\n#include \"char_ref.h\"\n#include \"error.h\"\n#include \"gumbo.h\"\n#include \"parser.h\"\n#include \"string_buffer.h\"\n#include \"string_piece.h\"\n#include \"token_type.h\"\n#include \"tokenizer_states.h\"\n#include \"utf8.h\"\n#include \"util.h\"\n#include \"vector.h\"\n\n// Compared against _script_data_buffer to determine if we're in double-escaped\n// script mode.\nconst GumboStringPiece kScriptTag = { \"script\", 6 };\n\n// An enum for the return value of each individual state.\ntypedef enum {\n  RETURN_ERROR,         // Return false (error) from the tokenizer.\n  RETURN_SUCCESS,       // Return true (success) from the tokenizer.\n  NEXT_CHAR             // Proceed to the next character and continue lexing.\n} StateResult;\n\n// This is a struct containing state necessary to build up a tag token,\n// character by character.\ntypedef struct GumboInternalTagState {\n  // A buffer to accumulate characters for various GumboStringPiece fields.\n  GumboStringBuffer _buffer;\n\n  // A pointer to the start of the original text corresponding to the contents\n  // of the buffer.\n  const char* _original_text;\n\n  // The current tag enum, computed once the tag name state has finished so that\n  // the buffer can be re-used for building up attributes.\n  GumboTag _tag;\n\n  // The starting location of the text in the buffer.\n  GumboSourcePosition _start_pos;\n\n  // The current list of attributes.  This is copied (and ownership of its data\n  // transferred) to the GumboStartTag token upon completion of the tag.  New\n  // attributes are added as soon as their attribute name state is complete, and\n  // values are filled in by operating on _attributes.data[attributes.length-1].\n  GumboVector /* GumboAttribute */ _attributes;\n\n  // If true, the next attribute value to be finished should be dropped.  This\n  // happens if a duplicate attribute name is encountered - we want to consume\n  // the attribute value, but shouldn't overwrite the existing value.\n  bool _drop_next_attr_value;\n\n  // The state that caused the tokenizer to switch into a character reference in\n  // attribute value state.  This is used to set the additional allowed\n  // character, and is switched back to on completion.  Initialized as the\n  // tokenizer enters the character reference state.\n  GumboTokenizerEnum _attr_value_state;\n\n  // The last start tag to have been emitted by the tokenizer.  This is\n  // necessary to check for appropriate end tags.\n  GumboTag _last_start_tag;\n\n  // If true, then this is a start tag.  If false, it's an end tag.  This is\n  // necessary to generate the appropriate token type at tag-closing time.\n  bool _is_start_tag;\n\n  // If true, then this tag is \"self-closing\" and doesn't have an end tag.\n  bool _is_self_closing;\n} GumboTagState;\n\n// This is the main tokenizer state struct, containing all state used by in\n// tokenizing the input stream.\ntypedef struct GumboInternalTokenizerState {\n  // The current lexer state.  Starts in GUMBO_LEX_DATA.\n  GumboTokenizerEnum _state;\n\n  // A flag indicating whether the current input character needs to reconsumed\n  // in another state, or whether the next input character should be read for\n  // the next iteration of the state loop.  This is set when the spec reads\n  // \"Reconsume the current input character in...\"\n  bool _reconsume_current_input;\n\n  // A flag indicating whether the current node is a foreign element.  This is\n  // set by gumbo_tokenizer_set_is_current_node_foreign and checked in the\n  // markup declaration state.\n  bool _is_current_node_foreign;\n\n  // Certain states (notably character references) may emit two character tokens\n  // at once, but the contract for lex() fills in only one token at a time.  The\n  // extra character is buffered here, and then this is checked on entry to\n  // lex().  If a character is stored here, it's immediately emitted and control\n  // returns from the lexer.  kGumboNoChar is used to represent 'no character\n  // stored.'\n  //\n  // Note that characters emitted through this mechanism will have their source\n  // position marked as the character under the mark, i.e. multiple characters\n  // may be emitted with the same position.  This is desirable for character\n  // references, but unsuitable for many other cases.  Use the _temporary_buffer\n  // mechanism if the buffered characters must have their original positions in\n  // the document.\n  int _buffered_emit_char;\n\n  // A temporary buffer to accumulate characters, as described by the \"temporary\n  // buffer\" phrase in the tokenizer spec.  We use this in a somewhat unorthodox\n  // way: we record the specific character to go into the buffer, which may\n  // sometimes be a lowercased version of the actual input character.  However,\n  // we *also* use utf8iterator_mark() to record the position at tag start.\n  // When we start flushing the temporary buffer, we set _temporary_buffer_emit\n  // to the start of it, and then increment it for each call to the tokenizer.\n  // We also call utf8iterator_reset(), and utf8iterator_next() through the\n  // input stream, so that tokens emitted by emit_char have the correct position\n  // and original text.\n  GumboStringBuffer _temporary_buffer;\n\n  // The current cursor position we're emitting from within\n  // _temporary_buffer.data.  NULL whenever we're not flushing the buffer.\n  const char* _temporary_buffer_emit;\n\n  // The temporary buffer is also used by the spec to check whether we should\n  // enter the script data double escaped state, but we can't use the same\n  // buffer for both because we have to flush out \"<s\" as emits while still\n  // maintaining the context that will eventually become \"script\".  This is a\n  // separate buffer that's used in place of the temporary buffer for states\n  // that may enter the script data double escape start state.\n  GumboStringBuffer _script_data_buffer;\n\n  // Pointer to the beginning of the current token in the original buffer; used\n  // to record the original text.\n  const char* _token_start;\n\n  // GumboSourcePosition recording the source location of the start of the\n  // current token.\n  GumboSourcePosition _token_start_pos;\n\n  // Current tag state.\n  GumboTagState _tag_state;\n\n  // Doctype state.  We use the temporary buffer to accumulate characters (it's\n  // not used for anything else in the doctype states), and then freshly\n  // allocate the strings in the doctype token, then copy it over on emit.\n  GumboTokenDocType _doc_type_state;\n\n  // The UTF8Iterator over the tokenizer input.\n  Utf8Iterator _input;\n} GumboTokenizerState;\n\n// Adds an ERR_UNEXPECTED_CODE_POINT parse error to the parser's error struct.\nstatic void add_parse_error(GumboParser* parser, GumboErrorType type) {\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  utf8iterator_get_position(&tokenizer->_input, &error->position);\n  error->original_text = utf8iterator_get_char_pointer(&tokenizer->_input);\n  error->type = type;\n  error->v.tokenizer.codepoint = utf8iterator_current(&tokenizer->_input);\n  switch (tokenizer->_state) {\n    case GUMBO_LEX_DATA:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_DATA;\n      break;\n    case GUMBO_LEX_CHAR_REF_IN_DATA:\n    case GUMBO_LEX_CHAR_REF_IN_RCDATA:\n    case GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_CHAR_REF;\n      break;\n    case GUMBO_LEX_RCDATA:\n    case GUMBO_LEX_RCDATA_LT:\n    case GUMBO_LEX_RCDATA_END_TAG_OPEN:\n    case GUMBO_LEX_RCDATA_END_TAG_NAME:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_RCDATA;\n      break;\n    case GUMBO_LEX_RAWTEXT:\n    case GUMBO_LEX_RAWTEXT_LT:\n    case GUMBO_LEX_RAWTEXT_END_TAG_OPEN:\n    case GUMBO_LEX_RAWTEXT_END_TAG_NAME:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_RAWTEXT;\n      break;\n    case GUMBO_LEX_PLAINTEXT:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_PLAINTEXT;\n      break;\n    case GUMBO_LEX_SCRIPT:\n    case GUMBO_LEX_SCRIPT_LT:\n    case GUMBO_LEX_SCRIPT_END_TAG_OPEN:\n    case GUMBO_LEX_SCRIPT_END_TAG_NAME:\n    case GUMBO_LEX_SCRIPT_ESCAPED_START:\n    case GUMBO_LEX_SCRIPT_ESCAPED_START_DASH:\n    case GUMBO_LEX_SCRIPT_ESCAPED:\n    case GUMBO_LEX_SCRIPT_ESCAPED_DASH:\n    case GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH:\n    case GUMBO_LEX_SCRIPT_ESCAPED_LT:\n    case GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN:\n    case GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT:\n    case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_SCRIPT;\n      break;\n    case GUMBO_LEX_TAG_OPEN:\n    case GUMBO_LEX_END_TAG_OPEN:\n    case GUMBO_LEX_TAG_NAME:\n    case GUMBO_LEX_BEFORE_ATTR_NAME:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_TAG;\n      break;\n    case GUMBO_LEX_SELF_CLOSING_START_TAG:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_SELF_CLOSING_TAG;\n      break;\n    case GUMBO_LEX_ATTR_NAME:\n    case GUMBO_LEX_AFTER_ATTR_NAME:\n    case GUMBO_LEX_BEFORE_ATTR_VALUE:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_ATTR_NAME;\n      break;\n    case GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED:\n    case GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED:\n    case GUMBO_LEX_ATTR_VALUE_UNQUOTED:\n    case GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_ATTR_VALUE;\n      break;\n    case GUMBO_LEX_BOGUS_COMMENT:\n    case GUMBO_LEX_COMMENT_START:\n    case GUMBO_LEX_COMMENT_START_DASH:\n    case GUMBO_LEX_COMMENT:\n    case GUMBO_LEX_COMMENT_END_DASH:\n    case GUMBO_LEX_COMMENT_END:\n    case GUMBO_LEX_COMMENT_END_BANG:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_COMMENT;\n      break;\n    case GUMBO_LEX_MARKUP_DECLARATION:\n    case GUMBO_LEX_DOCTYPE:\n    case GUMBO_LEX_BEFORE_DOCTYPE_NAME:\n    case GUMBO_LEX_DOCTYPE_NAME:\n    case GUMBO_LEX_AFTER_DOCTYPE_NAME:\n    case GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD:\n    case GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID:\n    case GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED:\n    case GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED:\n    case GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID:\n    case GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID:\n    case GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD:\n    case GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID:\n    case GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED:\n    case GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED:\n    case GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID:\n    case GUMBO_LEX_BOGUS_DOCTYPE:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_DOCTYPE;\n      break;\n    case GUMBO_LEX_CDATA:\n      error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_CDATA;\n      break;\n  }\n}\n\nstatic bool is_alpha(int c) {\n  // We don't use ISO C isupper/islower functions here because they\n  // depend upon the program's locale, while the behavior of the HTML5 spec is\n  // independent of which locale the program is run in.\n  return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');\n}\n\nstatic int ensure_lowercase(int c) {\n  return c >= 'A' && c <= 'Z' ? c + 0x20 : c;\n}\n\nstatic GumboTokenType get_char_token_type(int c) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\r':\n    case '\\f':\n    case ' ':\n      return GUMBO_TOKEN_WHITESPACE;\n    case 0:\n      gumbo_debug(\"Emitted null byte.\\n\");\n      return GUMBO_TOKEN_NULL;\n    case -1:\n      return GUMBO_TOKEN_EOF;\n    default:\n      return GUMBO_TOKEN_CHARACTER;\n  }\n}\n\n// Starts recording characters in the temporary buffer.\n// Because this needs to reset the utf8iterator_mark to the beginning of the\n// text that will eventually be emitted, it needs to be called a couple of\n// states before the spec says \"Set the temporary buffer to the empty string\".\n// In general, this should be called whenever there's a transition to a\n// \"less-than sign state\".  The initial < and possibly / then need to be\n// appended to the temporary buffer, their presence needs to be accounted for in\n// states that compare the temporary buffer against a literal value, and\n// spec stanzas that say \"emit a < and / character token along with a character\n// token for each character in the temporary buffer\" need to be adjusted to\n// account for the presence of the < and / inside the temporary buffer.\nstatic void clear_temporary_buffer(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  assert(!tokenizer->_temporary_buffer_emit);\n  utf8iterator_mark(&tokenizer->_input);\n  gumbo_string_buffer_destroy(parser, &tokenizer->_temporary_buffer);\n  gumbo_string_buffer_init(parser, &tokenizer->_temporary_buffer);\n  // The temporary buffer and script data buffer are the same object in the\n  // spec, so the script data buffer should be cleared as well.\n  gumbo_string_buffer_destroy(parser, &tokenizer->_script_data_buffer);\n  gumbo_string_buffer_init(parser, &tokenizer->_script_data_buffer);\n}\n\n// Appends a codepoint to the temporary buffer.\nstatic void append_char_to_temporary_buffer(\n    GumboParser* parser, int codepoint) {\n  gumbo_string_buffer_append_codepoint(\n      parser, codepoint, &parser->_tokenizer_state->_temporary_buffer);\n}\n\n// Checks to see if the temporary buffer equals a certain string.\n// Make sure this remains side-effect free; it's used in assertions.\n#ifndef NDEBUG\nstatic bool temporary_buffer_equals(\n    GumboParser* parser, const char* text) {\n  GumboStringBuffer* buffer = &parser->_tokenizer_state->_temporary_buffer;\n  // TODO(jdtang): See if the extra strlen is a performance problem, and replace\n  // it with an explicit sizeof(literal) if necessary.  I don't think it will\n  // be, as this is only used in a couple of rare states.\n  unsigned long text_len = strlen(text);\n  return text_len == buffer->length &&\n      memcmp(buffer->data, text, text_len) == 0;\n}\n#endif\n\nstatic void doc_type_state_init(GumboParser* parser) {\n  GumboTokenDocType* doc_type_state =\n      &parser->_tokenizer_state->_doc_type_state;\n  // We initialize these to NULL here so that we don't end up leaking memory if\n  // we never see a doctype token.  When we do see a doctype token, we reset\n  // them to a freshly-allocated empty string so that we can present a uniform\n  // interface to client code and not make them check for null.  Ownership is\n  // transferred to the doctype token when it's emitted.\n  doc_type_state->name = NULL;\n  doc_type_state->public_identifier = NULL;\n  doc_type_state->system_identifier = NULL;\n  doc_type_state->force_quirks = false;\n  doc_type_state->has_public_identifier = false;\n  doc_type_state->has_system_identifier = false;\n}\n\n// Sets the token original_text and position to the current iterator position.\n// This is necessary because [CDATA[ sections may include text that is ignored\n// by the tokenizer.\nstatic void reset_token_start_point(GumboTokenizerState* tokenizer) {\n  tokenizer->_token_start = utf8iterator_get_char_pointer(&tokenizer->_input);\n  utf8iterator_get_position(&tokenizer->_input, &tokenizer->_token_start_pos);\n}\n\n// Sets the tag buffer original text and start point to the current iterator\n// position.  This is necessary because attribute names & values may have\n// whitespace preceeding them, and so we can't assume that the actual token\n// starting point was the end of the last tag buffer usage.\nstatic void reset_tag_buffer_start_point(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n\n  utf8iterator_get_position(&tokenizer->_input, &tag_state->_start_pos);\n  tag_state->_original_text = utf8iterator_get_char_pointer(&tokenizer->_input);\n}\n\n// Moves the temporary buffer contents over to the specified output string,\n// and clears the temporary buffer.\nstatic void finish_temporary_buffer(GumboParser* parser, const char** output) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  *output =\n      gumbo_string_buffer_to_string(parser, &tokenizer->_temporary_buffer);\n  clear_temporary_buffer(parser);\n}\n\n// Advances the iterator past the end of the token, and then fills in the\n// relevant position fields.  It's assumed that after every emit, the tokenizer\n// will immediately return (letting the tree-construction stage read the filled\n// in Token).  Thus, it's safe to advance the input stream here, since it will\n// bypass the advance at the bottom of the state machine loop.\n//\n// Since this advances the iterator and resets the current input, make sure to\n// call it after you've recorded any other data you need for the token.\nstatic void finish_token(GumboParser* parser, GumboToken* token) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  if (!tokenizer->_reconsume_current_input) {\n    utf8iterator_next(&tokenizer->_input);\n  }\n\n  token->position = tokenizer->_token_start_pos;\n  token->original_text.data = tokenizer->_token_start;\n  reset_token_start_point(tokenizer);\n  token->original_text.length =\n      tokenizer->_token_start - token->original_text.data;\n  if (token->original_text.length > 0 && token->original_text.data[token->original_text.length - 1] == '\\r') {\n    // The UTF8 iterator will ignore carriage returns in the input stream, which\n    // means that the next token may start one past a \\r character.  The pointer\n    // arithmetic above results in that \\r being appended to the original text\n    // of the preceding token, so we have to adjust its length here to chop the\n    // \\r off.\n    --token->original_text.length;\n  }\n}\n\n// Records the doctype public ID, assumed to be in the temporary buffer.\n// Convenience method that also sets has_public_identifier to true.\nstatic void finish_doctype_public_id(GumboParser* parser) {\n  GumboTokenDocType* doc_type_state =\n      &parser->_tokenizer_state->_doc_type_state;\n  gumbo_parser_deallocate(parser, (void*) doc_type_state->public_identifier);\n  finish_temporary_buffer(parser, &doc_type_state->public_identifier);\n  doc_type_state->has_public_identifier = true;\n}\n\n// Records the doctype system ID, assumed to be in the temporary buffer.\n// Convenience method that also sets has_system_identifier to true.\nstatic void finish_doctype_system_id(GumboParser* parser) {\n  GumboTokenDocType* doc_type_state =\n      &parser->_tokenizer_state->_doc_type_state;\n  gumbo_parser_deallocate(parser, (void*) doc_type_state->system_identifier);\n  finish_temporary_buffer(parser, &doc_type_state->system_identifier);\n  doc_type_state->has_system_identifier = true;\n}\n\n// Writes a single specified character to the output token.\nstatic void emit_char(GumboParser* parser, int c, GumboToken* output) {\n  output->type = get_char_token_type(c);\n  output->v.character = c;\n  finish_token(parser, output);\n}\n\n// Writes a replacement character token and records a parse error.\n// Always returns RETURN_ERROR, per gumbo_lex return value.\nstatic StateResult emit_replacement_char(\n    GumboParser* parser, GumboToken* output) {\n  // In all cases, this is because of a null byte in the input stream.\n  add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n  emit_char(parser, kUtf8ReplacementChar, output);\n  return RETURN_ERROR;\n}\n\n// Writes an EOF character token.  Always returns RETURN_SUCCESS.\nstatic StateResult emit_eof(GumboParser* parser, GumboToken* output) {\n  emit_char(parser, -1, output);\n  return RETURN_SUCCESS;\n}\n\n// Writes the current input character out as a character token.\n// Always returns RETURN_SUCCESS.\nstatic bool emit_current_char(GumboParser* parser, GumboToken* output) {\n  emit_char(\n      parser, utf8iterator_current(&parser->_tokenizer_state->_input), output);\n  return RETURN_SUCCESS;\n}\n\n// Writes out a doctype token, copying it from the tokenizer state.\nstatic void emit_doctype(GumboParser* parser, GumboToken* output) {\n  output->type = GUMBO_TOKEN_DOCTYPE;\n  output->v.doc_type = parser->_tokenizer_state->_doc_type_state;\n  finish_token(parser, output);\n  doc_type_state_init(parser);\n}\n\n// Debug-only function that explicitly sets the attribute vector data to NULL so\n// it can be asserted on tag creation, verifying that there are no memory leaks.\nstatic void mark_tag_state_as_empty(GumboTagState* tag_state) {\n#ifndef NDEBUG\n  tag_state->_attributes = kGumboEmptyVector;\n#endif\n}\n\n// Writes out the current tag as a start or end tag token.\n// Always returns RETURN_SUCCESS.\nstatic StateResult emit_current_tag(GumboParser* parser, GumboToken* output) {\n  GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state;\n  if (tag_state->_is_start_tag) {\n    output->type = GUMBO_TOKEN_START_TAG;\n    output->v.start_tag.tag = tag_state->_tag;\n    output->v.start_tag.attributes = tag_state->_attributes;\n    output->v.start_tag.is_self_closing = tag_state->_is_self_closing;\n    tag_state->_last_start_tag = tag_state->_tag;\n    mark_tag_state_as_empty(tag_state);\n    gumbo_debug(\"Emitted start tag %s.\\n\",\n               gumbo_normalized_tagname(tag_state->_tag));\n  } else {\n    output->type = GUMBO_TOKEN_END_TAG;\n    output->v.end_tag = tag_state->_tag;\n    // In end tags, ownership of the attributes vector is not transferred to the\n    // token, but it's still initialized as normal, so it must be manually\n    // deallocated.  There may also be attributes to destroy, in certain broken\n    // cases like </div</th> (the \"th\" is an attribute there).\n    for (int i = 0; i < tag_state->_attributes.length; ++i) {\n      gumbo_destroy_attribute(parser, tag_state->_attributes.data[i]);\n    }\n    gumbo_parser_deallocate(parser, tag_state->_attributes.data);\n    mark_tag_state_as_empty(tag_state);\n    gumbo_debug(\"Emitted end tag %s.\\n\",\n               gumbo_normalized_tagname(tag_state->_tag));\n  }\n  gumbo_string_buffer_destroy(parser, &tag_state->_buffer);\n  finish_token(parser, output);\n  gumbo_debug(\"Original text = %.*s.\\n\", output->original_text.length, output->original_text.data);\n  assert(output->original_text.length >= 2);\n  assert(output->original_text.data[0] == '<');\n  assert(output->original_text.data[output->original_text.length - 1] == '>');\n  return RETURN_SUCCESS;\n}\n\n// In some states, we speculatively start a tag, but don't know whether it'll be\n// emitted as tag token or as a series of character tokens until we finish it.\n// We need to abandon the tag we'd started & free its memory in that case to\n// avoid a memory leak.\nstatic void abandon_current_tag(GumboParser* parser) {\n  GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state;\n  for (int i = 0; i < tag_state->_attributes.length; ++i) {\n    gumbo_destroy_attribute(parser, tag_state->_attributes.data[i]);\n  }\n  gumbo_parser_deallocate(parser, tag_state->_attributes.data);\n  mark_tag_state_as_empty(tag_state);\n  gumbo_string_buffer_destroy(parser, &tag_state->_buffer);\n  gumbo_debug(\"Abandoning current tag.\\n\");\n}\n\n// Wraps the consume_char_ref function to handle its output and make the\n// appropriate TokenizerState modifications.  Returns RETURN_ERROR if a parse\n// error occurred, RETURN_SUCCESS otherwise.\nstatic StateResult emit_char_ref(\n    GumboParser* parser, int additional_allowed_char,\n    bool is_in_attribute, GumboToken* output) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  OneOrTwoCodepoints char_ref;\n  bool status = consume_char_ref(\n      parser, &tokenizer->_input, additional_allowed_char, false, &char_ref);\n  if (char_ref.first != kGumboNoChar) {\n    // consume_char_ref ends with the iterator pointing at the next character,\n    // so we need to be sure not advance it again before reading the next token.\n    tokenizer->_reconsume_current_input = true;\n    emit_char(parser, char_ref.first, output);\n    tokenizer->_buffered_emit_char = char_ref.second;\n  } else {\n    emit_char(parser, '&', output);\n  }\n  return status ? RETURN_SUCCESS : RETURN_ERROR;\n}\n\n// Emits a comment token.  Comments use the temporary buffer to accumulate their\n// data, and then it's copied over and released to the 'text' field of the\n// GumboToken union.  Always returns RETURN_SUCCESS.\nstatic StateResult emit_comment(GumboParser* parser, GumboToken* output) {\n  output->type = GUMBO_TOKEN_COMMENT;\n  finish_temporary_buffer(parser, &output->v.text);\n  finish_token(parser, output);\n  return RETURN_SUCCESS;\n}\n\n// Checks to see we should be flushing accumulated characters in the temporary\n// buffer, and fills the output token with the next output character if so.\n// Returns true if a character has been emitted and the tokenizer should\n// immediately return, false if we're at the end of the temporary buffer and\n// should resume normal operation.\nstatic bool maybe_emit_from_temporary_buffer(\n    GumboParser* parser, GumboToken* output) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  const char* c = tokenizer->_temporary_buffer_emit;\n  GumboStringBuffer* buffer = &tokenizer->_temporary_buffer;\n\n  if (!c || c >= buffer->data + buffer->length) {\n    tokenizer->_temporary_buffer_emit = NULL;\n    return false;\n  }\n\n  assert(*c == utf8iterator_current(&tokenizer->_input));\n  // emit_char also advances the input stream.  We need to do some juggling of\n  // the _reconsume_current_input flag to get the proper behavior when emitting\n  // previous tokens.  Basically, _reconsume_current_input should *never* be set\n  // when emitting anything from the temporary buffer, since those characters\n  // have already been advanced past.  However, it should be preserved so that\n  // when the *next* character is encountered again, the tokenizer knows not to\n  // advance past it.\n  bool saved_reconsume_state = tokenizer->_reconsume_current_input;\n  tokenizer->_reconsume_current_input = false;\n  emit_char(parser, *c, output);\n  ++tokenizer->_temporary_buffer_emit;\n  tokenizer->_reconsume_current_input = saved_reconsume_state;\n  return true;\n}\n\n// Sets up the tokenizer to begin flushing the temporary buffer.\n// This resets the input iterator stream to the start of the last tag, sets up\n// _temporary_buffer_emit, and then (if the temporary buffer is non-empty) emits\n// the first character in it.  It returns true if a character was emitted, false\n// otherwise.\nstatic bool emit_temporary_buffer(\n    GumboParser* parser, GumboToken* output) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  assert(tokenizer->_temporary_buffer.data);\n  utf8iterator_reset(&tokenizer->_input);\n  tokenizer->_temporary_buffer_emit = tokenizer->_temporary_buffer.data;\n  return maybe_emit_from_temporary_buffer(parser, output);\n}\n\n// Appends a codepoint to the current tag buffer.  If\n// reinitilize_position_on_first is set, this also initializes the tag buffer\n// start point; the only time you would *not* want to pass true for this\n// parameter is if you want the original_text to include character (like an\n// opening quote) that doesn't appear in the value.\nstatic void append_char_to_tag_buffer(GumboParser* parser, int codepoint,\n                                      bool reinitilize_position_on_first) {\n  GumboStringBuffer* buffer = &parser->_tokenizer_state->_tag_state._buffer;\n  if (buffer->length == 0 && reinitilize_position_on_first) {\n    reset_tag_buffer_start_point(parser);\n  }\n  gumbo_string_buffer_append_codepoint(parser, codepoint, buffer);\n}\n\n// (Re-)initialize the tag buffer.  This also resets the original_text pointer\n// and _start_pos field to point to the current position.\nstatic void initialize_tag_buffer(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n\n  gumbo_string_buffer_init(parser, &tag_state->_buffer);\n  reset_tag_buffer_start_point(parser);\n}\n\n// Initializes the tag_state to start a new tag, keeping track of the opening\n// positions and original text.  Takes a boolean indicating whether this is a\n// start or end tag.\nstatic void start_new_tag(GumboParser* parser, bool is_start_tag) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n  int c = utf8iterator_current(&tokenizer->_input);\n  assert(is_alpha(c));\n  c = ensure_lowercase(c);\n  assert(is_alpha(c));\n\n  initialize_tag_buffer(parser);\n  gumbo_string_buffer_append_codepoint(parser, c, &tag_state->_buffer);\n\n  assert(tag_state->_attributes.data == NULL);\n  gumbo_vector_init(parser, 4, &tag_state->_attributes);\n  tag_state->_drop_next_attr_value = false;\n  tag_state->_is_start_tag = is_start_tag;\n  tag_state->_is_self_closing = false;\n  gumbo_debug(\"Starting new tag.\\n\");\n}\n\n// Fills in the specified char* with the contents of the tag buffer.\nstatic void copy_over_tag_buffer(GumboParser* parser, const char** output) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n  *output = gumbo_string_buffer_to_string(parser, &tag_state->_buffer);\n}\n\n// Fills in:\n// * The original_text GumboStringPiece with the portion of the original\n// buffer that corresponds to the tag buffer.\n// * The start_pos GumboSourcePosition with the start position of the tag\n// buffer.\n// * The end_pos GumboSourcePosition with the current source position.\nstatic void copy_over_original_tag_text(\n    GumboParser* parser, GumboStringPiece* original_text,\n    GumboSourcePosition* start_pos, GumboSourcePosition* end_pos) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n\n  original_text->data = tag_state->_original_text;\n  original_text->length =\n      utf8iterator_get_char_pointer(&tokenizer->_input) -\n      tag_state->_original_text;\n  if (original_text->data[original_text->length - 1] == '\\r') {\n    // Since \\r is skipped by the UTF-8 iterator, it can sometimes end up\n    // appended to the end of original text even when it's really the first part\n    // of the next character.  If we detect this situation, shrink the length of\n    // the original text by 1 to remove the carriage return.\n    --original_text->length;\n  }\n  *start_pos = tag_state->_start_pos;\n  utf8iterator_get_position(&tokenizer->_input, end_pos);\n}\n\n// Releases and then re-initializes the tag buffer.\nstatic void reinitialize_tag_buffer(GumboParser* parser) {\n  gumbo_parser_deallocate(\n      parser, parser->_tokenizer_state->_tag_state._buffer.data);\n  initialize_tag_buffer(parser);\n}\n\n// Moves some data from the temporary buffer over the the tag-based fields in\n// TagState.\nstatic void finish_tag_name(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n\n  const char* temp;\n  copy_over_tag_buffer(parser, &temp);\n  tag_state->_tag = gumbo_tag_enum(temp);\n  reinitialize_tag_buffer(parser);\n  gumbo_parser_deallocate(parser, (void*) temp);\n}\n\n// Adds an ERR_DUPLICATE_ATTR parse error to the parser's error struct.\nstatic void add_duplicate_attr_error(GumboParser* parser, const char* attr_name,\n                                     int original_index, int new_index) {\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state;\n  error->type = GUMBO_ERR_DUPLICATE_ATTR;\n  error->position = tag_state->_start_pos;\n  error->original_text = tag_state->_original_text;\n  error->v.duplicate_attr.original_index = original_index;\n  error->v.duplicate_attr.new_index = new_index;\n  copy_over_tag_buffer(parser, &error->v.duplicate_attr.name);\n  reinitialize_tag_buffer(parser);\n}\n\n// Creates a new attribute in the current tag, copying the current tag buffer to\n// the attribute's name.  The attribute's value starts out as the empty string\n// (following the \"Boolean attributes\" section of the spec) and is only\n// overwritten on finish_attribute_value().  If the attribute has already been\n// specified, the new attribute is dropped, a parse error is added, and the\n// function returns false.  Otherwise, this returns true.\nstatic bool finish_attribute_name(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  GumboTagState* tag_state = &tokenizer->_tag_state;\n  // May've been set by a previous attribute without a value; reset it here.\n  tag_state->_drop_next_attr_value = false;\n  assert(tag_state->_attributes.data);\n  assert(tag_state->_attributes.capacity);\n\n  GumboVector* /* GumboAttribute* */ attributes = &tag_state->_attributes;\n  for (int i = 0; i < attributes->length; ++i) {\n    GumboAttribute* attr = attributes->data[i];\n    if (strlen(attr->name) == tag_state->_buffer.length &&\n        memcmp(attr->name, tag_state->_buffer.data,\n               tag_state->_buffer.length) == 0) {\n      // Identical attribute; bail.\n      add_duplicate_attr_error(\n          parser, attr->name, i, attributes->length);\n      tag_state->_drop_next_attr_value = true;\n      return false;\n    }\n  }\n\n  GumboAttribute* attr = gumbo_parser_allocate(parser, sizeof(GumboAttribute));\n  attr->attr_namespace = GUMBO_ATTR_NAMESPACE_NONE;\n  copy_over_tag_buffer(parser, &attr->name);\n  copy_over_original_tag_text(parser, &attr->original_name,\n                              &attr->name_start, &attr->name_end);\n  attr->value = gumbo_copy_stringz(parser, \"\");\n  copy_over_original_tag_text(parser, &attr->original_value,\n                              &attr->name_start, &attr->name_end);\n  gumbo_vector_add(parser, attr, attributes);\n  reinitialize_tag_buffer(parser);\n  return true;\n}\n\n// Finishes an attribute value.  This sets the value of the most recently added\n// attribute to the current contents of the tag buffer.\nstatic void finish_attribute_value(GumboParser* parser) {\n  GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state;\n  if (tag_state->_drop_next_attr_value) {\n    // Duplicate attribute name detected in an earlier state, so we have to\n    // ignore the value.\n    tag_state->_drop_next_attr_value = false;\n    return;\n  }\n\n  GumboAttribute* attr =\n      tag_state->_attributes.data[tag_state->_attributes.length - 1];\n  gumbo_parser_deallocate(parser, (void*) attr->value);\n  copy_over_tag_buffer(parser, &attr->value);\n  copy_over_original_tag_text(parser, &attr->original_value,\n                              &attr->value_start, &attr->value_end);\n  reinitialize_tag_buffer(parser);\n}\n\n// Returns true if the current end tag matches the last start tag emitted.\nstatic bool is_appropriate_end_tag(GumboParser* parser) {\n  GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state;\n  assert(!tag_state->_is_start_tag);\n  // Null terminate the current string buffer, so it can be passed to\n  // gumbo_tag_enum, but don't increment the length in case we need to dump the\n  // buffer as character tokens.\n  gumbo_string_buffer_append_codepoint(parser, '\\0', &tag_state->_buffer);\n  --tag_state->_buffer.length;\n  return tag_state->_last_start_tag != GUMBO_TAG_LAST &&\n      tag_state->_last_start_tag == gumbo_tag_enum(tag_state->_buffer.data);\n}\n\nvoid gumbo_tokenizer_state_init(\n    GumboParser* parser, const char* text, size_t text_length) {\n  GumboTokenizerState* tokenizer =\n      gumbo_parser_allocate(parser, sizeof(GumboTokenizerState));\n  parser->_tokenizer_state = tokenizer;\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n  tokenizer->_reconsume_current_input = false;\n  tokenizer->_is_current_node_foreign = false;\n  tokenizer->_tag_state._last_start_tag = GUMBO_TAG_LAST;\n\n  tokenizer->_buffered_emit_char = kGumboNoChar;\n  gumbo_string_buffer_init(parser, &tokenizer->_temporary_buffer);\n  tokenizer->_temporary_buffer_emit = NULL;\n\n  mark_tag_state_as_empty(&tokenizer->_tag_state);\n\n  gumbo_string_buffer_init(parser, &tokenizer->_script_data_buffer);\n  tokenizer->_token_start = text;\n  utf8iterator_init(parser, text, text_length, &tokenizer->_input);\n  utf8iterator_get_position(&tokenizer->_input, &tokenizer->_token_start_pos);\n  doc_type_state_init(parser);\n}\n\nvoid gumbo_tokenizer_state_destroy(GumboParser* parser) {\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n  assert(tokenizer->_doc_type_state.name == NULL);\n  assert(tokenizer->_doc_type_state.public_identifier == NULL);\n  assert(tokenizer->_doc_type_state.system_identifier == NULL);\n  gumbo_string_buffer_destroy(parser, &tokenizer->_temporary_buffer);\n  gumbo_string_buffer_destroy(parser, &tokenizer->_script_data_buffer);\n  gumbo_parser_deallocate(parser, tokenizer);\n}\n\nvoid gumbo_tokenizer_set_state(GumboParser* parser, GumboTokenizerEnum state) {\n  parser->_tokenizer_state->_state = state;\n}\n\nvoid gumbo_tokenizer_set_is_current_node_foreign(\n    GumboParser* parser, bool is_foreign) {\n  if (is_foreign != parser->_tokenizer_state->_is_current_node_foreign) {\n    gumbo_debug(\"Toggling is_current_node_foreign to %s.\\n\",\n                is_foreign ? \"true\" : \"false\");\n  }\n  parser->_tokenizer_state->_is_current_node_foreign = is_foreign;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#data-state\nstatic StateResult handle_data_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '&':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_DATA);\n      // The char_ref machinery expects to be on the & so it can mark that\n      // and return to it if the text isn't a char ref, so we need to\n      // reconsume it.\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_OPEN);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, '<');\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      emit_char(parser, c, output);\n      return RETURN_ERROR;\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-data-state\nstatic StateResult handle_char_ref_in_data_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n  return emit_char_ref(parser, ' ', false, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rcdata-state\nstatic StateResult handle_rcdata_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '&':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_RCDATA);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, '<');\n      return NEXT_CHAR;\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      return emit_eof(parser, output);\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-rcdata-state\nstatic StateResult handle_char_ref_in_rcdata_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA);\n  return emit_char_ref(parser, ' ', false, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-state\nstatic StateResult handle_rawtext_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, '<');\n      return NEXT_CHAR;\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      return emit_eof(parser, output);\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-state\nstatic StateResult handle_script_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, '<');\n      return NEXT_CHAR;\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      return emit_eof(parser, output);\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#plaintext-state\nstatic StateResult handle_plaintext_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      return emit_eof(parser, output);\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#tag-open-state\nstatic StateResult handle_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"<\"));\n  switch (c) {\n    case '!':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_MARKUP_DECLARATION);\n      clear_temporary_buffer(parser);\n      return NEXT_CHAR;\n    case '/':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_END_TAG_OPEN);\n      append_char_to_temporary_buffer(parser, '/');\n      return NEXT_CHAR;\n    case '?':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, '?');\n      add_parse_error(parser, GUMBO_ERR_TAG_STARTS_WITH_QUESTION);\n      return NEXT_CHAR;\n    default:\n      if (is_alpha(c)) {\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_NAME);\n        start_new_tag(parser, true);\n        return NEXT_CHAR;\n      } else {\n        add_parse_error(parser, GUMBO_ERR_TAG_INVALID);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n        emit_temporary_buffer(parser, output);\n        return RETURN_ERROR;\n      }\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#end-tag-open-state\nstatic StateResult handle_end_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"</\"));\n  switch (c) {\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_EMPTY);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_temporary_buffer(parser, output);\n    default:\n      if (is_alpha(c)) {\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_NAME);\n        start_new_tag(parser, false);\n      } else {\n        add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_INVALID);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT);\n        clear_temporary_buffer(parser);\n        append_char_to_temporary_buffer(parser, c);\n      }\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#tag-name-state\nstatic StateResult handle_tag_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      finish_tag_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n      return NEXT_CHAR;\n    case '/':\n      finish_tag_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n      return NEXT_CHAR;\n    case '>':\n      finish_tag_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_current_tag(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_TAG_EOF);\n      abandon_current_tag(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-less-than-sign-state\nstatic StateResult handle_rcdata_lt_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"<\"));\n  if (c == '/') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_END_TAG_OPEN);\n    append_char_to_temporary_buffer(parser, '/');\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA);\n    tokenizer->_reconsume_current_input = true;\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-end-tag-open-state\nstatic StateResult handle_rcdata_end_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"</\"));\n  if (is_alpha(c)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_END_TAG_NAME);\n    start_new_tag(parser, false);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA);\n    return emit_temporary_buffer(parser, output);\n  }\n  return true;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-end-tag-name-state\nstatic StateResult handle_rcdata_end_tag_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(tokenizer->_temporary_buffer.length >= 2);\n  if (is_alpha(c)) {\n    append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else if (is_appropriate_end_tag(parser)) {\n    switch (c) {\n      case '\\t':\n      case '\\n':\n      case '\\f':\n      case ' ':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n        return NEXT_CHAR;\n      case '/':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n        return NEXT_CHAR;\n      case '>':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n        return emit_current_tag(parser, output);\n    }\n  }\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA);\n  abandon_current_tag(parser);\n  return emit_temporary_buffer(parser, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-less-than-sign-state\nstatic StateResult handle_rawtext_lt_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"<\"));\n  if (c == '/') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_END_TAG_OPEN);\n    append_char_to_temporary_buffer(parser, '/');\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT);\n    tokenizer->_reconsume_current_input = true;\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-end-tag-open-state\nstatic StateResult handle_rawtext_end_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"</\"));\n  if (is_alpha(c)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_END_TAG_NAME);\n    start_new_tag(parser, false);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT);\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-end-tag-name-state\nstatic StateResult handle_rawtext_end_tag_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(tokenizer->_temporary_buffer.length >= 2);\n  gumbo_debug(\"Last end tag: %*s\\n\", (int) tokenizer->_tag_state._buffer.length,\n             tokenizer->_tag_state._buffer.data);\n  if (is_alpha(c)) {\n    append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else if (is_appropriate_end_tag(parser)) {\n    gumbo_debug(\"Is an appropriate end tag.\\n\");\n    switch (c) {\n      case '\\t':\n      case '\\n':\n      case '\\f':\n      case ' ':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n        return NEXT_CHAR;\n      case '/':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n        return NEXT_CHAR;\n      case '>':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n        return emit_current_tag(parser, output);\n    }\n  }\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT);\n  abandon_current_tag(parser);\n  return emit_temporary_buffer(parser, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-less-than-sign-state\nstatic StateResult handle_script_lt_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"<\"));\n  if (c == '/') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_END_TAG_OPEN);\n    append_char_to_temporary_buffer(parser, '/');\n    return NEXT_CHAR;\n  } else if (c == '!') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_START);\n    append_char_to_temporary_buffer(parser, '!');\n    return emit_temporary_buffer(parser, output);\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n    tokenizer->_reconsume_current_input = true;\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-end-tag-open-state\nstatic StateResult handle_script_end_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"</\"));\n  if (is_alpha(c)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_END_TAG_NAME);\n    start_new_tag(parser, false);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-end-tag-name-state\nstatic StateResult handle_script_end_tag_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(tokenizer->_temporary_buffer.length >= 2);\n  if (is_alpha(c)) {\n    append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else if (is_appropriate_end_tag(parser)) {\n    switch (c) {\n      case '\\t':\n      case '\\n':\n      case '\\f':\n      case ' ':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n        return NEXT_CHAR;\n      case '/':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n        return NEXT_CHAR;\n      case '>':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n        return emit_current_tag(parser, output);\n    }\n  }\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n  abandon_current_tag(parser);\n  return emit_temporary_buffer(parser, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escape-start-state\nstatic StateResult handle_script_escaped_start_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (c == '-') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_START_DASH);\n    return emit_current_char(parser, output);\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n    tokenizer->_reconsume_current_input = true;\n    return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escape-start-dash-state\nstatic StateResult handle_script_escaped_start_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (c == '-') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH);\n    return emit_current_char(parser, output);\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n    tokenizer->_reconsume_current_input = true;\n    return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-state\nstatic StateResult handle_script_escaped_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH);\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      return emit_eof(parser, output);\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-dash-state\nstatic StateResult handle_script_escaped_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH);\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n    case '\\0':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-dash-dash-state\nstatic StateResult handle_script_escaped_dash_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT);\n      clear_temporary_buffer(parser);\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n      return emit_current_char(parser, output);\n    case '\\0':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-less-than-sign-state\nstatic StateResult handle_script_escaped_lt_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"<\"));\n  assert(!tokenizer->_script_data_buffer.length);\n  if (c == '/') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else if (is_alpha(c)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START);\n    append_char_to_temporary_buffer(parser, c);\n    gumbo_string_buffer_append_codepoint(\n        parser, ensure_lowercase(c), &tokenizer->_script_data_buffer);\n    return emit_temporary_buffer(parser, output);\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-end-tag-open-state\nstatic StateResult handle_script_escaped_end_tag_open_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(temporary_buffer_equals(parser, \"</\"));\n  if (is_alpha(c)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME);\n    start_new_tag(parser, false);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n    return emit_temporary_buffer(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-end-tag-name-state\nstatic StateResult handle_script_escaped_end_tag_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(tokenizer->_temporary_buffer.length >= 2);\n  if (is_alpha(c)) {\n    append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n    append_char_to_temporary_buffer(parser, c);\n    return NEXT_CHAR;\n  } else if (is_appropriate_end_tag(parser)) {\n    switch (c) {\n      case '\\t':\n      case '\\n':\n      case '\\f':\n      case ' ':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n        return NEXT_CHAR;\n      case '/':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n        return NEXT_CHAR;\n      case '>':\n        finish_tag_name(parser);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n        return emit_current_tag(parser, output);\n    }\n  }\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n  abandon_current_tag(parser);\n  return emit_temporary_buffer(parser, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escape-start-state\nstatic StateResult handle_script_double_escaped_start_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n    case '/':\n    case '>':\n      gumbo_tokenizer_set_state(parser, gumbo_string_equals(\n          &kScriptTag, (GumboStringPiece*) &tokenizer->_script_data_buffer)\n          ? GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED : GUMBO_LEX_SCRIPT_ESCAPED);\n      return emit_current_char(parser, output);\n    default:\n      if (is_alpha(c)) {\n        gumbo_string_buffer_append_codepoint(\n            parser, ensure_lowercase(c), &tokenizer->_script_data_buffer);\n        return emit_current_char(parser, output);\n      } else {\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED);\n        tokenizer->_reconsume_current_input = true;\n        return NEXT_CHAR;\n      }\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-state\nstatic StateResult handle_script_double_escaped_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH);\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT);\n      return emit_current_char(parser, output);\n    case '\\0':\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-dash-state\nstatic StateResult handle_script_double_escaped_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH);\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT);\n      return emit_current_char(parser, output);\n    case '\\0':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-dash-dash-state\nstatic StateResult handle_script_double_escaped_dash_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      return emit_current_char(parser, output);\n    case '<':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT);\n      return emit_current_char(parser, output);\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT);\n      return emit_current_char(parser, output);\n    case '\\0':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n      return emit_replacement_char(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return NEXT_CHAR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n      return emit_current_char(parser, output);\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-less-than-sign-state\nstatic StateResult handle_script_double_escaped_lt_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (c == '/') {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END);\n    gumbo_string_buffer_destroy(parser, &tokenizer->_script_data_buffer);\n    gumbo_string_buffer_init(parser, &tokenizer->_script_data_buffer);\n    return emit_current_char(parser, output);\n  } else {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n    tokenizer->_reconsume_current_input = true;\n    return NEXT_CHAR;\n  }\n\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escape-end-state\nstatic StateResult handle_script_double_escaped_end_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n    case '/':\n    case '>':\n      gumbo_tokenizer_set_state(parser, gumbo_string_equals(\n          &kScriptTag, (GumboStringPiece*) &tokenizer->_script_data_buffer)\n          ? GUMBO_LEX_SCRIPT_ESCAPED : GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n      return emit_current_char(parser, output);\n    default:\n      if (is_alpha(c)) {\n        gumbo_string_buffer_append_codepoint(\n            parser, ensure_lowercase(c), &tokenizer->_script_data_buffer);\n        return emit_current_char(parser, output);\n      } else {\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED);\n        tokenizer->_reconsume_current_input = true;\n        return NEXT_CHAR;\n      }\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-attribute-name-state\nstatic StateResult handle_before_attr_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '/':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_current_tag(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME);\n      append_char_to_temporary_buffer(parser, 0xfffd);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      return NEXT_CHAR;\n    case '\"':\n    case '\\'':\n    case '<':\n    case '=':\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID);\n      // Fall through.\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME);\n      append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-name-state\nstatic StateResult handle_attr_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      finish_attribute_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_NAME);\n      return NEXT_CHAR;\n    case '/':\n      finish_attribute_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n      return NEXT_CHAR;\n    case '=':\n      finish_attribute_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_VALUE);\n      return NEXT_CHAR;\n    case '>':\n      finish_attribute_name(parser);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_current_tag(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true);\n      return NEXT_CHAR;\n    case -1:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF);\n      return NEXT_CHAR;\n    case '\"':\n    case '\\'':\n    case '<':\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID);\n      // Fall through.\n    default:\n      append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#after-attribute-name-state\nstatic StateResult handle_after_attr_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '/':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n      return NEXT_CHAR;\n    case '=':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_VALUE);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_current_tag(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME);\n      append_char_to_temporary_buffer(parser, 0xfffd);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      return NEXT_CHAR;\n    case '\"':\n    case '\\'':\n    case '<':\n      add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID);\n      // Fall through.\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME);\n      append_char_to_tag_buffer(parser, ensure_lowercase(c), true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-attribute-value-state\nstatic StateResult handle_before_attr_value_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '\"':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED);\n      reset_tag_buffer_start_point(parser);\n      return NEXT_CHAR;\n    case '&':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '\\'':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED);\n      reset_tag_buffer_start_point(parser);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_RIGHT_BRACKET);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_current_tag(parser, output);\n      return RETURN_ERROR;\n    case '<':\n    case '=':\n    case '`':\n      add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EQUALS);\n      // Fall through.\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED);\n      append_char_to_tag_buffer(parser, c, true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-double-quoted-state\nstatic StateResult handle_attr_value_double_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\"':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED);\n      return NEXT_CHAR;\n    case '&':\n      tokenizer->_tag_state._attr_value_state = tokenizer->_state;\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, false);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_DOUBLE_QUOTE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    default:\n      append_char_to_tag_buffer(parser, c, false);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-single-quoted-state\nstatic StateResult handle_attr_value_single_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\'':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED);\n      return NEXT_CHAR;\n    case '&':\n      tokenizer->_tag_state._attr_value_state = tokenizer->_state;\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, false);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_SINGLE_QUOTE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    default:\n      append_char_to_tag_buffer(parser, c, false);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-unquoted-state\nstatic StateResult handle_attr_value_unquoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n      finish_attribute_value(parser);\n      return NEXT_CHAR;\n    case '&':\n      tokenizer->_tag_state._attr_value_state = tokenizer->_state;\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      finish_attribute_value(parser);\n      return emit_current_tag(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_reconsume_current_input = true;\n      abandon_current_tag(parser);\n      return NEXT_CHAR;\n    case '<':\n    case '=':\n    case '\"':\n    case '\\'':\n    case '`':\n      add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EQUALS);\n      // Fall through.\n    default:\n      append_char_to_tag_buffer(parser, c, true);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-attribute-value-state\nstatic StateResult handle_char_ref_in_attr_value_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  OneOrTwoCodepoints char_ref;\n  int allowed_char;\n  bool is_unquoted = false;\n  switch (tokenizer->_tag_state._attr_value_state) {\n    case GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED:\n      allowed_char = '\"';\n      break;\n    case GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED:\n      allowed_char = '\\'';\n      break;\n    case GUMBO_LEX_ATTR_VALUE_UNQUOTED:\n      allowed_char = '>';\n      is_unquoted = true;\n      break;\n    default:\n      // -Wmaybe-uninitialized is a little overzealous here, and doesn't\n      // get that the assert(0) means this codepath will never happen.\n      allowed_char = ' ';\n      assert(0);\n  }\n\n  // Ignore the status, since we don't have a convenient way of signalling that\n  // a parser error has occurred when the error occurs in the middle of a\n  // multi-state token.  We'd need a flag inside the TokenizerState to do this,\n  // but that's a low priority fix.\n  consume_char_ref(parser, &tokenizer->_input, allowed_char, true, &char_ref);\n  if (char_ref.first != kGumboNoChar) {\n    tokenizer->_reconsume_current_input = true;\n    append_char_to_tag_buffer(parser, char_ref.first, is_unquoted);\n    if (char_ref.second != kGumboNoChar) {\n      append_char_to_tag_buffer(parser, char_ref.second, is_unquoted);\n    }\n  } else {\n    append_char_to_tag_buffer(parser, '&', is_unquoted);\n  }\n  gumbo_tokenizer_set_state(parser, tokenizer->_tag_state._attr_value_state);\n  return NEXT_CHAR;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#after-attribute-value-quoted-state\nstatic StateResult handle_after_attr_value_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  finish_attribute_value(parser);\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n      return NEXT_CHAR;\n    case '/':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_current_tag(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_ATTR_AFTER_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_ATTR_AFTER_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#self-closing-start-tag-state\nstatic StateResult handle_self_closing_start_tag_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_tag_state._is_self_closing = true;\n      return emit_current_tag(parser, output);\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_SOLIDUS_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      abandon_current_tag(parser);\n      return NEXT_CHAR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_SOLIDUS_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME);\n      tokenizer->_reconsume_current_input = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#bogus-comment-state\nstatic StateResult handle_bogus_comment_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  while (c != '>' && c != -1) {\n    if (c == '\\0') {\n      c = 0xFFFD;\n    }\n    append_char_to_temporary_buffer(parser, c);\n    utf8iterator_next(&tokenizer->_input);\n    c = utf8iterator_current(&tokenizer->_input);\n  }\n  gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n  return emit_comment(parser, output);\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#markup-declaration-open-state\nstatic StateResult handle_markup_declaration_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (utf8iterator_maybe_consume_match(\n      &tokenizer->_input, \"--\", sizeof(\"--\") - 1, true)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_START);\n    tokenizer->_reconsume_current_input = true;\n  } else if (utf8iterator_maybe_consume_match(\n      &tokenizer->_input, \"DOCTYPE\", sizeof(\"DOCTYPE\") - 1, false)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE);\n    tokenizer->_reconsume_current_input = true;\n    // If we get here, we know we'll eventually emit a doctype token, so now is\n    // the time to initialize the doctype strings.  (Not in doctype_state_init,\n    // since then they'll leak if ownership never gets transferred to the\n    // doctype token.\n    tokenizer->_doc_type_state.name = gumbo_copy_stringz(parser, \"\");\n    tokenizer->_doc_type_state.public_identifier =\n        gumbo_copy_stringz(parser, \"\");\n    tokenizer->_doc_type_state.system_identifier =\n        gumbo_copy_stringz(parser, \"\");\n  } else if (tokenizer->_is_current_node_foreign &&\n             utf8iterator_maybe_consume_match(\n                &tokenizer->_input, \"[CDATA[\", sizeof(\"[CDATA[\") - 1, true)) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_CDATA);\n    tokenizer->_reconsume_current_input = true;\n  } else {\n    add_parse_error(parser, GUMBO_ERR_DASHES_OR_DOCTYPE);\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT);\n    tokenizer->_reconsume_current_input = true;\n    clear_temporary_buffer(parser);\n  }\n  return NEXT_CHAR;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-start-state\nstatic StateResult handle_comment_start_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_START_DASH);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-start-dash-state\nstatic StateResult handle_comment_start_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-state\nstatic StateResult handle_comment_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_DASH);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-dash-state\nstatic StateResult handle_comment_end_dash_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-state\nstatic StateResult handle_comment_end_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_comment(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '!':\n      add_parse_error(parser, GUMBO_ERR_COMMENT_BANG_AFTER_DOUBLE_DASH);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_BANG);\n      return NEXT_CHAR;\n    case '-':\n      add_parse_error(parser, GUMBO_ERR_COMMENT_DASH_AFTER_DOUBLE_DASH);\n      append_char_to_temporary_buffer(parser, '-');\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-bang-state\nstatic StateResult handle_comment_end_bang_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '-':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_DASH);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '!');\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      return emit_comment(parser, output);\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '!');\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_COMMENT_END_BANG_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_comment(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT);\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '-');\n      append_char_to_temporary_buffer(parser, '!');\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#doctype-state\nstatic StateResult handle_doctype_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  assert(!tokenizer->_temporary_buffer.length);\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_NAME);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_SPACE);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_NAME);\n      tokenizer->_reconsume_current_input = true;\n      tokenizer->_doc_type_state.force_quirks = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-doctype-name-state\nstatic StateResult handle_before_doctype_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME);\n      tokenizer->_doc_type_state.force_quirks = true;\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_RIGHT_BRACKET);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME);\n      tokenizer->_doc_type_state.force_quirks = false;\n      append_char_to_temporary_buffer(parser, ensure_lowercase(c));\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#doctype-name-state\nstatic StateResult handle_doctype_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_NAME);\n      gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name);\n      finish_temporary_buffer(\n          parser, &tokenizer->_doc_type_state.name);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name);\n      finish_temporary_buffer(\n          parser, &tokenizer->_doc_type_state.name);\n      emit_doctype(parser, output);\n      return RETURN_SUCCESS;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name);\n      finish_temporary_buffer(\n          parser, &tokenizer->_doc_type_state.name);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME);\n      tokenizer->_doc_type_state.force_quirks = false;\n      append_char_to_temporary_buffer(parser, ensure_lowercase(c));\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-name-state\nstatic StateResult handle_after_doctype_name_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_doctype(parser, output);\n      return RETURN_SUCCESS;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      if (utf8iterator_maybe_consume_match(\n          &tokenizer->_input, \"PUBLIC\", sizeof(\"PUBLIC\") - 1, false)) {\n        gumbo_tokenizer_set_state(\n            parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD);\n        tokenizer->_reconsume_current_input = true;\n      } else if (utf8iterator_maybe_consume_match(\n          &tokenizer->_input, \"SYSTEM\", sizeof(\"SYSTEM\") - 1, false)) {\n        gumbo_tokenizer_set_state(\n            parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD);\n        tokenizer->_reconsume_current_input = true;\n      } else {\n        add_parse_error(parser, GUMBO_ERR_DOCTYPE_SPACE_OR_RIGHT_BRACKET);\n        gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n        tokenizer->_doc_type_state.force_quirks = true;\n      }\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-public-keyword-state\nstatic StateResult handle_after_doctype_public_keyword_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID);\n      return NEXT_CHAR;\n    case '\"':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_RIGHT_BRACKET);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#before-doctype-public-identifier-state\nstatic StateResult handle_before_doctype_public_id_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '\"':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-public-identifier-(double-quoted)-state\nstatic StateResult handle_doctype_public_id_double_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\"':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID);\n      finish_doctype_public_id(parser);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_public_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_public_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-public-identifier-(single-quoted)-state\nstatic StateResult handle_doctype_public_id_single_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\'':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID);\n      finish_doctype_public_id(parser);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_public_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_public_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-public-identifier-state\nstatic StateResult handle_after_doctype_public_id_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID);\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_doctype(parser, output);\n      return RETURN_SUCCESS;\n    case '\"':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_reconsume_current_input = true;\n      tokenizer->_doc_type_state.force_quirks = true;\n      return NEXT_CHAR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#between-doctype-public-and-system-identifiers-state\nstatic StateResult handle_between_doctype_public_system_id_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_doctype(parser, output);\n      return RETURN_SUCCESS;\n    case '\"':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-system-keyword-state\nstatic StateResult handle_after_doctype_system_keyword_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID);\n      return NEXT_CHAR;\n    case '\"':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#before-doctype-system-identifier-state\nstatic StateResult handle_before_doctype_system_id_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '\"':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED);\n      return NEXT_CHAR;\n    case '\\'':\n      assert(temporary_buffer_equals(parser, \"\"));\n      gumbo_tokenizer_set_state(\n          parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      tokenizer->_doc_type_state.force_quirks = true;\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-system-identifier-(double-quoted)-state\nstatic StateResult handle_doctype_system_id_double_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\"':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID);\n      finish_doctype_system_id(parser);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_system_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_system_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-system-identifier-(single-quoted)-state\nstatic StateResult handle_doctype_system_id_single_quoted_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\'':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID);\n      finish_doctype_system_id(parser);\n      return NEXT_CHAR;\n    case '\\0':\n      add_parse_error(parser, GUMBO_ERR_UTF8_NULL);\n      append_char_to_temporary_buffer(parser, kUtf8ReplacementChar);\n      return NEXT_CHAR;\n    case '>':\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_END);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_system_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      finish_doctype_system_id(parser);\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      append_char_to_temporary_buffer(parser, c);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-system-identifier-state\nstatic StateResult handle_after_doctype_system_id_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  switch (c) {\n    case '\\t':\n    case '\\n':\n    case '\\f':\n    case ' ':\n      return NEXT_CHAR;\n    case '>':\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      emit_doctype(parser, output);\n      return RETURN_SUCCESS;\n    case -1:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n      tokenizer->_doc_type_state.force_quirks = true;\n      emit_doctype(parser, output);\n      return RETURN_ERROR;\n    default:\n      add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID);\n      gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE);\n      return NEXT_CHAR;\n  }\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#bogus-doctype-state\nstatic StateResult handle_bogus_doctype_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (c == '>' || c == -1) {\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n    emit_doctype(parser, output);\n    return RETURN_ERROR;\n  }\n  return NEXT_CHAR;\n}\n\n// http://www.whatwg.org/specs/web-apps/current-work/complete.html#cdata-section-state\nstatic StateResult handle_cdata_state(\n    GumboParser* parser, GumboTokenizerState* tokenizer,\n    int c, GumboToken* output) {\n  if (c == -1 || utf8iterator_maybe_consume_match(\n      &tokenizer->_input, \"]]>\", sizeof(\"]]>\") - 1, true)) {\n    tokenizer->_reconsume_current_input = true;\n    reset_token_start_point(tokenizer);\n    gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA);\n    return NEXT_CHAR;\n  } else {\n    return emit_current_char(parser, output);\n  }\n}\n\ntypedef StateResult (*GumboLexerStateFunction)(\n    GumboParser*, GumboTokenizerState*, int, GumboToken*);\n\nstatic GumboLexerStateFunction dispatch_table[] = {\n  handle_data_state,\n  handle_char_ref_in_data_state,\n  handle_rcdata_state,\n  handle_char_ref_in_rcdata_state,\n  handle_rawtext_state,\n  handle_script_state,\n  handle_plaintext_state,\n  handle_tag_open_state,\n  handle_end_tag_open_state,\n  handle_tag_name_state,\n  handle_rcdata_lt_state,\n  handle_rcdata_end_tag_open_state,\n  handle_rcdata_end_tag_name_state,\n  handle_rawtext_lt_state,\n  handle_rawtext_end_tag_open_state,\n  handle_rawtext_end_tag_name_state,\n  handle_script_lt_state,\n  handle_script_end_tag_open_state,\n  handle_script_end_tag_name_state,\n  handle_script_escaped_start_state,\n  handle_script_escaped_start_dash_state,\n  handle_script_escaped_state,\n  handle_script_escaped_dash_state,\n  handle_script_escaped_dash_dash_state,\n  handle_script_escaped_lt_state,\n  handle_script_escaped_end_tag_open_state,\n  handle_script_escaped_end_tag_name_state,\n  handle_script_double_escaped_start_state,\n  handle_script_double_escaped_state,\n  handle_script_double_escaped_dash_state,\n  handle_script_double_escaped_dash_dash_state,\n  handle_script_double_escaped_lt_state,\n  handle_script_double_escaped_end_state,\n  handle_before_attr_name_state,\n  handle_attr_name_state,\n  handle_after_attr_name_state,\n  handle_before_attr_value_state,\n  handle_attr_value_double_quoted_state,\n  handle_attr_value_single_quoted_state,\n  handle_attr_value_unquoted_state,\n  handle_char_ref_in_attr_value_state,\n  handle_after_attr_value_quoted_state,\n  handle_self_closing_start_tag_state,\n  handle_bogus_comment_state,\n  handle_markup_declaration_state,\n  handle_comment_start_state,\n  handle_comment_start_dash_state,\n  handle_comment_state,\n  handle_comment_end_dash_state,\n  handle_comment_end_state,\n  handle_comment_end_bang_state,\n  handle_doctype_state,\n  handle_before_doctype_name_state,\n  handle_doctype_name_state,\n  handle_after_doctype_name_state,\n  handle_after_doctype_public_keyword_state,\n  handle_before_doctype_public_id_state,\n  handle_doctype_public_id_double_quoted_state,\n  handle_doctype_public_id_single_quoted_state,\n  handle_after_doctype_public_id_state,\n  handle_between_doctype_public_system_id_state,\n  handle_after_doctype_system_keyword_state,\n  handle_before_doctype_system_id_state,\n  handle_doctype_system_id_double_quoted_state,\n  handle_doctype_system_id_single_quoted_state,\n  handle_after_doctype_system_id_state,\n  handle_bogus_doctype_state,\n  handle_cdata_state\n};\n\nbool gumbo_lex(GumboParser* parser, GumboToken* output) {\n  // Because of the spec requirements that...\n  //\n  // 1. Tokens be handled immediately by the parser upon emission.\n  // 2. Some states (eg. CDATA, or various error conditions) require the\n  // emission of multiple tokens in the same states.\n  // 3. The tokenizer often has to reconsume the same character in a different\n  // state.\n  //\n  // ...all state must be held in the GumboTokenizer struct instead of in local\n  // variables in this function.  That allows us to return from this method with\n  // a token, and then immediately jump back to the same state with the same\n  // input if we need to return a different token.  The various emit_* functions\n  // are responsible for changing state (eg. flushing the chardata buffer,\n  // reading the next input character) to avoid an infinite loop.\n  GumboTokenizerState* tokenizer = parser->_tokenizer_state;\n\n  if (tokenizer->_buffered_emit_char != kGumboNoChar) {\n    tokenizer->_reconsume_current_input = true;\n    emit_char(parser, tokenizer->_buffered_emit_char, output);\n    // And now that we've avoided advancing the input, make sure we set\n    // _reconsume_current_input back to false to make sure the *next* character\n    // isn't consumed twice.\n    tokenizer->_reconsume_current_input = false;\n    tokenizer->_buffered_emit_char = kGumboNoChar;\n    return true;\n  }\n\n  if (maybe_emit_from_temporary_buffer(parser, output)) {\n    return true;\n  }\n\n  while (1) {\n    assert(!tokenizer->_temporary_buffer_emit);\n    assert(tokenizer->_buffered_emit_char == kGumboNoChar);\n    int c = utf8iterator_current(&tokenizer->_input);\n    gumbo_debug(\"Lexing character '%c' in state %d.\\n\", c, tokenizer->_state);\n    StateResult result =\n        dispatch_table[tokenizer->_state](parser, tokenizer, c, output);\n    // We need to clear reconsume_current_input before returning to prevent\n    // certain infinite loop states.\n    bool should_advance = !tokenizer->_reconsume_current_input;\n    tokenizer->_reconsume_current_input = false;\n\n    if (result == RETURN_SUCCESS) {\n      return true;\n    } else if(result == RETURN_ERROR) {\n      return false;\n    }\n\n    if (should_advance) {\n      utf8iterator_next(&tokenizer->_input);\n    }\n  }\n}\n\nvoid gumbo_token_destroy(GumboParser* parser, GumboToken* token) {\n  if (!token) return;\n\n  switch (token->type) {\n    case GUMBO_TOKEN_DOCTYPE:\n      gumbo_parser_deallocate(parser, (void*) token->v.doc_type.name);\n      gumbo_parser_deallocate(\n          parser, (void*) token->v.doc_type.public_identifier);\n      gumbo_parser_deallocate(\n          parser, (void*) token->v.doc_type.system_identifier);\n      return;\n    case GUMBO_TOKEN_START_TAG:\n      for (int i = 0; i < token->v.start_tag.attributes.length; ++i) {\n        GumboAttribute* attr = token->v.start_tag.attributes.data[i];\n        if (attr) {\n          // May have been nulled out if this token was merged with another.\n          gumbo_destroy_attribute(parser, attr);\n        }\n      }\n      gumbo_parser_deallocate(\n          parser, (void*) token->v.start_tag.attributes.data);\n      return;\n    case GUMBO_TOKEN_COMMENT:\n      gumbo_parser_deallocate(parser, (void*) token->v.text);\n      return;\n    default:\n      return;\n  }\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/tokenizer.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// This contains an implementation of a tokenizer for HTML5.  It consumes a\n// buffer of UTF-8 characters, and then emits a stream of tokens.\n\n#ifndef GUMBO_TOKENIZER_H_\n#define GUMBO_TOKENIZER_H_\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"gumbo.h\"\n#include \"token_type.h\"\n#include \"tokenizer_states.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalParser;\n\n// Struct containing all information pertaining to doctype tokens.\ntypedef struct GumboInternalTokenDocType {\n  const char* name;\n  const char* public_identifier;\n  const char* system_identifier;\n  bool force_quirks;\n  // There's no way to tell a 0-length public or system ID apart from the\n  // absence of a public or system ID, but they're handled different by the\n  // spec, so we need bool flags for them.\n  bool has_public_identifier;\n  bool has_system_identifier;\n} GumboTokenDocType;\n\n// Struct containing all information pertaining to start tag tokens.\ntypedef struct GumboInternalTokenStartTag {\n  GumboTag tag;\n  GumboVector /* GumboAttribute */ attributes;\n  bool is_self_closing;\n} GumboTokenStartTag;\n\n// A data structure representing a single token in the input stream.  This\n// contains an enum for the type, the source position, a GumboStringPiece\n// pointing to the original text, and then a union for any parsed data.\ntypedef struct GumboInternalToken {\n  GumboTokenType type;\n  GumboSourcePosition position;\n  GumboStringPiece original_text;\n  union {\n    GumboTokenDocType doc_type;\n    GumboTokenStartTag start_tag;\n    GumboTag end_tag;\n    const char* text;    // For comments.\n    int character;      // For character, whitespace, null, and EOF tokens.\n  } v;\n} GumboToken;\n\n// Initializes the tokenizer state within the GumboParser object, setting up a\n// parse of the specified text.\nvoid gumbo_tokenizer_state_init(\n    struct GumboInternalParser* parser, const char* text, size_t text_length);\n\n// Destroys the tokenizer state within the GumboParser object, freeing any\n// dynamically-allocated structures within it.\nvoid gumbo_tokenizer_state_destroy(struct GumboInternalParser* parser);\n\n// Sets the tokenizer state to the specified value.  This is needed by some\n// parser states, which alter the state of the tokenizer in response to tags\n// seen.\nvoid gumbo_tokenizer_set_state(\n    struct GumboInternalParser* parser, GumboTokenizerEnum state);\n\n// Flags whether the current node is a foreign content element.  This is\n// necessary for the markup declaration open state, where the tokenizer must be\n// aware of the state of the parser to properly tokenize bad comment tags.\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#markup-declaration-open-state\nvoid gumbo_tokenizer_set_is_current_node_foreign(\n    struct GumboInternalParser* parser, bool is_foreign);\n\n// Lexes a single token from the specified buffer, filling the output with the\n// parsed GumboToken data structure.  Returns true for a successful\n// tokenization, false if a parse error occurs.\n//\n// Example:\n//   struct GumboInternalParser parser;\n//   GumboToken output;\n//   gumbo_tokenizer_state_init(&parser, text, strlen(text));\n//   while (gumbo_lex(&parser, &output)) {\n//     ...do stuff with output.\n//     gumbo_token_destroy(&parser, &token);\n//   }\n//   gumbo_tokenizer_state_destroy(&parser);\nbool gumbo_lex(struct GumboInternalParser* parser, GumboToken* output);\n\n// Frees the internally-allocated pointers within an GumboToken.  Note that this\n// doesn't free the token itself, since oftentimes it will be allocated on the\n// stack.  A simple call to free() (or GumboParser->deallocator, if\n// appropriate) can handle that.\n//\n// Note that if you are handing over ownership of the internal strings to some\n// other data structure - for example, a parse tree - these do not need to be\n// freed.\nvoid gumbo_token_destroy(struct GumboInternalParser* parser, GumboToken* token);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_TOKENIZER_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/tokenizer_states.h",
    "content": "// Copyright 2011 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// This contains the list of states used in the tokenizer.  Although at first\n// glance it seems like these could be kept internal to the tokenizer, several\n// of the actions in the parser require that it reach into the tokenizer and\n// reset the tokenizer state.  For that to work, it needs to have the\n// definitions of individual states available.\n//\n// This may also be useful for providing more detailed error messages for parse\n// errors, as we can match up states and inputs in a table without having to\n// clutter the tokenizer code with lots of precise error messages.\n\n#ifndef GUMBO_TOKENIZER_STATES_H_\n#define GUMBO_TOKENIZER_STATES_H_\n\n// The ordering of this enum is also used to build the dispatch table for the\n// tokenizer state machine, so if it is changed, be sure to update that too.\ntypedef enum {\n  GUMBO_LEX_DATA,\n  GUMBO_LEX_CHAR_REF_IN_DATA,\n  GUMBO_LEX_RCDATA,\n  GUMBO_LEX_CHAR_REF_IN_RCDATA,\n  GUMBO_LEX_RAWTEXT,\n  GUMBO_LEX_SCRIPT,\n  GUMBO_LEX_PLAINTEXT,\n  GUMBO_LEX_TAG_OPEN,\n  GUMBO_LEX_END_TAG_OPEN,\n  GUMBO_LEX_TAG_NAME,\n  GUMBO_LEX_RCDATA_LT,\n  GUMBO_LEX_RCDATA_END_TAG_OPEN,\n  GUMBO_LEX_RCDATA_END_TAG_NAME,\n  GUMBO_LEX_RAWTEXT_LT,\n  GUMBO_LEX_RAWTEXT_END_TAG_OPEN,\n  GUMBO_LEX_RAWTEXT_END_TAG_NAME,\n  GUMBO_LEX_SCRIPT_LT,\n  GUMBO_LEX_SCRIPT_END_TAG_OPEN,\n  GUMBO_LEX_SCRIPT_END_TAG_NAME,\n  GUMBO_LEX_SCRIPT_ESCAPED_START,\n  GUMBO_LEX_SCRIPT_ESCAPED_START_DASH,\n  GUMBO_LEX_SCRIPT_ESCAPED,\n  GUMBO_LEX_SCRIPT_ESCAPED_DASH,\n  GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH,\n  GUMBO_LEX_SCRIPT_ESCAPED_LT,\n  GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN,\n  GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT,\n  GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END,\n  GUMBO_LEX_BEFORE_ATTR_NAME,\n  GUMBO_LEX_ATTR_NAME,\n  GUMBO_LEX_AFTER_ATTR_NAME,\n  GUMBO_LEX_BEFORE_ATTR_VALUE,\n  GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED,\n  GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED,\n  GUMBO_LEX_ATTR_VALUE_UNQUOTED,\n  GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE,\n  GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED,\n  GUMBO_LEX_SELF_CLOSING_START_TAG,\n  GUMBO_LEX_BOGUS_COMMENT,\n  GUMBO_LEX_MARKUP_DECLARATION,\n  GUMBO_LEX_COMMENT_START,\n  GUMBO_LEX_COMMENT_START_DASH,\n  GUMBO_LEX_COMMENT,\n  GUMBO_LEX_COMMENT_END_DASH,\n  GUMBO_LEX_COMMENT_END,\n  GUMBO_LEX_COMMENT_END_BANG,\n  GUMBO_LEX_DOCTYPE,\n  GUMBO_LEX_BEFORE_DOCTYPE_NAME,\n  GUMBO_LEX_DOCTYPE_NAME,\n  GUMBO_LEX_AFTER_DOCTYPE_NAME,\n  GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD,\n  GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID,\n  GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED,\n  GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED,\n  GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID,\n  GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID,\n  GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD,\n  GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID,\n  GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED,\n  GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED,\n  GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID,\n  GUMBO_LEX_BOGUS_DOCTYPE,\n  GUMBO_LEX_CDATA\n} GumboTokenizerEnum;\n\n#endif  // GUMBO_TOKENIZER_STATES_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/utf8.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"utf8.h\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n#include <strings.h>    // For strncasecmp.\n\n#include \"error.h\"\n#include \"gumbo.h\"\n#include \"parser.h\"\n#include \"util.h\"\n#include \"vector.h\"\n\nconst int kUtf8ReplacementChar = 0xFFFD;\n\n// Reference material:\n// Wikipedia: http://en.wikipedia.org/wiki/UTF-8#Description\n// RFC 3629: http://tools.ietf.org/html/rfc3629\n// HTML5 Unicode handling:\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#decoded-as-utf-8,-with-error-handling\n\n// Adds a decoding error to the parser's error list, based on the current state\n// of the Utf8Iterator.\nstatic void add_error(Utf8Iterator* iter, GumboErrorType type) {\n  GumboParser* parser = iter->_parser;\n\n  GumboError* error = gumbo_add_error(parser);\n  if (!error) {\n    return;\n  }\n  error->type = type;\n  error->position = iter->_pos;\n  error->original_text = iter->_start;\n\n  // At the point the error is recorded, the code point hasn't been computed\n  // yet (and can't be, because it's invalid), so we need to build up the raw\n  // hex value from the bytes under the cursor.\n  uint64_t code_point = 0;\n  for (int i = 0; i < iter->_width; ++i) {\n    code_point = (code_point << 8) | (unsigned char) iter->_start[i];\n  }\n  error->v.codepoint = code_point;\n}\n\n// Reads the next UTF-8 character in the iter.\n// This assumes that iter->_start points to the beginning of the character.\n// When this method returns, iter->_width and iter->_current will be set\n// appropriately, as well as any error flags.\nstatic void read_char(Utf8Iterator* iter) {\n  unsigned char c;\n  unsigned char mask = '\\0';\n  int is_bad_char = false;\n\n  c = (unsigned char) *iter->_start;\n  if (c < 0x80) {\n    // Valid one-byte sequence.\n    iter->_width = 1;\n    mask = 0xFF;\n  } else if (c < 0xC0) {\n    // Continuation character not following a multibyte sequence.\n    // The HTML5 spec here says to consume the byte and output a replacement\n    // character.\n    iter->_width = 1;\n    is_bad_char = true;\n  } else if (c < 0xE0) {\n    iter->_width = 2;\n    mask = 0x1F;                // 00011111 in binary.\n    if (c < 0xC2) {\n      // Overlong encoding; error according to UTF8/HTML5 spec.\n      is_bad_char = true;\n    }\n  } else if (c < 0xF0) {\n    iter->_width = 3;\n    mask = 0xF;                 // 00001111 in binary.\n  } else if (c < 0xF5) {\n    iter->_width = 4;\n    mask = 0x7;                 // 00000111 in binary.\n  } else if (c < 0xF8) {\n    // The following cases are all errors, but we need to handle them separately\n    // so that we consume the proper number of bytes from the input stream\n    // before replacing them with the replacement char.  The HTML5 spec\n    // specifies that we should consume the shorter of the length specified by\n    // the first bit or the run leading up to the first non-continuation\n    // character.\n    iter->_width = 5;\n    is_bad_char = true;\n  } else if (c < 0xFC) {\n    iter->_width = 6;\n    is_bad_char = true;\n  } else if (c < 0xFE) {\n    iter->_width = 7;\n    is_bad_char = true;\n  } else {\n    iter->_width = 1;\n    is_bad_char = true;\n  }\n\n  // Check to make sure we have enough bytes left in the iter to read all that\n  // we want.  If not, we set the iter_truncated flag, mark this as a bad\n  // character, and adjust the current width so that it consumes the rest of the\n  // iter.\n  uint64_t code_point = c & mask;\n  if (iter->_start + iter->_width > iter->_end) {\n    iter->_width = (int)(iter->_end - iter->_start);\n    add_error(iter, GUMBO_ERR_UTF8_TRUNCATED);\n    is_bad_char = true;\n  }\n\n  // Now we decode continuation bytes, shift them appropriately, and build up\n  // the appropriate code point.\n  assert(iter->_width < 8);\n  for (int i = 1; i < iter->_width; ++i) {\n    c = (unsigned char) iter->_start[i];\n    if (c < 0x80 || c > 0xBF) {\n      // Per HTML5 spec, we don't include the invalid continuation char in the\n      // run that we consume here.\n      iter->_width = i;\n      is_bad_char = true;\n      break;\n    }\n    code_point = (code_point << 6) | (c & ~0x80);\n  }\n  if (code_point > 0x10FFFF) is_bad_char = true;\n\n  // If we had a decode error, set the current code point to the replacement\n  // character and flip the flag indicating that a decode error occurred.\n  // Ditto if we have a code point that is explicitly on the list of characters\n  // prohibited by the HTML5 spec, such as control characters.\n  if (is_bad_char || utf8_is_invalid_code_point((int)code_point)) {\n    add_error(iter, GUMBO_ERR_UTF8_INVALID);\n    code_point = kUtf8ReplacementChar;\n  }\n\n  // This is the special handling for carriage returns that is mandated by the\n  // HTML5 spec.  Since we're looking for particular 7-bit literal characters,\n  // we operate in terms of chars and only need a check for iter overrun,\n  // instead of having to read in a full next code point.\n  // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#preprocessing-the-input-stream\n  if (code_point == '\\r') {\n    const char* next = iter->_start + iter->_width;\n    if (next < iter->_end && *next == '\\n') {\n      // Advance the iter, as if the carriage return didn't exist.\n      ++iter->_start;\n      // Preserve the true offset, since other tools that look at it may be\n      // unaware of HTML5's rules for converting \\r into \\n.\n      ++iter->_pos.offset;\n    }\n    code_point = '\\n';\n  }\n\n  // At this point, we know we have a valid character as the code point, so we\n  // set it, and we're done.\n  iter->_current = (int)code_point;\n}\n\nstatic void update_position(Utf8Iterator* iter) {\n  iter->_pos.offset += iter->_width;\n  if (iter->_current == '\\n') {\n    ++iter->_pos.line;\n    iter->_pos.column = 1;\n  } else if(iter->_current == '\\t') {\n    int tab_stop = iter->_parser->_options->tab_stop;\n    iter->_pos.column = ((iter->_pos.column / tab_stop) + 1) * tab_stop;\n  } else {\n    ++iter->_pos.column;\n  }\n}\n\n// Returns true if this Unicode code point is in the list of characters\n// forbidden by the HTML5 spec, such as undefined control chars.\nbool utf8_is_invalid_code_point(int c) {\n  return (c >= 0x1 && c <= 0x8) || c == 0xB || (c >= 0xE && c <= 0x1F) ||\n      (c >= 0x7F && c <= 0x9F) || (c >= 0xFDD0 && c <= 0xFDEF) ||\n      ((c & 0xFFFF) == 0xFFFE) || ((c & 0xFFFF) == 0xFFFF);\n}\n\nvoid utf8iterator_init(\n    GumboParser* parser, const char* source, size_t source_length,\n    Utf8Iterator* iter) {\n  iter->_start = source;\n  iter->_end = source + source_length;\n  iter->_width = 0;\n  iter->_pos.line = 1;\n  iter->_pos.column = 1;\n  iter->_pos.offset = 0;\n  iter->_parser = parser;\n  if (source_length) {\n    read_char(iter);\n  } else {\n    iter->_current = -1;\n  }\n}\n\nvoid utf8iterator_next(Utf8Iterator* iter) {\n  iter->_start += iter->_width;\n  // We update positions based on the *last* character read, so that the first\n  // character following a newline is at column 1 in the next line.\n  update_position(iter);\n  if (iter->_start < iter->_end) {\n    read_char(iter);\n  } else {  // EOF\n    iter->_current = -1;\n  }\n}\n\nint utf8iterator_current(const Utf8Iterator* iter) {\n  return iter->_current;\n}\n\nvoid utf8iterator_get_position(\n    const Utf8Iterator* iter, GumboSourcePosition* output) {\n  *output = iter->_pos;\n}\n\nconst char* utf8iterator_get_char_pointer(const Utf8Iterator* iter) {\n  return iter->_start;\n}\n\nbool utf8iterator_maybe_consume_match(\n    Utf8Iterator* iter, const char* prefix, size_t length,\n    bool case_sensitive) {\n  bool matched = (iter->_start + length <= iter->_end) && (case_sensitive ?\n      !strncmp(iter->_start, prefix, length) :\n      !strncasecmp(iter->_start, prefix, length));\n  if (matched) {\n    for (int i = 0; i < length; ++i) {\n      utf8iterator_next(iter);\n    }\n    return true;\n  } else {\n    return false;\n  }\n}\n\nvoid utf8iterator_mark(Utf8Iterator* iter) {\n  iter->_mark = iter->_start;\n  iter->_mark_pos = iter->_pos;\n}\n\n// Returns the current input stream position to the mark.\nvoid utf8iterator_reset(Utf8Iterator* iter) {\n  iter->_start = iter->_mark;\n  iter->_pos = iter->_mark_pos;\n  read_char(iter);\n}\n\n// Sets the position and original text fields of an error to the value at the\n// mark.\nvoid utf8iterator_fill_error_at_mark(\n    Utf8Iterator* iter, GumboError* error) {\n  error->position = iter->_mark_pos;\n  error->original_text = iter->_mark;\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/utf8.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// This contains an implementation of a UTF8 iterator and decoder suitable for\n// an HTML5 parser.  This does a bit more than straight UTF-8 decoding.  The\n// HTML5 spec specifies that:\n// 1. Decoding errors are parse errors.\n// 2. Certain other codepoints (eg. control characters) are parse errors.\n// 3. Carriage returns and CR/LF groups are converted to line feeds.\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#decoded-as-utf-8,-with-error-handling\n//\n// Also, we want to keep track of source positions for error handling.  As a\n// result, we fold all that functionality into this decoder, and can't use an\n// off-the-shelf library.\n//\n// This header is internal-only, which is why we prefix functions with only\n// utf8_ or utf8_iterator_ instead of gumbo_utf8_.\n\n#ifndef GUMBO_UTF8_H_\n#define GUMBO_UTF8_H_\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#include \"gumbo.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct GumboInternalError;\nstruct GumboInternalParser;\n\n// Unicode replacement char.\nextern const int kUtf8ReplacementChar;\n\ntypedef struct GumboInternalUtf8Iterator {\n  // Points at the start of the code point most recently read into 'current'.\n  const char* _start;\n\n  // Points at the mark.  The mark is initially set to the beginning of the\n  // input.\n  const char* _mark;\n\n  // Points past the end of the iter, like a past-the-end iterator in the STL.\n  const char* _end;\n\n  // The code point under the cursor.\n  int _current;\n\n  // The width in bytes of the current code point.\n  int _width;\n\n  // The SourcePosition for the current location.\n  GumboSourcePosition _pos;\n\n  // The SourcePosition for the mark.\n  GumboSourcePosition _mark_pos;\n\n  // Pointer back to the GumboParser instance, for configuration options and\n  // error recording.\n  struct GumboInternalParser* _parser;\n} Utf8Iterator;\n\n// Returns true if this Unicode code point is in the list of characters\n// forbidden by the HTML5 spec, such as NUL bytes and undefined control chars.\nbool utf8_is_invalid_code_point(int c);\n\n// Initializes a new Utf8Iterator from the given byte buffer.  The source does\n// not have to be NUL-terminated, but the length must be passed in explicitly.\nvoid utf8iterator_init(\n    struct GumboInternalParser* parser, const char* source,\n    size_t source_length, Utf8Iterator* iter);\n\n// Advances the current position by one code point.\nvoid utf8iterator_next(Utf8Iterator* iter);\n\n// Returns the current code point as an integer.\nint utf8iterator_current(const Utf8Iterator* iter);\n\n// Retrieves and fills the output parameter with the current source position.\nvoid utf8iterator_get_position(\n    const Utf8Iterator* iter, GumboSourcePosition* output);\n\n// Retrieves a character pointer to the start of the current character.\nconst char* utf8iterator_get_char_pointer(const Utf8Iterator* iter);\n\n// If the upcoming text in the buffer matches the specified prefix (which has\n// length 'length'), consume it and return true.  Otherwise, return false with\n// no other effects.  If the length of the string would overflow the buffer,\n// this returns false.  Note that prefix should not contain null bytes because\n// of the use of strncmp/strncasecmp internally.  All existing use-cases adhere\n// to this.\nbool utf8iterator_maybe_consume_match(\n    Utf8Iterator* iter, const char* prefix, size_t length, bool case_sensitive);\n\n// \"Marks\" a particular location of interest in the input stream, so that it can\n// later be reset() to.  There's also the ability to record an error at the\n// point that was marked, as oftentimes that's more useful than the last\n// character before the error was detected.\nvoid utf8iterator_mark(Utf8Iterator* iter);\n\n// Returns the current input stream position to the mark.\nvoid utf8iterator_reset(Utf8Iterator* iter);\n\n// Sets the position and original text fields of an error to the value at the\n// mark.\nvoid utf8iterator_fill_error_at_mark(\n    Utf8Iterator* iter, struct GumboInternalError* error);\n\n#ifdef __cplusplus\n}\n#endif\n#endif  // GUMBO_UTF8_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/util.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"util.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <stdarg.h>\n#include <stdio.h>\n\n#include \"gumbo.h\"\n#include \"parser.h\"\n\n// TODO(jdtang): This should be elsewhere, but there's no .c file for\n// SourcePositions and yet the constant needs some linkage, so this is as good\n// as any.\nconst GumboSourcePosition kGumboEmptySourcePosition = { 0, 0, 0 };\n\nvoid* gumbo_parser_allocate(GumboParser* parser, size_t num_bytes) {\n  return parser->_options->allocator(parser->_options->userdata, num_bytes);\n}\n\nvoid gumbo_parser_deallocate(GumboParser* parser, void* ptr) {\n  return parser->_options->deallocator(parser->_options->userdata, ptr);\n}\n\nchar* gumbo_copy_stringz(GumboParser* parser, const char* str) {\n  char* buffer = gumbo_parser_allocate(parser, strlen(str) + 1);\n  strcpy(buffer, str);\n  return buffer;\n}\n\n// Debug function to trace operation of the parser.  Pass --copts=-DGUMBO_DEBUG\n// to use.\nvoid gumbo_debug(const char* format, ...) {\n#ifdef GUMBO_DEBUG\n  va_list args;\n  va_start(args, format);\n  vprintf(format, args);\n  va_end(args);\n  fflush(stdout);\n#endif\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/util.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n//\n// This contains some utility functions that didn't fit into any of the other\n// headers.\n\n#ifndef GUMBO_UTIL_H_\n#define GUMBO_UTIL_H_\n\n#include <stdbool.h>\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Forward declaration since it's passed into some of the functions in this\n// header.\nstruct GumboInternalParser;\n\n// Utility function for allocating & copying a null-terminated string into a\n// freshly-allocated buffer.  This is necessary for proper memory management; we\n// have the convention that all const char* in parse tree structures are\n// freshly-allocated, so if we didn't copy, we'd try to delete a literal string\n// when the parse tree is destroyed.\nchar* gumbo_copy_stringz(struct GumboInternalParser* parser, const char* str);\n\n// Allocate a chunk of memory, using the allocator specified in the Parser's\n// config options.\nvoid* gumbo_parser_allocate(\n    struct GumboInternalParser* parser, size_t num_bytes);\n\n// Deallocate a chunk of memory, using the deallocator specified in the Parser's\n// config options.\nvoid gumbo_parser_deallocate(struct GumboInternalParser* parser, void* ptr);\n\n// Debug wrapper for printf, to make it easier to turn off debugging info when\n// required.\nvoid gumbo_debug(const char* format, ...);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_UTIL_H_\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/vector.c",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#include \"vector.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n\n#include \"util.h\"\n\nstruct GumboInternalParser;\n\nconst GumboVector kGumboEmptyVector = { NULL, 0, 0 };\n\nvoid gumbo_vector_init(\n    struct GumboInternalParser* parser, size_t initial_capacity, GumboVector* vector) {\n  vector->length = 0;\n  vector->capacity = (int)initial_capacity;\n  if (initial_capacity > 0) {\n    vector->data = gumbo_parser_allocate(\n        parser, sizeof(void*) * initial_capacity);\n  } else {\n    vector->data = NULL;\n  }\n}\n\nvoid gumbo_vector_destroy(struct GumboInternalParser* parser, GumboVector* vector) {\n  if (vector->capacity > 0) {\n    gumbo_parser_deallocate(parser, vector->data);\n  }\n}\n\nstatic void enlarge_vector_if_full(\n    struct GumboInternalParser* parser, GumboVector* vector) {\n  if (vector->length >= vector->capacity) {\n    if (vector->capacity) {\n      size_t old_num_bytes = sizeof(void*) * vector->capacity;\n      vector->capacity *= 2;\n      size_t num_bytes = sizeof(void*) * vector->capacity;\n      void** temp = gumbo_parser_allocate(parser, num_bytes);\n      memcpy(temp, vector->data, old_num_bytes);\n      gumbo_parser_deallocate(parser, vector->data);\n      vector->data = temp;\n    } else {\n      // 0-capacity vector; no previous array to deallocate.\n      vector->capacity = 2;\n      vector->data = gumbo_parser_allocate(\n          parser, sizeof(void*) * vector->capacity);\n    }\n  }\n}\n\nvoid gumbo_vector_add(\n    struct GumboInternalParser* parser, void* element, GumboVector* vector) {\n  enlarge_vector_if_full(parser, vector);\n  assert(vector->data);\n  assert(vector->length < vector->capacity);\n  vector->data[vector->length++] = element;\n}\n\nvoid* gumbo_vector_pop(\n    struct GumboInternalParser* parser, GumboVector* vector) {\n  if (vector->length == 0) {\n    return NULL;\n  }\n  return vector->data[--vector->length];\n}\n\nint gumbo_vector_index_of(GumboVector* vector, void* element) {\n  for (int i = 0; i < vector->length; ++i) {\n    if (vector->data[i] == element) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nvoid gumbo_vector_insert_at(\n    struct GumboInternalParser* parser, void* element, int index,\n    GumboVector* vector) {\n  assert(index >= 0);\n  assert(index <= vector->length);\n  enlarge_vector_if_full(parser, vector);\n  ++vector->length;\n  memmove(&vector->data[index + 1], &vector->data[index],\n          sizeof(void*) * (vector->length - index - 1));\n  vector->data[index] = element;\n}\n\nvoid gumbo_vector_remove(\n    struct GumboInternalParser* parser, void* node, GumboVector* vector) {\n  int index = gumbo_vector_index_of(vector, node);\n  if (index == -1) {\n    return;\n  }\n  gumbo_vector_remove_at(parser, index, vector);\n}\n\nvoid* gumbo_vector_remove_at(\n    struct GumboInternalParser* parser, int index, GumboVector* vector) {\n  assert(index >= 0);\n  assert(index < vector->length);\n  void* result = vector->data[index];\n  memmove(&vector->data[index], &vector->data[index + 1],\n          sizeof(void*) * (vector->length - index - 1));\n  --vector->length;\n  return result;\n}\n"
  },
  {
    "path": "Pod/Classes/Private/Gumbo/vector.h",
    "content": "// Copyright 2010 Google Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Author: jdtang@google.com (Jonathan Tang)\n\n#ifndef GUMBO_VECTOR_H_\n#define GUMBO_VECTOR_H_\n\n#include \"gumbo.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Forward declaration since it's passed into some of the functions in this\n// header.\nstruct GumboInternalParser;\n\n// Initializes a new GumboVector with the specified initial capacity.\nvoid gumbo_vector_init(\n    struct GumboInternalParser* parser, size_t initial_capacity,\n    GumboVector* vector);\n\n// Frees the memory used by an GumboVector.  Does not free the contained\n// pointers.\nvoid gumbo_vector_destroy(\n    struct GumboInternalParser* parser, GumboVector* vector);\n\n// Adds a new element to an GumboVector.\nvoid gumbo_vector_add(\n    struct GumboInternalParser* parser, void* element, GumboVector* vector);\n\n// Removes and returns the element most recently added to the GumboVector.\n// Ownership is transferred to caller.  Capacity is unchanged.  If the vector is\n// empty, NULL is returned.\nvoid* gumbo_vector_pop(struct GumboInternalParser* parser, GumboVector* vector);\n\n// Inserts an element at a specific index.  This is potentially O(N) time, but\n// is necessary for some of the spec's behavior.\nvoid gumbo_vector_insert_at(\n    struct GumboInternalParser* parser, void* element, int index,\n    GumboVector* vector);\n\n// Removes an element from the vector, or does nothing if the element is not in\n// the vector.\nvoid gumbo_vector_remove(\n    struct GumboInternalParser* parser, void* element, GumboVector* vector);\n\n// Removes and returns an element at a specific index.  Note that this is\n// potentially O(N) time and should be used sparingly.\nvoid* gumbo_vector_remove_at(\n    struct GumboInternalParser* parser, int index, GumboVector* vector);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // GUMBO_VECTOR_H_\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/NSString+OGString.h",
    "content": "//\n//  NSString+OGString.h\n//  Hacker News\n//\n//  Created by Thomas Denney on 30/08/2013.\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSString (OGString)\n\n-(NSString*)escapedString;\n+(NSString*)indentationString:(int)indentationLevel;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/NSString+OGString.m",
    "content": "//\n//  NSString+OGString.m\n//  Hacker News\n//\n//  Created by Thomas Denney on 30/08/2013.\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"NSString+OGString.h\"\n\n@implementation NSString (OGString)\n\n-(NSString*)escapedString\n{\n    NSString *escapedString = [self stringByReplacingOccurrencesOfString:@\"\\\\\" withString:@\"\\\\\\\\\"];\n    escapedString = [escapedString stringByReplacingOccurrencesOfString:@\"\\\"\" withString:@\"\\\\\\\"\"];\n    return escapedString;\n}\n\n+(NSString*)indentationString:(int)indentationLevel\n{\n    NSMutableString * string = [NSMutableString new];\n    for (int n = 0; n < indentationLevel; n++)\n    {\n        [string appendString:@\"\\t\"];\n    }\n    return string;\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGDocument.h",
    "content": "//\n//  OGDocument.h\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGElement.h\"\n\n@interface OGDocument : OGElement\n\n@property NSString * name;\n@property NSString * publicIdentifier;\n@property NSString * systemIdentifier;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGDocument.m",
    "content": "//\n//  OGDocument.m\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGDocument.h\"\n\n@implementation OGDocument\n\n-(id)init\n{\n    self = [super init];\n    if (self)\n    {\n        self.publicIdentifier = @\"\";\n        self.systemIdentifier = @\"\";\n        self.name = @\"\";\n    }\n    return self;\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGElement.h",
    "content": "//\n//  OGElement.h\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGNode.h\"\n\n@interface OGElement : OGNode\n\n@property GumboTag tag;\n@property GumboNamespaceEnum tagNamespace;\n\n@property NSArray * children;\n@property NSArray * classes;\n@property NSDictionary * attributes;\n\n-(NSArray*)elementsWithAttribute:(NSString *)attribute andValue:(NSString *)value;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGElement.m",
    "content": "//\n//  OGElement.m\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGElement.h\"\n\n@implementation OGElement\n\n-(NSString*)text\n{\n    NSMutableString * text = [NSMutableString new];\n    for (OGNode * child in self.children)\n    {\n        [text appendString:[child text]];\n    }\n    return text;\n}\n\n-(NSString*)htmlWithIndentation:(int)indentationLevel\n{\n    NSMutableString * html = [NSMutableString stringWithFormat:@\"<%@\", [OGUtility tagForGumboTag:self.tag]];\n    for (NSString * attribute in self.attributes)\n    {\n        [html appendFormat:@\" %@=\\\"%@\\\"\", attribute, [self.attributes[attribute]  escapedString]];\n    }\n    if (self.children.count == 0)\n    {\n        [html appendString:@\" />\\n\"];\n    }\n    else\n    {\n        [html appendString:@\">\\n\"];\n        for (OGNode * child in self.children)\n        {\n            [html appendString:[child htmlWithIndentation:indentationLevel + 1]];\n        }\n        [html appendFormat:@\"</%@>\\n\", [OGUtility tagForGumboTag:self.tag]];\n    }\n    return html;\n}\n\n-(NSArray*)selectWithBlock:(SelectorBlock)block\n{\n    NSMutableArray * matchingChildren = [NSMutableArray new];\n    for (OGNode * child in self.children)\n    {\n        if (block(child))\n        {\n            [matchingChildren addObject:child];\n        }\n        [matchingChildren addObjectsFromArray:[child selectWithBlock:block]];\n    }\n    return matchingChildren;\n}\n\n-(NSArray*)elementsWithAttribute:(NSString *)attribute andValue:(NSString *)value\n{\n    return [self selectWithBlock:^BOOL(id node) {\n        if ([node isKindOfClass:[OGElement class]])\n        {\n            OGElement * element = (OGElement*)node;\n            return [element.attributes[attribute] isEqualToString:value];\n        }\n        return NO;\n    }];\n}\n\n-(NSArray*)elementsWithClass:(NSString*)class\n{\n    return [self selectWithBlock:^BOOL(id node) {\n        if ([node isKindOfClass:[OGElement class]])\n        {\n            OGElement * element = (OGElement*)node;\n            for (NSString * classes in element.classes)\n            {\n                if ([classes isEqualToString:class])\n                {\n                    return YES;\n                }\n            }\n        }\n        return NO;\n    }];\n}\n\n-(NSArray*)elementsWithID:(NSString *)elementId\n{\n    return [self selectWithBlock:^BOOL(id node) {\n        if ([node isKindOfClass:[OGElement class]]) {\n            OGElement * element = (OGElement*)node;\n            return [(NSString*)element.attributes[@\"id\"] isEqualToString:elementId];\n        }\n        return NO;\n    }];\n}\n\n-(NSArray*)elementsWithTag:(GumboTag)tag\n{\n    return [self selectWithBlock:^BOOL(id node) {\n        if ([node isKindOfClass:[OGElement class]])\n        {\n            OGElement * element = (OGElement*)node;\n            return element.tag == tag;\n        }\n        return NO;\n    }];\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGNode.h",
    "content": "//\n//  OGNode.h\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"OGUtility.h\"\n#import \"NSString+OGString.h\"\n\ntypedef BOOL(^SelectorBlock)(id node);\n\n@interface OGNode : NSObject\n\n@property OGNode * parent;\n\n-(NSString*)text;\n-(NSString*)html;\n-(NSString*)htmlWithIndentation:(int)indentationLevel;\n\n//Usage:\n//#stuffwiththisid .orthisclass orthistag\n-(NSArray*)select:(NSString*)selector;\n-(NSArray*)selectWithBlock:(SelectorBlock)block;\n\n//Returns the first OGNode from the select:\n-(OGNode*)first:(NSString*)selector;\n-(OGNode*)last:(NSString*)selector;\n\n-(NSArray*)elementsWithClass:(NSString*)class;\n-(NSArray*)elementsWithID:(NSString*)id;\n-(NSArray*)elementsWithTag:(GumboTag)tag;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGNode.m",
    "content": "//\n//  OGNode.m\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGNode.h\"\n\n@implementation OGNode\n\n-(NSString*)text\n{\n    return @\"\";\n}\n\n-(NSString*)html\n{\n    return [self htmlWithIndentation:0];\n}\n\n-(NSString*)htmlWithIndentation:(int)indentationLevel\n{\n    return @\"\";\n}\n\n-(NSArray*)select:(NSString *)selector\n{\n    NSArray * selectors = [selector componentsSeparatedByString:@\" \"];\n    NSMutableArray * allMatchingObjects = [NSMutableArray new];\n    for (NSString * individualSelector in selectors)\n    {\n        if ([individualSelector hasPrefix:@\"#\"])\n        {\n            [allMatchingObjects addObjectsFromArray:[self elementsWithID:[individualSelector substringFromIndex:1]]];\n        }\n        else if ([individualSelector hasPrefix:@\".\"])\n        {\n            [allMatchingObjects addObjectsFromArray:[self elementsWithClass:[individualSelector substringFromIndex:1]]];\n        }\n        else\n        {\n            [allMatchingObjects addObjectsFromArray:[self elementsWithTag:[OGUtility gumboTagForTag:individualSelector]]];\n        }\n    }\n    \n    //Remove duplicates\n    NSOrderedSet * set = [[NSOrderedSet alloc] initWithArray:allMatchingObjects];\n    allMatchingObjects = [[NSMutableArray alloc] initWithArray:[set array]];\n    \n    return allMatchingObjects;\n}\n\n-(NSArray*)selectWithBlock:(SelectorBlock)block\n{\n    return [NSArray new];\n}\n\n-(OGNode*)first:(NSString *)selector\n{\n    return [[self select:selector] firstObject];\n}\n\n-(OGNode*)last:(NSString *)selector\n{\n    return [[self select:selector] lastObject];\n}\n\n-(NSArray*)elementsWithClass:(NSString*)class\n{\n    return [NSArray new];\n}\n\n-(NSArray*)elementsWithID:(NSString *)id\n{\n    return [NSArray new];\n}\n\n-(NSArray*)elementsWithTag:(GumboTag)tag\n{\n    return [NSArray new];\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGText.h",
    "content": "//\n//  OGText.h\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGNode.h\"\n\n@interface OGText : OGNode\n{\n    NSString * _text;\n}\n\n@property BOOL isComment;\n@property BOOL isCData;\n@property BOOL isWhitespace;\n@property BOOL isText;\n\n-(id)initWithText:(NSString*)text andType:(GumboNodeType)type;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGText.m",
    "content": "//\n//  OGText.m\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGText.h\"\n\n@implementation OGText\n\n-(id)initWithText:(NSString *)text andType:(GumboNodeType)type\n{\n    self = [super init];\n    if (self)\n    {\n        _text = text;\n        self.isText = type == GUMBO_NODE_TEXT;\n        self.isWhitespace = type == GUMBO_NODE_WHITESPACE;\n        self.isComment = type == GUMBO_NODE_COMMENT;\n        self.isCData = type == GUMBO_NODE_CDATA;\n    }\n    return self;\n}\n\n-(NSString*)text\n{\n    if (self.isText)\n    {\n        return _text;\n    }\n    else\n    {\n        return @\"\";\n    }\n}\n\n-(NSString*)htmlWithIndentation:(int)indentationLevel\n{\n    _text = [_text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n    if (self.isText)\n    {\n        if ([_text hasSuffix:@\"\\n\"]) return _text;\n        return [NSString stringWithFormat:@\"%@\\n\", _text];\n    }\n    else if (self.isComment)\n    {\n        return [NSString stringWithFormat:@\"<!--%@-->\\n\", _text];\n    }\n    return [NSString indentationString:indentationLevel];\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGUtility.h",
    "content": "//\n//  OGUtility.h\n//  Hacker News\n//\n//  Created by Thomas Denney on 30/08/2013.\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"gumbo.h\"\n\n@interface OGUtility : NSObject\n\n+(NSString*)tagForGumboTag:(GumboTag)tag;\n+(GumboTag)gumboTagForTag:(NSString*)tag;\n+(NSArray*)tagStrings;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/OGUtility.m",
    "content": "//\n//  OGUtility.m\n//  Hacker News\n//\n//  Created by Thomas Denney on 30/08/2013.\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"OGUtility.h\"\n\n@implementation OGUtility\n\n+(NSString*)tagForGumboTag:(GumboTag)tag\n{\n    return [OGUtility tagStrings][tag];\n}\n\n+(GumboTag)gumboTagForTag:(NSString *)tag\n{\n    return (GumboTag)[[OGUtility tagStrings] indexOfObject:tag];\n}\n\n+(NSArray*)tagStrings\n{\n    NSMutableArray * array = [NSMutableArray arrayWithCapacity:GUMBO_TAG_LAST];\n    //These were generated using a Textmate macro\n    //A C equivalent of this exists in tag.c of Gumbo\n    array[GUMBO_TAG_HTML] = @\"html\";\n    array[GUMBO_TAG_HEAD] = @\"head\";\n    array[GUMBO_TAG_TITLE] = @\"title\";\n    array[GUMBO_TAG_BASE] = @\"base\";\n    array[GUMBO_TAG_LINK] = @\"link\";\n    array[GUMBO_TAG_META] = @\"meta\";\n    array[GUMBO_TAG_STYLE] = @\"style\";\n\tarray[GUMBO_TAG_SCRIPT] = @\"script\";\n    array[GUMBO_TAG_NOSCRIPT] = @\"noscript\";\n    array[GUMBO_TAG_BODY] = @\"body\";\n    array[GUMBO_TAG_SECTION] = @\"section\";\n    array[GUMBO_TAG_NAV] = @\"nav\";\n    array[GUMBO_TAG_ARTICLE] = @\"article\";\n    array[GUMBO_TAG_ASIDE] = @\"aside\";\n    array[GUMBO_TAG_H1] = @\"h1\";\n    array[GUMBO_TAG_H2] = @\"h2\";\n    array[GUMBO_TAG_H3] = @\"h3\";\n    array[GUMBO_TAG_H4] = @\"h4\";\n    array[GUMBO_TAG_H5] = @\"h5\";\n    array[GUMBO_TAG_H6] = @\"h6\";\n    array[GUMBO_TAG_HGROUP] = @\"hgroup\";\n    array[GUMBO_TAG_HEADER] = @\"header\";\n    array[GUMBO_TAG_FOOTER] = @\"footer\";\n    array[GUMBO_TAG_ADDRESS] = @\"address\";\n    array[GUMBO_TAG_P] = @\"p\";\n    array[GUMBO_TAG_HR] = @\"hr\";\n    array[GUMBO_TAG_PRE] = @\"pre\";\n    array[GUMBO_TAG_BLOCKQUOTE] = @\"blockquote\";\n    array[GUMBO_TAG_OL] = @\"ol\";\n    array[GUMBO_TAG_UL] = @\"ul\";\n    array[GUMBO_TAG_LI] = @\"li\";\n    array[GUMBO_TAG_DL] = @\"dl\";\n    array[GUMBO_TAG_DT] = @\"dt\";\n    array[GUMBO_TAG_DD] = @\"dd\";\n    array[GUMBO_TAG_FIGURE] = @\"figure\";\n    array[GUMBO_TAG_FIGCAPTION] = @\"figcaption\";\n    array[GUMBO_TAG_DIV] = @\"div\";\n    array[GUMBO_TAG_A] = @\"a\";\n    array[GUMBO_TAG_EM] = @\"em\";\n    array[GUMBO_TAG_STRONG] = @\"strong\";\n    array[GUMBO_TAG_SMALL] = @\"small\";\n    array[GUMBO_TAG_S] = @\"s\";\n    array[GUMBO_TAG_CITE] = @\"cite\";\n    array[GUMBO_TAG_Q] = @\"q\";\n    array[GUMBO_TAG_DFN] = @\"dfn\";\n    array[GUMBO_TAG_ABBR] = @\"abbr\";\n    array[GUMBO_TAG_TIME] = @\"time\";\n    array[GUMBO_TAG_CODE] = @\"code\";\n    array[GUMBO_TAG_VAR] = @\"var\";\n    array[GUMBO_TAG_SAMP] = @\"samp\";\n    array[GUMBO_TAG_KBD] = @\"kbd\";\n    array[GUMBO_TAG_SUB] = @\"sub\";\n    array[GUMBO_TAG_SUP] = @\"sup\";\n    array[GUMBO_TAG_I] = @\"i\";\n    array[GUMBO_TAG_B] = @\"b\";\n    array[GUMBO_TAG_MARK] = @\"mark\";\n    array[GUMBO_TAG_RUBY] = @\"ruby\";\n    array[GUMBO_TAG_RT] = @\"rt\";\n    array[GUMBO_TAG_RP] = @\"rp\";\n    array[GUMBO_TAG_BDI] = @\"bdi\";\n    array[GUMBO_TAG_BDO] = @\"bdo\";\n    array[GUMBO_TAG_SPAN] = @\"span\";\n    array[GUMBO_TAG_BR] = @\"br\";\n    array[GUMBO_TAG_WBR] = @\"wbr\";\n    array[GUMBO_TAG_INS] = @\"ins\";\n    array[GUMBO_TAG_DEL] = @\"del\";\n    array[GUMBO_TAG_IMAGE] = @\"image\";\n    array[GUMBO_TAG_IMG] = @\"img\";\n    array[GUMBO_TAG_IFRAME] = @\"iframe\";\n    array[GUMBO_TAG_EMBED] = @\"embed\";\n    array[GUMBO_TAG_OBJECT] = @\"object\";\n    array[GUMBO_TAG_PARAM] = @\"param\";\n    array[GUMBO_TAG_VIDEO] = @\"video\";\n    array[GUMBO_TAG_AUDIO] = @\"audio\";\n    array[GUMBO_TAG_SOURCE] = @\"source\";\n    array[GUMBO_TAG_TRACK] = @\"track\";\n    array[GUMBO_TAG_CANVAS] = @\"canvas\";\n    array[GUMBO_TAG_MAP] = @\"map\";\n    array[GUMBO_TAG_AREA] = @\"area\";\n    array[GUMBO_TAG_MATH] = @\"math\";\n    array[GUMBO_TAG_MI] = @\"mi\";\n    array[GUMBO_TAG_MO] = @\"mo\";\n    array[GUMBO_TAG_MN] = @\"mn\";\n    array[GUMBO_TAG_MS] = @\"ms\";\n    array[GUMBO_TAG_MTEXT] = @\"mtext\";\n    array[GUMBO_TAG_MGLYPH] = @\"mglyph\";\n    array[GUMBO_TAG_MALIGNMARK] = @\"malignmark\";\n    array[GUMBO_TAG_ANNOTATION_XML] = @\"xml\";\n    array[GUMBO_TAG_SVG] = @\"svg\";\n    array[GUMBO_TAG_FOREIGNOBJECT] = @\"foreignobject\";\n    array[GUMBO_TAG_DESC] = @\"desc\";\n    array[GUMBO_TAG_TABLE] = @\"table\";\n    array[GUMBO_TAG_CAPTION] = @\"caption\";\n    array[GUMBO_TAG_COLGROUP] = @\"colgroup\";\n    array[GUMBO_TAG_COL] = @\"col\";\n    array[GUMBO_TAG_TBODY] = @\"tbody\";\n    array[GUMBO_TAG_THEAD] = @\"thead\";\n    array[GUMBO_TAG_TFOOT] = @\"tfoot\";\n    array[GUMBO_TAG_TR] = @\"tr\";\n    array[GUMBO_TAG_TD] = @\"td\";\n    array[GUMBO_TAG_TH] = @\"th\";\n    array[GUMBO_TAG_FORM] = @\"form\";\n    array[GUMBO_TAG_FIELDSET] = @\"fieldset\";\n    array[GUMBO_TAG_LEGEND] = @\"legend\";\n    array[GUMBO_TAG_LABEL] = @\"label\";\n    array[GUMBO_TAG_INPUT] = @\"input\";\n    array[GUMBO_TAG_BUTTON] = @\"button\";\n    array[GUMBO_TAG_SELECT] = @\"select\";\n    array[GUMBO_TAG_DATALIST] = @\"datalist\";\n    array[GUMBO_TAG_OPTGROUP] = @\"optgroup\";\n    array[GUMBO_TAG_OPTION] = @\"option\";\n    array[GUMBO_TAG_TEXTAREA] = @\"textarea\";\n    array[GUMBO_TAG_KEYGEN] = @\"keygen\";\n    array[GUMBO_TAG_OUTPUT] = @\"output\";\n    array[GUMBO_TAG_PROGRESS] = @\"progress\";\n    array[GUMBO_TAG_METER] = @\"meter\";\n    array[GUMBO_TAG_DETAILS] = @\"details\";\n    array[GUMBO_TAG_SUMMARY] = @\"summary\";\n    array[GUMBO_TAG_COMMAND] = @\"command\";\n    array[GUMBO_TAG_MENU] = @\"menu\";\n    array[GUMBO_TAG_APPLET] = @\"applet\";\n    array[GUMBO_TAG_ACRONYM] = @\"acronym\";\n    array[GUMBO_TAG_BGSOUND] = @\"bgsound\";\n    array[GUMBO_TAG_DIR] = @\"dir\";\n    array[GUMBO_TAG_FRAME] = @\"frame\";\n    array[GUMBO_TAG_FRAMESET] = @\"frameset\";\n    array[GUMBO_TAG_NOFRAMES] = @\"noframes\";\n    array[GUMBO_TAG_ISINDEX] = @\"isindex\";\n    array[GUMBO_TAG_LISTING] = @\"listing\";\n    array[GUMBO_TAG_XMP] = @\"xmp\";\n    array[GUMBO_TAG_NEXTID] = @\"nextid\";\n    array[GUMBO_TAG_NOEMBED] = @\"noembed\";\n    array[GUMBO_TAG_PLAINTEXT] = @\"plaintext\";\n    array[GUMBO_TAG_RB] = @\"rb\";\n    array[GUMBO_TAG_STRIKE] = @\"strike\";\n    array[GUMBO_TAG_BASEFONT] = @\"basefont\";\n    array[GUMBO_TAG_BIG] = @\"big\";\n    array[GUMBO_TAG_BLINK] = @\"blink\";\n    array[GUMBO_TAG_CENTER] = @\"center\";\n    array[GUMBO_TAG_FONT] = @\"font\";\n    array[GUMBO_TAG_MARQUEE] = @\"marquee\";\n    array[GUMBO_TAG_MULTICOL] = @\"multicol\";\n    array[GUMBO_TAG_NOBR] = @\"nobr\";\n    array[GUMBO_TAG_SPACER] = @\"spacer\";\n    array[GUMBO_TAG_TT] = @\"tt\";\n    array[GUMBO_TAG_U] = @\"u\";\n    array[GUMBO_TAG_UNKNOWN] = @\"unknown\";\n    return array;\n}\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/ObjectiveGumbo.h",
    "content": "//\n//  ObjectiveGumbo.h\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n#import \"OGElement.h\"\n#import \"OGNode.h\"\n#import \"OGDocument.h\"\n#import \"OGText.h\"\n\n@interface ObjectiveGumbo : NSObject\n\n+(OGDocument*)parseDocumentWithData:(NSData*)data;\n+(OGDocument*)parseDocumentWithString:(NSString*)string;\n+(OGDocument*)parseDocumentWithUrl:(NSURL*)url;\n\n+(OGNode*)parseNodeWithData:(NSData*)data;\n+(OGNode*)parseNodeWithString:(NSString*)string;\n+(OGNode*)parseNodeWithUrl:(NSURL*)url;\n\n@end\n"
  },
  {
    "path": "Pod/Classes/Private/ObjectiveGumbo/ObjectiveGumbo.m",
    "content": "//\n//  ObjectiveGumbo.m\n//  ObjectiveGumbo\n//\n//  Copyright (c) 2013 Programming Thomas. All rights reserved.\n//\n\n#import \"ObjectiveGumbo.h\"\n\n@implementation ObjectiveGumbo\n\n+(OGNode*)parseNodeWithUrl:(NSURL *)url\n{\n    NSError * error;\n    NSString * string = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];\n    if (error == nil)\n    {\n        return [ObjectiveGumbo parseNodeWithString:string];\n    }\n    else\n    {\n        return nil;\n    }\n}\n\n+(OGNode*)parseNodeWithData:(NSData *)data\n{\n    NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n    return [ObjectiveGumbo parseNodeWithString:string];\n}\n\n+(OGNode*)parseNodeWithString:(NSString *)string\n{\n    GumboOutput * output = [ObjectiveGumbo outputFromString:string];\n    OGNode * node = [ObjectiveGumbo objectiveGumboNodeFromGumboNode:output->root];\n    gumbo_destroy_output(&kGumboDefaultOptions, output);\n    return node;\n}\n\n+(OGDocument*)parseDocumentWithUrl:(NSURL *)url\n{\n    NSError * error;\n    NSString * string = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];\n    if (error == nil)\n    {\n        return [ObjectiveGumbo parseDocumentWithString:string];\n    }\n    else\n    {\n        return nil;\n    }\n}\n\n+(OGDocument*)parseDocumentWithData:(NSData *)data\n{\n    NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n    return [ObjectiveGumbo parseDocumentWithString:string];\n}\n\n+(OGDocument*)parseDocumentWithString:(NSString *)string\n{\n    GumboOutput * output = [ObjectiveGumbo outputFromString:string];\n    OGDocument * node = (OGDocument*)[ObjectiveGumbo objectiveGumboNodeFromGumboNode:output->document];\n    gumbo_destroy_output(&kGumboDefaultOptions, output);\n    return node;\n}\n\n+(GumboOutput*)outputFromString:(NSString*)string\n{\n    GumboOutput * output = gumbo_parse(string.UTF8String);\n    return output;\n}\n\n+(OGNode*)objectiveGumboNodeFromGumboNode:(GumboNode*)gumboNode\n{\n    OGNode * node;\n    if (gumboNode->type == GUMBO_NODE_DOCUMENT)\n    {\n        OGDocument * documentNode = [[OGDocument alloc] init];\n        \n        const char * cName = gumboNode->v.document.name;\n        const char * cSystemIdentifier = gumboNode->v.document.system_identifier;\n        const char * cPublicIdentifier = gumboNode->v.document.public_identifier;\n        \n        documentNode.name = [[NSString alloc] initWithUTF8String:cName];\n        documentNode.systemIdentifier = [[NSString alloc] initWithUTF8String:cSystemIdentifier];\n        documentNode.publicIdentifier = [[NSString alloc] initWithUTF8String:cPublicIdentifier];\n        \n        GumboVector * cChildren = &gumboNode->v.document.children;\n        documentNode.children = [ObjectiveGumbo arrayOfObjectiveGumboNodesFromGumboVector:cChildren andParent:documentNode];\n        \n        node = documentNode;\n    }\n    else if (gumboNode->type == GUMBO_NODE_ELEMENT)\n    {\n        OGElement * elementNode = [[OGElement alloc] init];\n        \n        elementNode.tag = gumboNode->v.element.tag;\n        elementNode.tagNamespace = gumboNode->v.element.tag_namespace;\n        \n        NSMutableDictionary * attributes = [[NSMutableDictionary alloc] init];\n        \n        GumboVector * cAttributes = &gumboNode->v.element.attributes;\n        \n        for (int i = 0; i < cAttributes->length; i++)\n        {\n            GumboAttribute * cAttribute = (GumboAttribute*)cAttributes->data[i];\n            \n            const char * cName = cAttribute->name;\n            const char * cValue = cAttribute->value;\n            \n            NSString * name = [[NSString alloc] initWithUTF8String:cName];\n            NSString * value = [[NSString alloc] initWithUTF8String:cValue];\n            \n            [attributes setValue:value forKey:name];\n            \n            if ([name isEqualToString:@\"class\"])\n            {\n                elementNode.classes = [value componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n            }\n        }\n        \n        elementNode.attributes = attributes;\n        \n        GumboVector * cChildren = &gumboNode->v.element.children;\n        elementNode.children = [ObjectiveGumbo arrayOfObjectiveGumboNodesFromGumboVector:cChildren andParent:elementNode];\n        \n        node = elementNode;\n    }\n    else\n    {\n        const char * cText = gumboNode->v.text.text;\n        NSString * text = [[NSString alloc] initWithUTF8String:cText];\n        node = [[OGText alloc] initWithText:text andType:gumboNode->type];\n    }\n    \n    return node;\n}\n\n+(NSArray*)arrayOfObjectiveGumboNodesFromGumboVector:(GumboVector*)cChildren andParent:(OGNode*)parent\n{\n    NSMutableArray * children = [NSMutableArray new];\n    \n    for (int i = 0; i < cChildren->length; i++)\n    {\n        OGNode * childNode = [ObjectiveGumbo objectiveGumboNodeFromGumboNode:cChildren->data[i]];\n        childNode.parent = parent;\n        [children addObject:childNode];\n    }\n    \n    return children;\n}\n\n@end\n"
  },
  {
    "path": "README/Chinese.md",
    "content": "\n![image](https://raw.githubusercontent.com/zhuchaowe/EasyIOS/gh-pages/images/logo.png)\n\nEasyIOS Swift 2.0版本新鲜出炉！ \n=======\n\n[![Version](https://img.shields.io/cocoapods/v/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![License](https://img.shields.io/cocoapods/l/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![Platform](https://img.shields.io/cocoapods/p/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![qq](http://img.shields.io/badge/QQ%E7%BE%A4-340906744-green.svg)](http://shang.qq.com/wpa/qunwpa?idkey=562d002e275a8199081313b00580fb7111a4faf694216a239064d29f5238bc91)\n\n* [IOSX - EasyIOS官方论坛](http://www.iosx.me)\n* [EasyIOS-ObjC版本](https://github.com/zhuchaowe/EasyIOS)\n* [EasyIOS-Swift教程](http://zhuchaowe.gitbooks.io/easyios-swift/content/)\n\nQQ群:340906744\n\n## DEMO Video\n[![ScreenShot](http://g3.tdimg.com/0d239f40817111df0dfe941cbc6f9d5e/b0_2.jpg)](http://www.tudou.com/v/aWwPwUhdt5E/&rpid=6059352&resourceId=6059352_04_05_99/v.swf)\n\n## 新版特性\n\n* MVVM : `Model-View-ViewModel` 实现代码分离，分离ViewController中的大量逻辑代码，解决ViewController承担了过多角色而造成的代码质量低下。增加视图与模型的绑定特性。 \n* HTML To Native : 利用类似HTML的语言来对UI进行布局，简单易学，可重用\n* FlexBox Support:支持facebook的[flexbox实现](https://github.com/facebook/css-layout) ，可以很好的配合AutoLayout进行布局。\n\n![flexBox](flexbox.png)\n\n\n* DataBinding : 采用了第三方库`SwiftBond`,可以实现数据绑定操作，同样HTML里也可以进行数据绑定操作，识别标签是双大括号比如`{{title}}`\n* Reflect Cocoa Touch : 可以反射所有Cocoa Touch中UIKit的所有属性，目前实现了一部分，后面大家一起来维护，增加更多API\n* AutoLayout : 在HTML进行`Autolayout`布局，真的很简单！\n* Live Load : 在模拟器中运行app，在修改HTML之后进行保存，模拟器中会自动更新UI布局，不需要重新编译APP\n* Cryptographic HTML : 为了保证HTML代码的安全，我们提供了`AES Encryption`对HTML进行加密\n* URLManager : 我们可以利用URL来push或者present一个视图\n* Elegant PullToRefresh : 可以利用HTML轻松的添加下拉刷新和上拉加载控件\n\n## HTML To Native\n\n* UITableView With PullReflash\n* `align`,`margin` 来控制UIView的布局\n* `pull-to-refresh=\"handlePullRefresh.\" `,`infinite-scrolling=\"handleInfinite. PullFooter\"` 来添加下拉刷新和上拉加载\n* `handlePullRefresh.` handle the event by `func handlePullRefresh (tableView:UITableView)` ,you can define it by yourself.\n* `PullFooter` can load the custom PullReflashView \n\n```HTML\n<body>\n<div id=\"tableview\" align=\"64 0 0 0\" content-inset=\"{0,0,0,0}\" type=\"UITableView\"  estimated-row-height=\"100\"  separator-style=\"None\" pull-to-refresh=\"handlePullRefresh.\" infinite-scrolling=\"handleInfinite. PullFooter\">\n<div align=\"0 0 0 0\" type=\"cell\" id=\"cell\" >\n<img id=\"avatar\" align=\"10 10 -10 *\" clips-to-bounds=\"YES\" width=\"45\" height=\"45\" layer_corner-radius=\"5\" src=\"{{srcUrl}}\" />\n<span align=\"top:2 avatar;right:-10\" margin=\"left:12 avatar\"  font=\"15 system\" id=\"title\">{{title}}</span>\n<span align=\"bottom:0 avatar;right:-10\" margin=\"left:12 avatar\" font=\"13 system\" text-color=\"#ACACAC\" id=\"subTitle\" style=\"color:#ACACAC;\" link-style=\"color:green;\" >{{subTitle}}</span>\n</div>\n<div type=\"section\" id=\"bgView\" background-color=\"#F2F1F6\" >\n<span align=\"left:15;center-y:0\" font=\"14 system\">{{title}}</span>\n</div>\n</div>\n</body>\n```\n\n* UIScrollView With CSS\n* Use the CSS by `@` for example `@contentAlign`.\n\n```HTML\n<style>\n.contentAlign{\nedge:0 0 0 0;left:0 root;right:0 root;\n}\n.inputStyle{\nfont-size:15;color:#999999;\n}\n</style>\n<body>\n<div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n<div align=\"@contentAlign\">\n<img id=\"logo\" image=\"login-logo\" user-interaction-enabled=\"YES\" present=\"demo://login\" align=\"center-x:0;top:110;\"/>\n<div id=\"username\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:30 logo\" height=\"45\">\n<input class=\"userTextField\" id=\"userTextField\" align=\"edge:10 10 -10 -10;\" placeholder-style=\"@inputStyle\" keyboard-type=\"EmailAddress\" style=\"@inputStyle\" placeholder=\"上面的logo可以被点击\"/>\n</div>\n<div id=\"password\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:13 username\" height=\"45\">\n<input id=\"passwordTextField\" secure-text-entry=\"YES\" align=\"10 10 -10 -10\" placeholder=\"密码\" placeholder-style=\"@inputStyle\" style=\"@inputStyle\" />\n</div>\n<button id=\"submit\" style=\"color:white;font-size:20;\" background-color=\"#3FBCFB\" align=\"* 15 -10 -15\" margin=\"top:25 password\" height=\"45\" layer_corner-radius=\"8\" onEvent=\"touch-up-inside:login\">登陆</button>\n</div>\n</div>\n</body>\n```\n\n* HTML Label and reusable html\n* `@import(LabelHtml)` to import the `LabelHtml.xml` \n*  When span set `style=\"color:#ACACAC;font-size:18px;\"` node ,we can use the origin html inner the span tag.\n\n```HTML\n<style>\n<!--支持css 样式设置，html中利用@的方式进行调用-->\n.contentAlign{\nedge:0 0 0 0;left:0 root;right:0 root;\n}\n</style>\n\n<body>\n<div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n<div align=\"@contentAlign\">\n<!--span标签设置了style属性则启用富文本模式，span内部可以支持原生HTML的所有属性，具体请看LabelHtml.xml文件-->\n<span align=\"64 0 0 0\" style=\"color:#ACACAC;font-size:18px;\" link-style=\"color:green;\" number-of-lines=\"0\">\n<!--import the xml -->\n@import(LabelHtml)\n</span>\n</div>\n</div>\n</body>\n```\n\n\n* UICollectionView with FlowLayout\n\n```HTML\n<body>\n<div id=\"collectionView\" align=\"0 0 0 0\" type=\"UICollectionView\" flow-layout=\"scroll-direction:Vertical;item-size:{300,50};section-inset:{3,3,0,3};minimum-interitem-spacing:3;minimum-line-spacing:3\" content-inset=\"{64,0,0,0}\" background-color=\"white\" pull-to-refresh=\"handlePullRefresh.\" infinite-scrolling=\"handleInfinite.\">\n<div align=\"0 0 0 0\" type=\"cell\"  id=\"cell\"  background-color=\"red\">\n<span align=\"10 10 -10 -10\" font=\"10 system\">{{name}}</span>\n</div>\n</div>\n</body>\n```\n\n\n## MVVM\n\nThe MVVM based on the Swift binding framework [SwiftBond](https://github.com/SwiftBond/Bond)\n\nBond is a Swift binding framework that takes binding concept to a whole new level - boils it down to just one operator. It's simple, powerful, type-safe and multi-paradigm - just like Swift.\n\n\n## Usage\n\nTo run the example project, clone the repo, and run `pod install` from the Demo directory first.\n\n## Requirements\n\n* Swift\n* IOS8\n\n## Installation\n\nEasyIOS-Swift is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\nplatform :ios, '8.0'\nuse_frameworks!\npod 'EasyIOS-Swift', '~> 2.0'\n```\n\nimport the EasyIOS\n\n```swift\nimport EasyIOS\n```\n## Author\n\nzhuchao, zhuchao@iosx.me\n\n## License\n\nEasyIOS-Swift is available under the MIT license. See the LICENSE file for more info.\n"
  },
  {
    "path": "README.md",
    "content": "\n![image](https://raw.githubusercontent.com/zhuchaowe/EasyIOS/gh-pages/images/logo.png)\n\nEasyIOS For Swift 2.0\n=======\n\n[![Version](https://img.shields.io/cocoapods/v/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![License](https://img.shields.io/cocoapods/l/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![Platform](https://img.shields.io/cocoapods/p/EasyIOS-Swift.svg?style=flat)](http://cocoapods.org/pods/EasyIOS-Swift)\n[![qq](http://img.shields.io/badge/QQ%E7%BE%A4-340906744-green.svg)](http://shang.qq.com/wpa/qunwpa?idkey=562d002e275a8199081313b00580fb7111a4faf694216a239064d29f5238bc91)\n\n* [中文README](/README/Chinese.md)\n* [IOSX - EasyIOS Official Forum](https://www.iosx.me)\n* [EasyIOS-ObjC](https://github.com/zhuchaowe/EasyIOS)\n* [EasyIOS-Swift-Doc](http://swift.easyios.iosx.me)\n\n* EasyIOS官方qq群1群 :340906744(已满)\n* EasyIOS官方qq群2群 :495121980\n\n\n## DEMO Video\n[![ScreenShot](http://g3.tdimg.com/0d239f40817111df0dfe941cbc6f9d5e/b0_2.jpg)](http://www.tudou.com/v/aWwPwUhdt5E/&rpid=6059352&resourceId=6059352_04_05_99/v.swf)\n\n## Features\n\n* MVVM : `Model-View-ViewModel` inspired by [Functional Reactive Programming](http://en.wikipedia.org/wiki/Functional_reactive_programming) \n* HTML To Native : Transform HTML&CSS to Native Control.\n* FlexBox Support:It can uses Facebook's [flexbox implementation](https://github.com/facebook/css-layout) ，and work well with AutoLayout。\n\n![flexBox](README/flexbox.png)\n\n* JavaScript and Native Bridge: We can declare the js function in native and call the js function in html\n* DataBinding : We can use the SwiftBond to Bind the data via swift,and use the EZViewModel to Bind the data via html.example `{{title}}`\n* Reflect Cocoa Touch : Reflect all the Cocoa Touch Api ,we can use the Cocoa Touch Api via HTML \n* AutoLayout : The HTML layout based on the `AutoLayout`\n* Live Load : Edit the HTML and the view in smulator will update automaticly without rebuild your app\n* Cryptographic HTML : To make the HTML be safety,we provide the `AES Encryption` to encrypt the HTML\n* URLManager : Push or Present the Controller by the custom URL \n* Elegant PullToRefresh : Add  PullToRefresh or InfiniteScrolling by HTML\n\n## HTML To Native\n\n* UITableView With PullReflash\n    * `align`,`margin` to control the AutoLayout of the UIView\n    * `pull-to-refresh=\"handlePullRefresh.\" `,`infinite-scrolling=\"handleInfinite. PullFooter\"` to add the PullRefresh or InfiniteScrolling .\n    * `handlePullRefresh.` handle the event by `func handlePullRefresh (tableView:UITableView)` ,you can define it by yourself.\n    * `PullFooter` can load the custom PullReflashView \n\n```HTML\n<body>\n    <div id=\"tableview\" align=\"64 0 0 0\" content-inset=\"{0,0,0,0}\" type=\"UITableView\"  estimated-row-height=\"100\"  separator-style=\"None\" pull-to-refresh=\"handlePullRefresh()\" infinite-scrolling=\"handleInfinite() PullFooter\">\n        <div align=\"0 0 0 0\" type=\"cell\" id=\"cell\" ontap-bind=\"um.push('{{link}}',true)\" >\n            <img id=\"avatar\" align=\"10 10 -10 *\" clips-to-bounds=\"YES\" width=\"45\" height=\"45\" layer_corner-radius=\"5\" src=\"{{srcUrl}}\" />\n            <span align=\"top:2 avatar;right:-10\" margin=\"left:12 avatar\"  font=\"15 system\" id=\"title\">{{title}}</span>\n            <span align=\"bottom:0 avatar;right:-10\" margin=\"left:12 avatar\" font=\"13 system\" text-color=\"#ACACAC\" id=\"subTitle\" style=\"color:#ACACAC;\" link-style=\"color:green;\" >{{subTitle}}</span>\n        </div>\n        \n        <div type=\"section\" id=\"bgView\" background-color=\"#F2F1F6\" >\n            <span align=\"left:15;center-y:0\" font=\"14 system\">{{title}}</span>\n        </div>\n    </div>\n</body>\n```\n\n* UIScrollView With CSS and JS\n    * Use the CSS by `@` for example `@contentAlign`.\n   \n```HTML\n<style>\n    .contentAlign{\n        edge:0 0 0 0;\n    left:0 root;\n        right:0 root;\n    }\n    .inputStyle{\n        font-size:15;color:#999999;\n    }\n</style>\n<body>\n    <div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n        <div align=\"@contentAlign\">\n            <img id=\"logo\" image=\"login-logo\" user-interaction-enabled=\"YES\" ontap=\"tap()\" align=\"center-x:0;top:110;\"/>\n            <div id=\"username\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:30 logo\" height=\"45\">\n                <input class=\"userTextField\" id=\"userTextField\" align=\"edge:10 10 -10 -10;\" placeholder-style=\"@inputStyle\" keyboard-type=\"EmailAddress\" style=\"@inputStyle\" placeholder=\"上面的logo可以被点击\"/>\n            </div>\n            <div id=\"password\" layer_corner-radius=\"8\" background-color=\"white\" align=\"* 15 * -15\" margin=\"top:13 username\" height=\"45\">\n                <input id=\"passwordTextField\" secure-text-entry=\"YES\" align=\"10 10 -10 -10\" placeholder=\"密码\" placeholder-style=\"@inputStyle\" style=\"@inputStyle\" />\n            </div>\n            <button id=\"submit\" style=\"color:white;font-size:20;\" background-color=\"#3FBCFB\" align=\"* 15 -10 -15\" margin=\"top:25 password\" height=\"45\" layer_corner-radius=\"8\" onEvent=\"touch-up-inside:login()\">Login</button>\n        </div>\n    </div>\n</body>\n\n<script>\n    function tap(){\n        um.present('demo://login',true);\n    };\n    \n    function login(){\n        var password = document.getElementById(\"passwordTextField\");\n        password.attrs({\n            placeholder:\"hello\",\n            secureTextEntry:\"NO\"\n        });\n        \n<!--        var logo = document.getElementById(\"logo\")-->\n<!--        password.callWithObject(\"test:\",logo);-->\n\n        console.log(password.val(\"text\"));\n    }\n</script>\n```\n\n* HTML Label and reusable html\n    * `@import(LabelHtml)` to import the `LabelHtml.xml` \n    *  When span set `style=\"color:#ACACAC;font-size:18px;\"` node ,we can use the origin html inner the span tag.\n```HTML\n<style>\n    <!--支持css 样式设置，html中利用@的方式进行调用-->\n    .contentAlign{\n        edge:0 0 0 0;left:0 root;right:0 root;\n    }\n</style>\n\n<body>\n    <div align=\"0 0 0 0\" type=\"UIScrollView\" background-color=\"#F3F3F3\">\n        <div align=\"@contentAlign\">\n            <!--span标签设置了style属性则启用富文本模式，span内部可以支持原生HTML的所有属性，具体请看LabelHtml.xml文件-->\n            <span align=\"64 0 0 0\" style=\"color:#ACACAC;font-size:18px;\" link-style=\"color:green;\" number-of-lines=\"0\">\n                <!--import the xml -->\n                    @import(LabelHtml)\n            </span>\n        </div>\n    </div>\n</body>\n```\n\n* UICollectionView with FlowLayout\n\n```HTML\n<body>\n    <div id=\"collectionView\" align=\"0 0 0 0\" type=\"UICollectionView\" flow-layout=\"scroll-direction:Vertical;item-size:{300,50};section-inset:{3,3,0,3};minimum-interitem-spacing:3;minimum-line-spacing:3\" content-inset=\"{64,0,0,0}\" background-color=\"white\" pull-to-refresh=\"handlePullRefresh()\" infinite-scrolling=\"handleInfinite()\">\n        <div align=\"0 0 0 0\" type=\"cell\"  id=\"cell\"  background-color=\"red\">\n            <span align=\"10 10 -10 -10\" font=\"10 system\">{{name}}</span>\n        </div>\n    </div>\n</body>\n```\n\n## Declare JS funciton By Swfit\n\n```swift\n        //定义一个可以给JS调用的下拉刷新回调方法handlePullRefresh()\n        define(\"handlePullRefresh\"){\n            let delayTime = dispatch_time(DISPATCH_TIME_NOW,\n                Int64(3.0 * Double(NSEC_PER_SEC)))\n            dispatch_after(delayTime, dispatch_get_main_queue()) {\n                tableView?.pullToRefreshView?.stopAnimating()\n            }\n        }\n```\n\n## MVVM\n\nThe MVVM based on the Swift binding framework [SwiftBond](https://github.com/SwiftBond/Bond)\n\nBond is a Swift binding framework that takes binding concept to a whole new level - boils it down to just one operator. It's simple, powerful, type-safe and multi-paradigm - just like Swift.\n\n\n## [EasyCoreData](https://github.com/EasyIOS/EasyCoreData)(1.0.1)\n\n\n## Usage\n\nTo run the example project, clone the repo, and run `pod install` from the Demo directory first.\n\n## Requirements\n\n* Swift\n* IOS8\n\n## Installation\n\nEasyIOS-Swift is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\nplatform :ios, '8.0'\nuse_frameworks!\npod 'EasyIOS-Swift', '~> 2.0'\n```\n\nimport the EasyIOS\n\n```swift\nimport EasyIOS\n```\n## Author\n\nzhuchao, zhuchao@iosx.me\n\n## License\n\nEasyIOS-Swift is available under the MIT license. See the LICENSE file for more info.\n"
  }
]