[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbin/\nbuild/\ndevelop-eggs/\ndist/\neggs/\n#lib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.cache\nnosetests.xml\ncoverage.xml\n\n# Translations\n*.mo\n\n# Mr Developer\n.mr.developer.cfg\n.project\n.pydevproject\n\n# Rope\n.ropeproject\n\n# Django stuff:\n*.log\n*.pot\n\n# Sphinx documentation\ndocs/_build/\n\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n\n# CocoaPods\n#\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# Pods/\n\n\ntesting_database.db\nsecret.py\ncollected_static\nnewrelic.ini\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Ethan Lowman\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 all\ncopies 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 THE\nSOFTWARE."
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/APIClient.swift",
    "content": "\n//\n//  APIClient.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nclass APIClient: NSObject {\n    var prefs = PreferencesManager()\n    \n    var apiRoot: String {\n    get {\n        return \"https://api.\" + prefs.hostname\n    }\n    }\n    \n    var authToken: String\n    \n    override init() {\n        if let token = KeychainService.loadToken() {\n            authToken = token as String\n        } else {\n            authToken = \"\"\n        }\n        \n        super.init()\n    }\n    \n    \n    func request(uri: NSString, withAuth: Bool) -> NSMutableURLRequest {\n        let r = NSMutableURLRequest(URL: NSURL(string: apiRoot + (uri as String))!)\n        if withAuth {\n            r.setValue(\"Token \\(authToken)\", forHTTPHeaderField: \"Authorization\")\n        }\n        r.timeoutInterval = 10.0\n        return r\n    }\n    \n    \n    func getTokenForUsername(username: NSString, password: NSString, successCallback: ((NSString!) -> Void)?, errorCallback: (() -> Void)?) {\n        let req = request(\"/api-token-auth\", withAuth: false)\n        req.setValue(\"application/json; charset=utf-8\", forHTTPHeaderField: \"Content-Type\")\n        req.HTTPMethod = \"POST\"\n        \n        let requestJSON = JSON([\n            \"username\": username,\n            \"password\": password\n            ])\n        \n        req.HTTPBody = requestJSON.rawString()!.dataUsingEncoding(NSUTF8StringEncoding)\n        NSURLConnection.sendAsynchronousRequest(req, queue: NSOperationQueue.mainQueue()) {(response, data, error) in\n            guard let data = data where error == nil else {\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n            \n            let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)\n            var responseJSON = JSON(data: data)\n            \n            if let token = responseJSON[\"token\"].string {\n                if (successCallback != nil) {\n                    self.authToken = token\n                    successCallback!(token)\n\n                }\n            } else  {\n                print(responseString)\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n        \n        }\n    }\n    \n    \n    func addFile(fileData: NSData, filename: NSString, successCallback: ((NSURL!) -> Void)?, errorCallback: (() -> Void)?) {\n        let req = request(\"/media/add_file\", withAuth: true)\n        req.HTTPMethod = \"POST\"\n        \n        let boundary = \"gc0p4Jq0M2Yt08jU534c0pgc0p4Jq0M2Yt08jU534c0p\"\n        let contentType = \"multipart/form-data; boundary=\\(boundary)\"\n        req.setValue(contentType, forHTTPHeaderField: \"Content-Type\")\n        \n        let postData = NSMutableData()\n        postData.appendData(\"\\r\\n--\\(boundary)\\r\\n\".dataUsingEncoding(NSUTF8StringEncoding)!)\n        postData.appendData(\"Content-Disposition: form-data; name=\\\"file\\\"; filename=\\\"\\(filename)\\\"\\r\\n\".dataUsingEncoding(NSUTF8StringEncoding)!)\n        postData.appendData(\"Content-Type: application/octet-stream\\r\\n\\r\\n\".dataUsingEncoding(NSUTF8StringEncoding)!)\n        postData.appendData(NSData(data: fileData))\n        postData.appendData(\"\\r\\n--\\(boundary)--\\r\\n\".dataUsingEncoding(NSUTF8StringEncoding)!)\n        \n        req.HTTPBody = postData\n        \n        NSURLConnection.sendAsynchronousRequest(req, queue: NSOperationQueue.mainQueue()) {(response, data, error) in\n            guard let data = data where error == nil else {\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n            \n            let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)\n            var responseJSON = JSON(data: data)\n            \n            if let shareURL = responseJSON[\"share_url\"].URL {\n                if (successCallback != nil) {\n                    successCallback!(shareURL)\n                }\n            } else  {\n                print(responseString)\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n\n        }\n    }\n    \n    func addLink(link: NSURL, successCallback: ((NSURL!) -> Void)?, errorCallback: (() -> Void)?) {\n        let req = request(\"/media/add_link\", withAuth: true)\n        req.setValue(\"application/json; charset=utf-8\", forHTTPHeaderField: \"Content-Type\")\n        req.HTTPMethod = \"POST\"\n        \n        let requestJSON = JSON([\n            \"target_url\": link.absoluteString\n            ])\n        \n        req.HTTPBody = requestJSON.rawString()!.dataUsingEncoding(NSUTF8StringEncoding)\n        NSURLConnection.sendAsynchronousRequest(req, queue: NSOperationQueue.mainQueue()) {(response, data, error) in\n            guard let data = data where error == nil else {\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n            \n            let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)\n            var responseJSON = JSON(data: data)\n            \n            if let shareURL = responseJSON[\"share_url\"].URL {\n                if (successCallback != nil) {\n                    successCallback!(shareURL)\n                }\n            } else  {\n                print(responseString)\n                if (errorCallback != nil) {\n                    errorCallback!()\n                }\n                return\n            }\n\n            \n        }\n    }\n\n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nclass AppDelegate: NSObject, NSApplicationDelegate, NSMetadataQueryDelegate {\n    \n    var statusView = StatusItemView()\n    var prefs = PreferencesManager()\n    var api = APIClient()\n    var sw: ScreenshotWatcher?\n    \n    override init() {\n        super.init()\n    }\n    \n    func applicationDidFinishLaunching(aNotification: NSNotification) {\n        sw = ScreenshotWatcher(uploadFileCallback: uploadFile);\n        sw!.startWatchingPath(screenCaptureLocation())\n    }\n    \n    func screenCaptureLocation() -> String {\n        let screenCapturePrefs: NSDictionary? = NSUserDefaults.standardUserDefaults().persistentDomainForName(\"com.apple.screencapture\")\n        \n        let location: String? = screenCapturePrefs?.valueForKey(\"location\")?.stringByExpandingTildeInPath as String?\n        \n        if let loc = location {\n            return loc.hasSuffix(\"/\") ? loc : (loc + \"/\")\n        }\n        \n        return (\"~/Desktop\" as NSString).stringByExpandingTildeInPath + \"/\"\n    }\n    \n    func uploadFile(fileData: NSData!, filename: String!) {\n        print(filename);\n//        NSMetadataItem *metadata = NSMetadataItem(URL: filename)\n//        BOOL isScreenshot = [[metadata valueForAttribute:@\"kMDItemIsScreenCapture\"] integerValue] == 1;\n        statusView.status = .Working\n        api.addFile(fileData, filename: filename, successCallback: {(shareURL: NSURL!) -> Void in\n            let pb = NSPasteboard.generalPasteboard()\n            pb.clearContents()\n            pb.writeObjects([shareURL.absoluteString])\n            self.statusView.status = .Success\n            }, errorCallback: {() -> Void in\n                print(\"Error uploading file\")\n                self.statusView.status = .Error\n            })\n    }\n    \n    func uploadLink(link: NSURL) {\n        statusView.status = .Working\n        api.addLink(link, successCallback: {(shareURL: NSURL!) -> Void in\n            let pb = NSPasteboard.generalPasteboard()\n            pb.clearContents()\n            pb.writeObjects([shareURL.absoluteString])\n            self.statusView.status = .Success\n            }, errorCallback: {() -> Void in\n                print(\"Error uploading link\")\n                self.statusView.status = .Error\n            })\n        \n    }\n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"6254\" systemVersion=\"14C109\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"6254\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModule=\"Nimbus\" customModuleProvider=\"target\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"TcC-0d-qzF\">\n            <items>\n                <menuItem title=\"Nimbus\" id=\"j6L-po-JZS\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Nimbus\" systemMenu=\"apple\" id=\"18D-nT-g35\">\n                        <items>\n                            <menuItem title=\"About Nimbus\" id=\"ie0-vZ-qQE\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"orderFrontStandardAboutPanel:\" target=\"-1\" id=\"OLT-T6-eIh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"Lgi-uc-Ggn\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"wbL-nE-kQl\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"23F-jQ-kQG\"/>\n                            <menuItem title=\"Services\" id=\"IcQ-XN-bs3\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"CP7-iw-wGz\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"nZr-cS-3Tp\"/>\n                            <menuItem title=\"Hide Nimbus\" keyEquivalent=\"h\" id=\"rPB-nS-l2J\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"TUP-iv-CoE\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"nH8-9K-WRu\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"5Vt-hm-Low\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"oIv-Yx-hIT\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"63A-lT-6ua\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"pk8-av-w9O\"/>\n                            <menuItem title=\"Quit Nimbus\" keyEquivalent=\"q\" id=\"yCv-S3-Q4L\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"o86-pe-rOt\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"File\" id=\"baT-qG-pra\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"File\" id=\"weq-jU-nIX\">\n                        <items>\n                            <menuItem title=\"New\" keyEquivalent=\"n\" id=\"5DU-gI-c3T\">\n                                <connections>\n                                    <action selector=\"newDocument:\" target=\"-1\" id=\"N50-bd-Cgm\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"wtK-vV-wP1\">\n                                <connections>\n                                    <action selector=\"openDocument:\" target=\"-1\" id=\"Ovf-SJ-Svn\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open Recent\" id=\"ISk-fF-uwZ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"qan-vU-Fh4\">\n                                    <items>\n                                        <menuItem title=\"Clear Menu\" id=\"yPE-fU-NZb\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"clearRecentDocuments:\" target=\"-1\" id=\"aaW-Jh-K6L\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"R9j-gD-LXw\"/>\n                            <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"JBQ-fE-1zH\">\n                                <connections>\n                                    <action selector=\"performClose:\" target=\"-1\" id=\"hk9-H8-tLD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"dEM-te-Zmm\">\n                                <connections>\n                                    <action selector=\"saveDocument:\" target=\"-1\" id=\"DbK-WV-kFw\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"cA0-DT-V0B\">\n                                <connections>\n                                    <action selector=\"saveDocumentAs:\" target=\"-1\" id=\"G4H-U3-QgM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Revert to Saved\" id=\"AbR-nh-STx\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"revertDocumentToSaved:\" target=\"-1\" id=\"Z7W-Dy-oGX\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"gmr-39-ik0\"/>\n                            <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"zCv-D3-Oed\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"runPageLayout:\" target=\"-1\" id=\"f6F-by-eak\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"0up-Wo-BCZ\">\n                                <connections>\n                                    <action selector=\"print:\" target=\"-1\" id=\"o5D-gI-3tZ\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"DyV-jE-06b\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"qgZ-Nn-emE\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"fmJ-Sh-KFq\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"dhq-NH-kMT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"d3Q-T5-OU8\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"0Ea-mD-VTd\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"168-9g-WaY\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"181-ul-Cau\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"bDd-4z-sB8\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"P72-WL-Id7\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"LHS-H6-B8m\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"7lA-qr-RZz\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"I3E-a3-yfA\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"VH9-Yb-tdq\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"pasteAsPlainText:\" target=\"-1\" id=\"uXH-K8-c7j\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"97h-hS-W7v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"kCg-S1-rx3\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"7Ue-Rt-i6q\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"71A-Ji-sWi\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"UPl-Wn-clw\"/>\n                            <menuItem title=\"Find\" id=\"CKG-4G-sTK\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"QNB-no-pUC\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"nIp-d2-7Zh\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"lk6-Ij-CCh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"LcJ-El-Z1I\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"OKz-8m-vYD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"ye3-hv-uah\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"UGh-5H-FfU\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"4Ml-Pq-s7M\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cTh-EM-FUh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"v9q-nL-Meb\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"9GM-K8-lyI\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"lp0-ZI-HEt\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"bqp-Bs-Kqv\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Spelling and Grammar\" id=\"QaM-Gt-qxC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"XPN-Gf-Ub5\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"xZR-tm-YGO\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"r0Q-e0-GUS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"0NZ-hG-hjO\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"q6N-Id-SQM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"ePY-aV-eFd\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"ehv-Wy-fN7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"2gV-Vb-OEy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"0xZ-Ia-9Il\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"636-D3-CH0\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"XFQ-kR-keS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"TgM-rk-AoE\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" id=\"fpq-mx-GFH\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"hpB-LQ-Otm\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"aD0-B7-Qm6\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"ZMU-mB-P5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"fZA-Rd-nGB\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"DhQ-aZ-cnf\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"yqX-YV-7s5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"CFM-ml-rzh\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"MU1-oc-V6i\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"Rwy-4C-iXw\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"MXO-Ph-LaR\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"ZU5-Ff-QzG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"u8e-8t-zZh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"W5p-Hr-fyj\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"cyc-P9-hEh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"hse-yi-kCP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"O4g-ls-Fq1\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"unk-O2-a49\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"UEd-Wj-7xh\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"rHW-f0-qPE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"o6b-B3-ltZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"JW2-j7-JhF\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"kzy-JU-2nH\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"Fk4-Z6-v4Q\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"pGg-wR-daE\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" id=\"a0M-EM-ed9\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"aKc-Ca-gti\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"7re-r3-Pro\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"mp3-vG-uGU\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"OId-NR-wtt\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"gMu-NU-3xC\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Format\" id=\"G1Y-5b-SwM\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Format\" id=\"fcC-AB-A9D\">\n                        <items>\n                            <menuItem title=\"Font\" id=\"UrC-u6-ETY\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"tHh-IG-GJy\">\n                                    <items>\n                                        <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Mfr-5K-sAH\"/>\n                                        <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"2Ti-u0-RUI\"/>\n                                        <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"aZg-bT-62m\"/>\n                                        <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"Qr0-xL-Gtm\">\n                                            <connections>\n                                                <action selector=\"underline:\" target=\"-1\" id=\"9Pq-KC-lhY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"tig-KT-Cyx\"/>\n                                        <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"wfQ-pF-sGc\"/>\n                                        <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"o0g-b5-1TE\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"e3c-JQ-Trj\"/>\n                                        <menuItem title=\"Kern\" id=\"9kQ-fs-ysx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Kern\" id=\"d3U-kC-afj\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"N4a-9F-H48\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useStandardKerning:\" target=\"-1\" id=\"mWI-fb-9pd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use None\" id=\"3qY-XD-V1H\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"turnOffKerning:\" target=\"-1\" id=\"oTs-bT-o4k\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Tighten\" id=\"Vf5-aq-iBh\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"tightenKerning:\" target=\"-1\" id=\"Gmo-8O-s1w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Loosen\" id=\"fqw-RD-GHH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"loosenKerning:\" target=\"-1\" id=\"Xnt-e1-Y30\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Ligatures\" id=\"eWt-hD-tJX\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Ligatures\" id=\"BcY-cy-1Gg\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"0jG-MY-iEg\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useStandardLigatures:\" target=\"-1\" id=\"Uag-2h-94f\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use None\" id=\"iKs-eL-0pH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"turnOffLigatures:\" target=\"-1\" id=\"kvi-EJ-8kX\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use All\" id=\"7jE-bf-gh7\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"useAllLigatures:\" target=\"-1\" id=\"oE0-18-6aq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Baseline\" id=\"ecg-2N-yBT\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Baseline\" id=\"CfO-VG-LUQ\">\n                                                <items>\n                                                    <menuItem title=\"Use Default\" id=\"ecD-ro-3Lw\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"unscript:\" target=\"-1\" id=\"gRE-pT-XCg\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Superscript\" id=\"pDe-mH-2rr\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"superscript:\" target=\"-1\" id=\"BmN-pQ-6rJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Subscript\" id=\"Cgy-US-QV5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"subscript:\" target=\"-1\" id=\"qY7-KZ-prE\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Raise\" id=\"97t-JI-Vci\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"raiseBaseline:\" target=\"-1\" id=\"AEH-6D-Ze2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Lower\" id=\"E8f-c5-eLD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowerBaseline:\" target=\"-1\" id=\"L11-ur-xME\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"Pqf-Ac-0aL\"/>\n                                        <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"wiN-0Q-O1v\">\n                                            <connections>\n                                                <action selector=\"orderFrontColorPanel:\" target=\"-1\" id=\"ozg-52-WS2\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"3tS-37-gSL\"/>\n                                        <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"W5h-jb-HUs\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"copyFont:\" target=\"-1\" id=\"70y-2X-DvH\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"ad9-Oz-MDe\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteFont:\" target=\"-1\" id=\"e19-oa-chp\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Text\" id=\"OIj-gh-fhI\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Text\" id=\"Qro-5B-JFR\">\n                                    <items>\n                                        <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"dfU-RW-Wuk\">\n                                            <connections>\n                                                <action selector=\"alignLeft:\" target=\"-1\" id=\"6s6-M5-3dB\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"BiB-dD-IEF\">\n                                            <connections>\n                                                <action selector=\"alignCenter:\" target=\"-1\" id=\"Ias-ew-2WS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Justify\" id=\"Vx6-Lf-dBt\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"alignJustified:\" target=\"-1\" id=\"Cnd-95-vjd\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"Iaa-As-jVR\">\n                                            <connections>\n                                                <action selector=\"alignRight:\" target=\"-1\" id=\"QS8-5b-Yp9\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"yIX-7f-18k\"/>\n                                        <menuItem title=\"Writing Direction\" id=\"Iwb-Am-7cv\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Writing Direction\" id=\"6xl-tS-H9e\">\n                                                <items>\n                                                    <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"dhh-aS-WGH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                    </menuItem>\n                                                    <menuItem id=\"cqw-Km-0ZA\">\n                                                        <string key=\"title\">\tDefault</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionNatural:\" target=\"-1\" id=\"hTj-h3-Dbw\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"0AN-EA-sbS\">\n                                                        <string key=\"title\">\tLeft to Right</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"-1\" id=\"PvD-3f-fLh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"Urq-dN-eDm\">\n                                                        <string key=\"title\">\tRight to Left</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"-1\" id=\"wCK-bQ-kt8\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"rk9-8B-hH0\"/>\n                                                    <menuItem title=\"Selection\" enabled=\"NO\" id=\"5oD-c2-YaH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                    </menuItem>\n                                                    <menuItem id=\"TwC-9c-uu6\">\n                                                        <string key=\"title\">\tDefault</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionNatural:\" target=\"-1\" id=\"CJT-Ti-Pcj\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"ei1-Nz-VaB\">\n                                                        <string key=\"title\">\tLeft to Right</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"-1\" id=\"1aT-ds-P4d\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem id=\"gTl-D2-5nm\">\n                                                        <string key=\"title\">\tRight to Left</string>\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"-1\" id=\"iCN-qD-TNB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"v6h-Km-CDW\"/>\n                                        <menuItem title=\"Show Ruler\" id=\"KMn-rP-pjX\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleRuler:\" target=\"-1\" id=\"tbU-4g-dIN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"9PU-a9-pa5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"copyRuler:\" target=\"-1\" id=\"BON-cn-8km\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"Psd-Hu-DQ2\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteRuler:\" target=\"-1\" id=\"olo-DZ-QLd\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"View\" id=\"9e9-vl-rMp\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"Ufi-lb-m6J\">\n                        <items>\n                            <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"9uk-f8-cFm\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleToolbarShown:\" target=\"-1\" id=\"zlm-Zt-usB\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Customize Toolbar…\" id=\"WXO-Z7-zt9\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"runToolbarCustomizationPalette:\" target=\"-1\" id=\"VfH-K3-KqQ\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"V5i-yJ-hYY\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"qbq-Fv-HFU\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"iBF-A1-fu7\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"vc3-Wg-Bp8\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"N6d-4e-0TH\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"fKw-5N-G5L\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"0HB-oG-tGt\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"9gO-FD-Hbg\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"E96-rY-gTU\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"JsN-sb-abl\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"a0m-He-GWY\">\n                        <items>\n                            <menuItem title=\"Nimbus Help\" keyEquivalent=\"?\" id=\"bBd-XM-WKa\">\n                                <connections>\n                                    <action selector=\"showHelp:\" target=\"-1\" id=\"NMF-47-5fi\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n            </items>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_16x16.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_16x16@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_32x32.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_32x32@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_128x128.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_128x128@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_256x256.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_256x256@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_512x512.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"icon_512x512@2x.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/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>CFBundleIconFile</key>\n\t<string></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>LSMinimumSystemVersion</key>\n\t<string>${MACOSX_DEPLOYMENT_TARGET}</string>\n\t<key>LSUIElement</key>\n\t<true/>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2014 Ethanal. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/KeychainManager.swift",
    "content": "\nimport Cocoa\nimport Security\n\n// Identifiers\nlet serviceIdentifier = \"Nimbus\"\nlet userAccount = \"authenticatedUser\"\nlet accessGroup = \"Nimbus\"\n\n// Arguments for the keychain queries\nlet kSecClassValue = NSString(format: kSecClass)\nlet kSecAttrAccountValue = NSString(format: kSecAttrAccount)\nlet kSecValueDataValue = NSString(format: kSecValueData)\nlet kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword)\nlet kSecAttrServiceValue = NSString(format: kSecAttrService)\nlet kSecMatchLimitValue = NSString(format: kSecMatchLimit)\nlet kSecReturnDataValue = NSString(format: kSecReturnData)\nlet kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne)\n\nclass KeychainService: NSObject {\n    \n    /**\n    * Exposed methods to perform queries.\n    * Note: feel free to play around with the arguments\n    * for these if you want to be able to customise the\n    * service identifier, user accounts, access groups, etc.\n    */\n    internal class func saveToken(token: NSString) {\n        self.save(serviceIdentifier, data: token)\n    }\n    \n    internal class func loadToken() -> NSString? {\n        let token = self.load(serviceIdentifier)\n        \n        return token\n    }\n    \n    /**\n    * Internal methods for querying the keychain.\n    */\n    private class func save(service: NSString, data: NSString) {\n        let dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!\n        \n        // Instantiate a new default keychain query\n        let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])\n        \n        // Delete any existing items\n        SecItemDelete(keychainQuery as CFDictionaryRef)\n        \n        // Add the new keychain item\n        let status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)\n        if status != errSecSuccess {\n            print(\"Error saving to keychain\")\n        }\n    }\n    \n    private class func load(service: NSString) -> NSString? {\n        // Instantiate a new default keychain query\n        // Tell the query to return a result\n        // Limit our results to one item\n        let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])\n        \n        var extractedData : AnyObject?\n        \n        // Search for the keychain items\n        let status: OSStatus = SecItemCopyMatching(keychainQuery, &extractedData)\n        \n        var contentsOfKeychain: NSString?\n        \n        if let retrievedData = extractedData as? NSData where status == errSecSuccess {\n            // Convert the data retrieved from the keychain into a string\n            contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)\n        } else {\n            print(\"Nothing was retrieved from the keychain. Status code \\(status)\")\n        }\n        \n        return contentsOfKeychain\n    }\n}"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/Nimbus-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n\n#import \"ScreenshotWatcher.h\""
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/PreferencesManager.swift",
    "content": "//\n//  PreferencesManager.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nclass PreferencesManager: NSObject {\n    var prefs = NSUserDefaults.standardUserDefaults()\n    \n    var hostname: String {\n        get {\n            if let val = prefs.stringForKey(\"hostname\") as String! {\n                return val\n            }\n            return \"example.com\"\n        }\n        set {\n            prefs.setObject(newValue, forKey: \"hostname\")\n        }\n    }\n    \n    var loggedIn: Bool {\n        get {\n            if let val = prefs.boolForKey(\"loggedIn\") as Bool! {\n                return val\n            }\n            return false\n        }\n        set {\n            prefs.setBool(newValue, forKey: \"loggedIn\")\n        }\n    }\n    \n    var username: String {\n        get {\n            if let val = prefs.stringForKey(\"username\") as String! {\n                return val\n            }\n            return \"\"\n        }\n        set {\n            prefs.setValue(newValue, forKey: \"username\")\n        }\n    }\n    \n    \n    var uploadScreenshots: Int {\n        get {\n            if let val = prefs.integerForKey(\"uploadScreenshots\") as Int! {\n                return val\n            }\n            return 1\n        }\n        set {\n            prefs.setInteger(newValue, forKey: \"uploadScreenshots\")\n        }\n    }\n    \n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/PreferencesWindowController.swift",
    "content": "//\n//  PreferencesWindowController.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nclass PreferencesWindowController: NSWindowController, NSWindowDelegate {\n    var prefs = PreferencesManager()\n    var api = APIClient()\n    \n    @IBOutlet weak var hostnameField: NSTextField?\n    @IBOutlet weak var usernameField: NSTextField?\n    @IBOutlet weak var passwordField: NSSecureTextField?\n    @IBOutlet weak var uploadScreenshotsCheckbox: NSButton?\n    @IBOutlet weak var accountActionButton: NSButton?\n    @IBOutlet weak var hostnameLabel: NSTextField?\n    @IBOutlet weak var usernameLabel: NSTextField?\n    @IBOutlet weak var passwordLabel: NSTextField?\n    \n    @IBOutlet var appMenu: NSMenu!\n    \n    override func windowDidLoad() {\n        super.windowDidLoad()\n        updateAccountUI()\n    }\n    \n    @IBAction func uploadScreenshotsCheckboxPressed(sender: AnyObject) {\n        prefs.uploadScreenshots = uploadScreenshotsCheckbox!.state\n    }\n\n    @IBAction func accountActionButtonPressed(sender: AnyObject) {\n        if !prefs.loggedIn {\n            prefs.hostname = hostnameField!.stringValue\n            prefs.username = usernameField!.stringValue\n            \n            api.getTokenForUsername(usernameField!.stringValue, password: passwordField!.stringValue, successCallback: {(token: NSString!) -> Void in\n                    self.prefs.loggedIn = true\n                    KeychainService.saveToken(token)\n\n                    self.updateAccountUI()\n                }, errorCallback: {() -> Void in\n                    let alert = NSAlert()\n                    alert.messageText = \"Unable to login with provided credentials\"\n                    alert.runModal()\n                })\n            \n            \n        } else {\n            prefs.loggedIn = false\n            updateAccountUI()\n        }\n        \n        \n    }\n    \n    func updateAccountUI() {\n        uploadScreenshotsCheckbox!.state = prefs.uploadScreenshots\n\n        if prefs.loggedIn {\n            accountActionButton!.title = \"Logout\"\n            \n            hostnameField!.hidden = true\n            hostnameLabel!.hidden = false\n            hostnameLabel!.stringValue = prefs.hostname\n            \n            usernameField!.hidden = true\n            usernameLabel!.hidden = false\n            usernameLabel!.stringValue = prefs.username\n            \n            passwordField!.hidden = true\n            passwordLabel!.hidden = true\n            \n        } else {\n            accountActionButton!.title = \"Login\"\n            \n            hostnameField!.hidden = false\n            hostnameField!.stringValue = \"\"\n            hostnameLabel!.hidden = true\n            \n            usernameField!.hidden = false\n            usernameField!.stringValue = \"\"\n            usernameLabel!.hidden = true\n            \n            passwordField!.hidden = false\n            passwordField!.stringValue = \"\"\n            passwordLabel!.hidden = false\n        }\n    }\n    \n    \n    \n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/PreferencesWindowController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"6254\" systemVersion=\"14C109\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"6254\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"PreferencesWindowController\" customModule=\"Nimbus\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"accountActionButton\" destination=\"UjG-7X-3hu\" id=\"3Wb-Hf-8nj\"/>\n                <outlet property=\"hostnameField\" destination=\"r7s-Xv-pFO\" id=\"aCi-Hz-xmd\"/>\n                <outlet property=\"hostnameLabel\" destination=\"l4j-7h-KDy\" id=\"fpN-Nw-vaQ\"/>\n                <outlet property=\"passwordField\" destination=\"TkR-l3-2EX\" id=\"Tm3-ZR-hzY\"/>\n                <outlet property=\"passwordLabel\" destination=\"TR0-Ny-FOc\" id=\"Bmp-vE-pE8\"/>\n                <outlet property=\"uploadScreenshotsCheckbox\" destination=\"s89-w0-n9y\" id=\"eoF-mX-cKh\"/>\n                <outlet property=\"usernameField\" destination=\"ZH0-ad-kpJ\" id=\"l2e-rk-lQq\"/>\n                <outlet property=\"usernameLabel\" destination=\"bvA-pA-hcL\" id=\"hbL-cX-7rV\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Preferences\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"303\" height=\"187\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1440\" height=\"877\"/>\n            <view key=\"contentView\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"303\" height=\"187\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8qV-BX-YSG\">\n                        <rect key=\"frame\" x=\"18\" y=\"147\" width=\"72\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Hostname:\" id=\"6EW-XZ-sfN\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vtk-rD-6Sw\">\n                        <rect key=\"frame\" x=\"19\" y=\"117\" width=\"71\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Username:\" id=\"WBg-rY-sRf\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TR0-Ny-FOc\">\n                        <rect key=\"frame\" x=\"24\" y=\"85\" width=\"66\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Password:\" id=\"tbC-6h-ka6\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"r7s-Xv-pFO\">\n                        <rect key=\"frame\" x=\"96\" y=\"145\" width=\"187\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" placeholderString=\"\" drawsBackground=\"YES\" id=\"vhC-VW-U1U\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <secureTextField verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TkR-l3-2EX\">\n                        <rect key=\"frame\" x=\"96\" y=\"83\" width=\"187\" height=\"22\"/>\n                        <secureTextFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"Ly3-lX-Gdc\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <allowedInputSourceLocales>\n                                <string>NSAllRomanInputSourcesLocaleIdentifier</string>\n                            </allowedInputSourceLocales>\n                        </secureTextFieldCell>\n                    </secureTextField>\n                    <button verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UjG-7X-3hu\">\n                        <rect key=\"frame\" x=\"207\" y=\"47\" width=\"75\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Login\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"HXa-qJ-WsE\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"accountActionButtonPressed:\" target=\"-2\" id=\"lVz-g8-Fgi\"/>\n                        </connections>\n                    </button>\n                    <textField verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZH0-ad-kpJ\">\n                        <rect key=\"frame\" x=\"96\" y=\"115\" width=\"187\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" placeholderString=\"\" drawsBackground=\"YES\" id=\"BrX-eL-YLY\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField hidden=\"YES\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bvA-pA-hcL\">\n                        <rect key=\"frame\" x=\"99\" y=\"117\" width=\"186\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"username\" id=\"Gd6-bB-49G\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField hidden=\"YES\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l4j-7h-KDy\">\n                        <rect key=\"frame\" x=\"99\" y=\"147\" width=\"186\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"hostname\" id=\"sct-P4-9oO\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s89-w0-n9y\">\n                        <rect key=\"frame\" x=\"94\" y=\"18\" width=\"147\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Upload Screenshots\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"6Bw-6k-7Le\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"uploadScreenshotsCheckboxPressed:\" target=\"-2\" id=\"cB0-69-Txb\"/>\n                        </connections>\n                    </button>\n                </subviews>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"332.5\" y=\"216.5\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/ScreenshotWatcher.h",
    "content": "//\n//  ScreenshotWatch.h\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/27/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\ntypedef void(^FileCallbackBlock)(NSData*, NSString*);\n\n@interface ScreenshotWatcher : NSObject\n\n@property (nonatomic, copy) FileCallbackBlock uploadCallback;\n\n- (instancetype)initWithUploadFileCallback:(FileCallbackBlock)callback;\n- (void)startWatchingPath:(NSString*) path;\n\n@end\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/ScreenshotWatcher.m",
    "content": "//\n//  ScreenshotWatch.m\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/27/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\n#import \"ScreenshotWatcher.h\"\n\n\n@interface ScreenshotWatcher()\n\n@property (nonatomic, assign) FSEventStreamRef eventStream;\n\n@end\n\nstatic NSMutableSet *uploadedFilenames;\n\n@implementation ScreenshotWatcher\n\n- (instancetype)initWithUploadFileCallback:(FileCallbackBlock) callback {\n    self = [super init];\n    if (self) {\n        if (uploadedFilenames == nil) {\n            uploadedFilenames = [NSMutableSet new];\n        }\n        \n        self.uploadCallback = callback;\n    }\n    return self;\n}\n\nvoid describeFSEvent(FSEventStreamEventFlags eventFlags) {\n    // if (eventFlags & kFSEventStreamEventFlagNone)               printf(\"None\\t\");\n    if (eventFlags & kFSEventStreamEventFlagMustScanSubDirs)    printf(\"MustScanSubDirs\\t\");\n    if (eventFlags & kFSEventStreamEventFlagUserDropped)        printf(\"UserDropped\\t\");\n    if (eventFlags & kFSEventStreamEventFlagKernelDropped)      printf(\"KernelDropped\\t\");\n    if (eventFlags & kFSEventStreamEventFlagEventIdsWrapped)    printf(\"EventIdsWrapped\\t\");\n    if (eventFlags & kFSEventStreamEventFlagHistoryDone)        printf(\"HistoryDone\\t\");\n    if (eventFlags & kFSEventStreamEventFlagRootChanged)        printf(\"RootChanged\\t\");\n    if (eventFlags & kFSEventStreamEventFlagMount)              printf(\"Mount\\t\");\n    if (eventFlags & kFSEventStreamEventFlagUnmount)            printf(\"Unmount\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemCreated)        printf(\"ItemCreated\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemRemoved)        printf(\"ItemRemoved\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemInodeMetaMod)   printf(\"ItemInodeMetaMod\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemRenamed)        printf(\"ItemRenamed\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemModified)       printf(\"ItemModified\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemFinderInfoMod)  printf(\"ItemFinderInfoMod\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemChangeOwner)    printf(\"ItemChangeOwner\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemXattrMod)       printf(\"ItemXattrMod\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemIsFile)         printf(\"ItemIsFile\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemIsDir)          printf(\"ItemIsDir\\t\");\n    if (eventFlags & kFSEventStreamEventFlagItemIsSymlink)      printf(\"ItemIsSymlink\\t\");\n    printf(\"\\n\");\n}\n\n\nvoid fsEventsCallback(ConstFSEventStreamRef streamRef,\n                      void *info,\n                      size_t numEvents,\n                      void *eventPaths,\n                      const FSEventStreamEventFlags eventFlags[],\n                      const FSEventStreamEventId eventIds[])\n{\n    char** paths = (char**)eventPaths;\n    \n    for (int i = 0; i < numEvents; i++) {\n        NSString *path = [NSString stringWithUTF8String:paths[i]];\n        NSURL *fileURL = [NSURL fileURLWithPath:path];\n        NSFileManager *fileManager = [NSFileManager defaultManager];\n        \n//        if (![fileURL.lastPathComponent hasPrefix:@\".\"]) {\n//            printf(\"%s\\t\", [fileURL.lastPathComponent cStringUsingEncoding:NSUTF8StringEncoding]);\n//            describeFSEvent(eventFlags[i]);\n//        }\n        \n        if ((eventFlags[i] & kFSEventStreamEventFlagItemRenamed) &&\n            (eventFlags[i] & kFSEventStreamEventFlagItemXattrMod) &&\n            !([uploadedFilenames containsObject:path])) {\n            \n            if (![fileURL.lastPathComponent hasPrefix:@\".\"]) {\n                NSMetadataItem *metadata = [[NSMetadataItem alloc] initWithURL:fileURL];\n                if ([fileManager fileExistsAtPath:path]) {\n                    BOOL isScreenshot = [[metadata valueForAttribute:@\"kMDItemIsScreenCapture\"] integerValue] == 1;\n                    if (isScreenshot) {\n//                        printf(\"Uploading %s\\n\", [fileURL.lastPathComponent cStringUsingEncoding:NSUTF8StringEncoding]);\n                        NSData *fileData = [fileManager contentsAtPath:path];\n                        ScreenshotWatcher *watcher = (__bridge ScreenshotWatcher*)info;\n                        watcher.uploadCallback(fileData, path);\n                        \n                        [uploadedFilenames addObject:path];\n                    }\n                }\n            }\n\n        }\n        \n    }\n}\n\n- (void)startWatchingPath:(NSString*) path {\n    FSEventStreamContext context;\n    context.info = (__bridge void *)(self);\n    context.version = 0;\n    context.retain = NULL;\n    context.release = NULL;\n    context.copyDescription = NULL;\n    \n    NSArray *pathsToWatch = @[path];\n    \n    self.eventStream = FSEventStreamCreate(NULL,\n                                           &fsEventsCallback,\n                                           &context,\n                                           (__bridge CFArrayRef)(pathsToWatch),\n                                           kFSEventStreamEventIdSinceNow,\n                                           0.1,\n                                           kFSEventStreamCreateFlagFileEvents\n                                           );\n    \n    FSEventStreamScheduleWithRunLoop(self.eventStream, CFRunLoopGetCurrent(),\n                                     kCFRunLoopDefaultMode);\n    FSEventStreamStart(self.eventStream);\n}\n\n@end"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/StatusItemView.swift",
    "content": "//\n//  StatusItemView.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nenum StatusItemViewStatus: String {\n    case Normal = \"Normal\"\n    case Error = \"Error\"\n    case Success = \"Success\"\n    case Working = \"Working\"\n}\n\nfunc delay(delay:Double, closure:()->()) {\n    dispatch_after(\n        dispatch_time(\n            DISPATCH_TIME_NOW,\n            Int64(delay * Double(NSEC_PER_SEC))\n        ),\n        dispatch_get_main_queue(), closure)\n}\n\nclass StatusItemView: NSView, NSMenuDelegate, NSWindowDelegate {\n    let statusItemWidth = 30.0\n    let statusBarHeight = NSStatusBar.systemStatusBar().thickness\n    let statusItemRect: NSRect\n    \n    var status: StatusItemViewStatus = .Normal {\n    didSet {\n        switch status {\n        case .Normal:\n            progressFrame = 0\n        case .Working:\n            if oldValue != .Working {\n                progressFrame = 1\n            }\n        default:\n            progressFrame = 0\n            \n            let statusAtDispatch = status\n            delay(2.0) {\n                if statusAtDispatch == self.status {\n                    self.status = .Normal\n                    self.updateUI()\n                }\n            }\n        }\n        self.updateUI()\n    }\n    }\n    \n    var active: Bool = false {\n    didSet {\n        self.updateUI()\n    }\n    }\n    \n    var progressFrame: Int = 0 {\n    didSet {\n        if self.progressFrame != 0 {\n            delay(0.25) {\n                if self.progressFrame != 0 {\n                    self.progressFrame = 1 + (self.progressFrame % 3)\n                }\n            }\n        }\n\n        updateUI()\n    }\n    }\n    \n    \n    var statusItem: NSStatusItem\n    var popover: NSPopover?\n    var preferencesWindowController: NSWindowController?\n    \n    var prefs = PreferencesManager()\n    \n    lazy var imageView: NSImageView = {\n        let view:NSImageView = NSImageView(frame: self.statusItemRect)\n        view.unregisterDraggedTypes()\n        return view\n        }()\n    \n    lazy var statusItemMenu: NSMenu = {\n        let menu: NSMenu = NSMenu()\n        menu.delegate = self\n        menu.autoenablesItems = true\n        menu.addItem(self.websiteItem)\n        menu.addItem(self.preferencesItem)\n        menu.addItem(self.quitItem)\n        return menu\n        }()\n    \n    lazy var websiteItem: NSMenuItem = {\n        let item = NSMenuItem(title: \"Launch Nimbus Website\", action: \"openWebsite:\", keyEquivalent: \"\")\n        item.target = self\n        return item\n        }()\n    \n    lazy var preferencesItem: NSMenuItem = {\n        let item = NSMenuItem(title: \"Preferences\", action: \"openPreferences:\", keyEquivalent: \"\")\n        item.target = self\n        return item\n        }()\n    \n    lazy var quitItem: NSMenuItem = {\n        let item = NSMenuItem(title: \"Quit\", action: \"quitApp:\", keyEquivalent: \"\")\n        item.target = self\n        return item\n        }()\n    \n    \n    \n    init() {\n        statusItemRect = NSMakeRect(0, 0, CGFloat(statusItemWidth), CGFloat(statusBarHeight))\n        statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(CGFloat(statusItemWidth))\n        \n        super.init(frame: statusItemRect)\n        \n        statusItem.view = self\n        statusItem.menu = statusItemMenu\n        self.addSubview(imageView)\n        \n        self.registerForDraggedTypes([NSFilenamesPboardType, NSURLPboardType, NSStringPboardType])\n        \n        updateUI()\n    }\n\n    required convenience init?(coder: NSCoder) {\n        self.init()\n    }\n\n    override func drawRect(dirtyRect: NSRect) {\n        if active {\n            NSColor.selectedMenuItemColor().setFill()\n            NSRectFill(dirtyRect)\n        } else {\n            NSColor.clearColor().setFill()\n            NSRectFill(dirtyRect)\n        }\n    }\n    \n    func updateUI() {\n        if (active) {\n            self.imageView.image = NSImage(named: \"menubar-highlighted\")\n        } else {\n            if status != .Working {\n                var imageNames: Dictionary<StatusItemViewStatus, String> = [\n                    .Normal: \"menubar\",\n                    .Error: \"menubar-error\",\n                    .Success: \"menubar-success\",\n                ]\n                self.imageView.image = NSImage(named: imageNames[status]!)\n            } else {\n                self.imageView.image = NSImage(named: \"menubar-progress-\\(progressFrame)\")\n            }\n        }\n        \n        self.needsDisplay = true\n    }\n    \n    override func mouseDown(theEvent: NSEvent) {\n        active = true\n        statusItem.popUpStatusItemMenu(statusItemMenu)\n    }\n    \n    override func mouseUp(theEvent: NSEvent) {\n        active = false\n    }\n    \n    func openWebsite(sender: NSStatusItem!) {\n        NSWorkspace.sharedWorkspace().openURL(NSURL(string: \"http://account.\" + prefs.hostname)!)\n    }\n    \n    func openPreferences(sender: NSStatusItem!) {\n        if !(preferencesWindowController != nil) {\n            preferencesWindowController = PreferencesWindowController(windowNibName: \"PreferencesWindowController\")\n        }\n        preferencesWindowController!.showWindow(self)\n        NSApp.activateIgnoringOtherApps(true)\n    }\n    \n    func quitApp(sender: NSStatusItem!) {\n        NSApplication.sharedApplication().terminate(nil)\n    }\n    \n    // NSMenuDelegate\n    func menuDidClose(menu: NSMenu) {\n        active = false\n    }\n    \n    override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {\n        return .Copy\n    }\n    \n    override func draggingEnded(sender: NSDraggingInfo!) {\n        if NSPointInRect(sender.draggingLocation(), self.frame) {\n            handleDrop(sender)\n        }\n    }\n    \n    // Manually called instead of performDragOperation\n    // http://openradar.appspot.com/radar?id=1745403\n    func handleDrop(sender: NSDraggingInfo!) -> Bool {\n        let pboard = sender.draggingPasteboard();\n        let types: NSArray = pboard.types!\n        let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate\n        let fileManager = NSFileManager.defaultManager()\n        \n        if types.containsObject(NSFilenamesPboardType) {\n            let fileURL = NSURL(fromPasteboard: pboard)!\n            let fileData = fileManager.contentsAtPath(fileURL.path!)\n            let fileName = fileURL.lastPathComponent\n            \n            if (fileData != nil) && (fileName != nil) {\n                appDelegate.uploadFile(fileData!, filename: fileName!)\n            } else {\n                status = .Error\n            }\n            \n        } else if types.containsObject(NSURLPboardType) {\n            let url = NSURL(fromPasteboard: pboard)!\n            appDelegate.uploadLink(url)\n            \n        } else if types.containsObject(NSStringPboardType) {\n            let text = pboard.stringForType(NSStringPboardType) as NSString!\n            \n            let legalChars = NSMutableCharacterSet.alphanumericCharacterSet()\n            legalChars.formUnionWithCharacterSet(NSCharacterSet.whitespaceCharacterSet())\n            legalChars.invert()\n            var filename = (text.componentsSeparatedByCharactersInSet(legalChars) as NSArray).componentsJoinedByString(\"\") as NSString\n            filename = filename.substringToIndex(30 > text.length ? text.length : 30) + \".txt\"\n            \n            let fileData = text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)\n            \n            if let d = fileData {\n                    appDelegate.uploadFile(d, filename: filename as String)\n            } else {\n                status = .Error\n            }\n        }\n        \n        return true;\n    }\n    \n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/SwiftyJSON.swift",
    "content": "//  SwiftyJSON.swift\n//\n//  Copyright (c) 2014 Ruoyu Fu, Pinglin Tang\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\n//  all 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\n//  THE SOFTWARE.\n\nimport Foundation\n\n// MARK: - Error\n\n///Error domain\npublic let ErrorDomain: String = \"SwiftyJSONErrorDomain\"\n\n///Error code\npublic let ErrorUnsupportedType: Int = 999\npublic let ErrorIndexOutOfBounds: Int = 900\npublic let ErrorWrongType: Int = 901\npublic let ErrorNotExist: Int = 500\npublic let ErrorInvalidJSON: Int = 490\n\n// MARK: - JSON Type\n\n/**\nJSON's type definitions.\n\nSee http://www.json.org\n*/\npublic enum Type :Int{\n    \n    case Number\n    case String\n    case Bool\n    case Array\n    case Dictionary\n    case Null\n    case Unknown\n}\n\n// MARK: - JSON Base\n\npublic struct JSON {\n    \n    /**\n     Creates a JSON using the data.\n     \n     - parameter data:  The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary\n     - parameter opt:   The JSON serialization reading options. `.AllowFragments` by default.\n     - parameter error: error The NSErrorPointer used to return the error. `nil` by default.\n     \n     - returns: The created JSON\n     */\n    public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {\n        do {\n            let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt)\n            self.init(object)\n        } catch let aError as NSError {\n            if error != nil {\n                error.memory = aError\n            }\n            self.init(NSNull())\n        }\n    }\n    \n    /**\n     Create a JSON from JSON string\n     - parameter string: Normal json string like '{\"a\":\"b\"}'\n     \n     - returns: The created JSON\n     */\n    public static func parse(string:String) -> JSON {\n        return string.dataUsingEncoding(NSUTF8StringEncoding)\n            .flatMap({JSON(data: $0)}) ?? JSON(NSNull())\n    }\n    \n    /**\n     Creates a JSON using the object.\n     \n     - parameter object:  The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.\n     \n     - returns: The created JSON\n     */\n    public init(_ object: AnyObject) {\n        self.object = object\n    }\n    \n    /**\n     Creates a JSON from a [JSON]\n     \n     - parameter jsonArray: A Swift array of JSON objects\n     \n     - returns: The created JSON\n     */\n    public init(_ jsonArray:[JSON]) {\n        self.init(jsonArray.map { $0.object })\n    }\n    \n    /**\n     Creates a JSON from a [String: JSON]\n     \n     - parameter jsonDictionary: A Swift dictionary of JSON objects\n     \n     - returns: The created JSON\n     */\n    public init(_ jsonDictionary:[String: JSON]) {\n        var dictionary = [String: AnyObject]()\n        for (key, json) in jsonDictionary {\n            dictionary[key] = json.object\n        }\n        self.init(dictionary)\n    }\n    \n    /// Private object\n    private var rawArray: [AnyObject] = []\n    private var rawDictionary: [String : AnyObject] = [:]\n    private var rawString: String = \"\"\n    private var rawNumber: NSNumber = 0\n    private var rawNull: NSNull = NSNull()\n    /// Private type\n    private var _type: Type = .Null\n    /// prviate error\n    private var _error: NSError? = nil\n    \n    /// Object in JSON\n    public var object: AnyObject {\n        get {\n            switch self.type {\n            case .Array:\n                return self.rawArray\n            case .Dictionary:\n                return self.rawDictionary\n            case .String:\n                return self.rawString\n            case .Number:\n                return self.rawNumber\n            case .Bool:\n                return self.rawNumber\n            default:\n                return self.rawNull\n            }\n        }\n        set {\n            _error = nil\n            switch newValue {\n            case let number as NSNumber:\n                if number.isBool {\n                    _type = .Bool\n                } else {\n                    _type = .Number\n                }\n                self.rawNumber = number\n            case  let string as String:\n                _type = .String\n                self.rawString = string\n            case  _ as NSNull:\n                _type = .Null\n            case let array as [AnyObject]:\n                _type = .Array\n                self.rawArray = array\n            case let dictionary as [String : AnyObject]:\n                _type = .Dictionary\n                self.rawDictionary = dictionary\n            default:\n                _type = .Unknown\n                _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: \"It is a unsupported type\"])\n            }\n        }\n    }\n    \n    /// json type\n    public var type: Type { get { return _type } }\n    \n    /// Error in JSON\n    public var error: NSError? { get { return self._error } }\n    \n    /// The static null json\n    @available(*, unavailable, renamed=\"null\")\n    public static var nullJSON: JSON { get { return null } }\n    public static var null: JSON { get { return JSON(NSNull()) } }\n}\n\n// MARK: - CollectionType, SequenceType, Indexable\nextension JSON : Swift.CollectionType, Swift.SequenceType, Swift.Indexable {\n    \n    public typealias Generator = JSONGenerator\n    \n    public typealias Index = JSONIndex\n    \n    public var startIndex: JSON.Index {\n        switch self.type {\n        case .Array:\n            return JSONIndex(arrayIndex: self.rawArray.startIndex)\n        case .Dictionary:\n            return JSONIndex(dictionaryIndex: self.rawDictionary.startIndex)\n        default:\n            return JSONIndex()\n        }\n    }\n    \n    public var endIndex: JSON.Index {\n        switch self.type {\n        case .Array:\n            return JSONIndex(arrayIndex: self.rawArray.endIndex)\n        case .Dictionary:\n            return JSONIndex(dictionaryIndex: self.rawDictionary.endIndex)\n        default:\n            return JSONIndex()\n        }\n    }\n    \n    public subscript (position: JSON.Index) -> JSON.Generator.Element {\n        switch self.type {\n        case .Array:\n            return (String(position.arrayIndex), JSON(self.rawArray[position.arrayIndex!]))\n        case .Dictionary:\n            let (key, value) = self.rawDictionary[position.dictionaryIndex!]\n            return (key, JSON(value))\n        default:\n            return (\"\", JSON.null)\n        }\n    }\n    \n    /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `true`.\n    public var isEmpty: Bool {\n        get {\n            switch self.type {\n            case .Array:\n                return self.rawArray.isEmpty\n            case .Dictionary:\n                return self.rawDictionary.isEmpty\n            default:\n                return true\n            }\n        }\n    }\n    \n    /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.\n    public var count: Int {\n        switch self.type {\n        case .Array:\n            return self.rawArray.count\n        case .Dictionary:\n            return self.rawDictionary.count\n        default:\n            return 0\n        }\n    }\n    \n    public func underestimateCount() -> Int {\n        switch self.type {\n        case .Array:\n            return self.rawArray.underestimateCount()\n        case .Dictionary:\n            return self.rawDictionary.underestimateCount()\n        default:\n            return 0\n        }\n    }\n    \n    /**\n     If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary`, otherwise return a generator over empty.\n     \n     - returns: Return a *generator* over the elements of JSON.\n     */\n    public func generate() -> JSON.Generator {\n        return JSON.Generator(self)\n    }\n}\n\npublic struct JSONIndex: ForwardIndexType, _Incrementable, Equatable, Comparable {\n    \n    let arrayIndex: Int?\n    let dictionaryIndex: DictionaryIndex<String, AnyObject>?\n    \n    let type: Type\n    \n    init(){\n        self.arrayIndex = nil\n        self.dictionaryIndex = nil\n        self.type = .Unknown\n    }\n    \n    init(arrayIndex: Int) {\n        self.arrayIndex = arrayIndex\n        self.dictionaryIndex = nil\n        self.type = .Array\n    }\n    \n    init(dictionaryIndex: DictionaryIndex<String, AnyObject>) {\n        self.arrayIndex = nil\n        self.dictionaryIndex = dictionaryIndex\n        self.type = .Dictionary\n    }\n    \n    public func successor() -> JSONIndex {\n        switch self.type {\n        case .Array:\n            return JSONIndex(arrayIndex: self.arrayIndex!.successor())\n        case .Dictionary:\n            return JSONIndex(dictionaryIndex: self.dictionaryIndex!.successor())\n        default:\n            return JSONIndex()\n        }\n    }\n}\n\npublic func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool {\n    switch (lhs.type, rhs.type) {\n    case (.Array, .Array):\n        return lhs.arrayIndex == rhs.arrayIndex\n    case (.Dictionary, .Dictionary):\n        return lhs.dictionaryIndex == rhs.dictionaryIndex\n    default:\n        return false\n    }\n}\n\npublic func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool {\n    switch (lhs.type, rhs.type) {\n    case (.Array, .Array):\n        return lhs.arrayIndex < rhs.arrayIndex\n    case (.Dictionary, .Dictionary):\n        return lhs.dictionaryIndex < rhs.dictionaryIndex\n    default:\n        return false\n    }\n}\n\npublic func <=(lhs: JSONIndex, rhs: JSONIndex) -> Bool {\n    switch (lhs.type, rhs.type) {\n    case (.Array, .Array):\n        return lhs.arrayIndex <= rhs.arrayIndex\n    case (.Dictionary, .Dictionary):\n        return lhs.dictionaryIndex <= rhs.dictionaryIndex\n    default:\n        return false\n    }\n}\n\npublic func >=(lhs: JSONIndex, rhs: JSONIndex) -> Bool {\n    switch (lhs.type, rhs.type) {\n    case (.Array, .Array):\n        return lhs.arrayIndex >= rhs.arrayIndex\n    case (.Dictionary, .Dictionary):\n        return lhs.dictionaryIndex >= rhs.dictionaryIndex\n    default:\n        return false\n    }\n}\n\npublic func >(lhs: JSONIndex, rhs: JSONIndex) -> Bool {\n    switch (lhs.type, rhs.type) {\n    case (.Array, .Array):\n        return lhs.arrayIndex > rhs.arrayIndex\n    case (.Dictionary, .Dictionary):\n        return lhs.dictionaryIndex > rhs.dictionaryIndex\n    default:\n        return false\n    }\n}\n\npublic struct JSONGenerator : GeneratorType {\n    \n    public typealias Element = (String, JSON)\n    \n    private let type: Type\n    private var dictionayGenerate: DictionaryGenerator<String, AnyObject>?\n    private var arrayGenerate: IndexingGenerator<[AnyObject]>?\n    private var arrayIndex: Int = 0\n    \n    init(_ json: JSON) {\n        self.type = json.type\n        if type == .Array {\n            self.arrayGenerate = json.rawArray.generate()\n        }else {\n            self.dictionayGenerate = json.rawDictionary.generate()\n        }\n    }\n    \n    public mutating func next() -> JSONGenerator.Element? {\n        switch self.type {\n        case .Array:\n            if let o = self.arrayGenerate?.next() {\n                return (String(self.arrayIndex++), JSON(o))\n            } else {\n                return nil\n            }\n        case .Dictionary:\n            if let (k, v): (String, AnyObject) = self.dictionayGenerate?.next() {\n                return (k, JSON(v))\n            } else {\n                return nil\n            }\n        default:\n            return nil\n        }\n    }\n}\n\n// MARK: - Subscript\n\n/**\n*  To mark both String and Int can be used in subscript.\n*/\npublic enum JSONKey {\n    case Index(Int)\n    case Key(String)\n}\n\npublic protocol JSONSubscriptType {\n    var jsonKey:JSONKey { get }\n}\n\nextension Int: JSONSubscriptType {\n    public var jsonKey:JSONKey {\n        return JSONKey.Index(self)\n    }\n}\n\nextension String: JSONSubscriptType {\n    public var jsonKey:JSONKey {\n        return JSONKey.Key(self)\n    }\n}\n\nextension JSON {\n    \n    /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.\n    private subscript(index index: Int) -> JSON {\n        get {\n            if self.type != .Array {\n                var r = JSON.null\n                r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: \"Array[\\(index)] failure, It is not an array\"])\n                return r\n            } else if index >= 0 && index < self.rawArray.count {\n                return JSON(self.rawArray[index])\n            } else {\n                var r = JSON.null\n                r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: \"Array[\\(index)] is out of bounds\"])\n                return r\n            }\n        }\n        set {\n            if self.type == .Array {\n                if self.rawArray.count > index && newValue.error == nil {\n                    self.rawArray[index] = newValue.object\n                }\n            }\n        }\n    }\n    \n    /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.\n    private subscript(key key: String) -> JSON {\n        get {\n            var r = JSON.null\n            if self.type == .Dictionary {\n                if let o = self.rawDictionary[key] {\n                    r = JSON(o)\n                } else {\n                    r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: \"Dictionary[\\\"\\(key)\\\"] does not exist\"])\n                }\n            } else {\n                r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: \"Dictionary[\\\"\\(key)\\\"] failure, It is not an dictionary\"])\n            }\n            return r\n        }\n        set {\n            if self.type == .Dictionary && newValue.error == nil {\n                self.rawDictionary[key] = newValue.object\n            }\n        }\n    }\n    \n    /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`,  return `subscript(key:)`.\n    private subscript(sub sub: JSONSubscriptType) -> JSON {\n        get {\n            switch sub.jsonKey {\n            case .Index(let index): return self[index: index]\n            case .Key(let key): return self[key: key]\n            }\n        }\n        set {\n            switch sub.jsonKey {\n            case .Index(let index): self[index: index] = newValue\n            case .Key(let key): self[key: key] = newValue\n            }\n        }\n    }\n    \n    /**\n     Find a json in the complex data structuresby using the Int/String's array.\n     \n     - parameter path: The target json's path. Example:\n     \n     let json = JSON[data]\n     let path = [9,\"list\",\"person\",\"name\"]\n     let name = json[path]\n     \n     The same as: let name = json[9][\"list\"][\"person\"][\"name\"]\n     \n     - returns: Return a json found by the path or a null json with error\n     */\n    public subscript(path: [JSONSubscriptType]) -> JSON {\n        get {\n            return path.reduce(self) { $0[sub: $1] }\n        }\n        set {\n            switch path.count {\n            case 0:\n                return\n            case 1:\n                self[sub:path[0]].object = newValue.object\n            default:\n                var aPath = path; aPath.removeAtIndex(0)\n                var nextJSON = self[sub: path[0]]\n                nextJSON[aPath] = newValue\n                self[sub: path[0]] = nextJSON\n            }\n        }\n    }\n    \n    /**\n     Find a json in the complex data structuresby using the Int/String's array.\n     \n     - parameter path: The target json's path. Example:\n     \n     let name = json[9,\"list\",\"person\",\"name\"]\n     \n     The same as: let name = json[9][\"list\"][\"person\"][\"name\"]\n     \n     - returns: Return a json found by the path or a null json with error\n     */\n    public subscript(path: JSONSubscriptType...) -> JSON {\n        get {\n            return self[path]\n        }\n        set {\n            self[path] = newValue\n        }\n    }\n}\n\n// MARK: - LiteralConvertible\n\nextension JSON: Swift.StringLiteralConvertible {\n    \n    public init(stringLiteral value: StringLiteralType) {\n        self.init(value)\n    }\n    \n    public init(extendedGraphemeClusterLiteral value: StringLiteralType) {\n        self.init(value)\n    }\n    \n    public init(unicodeScalarLiteral value: StringLiteralType) {\n        self.init(value)\n    }\n}\n\nextension JSON: Swift.IntegerLiteralConvertible {\n    \n    public init(integerLiteral value: IntegerLiteralType) {\n        self.init(value)\n    }\n}\n\nextension JSON: Swift.BooleanLiteralConvertible {\n    \n    public init(booleanLiteral value: BooleanLiteralType) {\n        self.init(value)\n    }\n}\n\nextension JSON: Swift.FloatLiteralConvertible {\n    \n    public init(floatLiteral value: FloatLiteralType) {\n        self.init(value)\n    }\n}\n\nextension JSON: Swift.DictionaryLiteralConvertible {\n    \n    public init(dictionaryLiteral elements: (String, AnyObject)...) {\n        self.init(elements.reduce([String : AnyObject]()){(dictionary: [String : AnyObject], element:(String, AnyObject)) -> [String : AnyObject] in\n            var d = dictionary\n            d[element.0] = element.1\n            return d\n            })\n    }\n}\n\nextension JSON: Swift.ArrayLiteralConvertible {\n    \n    public init(arrayLiteral elements: AnyObject...) {\n        self.init(elements)\n    }\n}\n\nextension JSON: Swift.NilLiteralConvertible {\n    \n    public init(nilLiteral: ()) {\n        self.init(NSNull())\n    }\n}\n\n// MARK: - Raw\n\nextension JSON: Swift.RawRepresentable {\n    \n    public init?(rawValue: AnyObject) {\n        if JSON(rawValue).type == .Unknown {\n            return nil\n        } else {\n            self.init(rawValue)\n        }\n    }\n    \n    public var rawValue: AnyObject {\n        return self.object\n    }\n    \n    public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(rawValue: 0)) throws -> NSData {\n        guard NSJSONSerialization.isValidJSONObject(self.object) else {\n            throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: \"JSON is invalid\"])\n        }\n        \n        return try NSJSONSerialization.dataWithJSONObject(self.object, options: opt)\n    }\n    \n    public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {\n        switch self.type {\n        case .Array, .Dictionary:\n            do {\n                let data = try self.rawData(options: opt)\n                return NSString(data: data, encoding: encoding) as? String\n            } catch _ {\n                return nil\n            }\n        case .String:\n            return self.rawString\n        case .Number:\n            return self.rawNumber.stringValue\n        case .Bool:\n            return self.rawNumber.boolValue.description\n        case .Null:\n            return \"null\"\n        default:\n            return nil\n        }\n    }\n}\n\n// MARK: - Printable, DebugPrintable\n\nextension JSON: Swift.Printable, Swift.DebugPrintable {\n    \n    public var description: String {\n        if let string = self.rawString(options:.PrettyPrinted) {\n            return string\n        } else {\n            return \"unknown\"\n        }\n    }\n    \n    public var debugDescription: String {\n        return description\n    }\n}\n\n// MARK: - Array\n\nextension JSON {\n    \n    //Optional [JSON]\n    public var array: [JSON]? {\n        get {\n            if self.type == .Array {\n                return self.rawArray.map{ JSON($0) }\n            } else {\n                return nil\n            }\n        }\n    }\n    \n    //Non-optional [JSON]\n    public var arrayValue: [JSON] {\n        get {\n            return self.array ?? []\n        }\n    }\n    \n    //Optional [AnyObject]\n    public var arrayObject: [AnyObject]? {\n        get {\n            switch self.type {\n            case .Array:\n                return self.rawArray\n            default:\n                return nil\n            }\n        }\n        set {\n            if let array = newValue {\n                self.object = array\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n}\n\n// MARK: - Dictionary\n\nextension JSON {\n    \n    //Optional [String : JSON]\n    public var dictionary: [String : JSON]? {\n        if self.type == .Dictionary {\n            return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, AnyObject)) -> [String : JSON] in\n                var d = dictionary\n                d[element.0] = JSON(element.1)\n                return d\n            }\n        } else {\n            return nil\n        }\n    }\n    \n    //Non-optional [String : JSON]\n    public var dictionaryValue: [String : JSON] {\n        return self.dictionary ?? [:]\n    }\n    \n    //Optional [String : AnyObject]\n    public var dictionaryObject: [String : AnyObject]? {\n        get {\n            switch self.type {\n            case .Dictionary:\n                return self.rawDictionary\n            default:\n                return nil\n            }\n        }\n        set {\n            if let v = newValue {\n                self.object = v\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n}\n\n// MARK: - Bool\n\nextension JSON: Swift.BooleanType {\n    \n    //Optional bool\n    public var bool: Bool? {\n        get {\n            switch self.type {\n            case .Bool:\n                return self.rawNumber.boolValue\n            default:\n                return nil\n            }\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(bool: newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    //Non-optional bool\n    public var boolValue: Bool {\n        get {\n            switch self.type {\n            case .Bool, .Number, .String:\n                return self.object.boolValue\n            default:\n                return false\n            }\n        }\n        set {\n            self.object = NSNumber(bool: newValue)\n        }\n    }\n}\n\n// MARK: - String\n\nextension JSON {\n    \n    //Optional string\n    public var string: String? {\n        get {\n            switch self.type {\n            case .String:\n                return self.object as? String\n            default:\n                return nil\n            }\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSString(string:newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    //Non-optional string\n    public var stringValue: String {\n        get {\n            switch self.type {\n            case .String:\n                return self.object as? String ?? \"\"\n            case .Number:\n                return self.object.stringValue\n            case .Bool:\n                return (self.object as? Bool).map { String($0) } ?? \"\"\n            default:\n                return \"\"\n            }\n        }\n        set {\n            self.object = NSString(string:newValue)\n        }\n    }\n}\n\n// MARK: - Number\nextension JSON {\n    \n    //Optional number\n    public var number: NSNumber? {\n        get {\n            switch self.type {\n            case .Number, .Bool:\n                return self.rawNumber\n            default:\n                return nil\n            }\n        }\n        set {\n            self.object = newValue ?? NSNull()\n        }\n    }\n    \n    //Non-optional number\n    public var numberValue: NSNumber {\n        get {\n            switch self.type {\n            case .String:\n                let decimal = NSDecimalNumber(string: self.object as? String)\n                if decimal == NSDecimalNumber.notANumber() {  // indicates parse error\n                    return NSDecimalNumber.zero()\n                }\n                return decimal\n            case .Number, .Bool:\n                return self.object as? NSNumber ?? NSNumber(int: 0)\n            default:\n                return NSNumber(double: 0.0)\n            }\n        }\n        set {\n            self.object = newValue\n        }\n    }\n}\n\n//MARK: - Null\nextension JSON {\n    \n    public var null: NSNull? {\n        get {\n            switch self.type {\n            case .Null:\n                return self.rawNull\n            default:\n                return nil\n            }\n        }\n        set {\n            self.object = NSNull()\n        }\n    }\n    public func isExists() -> Bool{\n        if let errorValue = error where errorValue.code == ErrorNotExist{\n            return false\n        }\n        return true\n    }\n}\n\n//MARK: - URL\nextension JSON {\n    \n    //Optional URL\n    public var URL: NSURL? {\n        get {\n            switch self.type {\n            case .String:\n                if let encodedString_ = self.rawString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {\n                    return NSURL(string: encodedString_)\n                } else {\n                    return nil\n                }\n            default:\n                return nil\n            }\n        }\n        set {\n            self.object = newValue?.absoluteString ?? NSNull()\n        }\n    }\n}\n\n// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64\n\nextension JSON {\n    \n    public var double: Double? {\n        get {\n            return self.number?.doubleValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(double: newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    public var doubleValue: Double {\n        get {\n            return self.numberValue.doubleValue\n        }\n        set {\n            self.object = NSNumber(double: newValue)\n        }\n    }\n    \n    public var float: Float? {\n        get {\n            return self.number?.floatValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(float: newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    public var floatValue: Float {\n        get {\n            return self.numberValue.floatValue\n        }\n        set {\n            self.object = NSNumber(float: newValue)\n        }\n    }\n    \n    public var int: Int? {\n        get {\n            return self.number?.longValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(integer: newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    public var intValue: Int {\n        get {\n            return self.numberValue.integerValue\n        }\n        set {\n            self.object = NSNumber(integer: newValue)\n        }\n    }\n    \n    public var uInt: UInt? {\n        get {\n            return self.number?.unsignedLongValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(unsignedLong: newValue)\n            } else {\n                self.object = NSNull()\n            }\n        }\n    }\n    \n    public var uIntValue: UInt {\n        get {\n            return self.numberValue.unsignedLongValue\n        }\n        set {\n            self.object = NSNumber(unsignedLong: newValue)\n        }\n    }\n    \n    public var int8: Int8? {\n        get {\n            return self.number?.charValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(char: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var int8Value: Int8 {\n        get {\n            return self.numberValue.charValue\n        }\n        set {\n            self.object = NSNumber(char: newValue)\n        }\n    }\n    \n    public var uInt8: UInt8? {\n        get {\n            return self.number?.unsignedCharValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(unsignedChar: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var uInt8Value: UInt8 {\n        get {\n            return self.numberValue.unsignedCharValue\n        }\n        set {\n            self.object = NSNumber(unsignedChar: newValue)\n        }\n    }\n    \n    public var int16: Int16? {\n        get {\n            return self.number?.shortValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(short: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var int16Value: Int16 {\n        get {\n            return self.numberValue.shortValue\n        }\n        set {\n            self.object = NSNumber(short: newValue)\n        }\n    }\n    \n    public var uInt16: UInt16? {\n        get {\n            return self.number?.unsignedShortValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(unsignedShort: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var uInt16Value: UInt16 {\n        get {\n            return self.numberValue.unsignedShortValue\n        }\n        set {\n            self.object = NSNumber(unsignedShort: newValue)\n        }\n    }\n    \n    public var int32: Int32? {\n        get {\n            return self.number?.intValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(int: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var int32Value: Int32 {\n        get {\n            return self.numberValue.intValue\n        }\n        set {\n            self.object = NSNumber(int: newValue)\n        }\n    }\n    \n    public var uInt32: UInt32? {\n        get {\n            return self.number?.unsignedIntValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(unsignedInt: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var uInt32Value: UInt32 {\n        get {\n            return self.numberValue.unsignedIntValue\n        }\n        set {\n            self.object = NSNumber(unsignedInt: newValue)\n        }\n    }\n    \n    public var int64: Int64? {\n        get {\n            return self.number?.longLongValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(longLong: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var int64Value: Int64 {\n        get {\n            return self.numberValue.longLongValue\n        }\n        set {\n            self.object = NSNumber(longLong: newValue)\n        }\n    }\n    \n    public var uInt64: UInt64? {\n        get {\n            return self.number?.unsignedLongLongValue\n        }\n        set {\n            if let newValue = newValue {\n                self.object = NSNumber(unsignedLongLong: newValue)\n            } else {\n                self.object =  NSNull()\n            }\n        }\n    }\n    \n    public var uInt64Value: UInt64 {\n        get {\n            return self.numberValue.unsignedLongLongValue\n        }\n        set {\n            self.object = NSNumber(unsignedLongLong: newValue)\n        }\n    }\n}\n\n//MARK: - Comparable\nextension JSON : Swift.Comparable {}\n\npublic func ==(lhs: JSON, rhs: JSON) -> Bool {\n    \n    switch (lhs.type, rhs.type) {\n    case (.Number, .Number):\n        return lhs.rawNumber == rhs.rawNumber\n    case (.String, .String):\n        return lhs.rawString == rhs.rawString\n    case (.Bool, .Bool):\n        return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue\n    case (.Array, .Array):\n        return lhs.rawArray as NSArray == rhs.rawArray as NSArray\n    case (.Dictionary, .Dictionary):\n        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary\n    case (.Null, .Null):\n        return true\n    default:\n        return false\n    }\n}\n\npublic func <=(lhs: JSON, rhs: JSON) -> Bool {\n    \n    switch (lhs.type, rhs.type) {\n    case (.Number, .Number):\n        return lhs.rawNumber <= rhs.rawNumber\n    case (.String, .String):\n        return lhs.rawString <= rhs.rawString\n    case (.Bool, .Bool):\n        return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue\n    case (.Array, .Array):\n        return lhs.rawArray as NSArray == rhs.rawArray as NSArray\n    case (.Dictionary, .Dictionary):\n        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary\n    case (.Null, .Null):\n        return true\n    default:\n        return false\n    }\n}\n\npublic func >=(lhs: JSON, rhs: JSON) -> Bool {\n    \n    switch (lhs.type, rhs.type) {\n    case (.Number, .Number):\n        return lhs.rawNumber >= rhs.rawNumber\n    case (.String, .String):\n        return lhs.rawString >= rhs.rawString\n    case (.Bool, .Bool):\n        return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue\n    case (.Array, .Array):\n        return lhs.rawArray as NSArray == rhs.rawArray as NSArray\n    case (.Dictionary, .Dictionary):\n        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary\n    case (.Null, .Null):\n        return true\n    default:\n        return false\n    }\n}\n\npublic func >(lhs: JSON, rhs: JSON) -> Bool {\n    \n    switch (lhs.type, rhs.type) {\n    case (.Number, .Number):\n        return lhs.rawNumber > rhs.rawNumber\n    case (.String, .String):\n        return lhs.rawString > rhs.rawString\n    default:\n        return false\n    }\n}\n\npublic func <(lhs: JSON, rhs: JSON) -> Bool {\n    \n    switch (lhs.type, rhs.type) {\n    case (.Number, .Number):\n        return lhs.rawNumber < rhs.rawNumber\n    case (.String, .String):\n        return lhs.rawString < rhs.rawString\n    default:\n        return false\n    }\n}\n\nprivate let trueNumber = NSNumber(bool: true)\nprivate let falseNumber = NSNumber(bool: false)\nprivate let trueObjCType = String.fromCString(trueNumber.objCType)\nprivate let falseObjCType = String.fromCString(falseNumber.objCType)\n\n// MARK: - NSNumber: Comparable\n\nextension NSNumber {\n    var isBool:Bool {\n        get {\n            let objCType = String.fromCString(self.objCType)\n            if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType)\n                || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){\n                    return true\n            } else {\n                return false\n            }\n        }\n    }\n}\n\nfunc ==(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    switch (lhs.isBool, rhs.isBool) {\n    case (false, true):\n        return false\n    case (true, false):\n        return false\n    default:\n        return lhs.compare(rhs) == NSComparisonResult.OrderedSame\n    }\n}\n\nfunc !=(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    return !(lhs == rhs)\n}\n\nfunc <(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    \n    switch (lhs.isBool, rhs.isBool) {\n    case (false, true):\n        return false\n    case (true, false):\n        return false\n    default:\n        return lhs.compare(rhs) == NSComparisonResult.OrderedAscending\n    }\n}\n\nfunc >(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    \n    switch (lhs.isBool, rhs.isBool) {\n    case (false, true):\n        return false\n    case (true, false):\n        return false\n    default:\n        return lhs.compare(rhs) == NSComparisonResult.OrderedDescending\n    }\n}\n\nfunc <=(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    \n    switch (lhs.isBool, rhs.isBool) {\n    case (false, true):\n        return false\n    case (true, false):\n        return false\n    default:\n        return lhs.compare(rhs) != NSComparisonResult.OrderedDescending\n    }\n}\n\nfunc >=(lhs: NSNumber, rhs: NSNumber) -> Bool {\n    \n    switch (lhs.isBool, rhs.isBool) {\n    case (false, true):\n        return false\n    case (true, false):\n        return false\n    default:\n        return lhs.compare(rhs) != NSComparisonResult.OrderedAscending\n    }\n}"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus/main.swift",
    "content": "//\n//  main.swift\n//  Nimbus\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\n\nNSApplicationMain(Process.argc, Process.unsafeArgv)"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus.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\tAA0C67691983375C004BBF89 /* menubar-error.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C675B1983375C004BBF89 /* menubar-error.png */; };\n\t\tAA0C676A1983375C004BBF89 /* menubar-error@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C675C1983375C004BBF89 /* menubar-error@2x.png */; };\n\t\tAA0C676B1983375C004BBF89 /* menubar-highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C675D1983375C004BBF89 /* menubar-highlighted.png */; };\n\t\tAA0C676C1983375C004BBF89 /* menubar-highlighted@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C675E1983375C004BBF89 /* menubar-highlighted@2x.png */; };\n\t\tAA0C676D1983375C004BBF89 /* menubar-progress-1.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C675F1983375C004BBF89 /* menubar-progress-1.png */; };\n\t\tAA0C676E1983375C004BBF89 /* menubar-progress-1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67601983375C004BBF89 /* menubar-progress-1@2x.png */; };\n\t\tAA0C676F1983375C004BBF89 /* menubar-progress-2.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67611983375C004BBF89 /* menubar-progress-2.png */; };\n\t\tAA0C67701983375C004BBF89 /* menubar-progress-2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67621983375C004BBF89 /* menubar-progress-2@2x.png */; };\n\t\tAA0C67711983375C004BBF89 /* menubar-progress-3.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67631983375C004BBF89 /* menubar-progress-3.png */; };\n\t\tAA0C67721983375C004BBF89 /* menubar-progress-3@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67641983375C004BBF89 /* menubar-progress-3@2x.png */; };\n\t\tAA0C67731983375C004BBF89 /* menubar-success.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67651983375C004BBF89 /* menubar-success.png */; };\n\t\tAA0C67741983375C004BBF89 /* menubar-success@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67661983375C004BBF89 /* menubar-success@2x.png */; };\n\t\tAA0C67751983375C004BBF89 /* menubar.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67671983375C004BBF89 /* menubar.png */; };\n\t\tAA0C67761983375C004BBF89 /* menubar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA0C67681983375C004BBF89 /* menubar@2x.png */; };\n\t\tAA0C678619835367004BBF89 /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0C678519835367004BBF89 /* APIClient.swift */; };\n\t\tAA9325B319831B3E0027847E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9325B219831B3E0027847E /* main.swift */; };\n\t\tAA9325B519831B3E0027847E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9325B419831B3E0027847E /* AppDelegate.swift */; };\n\t\tAA9325B719831B3E0027847E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AA9325B619831B3E0027847E /* Images.xcassets */; };\n\t\tAA9325BA19831B3E0027847E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA9325B819831B3E0027847E /* MainMenu.xib */; };\n\t\tAA9325C619831B3E0027847E /* NimbusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9325C519831B3E0027847E /* NimbusTests.swift */; };\n\t\tAA9325F119831C860027847E /* StatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9325F019831C860027847E /* StatusItemView.swift */; };\n\t\tAAD4434A19835E9900AA5459 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD4434819835E9900AA5459 /* PreferencesWindowController.swift */; };\n\t\tAAD4434B19835E9900AA5459 /* PreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AAD4434919835E9900AA5459 /* PreferencesWindowController.xib */; };\n\t\tAAD4434D19835ED800AA5459 /* PreferencesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD4434C19835ED800AA5459 /* PreferencesManager.swift */; };\n\t\tAAD4434F1983952100AA5459 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD4434E1983952100AA5459 /* KeychainManager.swift */; };\n\t\tAAD443511984085B00AA5459 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD443501984085B00AA5459 /* SwiftyJSON.swift */; };\n\t\tAADCA9EE1984DFEB00304703 /* ScreenshotWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = AADCA9ED1984DFEB00304703 /* ScreenshotWatcher.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tAA9325C019831B3E0027847E /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = AA9325A519831B3E0027847E /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = AA9325AC19831B3E0027847E;\n\t\t\tremoteInfo = Nimbus;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tAA0C675B1983375C004BBF89 /* menubar-error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-error.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C675C1983375C004BBF89 /* menubar-error@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-error@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C675D1983375C004BBF89 /* menubar-highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-highlighted.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C675E1983375C004BBF89 /* menubar-highlighted@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-highlighted@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C675F1983375C004BBF89 /* menubar-progress-1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-1.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67601983375C004BBF89 /* menubar-progress-1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-1@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67611983375C004BBF89 /* menubar-progress-2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-2.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67621983375C004BBF89 /* menubar-progress-2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-2@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67631983375C004BBF89 /* menubar-progress-3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-3.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67641983375C004BBF89 /* menubar-progress-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-progress-3@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67651983375C004BBF89 /* menubar-success.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-success.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67661983375C004BBF89 /* menubar-success@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar-success@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C67671983375C004BBF89 /* menubar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menubar.png; sourceTree = \"<group>\"; };\n\t\tAA0C67681983375C004BBF89 /* menubar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"menubar@2x.png\"; sourceTree = \"<group>\"; };\n\t\tAA0C678519835367004BBF89 /* APIClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIClient.swift; sourceTree = \"<group>\"; };\n\t\tAA9325AD19831B3E0027847E /* Nimbus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nimbus.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tAA9325B119831B3E0027847E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tAA9325B219831B3E0027847E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = \"<group>\"; };\n\t\tAA9325B419831B3E0027847E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tAA9325B619831B3E0027847E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\tAA9325B919831B3E0027847E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\tAA9325BF19831B3E0027847E /* NimbusTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbusTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tAA9325C419831B3E0027847E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tAA9325C519831B3E0027847E /* NimbusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NimbusTests.swift; sourceTree = \"<group>\"; };\n\t\tAA9325F019831C860027847E /* StatusItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusItemView.swift; sourceTree = \"<group>\"; };\n\t\tAAD4434819835E9900AA5459 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = \"<group>\"; };\n\t\tAAD4434919835E9900AA5459 /* PreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesWindowController.xib; sourceTree = \"<group>\"; };\n\t\tAAD4434C19835ED800AA5459 /* PreferencesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesManager.swift; sourceTree = \"<group>\"; };\n\t\tAAD4434E1983952100AA5459 /* KeychainManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = \"<group>\"; };\n\t\tAAD443501984085B00AA5459 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = \"<group>\"; };\n\t\tAADCA9E81984DCC400304703 /* Nimbus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Nimbus-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tAADCA9EC1984DFEB00304703 /* ScreenshotWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenshotWatcher.h; sourceTree = \"<group>\"; };\n\t\tAADCA9ED1984DFEB00304703 /* ScreenshotWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScreenshotWatcher.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tAA9325AA19831B3E0027847E /* 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\t\tAA9325BC19831B3E0027847E /* 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\tAA9325A419831B3E0027847E = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325AF19831B3E0027847E /* Nimbus */,\n\t\t\t\tAA9325C219831B3E0027847E /* NimbusTests */,\n\t\t\t\tAA9325AE19831B3E0027847E /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325AE19831B3E0027847E /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325AD19831B3E0027847E /* Nimbus.app */,\n\t\t\t\tAA9325BF19831B3E0027847E /* NimbusTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325AF19831B3E0027847E /* Nimbus */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325B419831B3E0027847E /* AppDelegate.swift */,\n\t\t\t\tAA9325F019831C860027847E /* StatusItemView.swift */,\n\t\t\t\tAAD4434819835E9900AA5459 /* PreferencesWindowController.swift */,\n\t\t\t\tAAD4434919835E9900AA5459 /* PreferencesWindowController.xib */,\n\t\t\t\tAA0C678519835367004BBF89 /* APIClient.swift */,\n\t\t\t\tAAD4434C19835ED800AA5459 /* PreferencesManager.swift */,\n\t\t\t\tAAD4434E1983952100AA5459 /* KeychainManager.swift */,\n\t\t\t\tAAD443501984085B00AA5459 /* SwiftyJSON.swift */,\n\t\t\t\tAADCA9EC1984DFEB00304703 /* ScreenshotWatcher.h */,\n\t\t\t\tAADCA9ED1984DFEB00304703 /* ScreenshotWatcher.m */,\n\t\t\t\tAADCA9E81984DCC400304703 /* Nimbus-Bridging-Header.h */,\n\t\t\t\tAA9325B619831B3E0027847E /* Images.xcassets */,\n\t\t\t\tAA9325CF19831B6A0027847E /* Assets */,\n\t\t\t\tAA9325B019831B3E0027847E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = Nimbus;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325B019831B3E0027847E /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325B119831B3E0027847E /* Info.plist */,\n\t\t\t\tAA9325B819831B3E0027847E /* MainMenu.xib */,\n\t\t\t\tAA9325B219831B3E0027847E /* main.swift */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325C219831B3E0027847E /* NimbusTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325C519831B3E0027847E /* NimbusTests.swift */,\n\t\t\t\tAA9325C319831B3E0027847E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = NimbusTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325C319831B3E0027847E /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325C419831B3E0027847E /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tAA9325CF19831B6A0027847E /* Assets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA0C675B1983375C004BBF89 /* menubar-error.png */,\n\t\t\t\tAA0C675C1983375C004BBF89 /* menubar-error@2x.png */,\n\t\t\t\tAA0C675D1983375C004BBF89 /* menubar-highlighted.png */,\n\t\t\t\tAA0C675E1983375C004BBF89 /* menubar-highlighted@2x.png */,\n\t\t\t\tAA0C675F1983375C004BBF89 /* menubar-progress-1.png */,\n\t\t\t\tAA0C67601983375C004BBF89 /* menubar-progress-1@2x.png */,\n\t\t\t\tAA0C67611983375C004BBF89 /* menubar-progress-2.png */,\n\t\t\t\tAA0C67621983375C004BBF89 /* menubar-progress-2@2x.png */,\n\t\t\t\tAA0C67631983375C004BBF89 /* menubar-progress-3.png */,\n\t\t\t\tAA0C67641983375C004BBF89 /* menubar-progress-3@2x.png */,\n\t\t\t\tAA0C67651983375C004BBF89 /* menubar-success.png */,\n\t\t\t\tAA0C67661983375C004BBF89 /* menubar-success@2x.png */,\n\t\t\t\tAA0C67671983375C004BBF89 /* menubar.png */,\n\t\t\t\tAA0C67681983375C004BBF89 /* menubar@2x.png */,\n\t\t\t);\n\t\t\tname = Assets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tAA9325AC19831B3E0027847E /* Nimbus */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = AA9325C919831B3E0027847E /* Build configuration list for PBXNativeTarget \"Nimbus\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tAA9325A919831B3E0027847E /* Sources */,\n\t\t\t\tAA9325AA19831B3E0027847E /* Frameworks */,\n\t\t\t\tAA9325AB19831B3E0027847E /* 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 = Nimbus;\n\t\t\tproductName = Nimbus;\n\t\t\tproductReference = AA9325AD19831B3E0027847E /* Nimbus.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tAA9325BE19831B3E0027847E /* NimbusTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = AA9325CC19831B3E0027847E /* Build configuration list for PBXNativeTarget \"NimbusTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tAA9325BB19831B3E0027847E /* Sources */,\n\t\t\t\tAA9325BC19831B3E0027847E /* Frameworks */,\n\t\t\t\tAA9325BD19831B3E0027847E /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tAA9325C119831B3E0027847E /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = NimbusTests;\n\t\t\tproductName = NimbusTests;\n\t\t\tproductReference = AA9325BF19831B3E0027847E /* NimbusTests.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\tAA9325A519831B3E0027847E /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftMigration = 0720;\n\t\t\t\tLastSwiftUpdateCheck = 0720;\n\t\t\t\tLastUpgradeCheck = 0720;\n\t\t\t\tORGANIZATIONNAME = Ethanal;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tAA9325AC19831B3E0027847E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t};\n\t\t\t\t\tAA9325BE19831B3E0027847E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t\tTestTargetID = AA9325AC19831B3E0027847E;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = AA9325A819831B3E0027847E /* Build configuration list for PBXProject \"Nimbus\" */;\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 = AA9325A419831B3E0027847E;\n\t\t\tproductRefGroup = AA9325AE19831B3E0027847E /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tAA9325AC19831B3E0027847E /* Nimbus */,\n\t\t\t\tAA9325BE19831B3E0027847E /* NimbusTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tAA9325AB19831B3E0027847E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tAAD4434B19835E9900AA5459 /* PreferencesWindowController.xib in Resources */,\n\t\t\t\tAA0C676F1983375C004BBF89 /* menubar-progress-2.png in Resources */,\n\t\t\t\tAA0C67711983375C004BBF89 /* menubar-progress-3.png in Resources */,\n\t\t\t\tAA0C67701983375C004BBF89 /* menubar-progress-2@2x.png in Resources */,\n\t\t\t\tAA9325B719831B3E0027847E /* Images.xcassets in Resources */,\n\t\t\t\tAA0C67691983375C004BBF89 /* menubar-error.png in Resources */,\n\t\t\t\tAA0C676E1983375C004BBF89 /* menubar-progress-1@2x.png in Resources */,\n\t\t\t\tAA0C67761983375C004BBF89 /* menubar@2x.png in Resources */,\n\t\t\t\tAA0C67721983375C004BBF89 /* menubar-progress-3@2x.png in Resources */,\n\t\t\t\tAA0C676A1983375C004BBF89 /* menubar-error@2x.png in Resources */,\n\t\t\t\tAA0C67751983375C004BBF89 /* menubar.png in Resources */,\n\t\t\t\tAA0C676D1983375C004BBF89 /* menubar-progress-1.png in Resources */,\n\t\t\t\tAA0C676C1983375C004BBF89 /* menubar-highlighted@2x.png in Resources */,\n\t\t\t\tAA0C67731983375C004BBF89 /* menubar-success.png in Resources */,\n\t\t\t\tAA0C67741983375C004BBF89 /* menubar-success@2x.png in Resources */,\n\t\t\t\tAA9325BA19831B3E0027847E /* MainMenu.xib in Resources */,\n\t\t\t\tAA0C676B1983375C004BBF89 /* menubar-highlighted.png in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tAA9325BD19831B3E0027847E /* 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 PBXSourcesBuildPhase section */\n\t\tAA9325A919831B3E0027847E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tAAD4434D19835ED800AA5459 /* PreferencesManager.swift in Sources */,\n\t\t\t\tAAD4434A19835E9900AA5459 /* PreferencesWindowController.swift in Sources */,\n\t\t\t\tAAD4434F1983952100AA5459 /* KeychainManager.swift in Sources */,\n\t\t\t\tAAD443511984085B00AA5459 /* SwiftyJSON.swift in Sources */,\n\t\t\t\tAA9325F119831C860027847E /* StatusItemView.swift in Sources */,\n\t\t\t\tAADCA9EE1984DFEB00304703 /* ScreenshotWatcher.m in Sources */,\n\t\t\t\tAA9325B519831B3E0027847E /* AppDelegate.swift in Sources */,\n\t\t\t\tAA0C678619835367004BBF89 /* APIClient.swift in Sources */,\n\t\t\t\tAA9325B319831B3E0027847E /* main.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tAA9325BB19831B3E0027847E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tAA9325C619831B3E0027847E /* NimbusTests.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\tAA9325C119831B3E0027847E /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = AA9325AC19831B3E0027847E /* Nimbus */;\n\t\t\ttargetProxy = AA9325C019831B3E0027847E /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tAA9325B819831B3E0027847E /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tAA9325B919831B3E0027847E /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tAA9325C719831B3E0027847E /* 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\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\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_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\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tAA9325C819831B3E0027847E /* 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\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\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_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\tMACOSX_DEPLOYMENT_TARGET = 10.9;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tAA9325CA19831B3E0027847E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\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\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tINFOPLIST_FILE = Nimbus/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.ethanal.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Nimbus/Nimbus-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tAA9325CB19831B3E0027847E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\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\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = fast;\n\t\t\t\tINFOPLIST_FILE = Nimbus/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.ethanal.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Nimbus/Nimbus-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tAA9325CD19831B3E0027847E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(BUILT_PRODUCTS_DIR)/Nimbus.app/Contents/MacOS/Nimbus\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DEVELOPER_FRAMEWORKS_DIR)\",\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 = NimbusTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.ethanal.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUNDLE_LOADER)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tAA9325CE19831B3E0027847E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(BUILT_PRODUCTS_DIR)/Nimbus.app/Contents/MacOS/Nimbus\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(DEVELOPER_FRAMEWORKS_DIR)\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = NimbusTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.ethanal.${PRODUCT_NAME:rfc1034identifier}\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUNDLE_LOADER)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tAA9325A819831B3E0027847E /* Build configuration list for PBXProject \"Nimbus\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tAA9325C719831B3E0027847E /* Debug */,\n\t\t\t\tAA9325C819831B3E0027847E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tAA9325C919831B3E0027847E /* Build configuration list for PBXNativeTarget \"Nimbus\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tAA9325CA19831B3E0027847E /* Debug */,\n\t\t\t\tAA9325CB19831B3E0027847E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tAA9325CC19831B3E0027847E /* Build configuration list for PBXNativeTarget \"NimbusTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tAA9325CD19831B3E0027847E /* Debug */,\n\t\t\t\tAA9325CE19831B3E0027847E /* 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 = AA9325A519831B3E0027847E /* Project object */;\n}\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Nimbus.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/Nimbus.xcodeproj/xcshareddata/xcschemes/Nimbus.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0720\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"AA9325AC19831B3E0027847E\"\n               BuildableName = \"Nimbus.app\"\n               BlueprintName = \"Nimbus\"\n               ReferencedContainer = \"container:Nimbus.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"AA9325BE19831B3E0027847E\"\n               BuildableName = \"NimbusTests.xctest\"\n               BlueprintName = \"NimbusTests\"\n               ReferencedContainer = \"container:Nimbus.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"AA9325AC19831B3E0027847E\"\n            BuildableName = \"Nimbus.app\"\n            BlueprintName = \"Nimbus\"\n            ReferencedContainer = \"container:Nimbus.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"AA9325AC19831B3E0027847E\"\n            BuildableName = \"Nimbus.app\"\n            BlueprintName = \"Nimbus\"\n            ReferencedContainer = \"container:Nimbus.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n         <AdditionalOption\n            key = \"NSZombieEnabled\"\n            value = \"YES\"\n            isEnabled = \"YES\">\n         </AdditionalOption>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"AA9325AC19831B3E0027847E\"\n            BuildableName = \"Nimbus.app\"\n            BlueprintName = \"Nimbus\"\n            ReferencedContainer = \"container:Nimbus.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "NimbusMenuBarApp/Nimbus/NimbusTests/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": "NimbusMenuBarApp/Nimbus/NimbusTests/NimbusTests.swift",
    "content": "//\n//  NimbusTests.swift\n//  NimbusTests\n//\n//  Created by Ethan Lowman on 7/25/14.\n//  Copyright (c) 2014 Ethanal. All rights reserved.\n//\n\nimport Cocoa\nimport XCTest\n\nclass NimbusTests: 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": "README.md",
    "content": "<h1 align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ethanal/Nimbus/master/graphics_assets/exports/login_logo.png\" alt=\"Nimbus Logo\">\n  <br>\n  Nimbus\n</h1>\n\nNimbus is a private file sharer and URL shortener. Heavily inspired by [Cloudapp](http://www.getcloudapp.com/), Nimbus is a free and open source solution to file sharing and URL shortening that you can host yourself and fully control.\n\nNimbus consists of several components:\n\n* A website that displays sharing pages for generated links and redirects shortened URLs to their targets\n* A website to manage shared items\n* An API to manipulate shared items\n* A Mac OS X menubar app to upload files and shorten links\n\nThe menubar app is only compatible with OS X 10.9 and up since it is written in [Swift](https://developer.apple.com/swift/). The files are stored in Amazon S3, so you must have an AWS account.\n\n## Screenshots\n<table>\n  <tr>\n    <td><img src=\"https://raw.githubusercontent.com/ethanal/Nimbus/master/graphics_assets/docs/screenshot_management.png\" alt=\"Screenshot\"></td>\n    <td><img src=\"https://raw.githubusercontent.com/ethanal/Nimbus/master/graphics_assets/docs/screenshot_img_preview.png\" alt=\"Screenshot\"></td>\n  </tr>\n  <tr>\n    <td><img src=\"https://raw.githubusercontent.com/ethanal/Nimbus/master/graphics_assets/docs/screenshot_code_preview.png\" alt=\"Screenshot\"></td>\n    <td><img src=\"https://raw.githubusercontent.com/ethanal/Nimbus/master/graphics_assets/docs/screenshot_upload.png\" alt=\"Screenshot\"></td>\n  </tr>\n</table>\n\n## Features\n\n- Share pages that show file previews or redirect to the shortened link\n  - Image file previews\n  - Text file previews with automatic syntax highlighting if applicable\n- Screenshots are automatically uploaded and the share link is copied to the clipboard\n- Drag a file or text to the menubar icon to upload it and copy the share link to the clipboard\n- Drag a URL to the menubar icon to create a shortened link and copy it to the clipboard\n- Keep track of view counts for files and shortened URLS\n\n## Setup\n\nTo set up the Django app, perform the following steps on your server (assumes [pip](http://pip.readthedocs.org/en/latest/), [virtualenv](http://virtualenv.readthedocs.org/en/latest/), and [MySQL](http://www.mysql.com/) are already installed)\n\n1. Create a virtualenv and activate it\n2. Clone the repository (from here on, it is assumed that the respository's location is `/usr/local/www/Nimbus`)\n3. While in the repository root, install the Python requirements by running\n\n   ```bash\n   pip install -r requirements/production.txt\n   ```\n\n4. Create a database and grant a user full access to it.\n5. Follow the instructions in `nimbus/settings/secret.sample.py` to create a secrets file with your MySQL and Amazon S3 credentials\n6. Set up the environment for the Django app by running\n\n   ```bash\n   export PRODUCTION=TRUE\n   ```\n\n7. Set up the database and create your user by running `./manage.py syncdb`\n8. Start a Django shell (`./manage.py shell`) and run the following commands, replacing `example.com` with your domain name\n\n   ```python\n   from django.contrib.sites.models import Site\n   Site.objects.update(name=\"example.com\", domain=\"example.com\")\n   ```\n\n9. Collect static files by running\n\n   ```bash\n   yes yes | ./manage.py collectstatic\n   ```\n\n### Serving Nimbus\n\nMake sure you have a domain name configured with the following records:\n\n```\n@       IN A  <IP address of your server>\napi     CNAME @\naccount CNAME @\nfiles   CNAME files.<your domain name>.s3.amazonaws.com.\n```\n\nAlso make sure you have an Amazon S3 bucket called `files.<your domain name>`\n\nThe recommended setup for serving Nimbus is [Gunicorn](http://gunicorn.org/) managed by [Supervisor](http://supervisord.org/) with [nginx](http://nginx.org/) as a reverse proxy. Configuration requirements are as follows.\n\n* Nginx must be listening on the subdomains `account` and `api` of your domain as well as the root domain. Forward all of this traffic to Gunicorn - the Django app handles the subdomain routing.\n* The attribute `client_max_body_size` must be set in the nginx config to a sufficiently large value to allow uploads of big files.\n* Static file requests (`/static/`) should be aliased to `nimbus/collected_static` in the repository root\n* Supervisor must call the version of gunicorn in your virtualenv\n\n#### Example Supervisor Configuration\n\n```ini\n[program:nimbus]\ndirectory = /usr/local/www/Nimbus\nuser = nobody\ncommand = /usr/local/virtualenvs/Nimbus/bin/gunicorn nimbus.wsgi:application --user=nobody --workers=1 --bind=127.0.0.1:8080\nenvironment = PRODUCTION=TRUE\nstdout_logfile = /var/log/sites/nimbus.gunicorn.log\nstderr_logfile = /var/log/sites/nimbus.gunicorn.log\nautostart = true\nautorestart = true\n```\n\n#### Example Nginx Configuration\n```nginx\nserver {\n    listen 80;\n    server_name example.com account.example.com api.example.com;\n    return 301 https://$host$request_uri;\n}\n\nserver {\n    listen 443 ssl;\n    server_name example.com account.example.com api.example.com;\n\n    ssl on;\n    ssl_certificate /usr/local/certs/example.com.crt;\n    ssl_certificate_key /usr/local/certs/example.com.key;\n\n    client_max_body_size 1024M;\n\n    access_log /var/log/sites/nimbus.access.log;\n    error_log /var/log/sites/nimbus.error.log;\n\n    location /favicon.ico {\n        alias /usr/local/www/Nimbus/nimbus/static/img/favicon.ico;\n    }\n\n    location /static/ {\n        alias /usr/local/www/Nimbus/nimbus/collected_static/;\n    }\n\n    location / {\n        rewrite ^/((?!(api-auth|admin))(.*))/$ /$1 permanent;\n        proxy_pass http://127.0.0.1:8080;\n        proxy_set_header X-Forwarded-Host $host;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n```\n\n## API Reference\nAPI documentation can be found [here](api_docs.md).\n\n## Contact\nEthan Lowman\n- https://github.com/ethanal\n- ethan@ethanlowman.com\n"
  },
  {
    "path": "api_docs.md",
    "content": "# API Reference\n\nThe Nimbus API uses token authentication, so it is recommended that you secure the `account` and `api` subdomains with HTTPS. The `Authorization` header for requests that require it should have the following form:\n\n```\nToken 81d1445d307741e63f5c6f26d4e840175c21a34d\n```\n\nThe term \"media item\" refers to a file or a shortened link.\n\n***\n\n## Obtain Authorization Token\nObtain the API authorization token corresponding to a username/password pair.\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `POST`\n- URL: `/api-token-auth`\n- Parameters\n  - `username`: The username for the user whose token should be returned\n  - `password`: The password for the user whose token should be returned\n\n### Response\n- Status: 200 OK\n- Body:\n\n  ```js\n  {\n      \"token\": \"81d1445d307741e63f5c6f26d4e840175c21a34d\"\n  }\n  ```\n\n### Errors\n\nIf the provided credentials are not valid, the following response is returned:\n\n- Status: 400 Bad Request\n- Body:\n\n  ```js\n  {\n      \"non_field_errors\": [\n          \"Unable to login with provided credentials.\"\n      ]\n  }\n  ```\n\n***\n\n## List Media Items\nList all media items created by the authorized user.\n\nAll media items are serialized the same way. Links and files can be differentiated using the `media_type` attribute.\n\nValid media type codes are as follows:\n\n- `URL`: Shortened URLS\n- `IMG`: Image files\n- `TXT`: Text files\n- `ARC`: Archive files\n- `AUD`: Audio files\n- `VID`: Video files\n- `ETC`: Other files\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `GET`\n- URL: `/media/list`\n- Optional URL Parameters:\n  - `media_type`: The media type code used to filter the list (e.g. `GET /media/list?media_type=IMG` will list all images)\n\n### Response\n- Status: 200 OK\n- Body:\n\n  ```js\n  [\n      {\n          \"url_hash\": \"clJwWj\",\n          \"share_url\": \"http://example.com/clJwWj\",\n          \"name\": \"example.png\",\n          \"target_url\": \"\",\n          \"target_file\": \"de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n          \"target_file_url\": \"http://files.example.com/de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n          \"view_count\": 4,\n          \"upload_date\": \"2014-01-02T03:04:05.060Z\",\n          \"media_type\": \"IMG\"\n      },\n      {\n          \"url_hash\": \"i7UrcU\",\n          \"share_url\": \"http://example.com/i7UrcU\",\n          \"name\": \"http://en.wikipedia.org/wiki/Example\",\n          \"target_url\": \"http://en.wikipedia.org/wiki/Example\",\n          \"target_file\": \"\",\n          \"target_file_url\": \"\",\n          \"view_count\": 2,\n          \"upload_date\": \"upload_date\": \"2014-01-02T03:45:06.070Z\",\n          \"media_type\": \"URL\"\n      }\n  ]\n  ```\n\n***\n\n## Show Media Item Details\nShow details for a media item.\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `GET`\n- URL: `/media/show`\n- URL Parameters:\n  - `url_hash`: The media type code used to filter the list (e.g. `GET /media/list?media_type=IMG` will list all images)\n\n### Response\n- Status: 200 OK\n- Body:\n\n  ```js\n  {\n      \"url_hash\": \"clJwWj\",\n      \"share_url\": \"http://example.com/clJwWj\",\n      \"name\": \"example.png\",\n      \"target_url\": \"\",\n      \"target_file\": \"de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n      \"target_file_url\": \"http://files.example.com/de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n      \"view_count\": 4,\n      \"upload_date\": \"2014-01-02T03:04:05.060Z\",\n      \"media_type\": \"IMG\"\n  }\n  ```\n\n***\n\n## Upload File\nCreate a media item for a file.\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `POST`\n- URL: `/media/add_file`\n- Parameters\n  - `file`: The file to upload.\n\n### Response\n- Status: 201 Created\n- Body:\n\n  ```js\n  {\n      \"url_hash\": \"clJwWj\",\n      \"share_url\": \"http://example.com/clJwWj\",\n      \"name\": \"example.png\",\n      \"target_file\": \"de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n      \"target_file_url\": \"http://files.example.com/de807a6626ed47c1adf3696bfb2cb9ef/example.png\",\n      \"upload_date\": \"2014-01-02T03:04:05.060Z\",\n      \"media_type\": \"IMG\"\n  }\n  ```\n\n***\n\n## Add Link\nCreate a media item for a URL.\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `POST`\n- URL: `/media/add_link`\n- Parameters\n  - `target_url`: The URL to shorten.\n\n### Response\n- Status: 201 Created\n- Body:\n\n  ```js\n  {\n      \"url_hash\": \"i7UrcU\",\n      \"share_url\": \"http://example.com/i7UrcU\",\n      \"target_url\": \"http://en.wikipedia.org/wiki/Example\",\n      \"upload_date\": \"2014-01-02T03:45:06.070Z\"\n  }\n  ```\n\n***\n\n## Delete Media Items\nDelete one or more media items.\n\n### Request\n- Requires: Authentication\n- HTTP Request Method: `DELETE`\n- URL: `/media/delete`\n- URL Parameters\n  - `url_hash`: The URL hash of the media item that should be deleted. This parameter can be repeated to delete multiple items.\n\n### Response\n- Status: 204 No Content\n\n***\n"
  },
  {
    "path": "graphics_assets/assets.sketch/metadata",
    "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>app</key>\n\t<string>com.bohemiancoding.sketch3</string>\n\t<key>build</key>\n\t<integer>8054</integer>\n\t<key>commit</key>\n\t<string>b2079fe10151ad0eef6cc553b7369ec78d67b9b5</string>\n\t<key>fonts</key>\n\t<array/>\n\t<key>length</key>\n\t<integer>193569</integer>\n\t<key>version</key>\n\t<integer>37</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "graphics_assets/assets.sketch/version",
    "content": "37"
  },
  {
    "path": "manage.py",
    "content": "#!/usr/bin/env python\nimport os\nimport sys\n\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"nimbus.settings\")\n\n    from django.core.management import execute_from_command_line\n\n    execute_from_command_line(sys.argv)\n"
  },
  {
    "path": "nimbus/__init__.py",
    "content": ""
  },
  {
    "path": "nimbus/apps/__init__.py",
    "content": "from django.conf.urls import patterns, include, url\nfrom nimbus import settings\n\n\ndef debug_urls():\n    if settings.SHOW_DEBUG_TOOLBAR:\n        import debug_toolbar\n\n        return patterns(\"\",\n            url(r\"^__debug__/\", include(debug_toolbar.urls)),\n        )\n    return []\n"
  },
  {
    "path": "nimbus/apps/accounts/__init__.py",
    "content": ""
  },
  {
    "path": "nimbus/apps/accounts/forms.py",
    "content": "import logging\nfrom django.contrib.auth.forms import AuthenticationForm\nfrom django import forms\nfrom django.utils.html import strip_tags\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass AuthenticateForm(AuthenticationForm):\n    username = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={\"placeholder\": \"Username\"}), error_messages={\"required\": \"Invalid username\"})\n    password = forms.CharField(required=True, widget=forms.widgets.PasswordInput(attrs={\"placeholder\": \"Password\"}), error_messages={\"required\": \"Invalid password\"})\n\n    def is_valid(self):\n        form = super(AuthenticateForm, self).is_valid()\n\n        for f, error in self.errors.iteritems():\n            if f == \"__all__\":\n                self.fields[\"password\"].widget.attrs.update({\"class\": \"error\", \"placeholder\": \"Invalid password\"})\n            else:\n                self.fields[f].widget.attrs.update({\"class\": \"error\", \"placeholder\": strip_tags(str(error))})\n        logger.debug(self.errors)\n        return form\n\n\nclass UploadFileForm(forms.Form):\n    file = forms.FileField()\n"
  },
  {
    "path": "nimbus/apps/accounts/urls.py",
    "content": "from django.conf.urls import include, url\nfrom django.contrib import admin\nfrom . import views\nfrom nimbus.apps import debug_urls\n\n\nurlpatterns = debug_urls()\n\nadmin.autodiscover()\n\nurlpatterns += [\n    url(r'^admin/', include(admin.site.urls)),\n    url(r\"^$\", views.index, name=\"index\"),\n    url(r\"^login$\", views.login_view.as_view(), name=\"login\"),\n    url(r\"^logout$\", views.logout_view, name=\"logout\"),\n    url(r\"^(?P<media_type>(images)|(links)|(text)|(archives)|(audio)|(video)|(other))$\", views.dashboard_view, name=\"filter_media\"),\n]\n"
  },
  {
    "path": "nimbus/apps/accounts/views.py",
    "content": "import logging\nfrom .forms import AuthenticateForm\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.paginator import Paginator, EmptyPage, PageNotAnInteger\nfrom django.shortcuts import render, redirect\nfrom django.contrib.auth import login, logout\nfrom django.views.generic.base import View\nfrom nimbus.apps.media.models import Media\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef index(request, auth_form=None):\n    if request.user.is_authenticated():\n        return dashboard_view(request)\n    else:\n        auth_form = auth_form or AuthenticateForm()\n        request.session.set_test_cookie()\n        return render(request, \"nimbus/accounts/login.html\", {\n            \"auth_form\": auth_form\n        })\n\n\nclass login_view(View):\n    def post(self, request):\n        form = AuthenticateForm(data=request.POST)\n\n        if request.session.test_cookie_worked():\n            request.session.delete_test_cookie()\n        else:\n            logger.error(\"No cookie support detected! This could cause problems.\")\n\n        if form.is_valid():\n            login(request, form.get_user())\n            logger.info(\"Login succeeded as {}\".format(request.POST.get(\"username\", \"unknown\")))\n            next = request.GET.get(\"next\", \"/\")\n            return redirect(next)\n        else:\n            logger.info(\"Login failed as {}\".format(request.POST.get(\"username\", \"unknown\")))\n            return index(request, auth_form=form)  # Modified to show errors\n\n    def get(self, request):\n        return index(request)\n\n\ndef logout_view(request):\n    logout(request)\n    return redirect(\"/\")\n\n\n@login_required\ndef dashboard_view(request, media_type=\"all\"):\n    media_type_codes = {j.lower(): i for i, j in Media.MEDIA_TYPES_PLURAL}\n    if media_type == \"all\":\n        media_list = Media.objects.filter(user=request.user).order_by(\"-upload_date\", \"name\")\n    else:\n        media_list = Media.objects.filter(user=request.user, media_type=media_type_codes[media_type]).order_by(\"-upload_date\", \"name\")\n\n    paginator = Paginator(media_list, 50)\n    page = request.GET.get(\"p\")\n    try:\n        media = paginator.page(page)\n    except PageNotAnInteger:\n        media = paginator.page(1)\n    except EmptyPage:\n        media = paginator.page(paginator.num_pages)\n\n    return render(request, \"nimbus/accounts/dashboard.html\", {\n        \"media_type\": media_type,\n        \"media_type_code\": media_type_codes.get(media_type, \"ALL\"),\n        \"media\": media\n    })\n"
  },
  {
    "path": "nimbus/apps/api/__init__.py",
    "content": ""
  },
  {
    "path": "nimbus/apps/api/urls.py",
    "content": "from django.conf.urls import url, include\nfrom nimbus.apps import debug_urls\nfrom . import views\n\n\nurlpatterns = debug_urls()\n\nurlpatterns += [\n    url(r\"^$\", views.api_root, name=\"api_root\"),\n    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),\n    url(r'^api-token-auth$', 'rest_framework.authtoken.views.obtain_auth_token'),\n    url(r\"^media/list$\", views.MediaList.as_view(), name=\"media_list\"),\n    url(r\"^media/show$\", views.MediaDetail.as_view(), name=\"media_detail\"),\n    url(r\"^media/add_file$\", views.AddFile.as_view(), name=\"add_file\"),\n    url(r\"^media/add_link$\", views.AddLink.as_view(), name=\"add_link\"),\n    url(r\"^media/delete$\", views.delete_media, name=\"delete_media\"),\n]\n"
  },
  {
    "path": "nimbus/apps/api/views.py",
    "content": "from django.shortcuts import get_object_or_404\nfrom django.template.loader import render_to_string\nfrom rest_framework import generics, views, status\nfrom rest_framework.decorators import api_view\nfrom rest_framework.exceptions import APIException\nfrom rest_framework.response import Response\nfrom rest_framework.parsers import MultiPartParser\nfrom nimbus.apps.media.models import Media\nfrom nimbus.apps.media.serializers import MediaSerializer, CreateLinkSerializer, ViewCreatedFileSerializer, ViewCreatedLinkSerializer\n\n\nclass URLHashParameterRequiredException(APIException):\n    status_code = 400\n    default_detail = \"'url_hash' parameter required\"\n\n\n@api_view((\"GET\",))\ndef api_root(request):\n    \"\"\"Welcome to the Nimbus API!\n    Documentation can be found at [github.com/ethanal/nimbus](http://github.com/ethanal/nimbus)\n    \"\"\"\n\n    return Response(\"Documentation can be found at http://github.com/ethanal/nimbus\")\n\n\nclass MediaList(generics.ListAPIView):\n    serializer_class = MediaSerializer\n\n    def get_queryset(self):\n        user = self.request.user\n        if \"media_type\" in self.request.QUERY_PARAMS:\n            return Media.objects.filter(user=user, media_type=self.requeset.QUERY_PARAMS[\"media_type\"])\n        return Media.objects.filter(user=user)\n\n\nclass MediaDetail(generics.RetrieveAPIView):\n    serializer_class = MediaSerializer\n\n    def get_object(self):\n        if \"url_hash\" not in self.request.QUERY_PARAMS:\n            raise URLHashParameterRequiredException()\n\n        queryset = Media.objects.filter(user=self.request.user)\n        return get_object_or_404(queryset, url_hash=self.request.QUERY_PARAMS[\"url_hash\"])\n\n\nclass AddFile(views.APIView):\n    parser_classes = (MultiPartParser,)\n\n    def post(self, request):\n        f = request.FILES.get(\"file\", None)\n\n        if not f:\n            return Response(status=400)\n\n        media_item = Media(name=f.name, user=request.user, target_file=f)\n        media_item.save()\n        if media_item.media_type == \"TXT\":\n            text = f.file.getvalue()\n            media_item.fill_syntax_highlighted(text)\n\n        data = ViewCreatedFileSerializer(media_item).data\n\n        if \"include-html\" in request.QUERY_PARAMS:\n            context = {\n                \"media_item\": media_item\n            }\n            html = render_to_string(\"nimbus/accounts/media_table_row.html\", context)\n            data[\"html\"] = html\n\n        return Response(data, status=201)\n\n\nclass AddLink(generics.CreateAPIView):\n    serializer_class = CreateLinkSerializer\n\n    def pre_save(self, obj):\n        obj.user = self.request.user\n        obj.name = obj.target_url\n\n    def create(self, request, *args, **kwargs):\n        response = super(AddLink, self).create(request, *args, **kwargs)\n        if response.status_code == status.HTTP_201_CREATED:\n            response.data = ViewCreatedLinkSerializer(self.object).data\n        return response\n\n\n@api_view((\"DELETE\",))\ndef delete_media(request):\n    user = request.user\n    hashes = request.QUERY_PARAMS.getlist(\"url_hash\")\n    Media.objects.filter(user=user, url_hash__in=hashes).delete()\n    return Response(status=204)\n"
  },
  {
    "path": "nimbus/apps/media/__init__.py",
    "content": ""
  },
  {
    "path": "nimbus/apps/media/admin.py",
    "content": "from django.contrib import admin\nfrom .models import Media\n\n\n\nclass MediaAdmin(admin.ModelAdmin):\n    fields = (\"url_hash\",\n              \"name\",\n              \"target_url\",\n              \"target_file\",\n              \"user\",\n              \"syntax_highlighted\")\n    list_display = (\"id\",\n                    \"url_hash\",\n                    \"name\",\n                    \"user\",\n                    \"target_url\",\n                    \"target_file\",\n                    \"upload_date\",\n                    \"view_count\",\n                    \"media_type\")\n    list_filter = (\"media_type\",)\n    search_fields = (\"id\",\n                     \"url_hash\",\n                     \"name\",\n                     \"user__username\",\n                     \"target_url\",\n                     \"target_file\",\n                     \"upload_date\",\n                     \"view_count\",\n                     \"media_type\")\n\nadmin.site.register(Media, MediaAdmin)\n"
  },
  {
    "path": "nimbus/apps/media/models.py",
    "content": "import mimetypes\nimport uuid\nimport string\nimport random\nfrom pygments import highlight\nfrom pygments.lexers import guess_lexer_for_filename\nfrom pygments.formatters import HtmlFormatter\nfrom django.db import models\nfrom django.db.models.signals import post_save, pre_delete\nfrom django.dispatch import receiver\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.models import User\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import URLValidator\nfrom django.utils.encoding import filepath_to_uri\nfrom rest_framework.authtoken.models import Token\n\n\nclass Media(models.Model):\n    MEDIA_TYPES = (\n        (\"IMG\", \"Image\"),\n        (\"URL\", \"Link\"),\n        (\"TXT\", \"Text\"),\n        (\"ARC\", \"Archive\"),\n        (\"AUD\", \"Audio\"),\n        (\"VID\", \"Video\"),\n        (\"ETC\", \"Other\")\n    )\n\n    MEDIA_TYPES_PLURAL = (\n        (\"IMG\", \"Images\"),\n        (\"URL\", \"Links\"),\n        (\"TXT\", \"Text\"),\n        (\"ARC\", \"Archives\"),\n        (\"AUD\", \"Audio\"),\n        (\"VID\", \"Video\"),\n        (\"ETC\", \"Other\")\n    )\n\n    _random_filename = lambda i, f: str(uuid.uuid4()).replace(\"-\", \"\") + \"/\" + f\n\n    url_hash = models.CharField(max_length=100, blank=True)\n    name = models.CharField(max_length=500)\n    target_url = models.URLField(max_length=2048, blank=True)\n    target_file = models.FileField(upload_to=_random_filename, blank=True)\n    view_count = models.IntegerField(default=0)\n    upload_date = models.DateTimeField(auto_now_add=True)\n    user = models.ForeignKey(User)\n    media_type = models.CharField(max_length=3, choices=MEDIA_TYPES, blank=True)\n    syntax_highlighted = models.TextField(blank=True)\n\n    # all prefixed by \"application/\"\n    ARCHIVE_MIME_TYPES = [\"x-cpio\",\n                          \"x-shar\",\n                          \"x-tar\",\n                          \"x-bzip2\",\n                          \"x-gzip\",\n                          \"x-lzip\",\n                          \"x-lzma\",\n                          \"x-lzop\",\n                          \"x-xz\",\n                          \"x-compress\",\n                          \"x-compress\",\n                          \"x-7z-compressed\",\n                          \"x-ace-compressed\",\n                          \"x-astrotite-afa\",\n                          \"x-alz-compressed\",\n                          \"vnd.android.package-archive\",\n                          \"x-arj\",\n                          \"x-b1\",\n                          \"vnd.ms-cab-compressed\",\n                          \"x-cfs-compressed\",\n                          \"x-dar\",\n                          \"x-dgc-compressed\",\n                          \"x-apple-diskimage\",\n                          \"x-gca-compressed\",\n                          \"x-lzh\",\n                          \"x-lzx\",\n                          \"x-rar-compressed\",\n                          \"x-stuffit\",\n                          \"x-stuffitx\",\n                          \"x-gtar\",\n                          \"zip\",\n                          \"x-zoo\",\n                          \"x-par2\"]\n\n    @property\n    def raw_url(self):\n        return self.target_file.storage.url(self.target_file.name)\n\n    @property\n    def raw_ssl_url(self):\n        storage = self.target_file.storage\n        name = storage._normalize_name(storage._clean_name(self.target_file.name))\n        return \"https://s3.amazonaws.com/{}/{}\".format(storage.bucket_name, filepath_to_uri(name))\n\n    @staticmethod\n    def guess_media_type(resource_name):\n        validator = URLValidator()\n        try:\n            validator(resource_name)\n        except ValidationError:\n            pass\n        else:\n            return \"URL\"\n\n        top, sub = (mimetypes.guess_type(resource_name, strict=False)[0] or \"/\").split(\"/\")\n        if top == \"image\":\n            return \"IMG\"\n        if top == \"text\":\n            return \"TXT\"\n        if top == \"audio\":\n            return \"AUD\"\n        if top == \"video\":\n            return \"VID\"\n        if (top == \"application\") and (sub in Media.ARCHIVE_MIME_TYPES):\n            return \"ARC\"\n        return \"ETC\"\n\n    def fill_syntax_highlighted(self, text):\n        lexer = guess_lexer_for_filename(self.name, text)\n        html = highlight(text, lexer, HtmlFormatter())\n        self.syntax_highlighted = html\n        self.save()\n\n    def __unicode__(self):\n        return self.name\n\n    class Meta:\n        verbose_name_plural = \"Media\"\n\n\n@receiver(post_save, sender=Media)\ndef fill_auto_fields(sender, **kwargs):\n    instance = kwargs.get(\"instance\")\n\n    fields = {}\n    if not instance.media_type:\n        fields[\"media_type\"] = Media.guess_media_type(instance.name)\n    if not instance.url_hash:\n        url_hash = None\n        alphabet = string.uppercase + string.lowercase + string.digits\n        length = 5\n        tries = 0\n        while url_hash is None or Media.objects.filter(url_hash=url_hash).exists():\n            url_hash = \"\".join(random.SystemRandom().choice(alphabet) for _ in range(length))\n            tries += 1\n            if tries % 3 == 0:\n                length += 1\n        fields[\"url_hash\"] = url_hash\n\n    if fields:\n        for field, value in fields.items():\n            setattr(instance, field, value)\n        instance.save()\n\n\n@receiver(pre_delete, sender=Media)\ndef delete_file_from_storage(sender, **kwargs):\n    instance = kwargs.get(\"instance\")\n\n    if instance.target_file:\n        instance.target_file.delete()\n\n\n# No real better place to put this...\n@receiver(post_save, sender=get_user_model())\ndef create_auth_token(sender, instance=None, created=False, **kwargs):\n    if created:\n        Token.objects.create(user=instance)\n"
  },
  {
    "path": "nimbus/apps/media/serializers.py",
    "content": "from rest_framework import serializers\nfrom subdomains.utils import reverse\nfrom nimbus.apps.media.models import Media\n\n\ndef _get_target_file_url(obj):\n    if obj.target_file:\n        return obj.raw_url\n    return \"\"\n\n\ndef _get_share_url(obj):\n    return reverse(\"share\",\n                   subdomain=None,\n                   kwargs={\"url_hash\": obj.url_hash})\n\n\nclass MediaSerializer(serializers.ModelSerializer):\n    target_file_url = serializers.SerializerMethodField(\"get_target_file_url\")\n    share_url = serializers.SerializerMethodField(\"get_share_url\")\n\n    def get_target_file_url(self, obj):\n        return _get_target_file_url(obj)\n\n    def get_share_url(self, obj):\n        return _get_share_url(obj)\n\n    class Meta:\n        model = Media\n        fields = (\"url_hash\",\n                  \"share_url\",\n                  \"name\",\n                  \"target_url\",\n                  \"target_file\",\n                  \"target_file_url\",\n                  \"view_count\",\n                  \"upload_date\",\n                  \"media_type\")\n\n\nclass ViewCreatedFileSerializer(serializers.ModelSerializer):\n    target_file_url = serializers.SerializerMethodField(\"get_target_file_url\")\n    share_url = serializers.SerializerMethodField(\"get_share_url\")\n\n    def get_target_file_url(self, obj):\n        return _get_target_file_url(obj)\n\n    def get_share_url(self, obj):\n        return _get_share_url(obj)\n\n    class Meta:\n        model = Media\n        fields = (\"url_hash\",\n                  \"share_url\",\n                  \"name\",\n                  \"target_file\",\n                  \"target_file_url\",\n                  \"upload_date\",\n                  \"media_type\")\n\n\nclass CreateLinkSerializer(serializers.ModelSerializer):\n    target_url = serializers.URLField(max_length=2048)\n\n    class Meta:\n        model = Media\n        fields = (\"target_url\",)\n\n\nclass ViewCreatedLinkSerializer(serializers.ModelSerializer):\n    share_url = serializers.SerializerMethodField(\"get_share_url\")\n\n    def get_share_url(self, obj):\n        return _get_share_url(obj)\n\n    class Meta:\n        model = Media\n        fields = (\"url_hash\",\n                  \"share_url\",\n                  \"target_url\",\n                  \"upload_date\")\n"
  },
  {
    "path": "nimbus/apps/media/urls.py",
    "content": "from django.conf.urls import url\nfrom django.views.generic.base import RedirectView\nfrom subdomains.utils import reverse\nfrom nimbus.apps import debug_urls\nfrom nimbus.apps.media import views\n\nurlpatterns = debug_urls()\n\nurlpatterns += [\n    url(r\"^$\", RedirectView.as_view(url=reverse(\"index\", subdomain=\"account\"))),\n    url(r\"^(?P<url_hash>[a-zA-Z0-9]+)$\", views.share_view, name=\"share\"),\n]\n"
  },
  {
    "path": "nimbus/apps/media/views.py",
    "content": "from pygments.formatters import HtmlFormatter\nfrom django.shortcuts import render, get_object_or_404, redirect\nfrom .models import Media\n\n\ndef share_view(request, url_hash):\n    media_item = get_object_or_404(Media, url_hash=url_hash)\n    media_item.view_count += 1\n    media_item.save()\n\n    if media_item.media_type == \"URL\":\n        return redirect(media_item.target_url)\n\n    templates = {\n        \"IMG\": \"nimbus/media/share_img_preview.html\",\n        \"TXT\": \"nimbus/media/share_txt_preview.html\"\n    }\n    template = templates.setdefault(media_item.media_type, \"nimbus/media/share_download.html\")\n\n    context = {\n        \"media_item\": media_item\n    }\n\n    if media_item.media_type == \"TXT\":\n        context[\"syntax_highlighting_style_defs\"] = HtmlFormatter().get_style_defs('.highlight')\n\n    return render(request, template, context)\n"
  },
  {
    "path": "nimbus/settings/__init__.py",
    "content": "import os\nimport sys\n\nif os.getenv(\"PRODUCTION\", \"FALSE\") == \"TRUE\":\n    from production import *\nelse:\n    from local import *\n"
  },
  {
    "path": "nimbus/settings/base.py",
    "content": "import os\nimport re\nfrom fnmatch import fnmatch\nfrom boto.s3.connection import VHostCallingFormat\nfrom secret import *\n\n\nPROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\nLOGIN_URL = \"/login\"\nLOGIN_REDIRECT_URL = \"/\"\n\nALLOWED_HOSTS = [\".\" + HOSTNAME]\n\nAPPEND_SLASH = False\n\n\nADMINS = (\n    # ('Your Name', 'your_email@example.com'),\n)\n\nMANAGERS = ADMINS\n\n# Local time zone for this installation. Choices can be found here:\n# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name\n# although not all choices may be available on all operating systems.\n# In a Windows environment this must be set to your system time zone.\nTIME_ZONE = \"America/New_York\"\n\n# Language code for this installation. All choices can be found here:\n# http://www.i18nguy.com/unicode/language-identifiers.html\nLANGUAGE_CODE = \"en-us\"\n\nSITE_ID = 1\n\n# If you set this to False, Django will make some optimizations so as not\n# to load the internationalization machinery.\nUSE_I18N = False\n\n# If you set this to False, Django will not format dates, numbers and\n# calendars according to the current locale.\nUSE_L10N = True\n\n# If you set this to False, Django will not use timezone-aware datetimes.\nUSE_TZ = True\n\n# Absolute path to the directory static files should be collected to.\n# Don't put anything in this directory yourself; store your static files\n# in apps' \"static/\" subdirectories and in STATICFILES_DIRS.\n# Example: \"/home/media/media.lawrence.com/static/\"\nSTATIC_ROOT = os.path.join(PROJECT_ROOT, \"collected_static\")\n\n# URL prefix for static files.\n# Example: \"http://media.lawrence.com/static/\"\nSTATIC_URL = \"/static/\"\n\n# Additional locations of static files\nSTATICFILES_DIRS = (\n    # Put strings here, like \"/home/html/static\" or \"C:/www/django/static\".\n    # Always use forward slashes, even on Windows.\n    # Don't forget to use absolute paths, not relative paths.\n    os.path.join(PROJECT_ROOT, \"static\"),\n)\n\n# List of finder classes that know how to find static files in\n# various locations.\nSTATICFILES_FINDERS = (\n    'django.contrib.staticfiles.finders.FileSystemFinder',\n    'django.contrib.staticfiles.finders.AppDirectoriesFinder',\n#    'django.contrib.staticfiles.finders.DefaultStorageFinder',\n)\n\n# List of callables that know how to import templates from various sources.\nTEMPLATE_LOADERS = (\n    'django.template.loaders.filesystem.Loader',\n    'django.template.loaders.app_directories.Loader',\n#     'django.template.loaders.eggs.Loader',\n)\n\nTEMPLATE_CONTEXT_PROCESSORS = (\n    \"django.core.context_processors.request\",\n    \"django.contrib.auth.context_processors.auth\",\n)\n\n\nMIDDLEWARE_CLASSES = (\n    \"corsheaders.middleware.CorsMiddleware\",\n    \"subdomains.middleware.SubdomainURLRoutingMiddleware\",\n    'django.middleware.common.CommonMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'corsheaders.middleware.CorsPostCsrfMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    # Uncomment the next line for simple clickjacking protection:\n    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',\n)\n\nROOT_URLCONF = \"nimbus.apps.media.urls\"\n\nSUBDOMAIN_URLCONFS = {\n    None: \"nimbus.apps.media.urls\",\n    \"account\": \"nimbus.apps.accounts.urls\",\n    \"api\": \"nimbus.apps.api.urls\"\n}\n\n# Python dotted path to the WSGI application used by Django's runserver.\nWSGI_APPLICATION = 'nimbus.wsgi.application'\n\nTEMPLATE_DIRS = (\n    # Put strings here, like \"/home/html/django_templates\" or \"C:/www/django/templates\".\n    # Always use forward slashes, even on Windows.\n    # Don't forget to use absolute paths, not relative paths.\n    os.path.join(PROJECT_ROOT, \"templates\"),\n)\n\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': (\n        \"rest_framework.authentication.TokenAuthentication\",\n        #'rest_framework.authentication.SessionAuthentication',\n        \"nimbus.utils.SessionAuthentication\",\n    ),\n    'DEFAULT_PERMISSION_CLASSES': (\n        'rest_framework.permissions.IsAuthenticated',\n    ),\n}\n\n\nINSTALLED_APPS = (\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.sites',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'django.contrib.admin',\n    \"nimbus.apps.accounts\",\n    \"nimbus.apps.api\",\n    \"nimbus.apps.media\",\n    \"subdomains\",\n    \"rest_framework\",\n    \"rest_framework.authtoken\",\n    \"widget_tweaks\",\n    \"corsheaders\",\n    \"storages\"\n)\n\nSESSION_COOKIE_DOMAIN = \".\" + HOSTNAME\nCSRF_COOKIE_DOMAIN = SESSION_COOKIE_DOMAIN\n\nCORS_ORIGIN_REGEX_WHITELIST = (r\"^(https?://)?(\\w+\\.)?{}$\".format(re.escape(HOSTNAME)),)\nCORS_ALLOW_CREDENTIALS = True\nCORS_ALLOW_HEADERS = (\n    'x-requested-with',\n    'content-type',\n    'accept',\n    'origin',\n    'authorization',\n    'x-csrftoken',\n    'cache-control'\n)\nCORS_REPLACE_HTTPS_REFERER = True\n\nDEFAULT_FILE_STORAGE = \"storages.backends.s3boto.S3BotoStorage\"\nAWS_STORAGE_BUCKET_NAME = \"files.\" + HOSTNAME\nAWS_S3_CALLING_FORMAT = VHostCallingFormat()\nAWS_S3_SECURE_URLS = False\nAWS_S3_CUSTOM_DOMAIN = \"files.\" + HOSTNAME\n\n\nclass glob_list(list):\n    \"\"\"A list of glob-style strings.\"\"\"\n\n    def __contains__(self, key):\n        print(key)\n        \"\"\"Check if a string matches a glob in the list.\"\"\"\n        for elt in self:\n            if fnmatch(key, elt):\n                return True\n        return False\n\nINTERNAL_IPS = glob_list([\n    \"127.0.0.1\"\n])\n\n\n# A sample logging configuration. The only tangible logging\n# performed by this configuration is to send an email to\n# the site admins on every HTTP 500 error when DEBUG=False.\n# See http://docs.djangoproject.com/en/dev/topics/logging for\n# more details on how to customize your logging configuration.\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'filters': {\n        'require_debug_false': {\n            '()': 'django.utils.log.RequireDebugFalse'\n        }\n    },\n    'handlers': {\n        'mail_admins': {\n            'level': 'ERROR',\n            'filters': ['require_debug_false'],\n            'class': 'django.utils.log.AdminEmailHandler'\n        }\n    },\n    'loggers': {\n        'django.request': {\n            'handlers': ['mail_admins'],\n            'level': 'ERROR',\n            'propagate': True,\n        },\n    }\n}\n\n"
  },
  {
    "path": "nimbus/settings/local.py",
    "content": "import os\nimport logging\nfrom .base import *\n\nlogger = logging.getLogger(__name__)\n\nDEBUG = True\nTEMPLATE_DEBUG = DEBUG\n\nDATABASES = {\n    \"default\": {\n        \"ENGINE\": \"django.db.backends.sqlite3\",\n        \"NAME\": os.path.join(os.path.dirname(PROJECT_ROOT),\n                             \"testing_database.db\"),\n    }\n}\n\n\nINSTALLED_APPS += (\"django_extensions\",)\n\nSHOW_DEBUG_TOOLBAR = os.getenv(\"SHOW_DEBUG_TOOLBAR\", \"YES\") == \"YES\"\n\nif SHOW_DEBUG_TOOLBAR:\n    DEBUG_TOOLBAR_PATCH_SETTINGS = False\n\n    DEBUG_TOOLBAR_CONFIG = {\n    }\n\n    DEBUG_TOOLBAR_PANELS = [\n        \"debug_toolbar.panels.versions.VersionsPanel\",\n        \"debug_toolbar.panels.timer.TimerPanel\",\n        # \"debug_toolbar.panels.profiling.ProfilingPanel\",\n        \"debug_toolbar.panels.settings.SettingsPanel\",\n        \"debug_toolbar.panels.headers.HeadersPanel\",\n        \"debug_toolbar.panels.request.RequestPanel\",\n        \"debug_toolbar.panels.sql.SQLPanel\",\n        \"debug_toolbar.panels.staticfiles.StaticFilesPanel\",\n        \"debug_toolbar.panels.templates.TemplatesPanel\",\n        \"debug_toolbar.panels.signals.SignalsPanel\",\n        \"debug_toolbar.panels.logging.LoggingPanel\",\n        \"debug_toolbar.panels.redirects.RedirectsPanel\",\n    ]\n\n    MIDDLEWARE_CLASSES = (\n        \"debug_toolbar.middleware.DebugToolbarMiddleware\",\n    ) + MIDDLEWARE_CLASSES\n\n    INSTALLED_APPS += (\"debug_toolbar\",)\n\n"
  },
  {
    "path": "nimbus/settings/production.py",
    "content": "import urlparse\nfrom .base import *\n\n\nDEBUG = os.getenv(\"DEBUG\", \"FALSE\") == \"TRUE\"\nTEMPLATE_DEBUG = DEBUG\n\nSHOW_DEBUG_TOOLBAR = False\n\nurlparse.uses_netloc.append(\"mysql\")\nurl = urlparse.urlparse(DATABASE_URL)\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.mysql',\n        'NAME': url.path[1:],\n        'USER': url.username,\n        'PASSWORD': url.password,\n        'HOST': url.hostname\n    }\n}\n\nSESSION_COOKIE_SECURE = False\nCSRF_COOKIE_SECURE = False\nDEFAULT_URL_SCHEME = \"https\"\nSECURE_PROXY_SSL_HEADER = (\"HTTP_X_FORWARDED_PROTO\", \"https\")\n\ntry:\n    RAVEN_CONFIG\n    INSTALLED_APPS += (\n        'raven.contrib.django.raven_compat',\n    )\nexcept NameError:\n    pass\n"
  },
  {
    "path": "nimbus/settings/secret.sample.py",
    "content": "\"\"\"\nRename this file to 'secret.py' once all settings are defined\n\n\"\"\"\n\nSECRET_KEY = \"...\"\n\nHOSTNAME = \"example.com\"\n\nDATABASE_URL = \"mysql://<user>:<password>@<host>/<database>\"\n\nAWS_ACCESS_KEY_ID = \"12345\"\nAWS_SECRET_ACCESS_KEY = \"12345\"\n"
  },
  {
    "path": "nimbus/static/css/base.css",
    "content": "#main-nav {\n    border-radius: 0;\n}\n#main-nav .navbar-brand {\n    padding: 7px 15px;\n}\n.cloud-logo {\n    vertical-align: middle;\n    font-size: 36px;\n}\n\ninput {\n    -webkit-box-shadow: none !important;\n    box-shadow: none !important;\n}\n\n.navbar-text {\n    margin-left: 15px;\n}\n\ninput.error {\n    border-color: #d9534f;\n}\n\n.navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus, .navbar-default .navbar-nav>li>a:hover, .navbar-default .navbar-nav>li>a:focus {\n    color: #66afe9;\n}\n\n.btn:focus {\n    outline:none!important;\n}\n"
  },
  {
    "path": "nimbus/static/css/dashboard.css",
    "content": "body {\n    margin-bottom: 50px;\n}\n\n#media-type-selector a {\n    color: #777;\n}\n\n#media-type-selector li.active a {\n    background-color: #428bca;;\n    color: white;\n}\n\nh2 {\n    font-size: 20px;\n    margin-top: 0;\n    margin-bottom: 20px;\n    float: left;\n}\n\n.delete-selected {\n    float: right;\n    margin-bottom: 10px;\n    display: none;\n}\n\n\n#main-content {\n    margin-left: 0;\n    margin-right: 0;\n}\n\n#media-list {\n    margin-left: -15px;\n    margin-right: -15px;\n    color: rgb(139, 139, 139);\n}\n\n#media-list input[type=\"checkbox\"] {\n    margin-right: 10px;\n}\n\n#media-list tr input[type=\"checkbox\"]:checked {\n    background-color: green;\n}\n\n.view-count {\n    font-weight: bold;\n}\n\n\n.dropzone{\n    text-align: center;\n    border: 1px rgb(211, 211, 211) dashed;\n    border-radius: 8px;\n    background-color: rgb(252, 252, 252);\n    margin-bottom: 1em;\n    cursor: pointer;\n    display: table;\n    color: rgb(211, 211, 211);\n    padding: 10px;\n    width: 100%;\n}\n\n.dropzone.loading {\n    -webkit-animation: loading-pulse 2s infinite;\n}\n\n@-webkit-keyframes loading-pulse {\n    50% {color: #428bca;}\n}\n\n.dropzone.error {\n    -webkit-animation: error-pulse 0.5s infinite;\n}\n\n@-webkit-keyframes error-pulse {\n    50% {color: #d9534f;}\n}\n\n.upload-icon {\n    font-size: 60px;\n    display: table-row;\n}\n\n.dz-message {\n    display: table-row;\n}\n\n\n@media (min-width: 992px) {\n    .nav-stacked-responsive > li {\n      float: none;\n    }\n    .nav-stacked-responsive > li + li {\n      margin-top: 2px;\n      margin-left: 0;\n    }\n}\n\n@media (max-width: 992px) {\n    .nav-stacked-responsive {\n        text-align: center;\n    }\n\n    .nav-stacked-responsive>li {\n        float: none;\n        display: inline-block;\n    }\n}\n\n@media (max-width: 768px) {\n    .media-type-label {\n        display: none;\n    }\n}\n\n.empty-state {\n    text-align: center;\n}\n\n.pager li {\n    margin: 0 10px;\n}\n"
  },
  {
    "path": "nimbus/static/css/login.css",
    "content": "#login-heading {\n    margin-top: 40px;\n    text-align: center;\n}\n\n#cloud-logo {\n    margin: 20px;\n    width: 240px;\n}\n\nh1 {\n    margin-top: -10px;\n}\n\n#login-form .form-control {\n    margin-bottom: 6px;\n}\n\n\n"
  },
  {
    "path": "nimbus/static/css/share_preview.css",
    "content": ".wrapper {\n    margin: 30px auto;\n    padding: 10px;\n}\n\n#text-preview {\n    max-width: 780px;\n}\n\n#media-name {\n    position: absolute;\n    width: 100%;\n    text-align: center;\n    top: 0;\n    margin-left: -15px;\n    font-weight: bold;\n    pointer-events: none;\n}\n\n#download-original {\n    line-height: 50px;\n    font-size: 25px;\n}\n\n#img-preview {\n    text-align: center;\n    padding: 0;\n}\n\n#file-download {\n    text-align: center;\n}\n\n#file-icon {\n    font-size: 160px;\n    color: #DDD;\n    display: block;\n    margin-top: 50px;\n    margin-bottom: 20px;\n}\n\n#file-download .glyphicon-file {\n    margin-left: 14px;\n}\n\n.navbar-header:after {\n    clear: none;\n}\n"
  },
  {
    "path": "nimbus/static/js/dashboard.js",
    "content": "$(function() {\n    var deleteCheckboxClicked = function() {\n        if ($(\".delete-checkbox\").filter(\":checked\").length === 0)\n            $(\".delete-selected\").hide()\n        else\n            $(\".delete-selected\").show()\n    };\n\n    $(\".delete-checkbox\").click(deleteCheckboxClicked);\n\n    var resetDropzone = function(el) {\n        var $e = $(el);\n        var $m = $e.children(\".dz-message\");\n        $e.removeClass(\"loading\");\n        $e.removeClass(\"error\");\n        $m.text($e.data(\"initial-message\"));\n        $m.css(\"line-height\", $m.data(\"initial-line-height\"));\n    }\n\n    Dropzone.options.uploadDropzone = {\n        clickable: \"#upload-dropzone, .upload-icon\",\n        uploadMultiple: false,\n        maxFiles: 1,\n        complete: function(file) {\n            this.removeFile(file);\n        },\n        success: function(file, response) {\n            resetDropzone(this.element);\n            displayedMediaType = $(\"#media-list\").data(\"media-type-code\");\n\n            var mediaItem = response;\n            if (displayedMediaType == \"ALL\" || displayedMediaType == mediaItem.media_type) {\n                var $table = $(\"#media-list>table\"),\n                    $tbody = $(\"#media-list>table>tbody\");\n\n                if ($table.hasClass(\"empty-state\")) {\n                    $tbody.html(mediaItem.html);\n                } else {\n                    $tbody.prepend(mediaItem.html);\n                }\n\n                $table.addClass(\"table-hover\");\n                $table.removeClass(\"empty-state\");\n            }\n\n            $(\".delete-checkbox\").click(deleteCheckboxClicked);\n        },\n        error: function(file, error) {\n            console.error(error);\n            $e = $(this.element);\n            $e.removeClass(\"loading\");\n            $e.addClass(\"error\");\n            $e.children(\".dz-message\").text(\"Error Uploading File\");\n            setTimeout(function(){\n                resetDropzone($e);\n            }, 2000);\n        },\n        addedfile: function(file) {\n            var $e = $(this.element);\n            var $m = $e.children(\".dz-message\");\n            if (!$e.data(\"initial-message\")) {\n                $e.data(\"initial-message\", $m.text());\n            }\n            $e.addClass(\"loading\");\n            var messageHeight = $m.height();\n            var lineHeight = parseInt($m.css(\"line-height\").replace(\"px\",\"\"));\n            var lines = Math.round(messageHeight / lineHeight);\n            if (!$m.data(\"initial-line-height\")) {\n                $m.data(\"initial-line-height\", $m.css(\"line-height\"));\n            }\n            $m.css(\"line-height\", (lines * lineHeight) + \"px\");\n            $m.text(\"Uploading...\");\n        },\n        sending: function(file, xhr, formData) {\n            xhr.withCredentials = true; // send cookies even though this is a cross-site request\n        }\n    };\n\n    $(\".delete-selected\").click(function() {\n        $(this).css(\"width\", $(this).outerWidth());\n        $(this).text(\"Deleting...\");\n\n        var $rows = [];\n        var hashes = $.map($(\".delete-checkbox\").filter(\":checked\"), function(e){\n            var $p = $(e).parent().parent();\n            var hash = $p.data(\"url_hash\");\n            $rows.push($p);\n            return hash;\n        });\n\n        var params = hashes.map(function(hash){return \"url_hash=\" + hash}).join(\"&\");\n        var button = this;\n        $.ajax({\n            url: $(this).data(\"delete-api-endpoint\") + \"?\" + params,\n            type: \"DELETE\",\n            xhrFields: {\n                withCredentials: true\n            },\n            beforeSend: function(xhr, settings) {\n                xhr.setRequestHeader(\"X-CSRFToken\", $.cookie(\"csrftoken\"));\n            },\n            success: function() {\n                $(button).text(\"Delete Selected\");\n\n                $.map($rows, function($r) {\n                    $r.remove();\n                });\n\n                $(button).hide();\n\n                var $table = $(\"#media-list>table\"),\n                    $tbody = $(\"#media-list>table>tbody\");\n                if ($(\"#media-list tr\").length == 0) {\n                    location.reload();\n                    // $tbody.append(\"<tr><td>Nothing here yet</td></tr>\");\n                    // $table.removeClass(\"table-hover\");\n                    // $table.addClass(\"empty-state\");\n                }\n            },\n            error: function(xhr, status, error) {\n                console.log(xhr);\n                $(button).text(\"Error!\");\n                setTimeout(function() {\n                    $(button).text(\"Delete Selected\");\n                }, 1000);\n            }\n        });\n\n\n\n    });\n});\n"
  },
  {
    "path": "nimbus/static/js/jquery-photo-resize.js",
    "content": "(function ($) {\n\n    $.fn.photoResize = function (options) {\n\n        var element = $(this),\n            defaults = {\n                padding: 10\n            };\n\n        $(element).load(function () {\n            updatePhotoSize();\n\n            $(window).bind(\"resize\", function () {\n                updatePhotoSize();\n            });\n        });\n\n        options = $.extend(defaults, options);\n\n        function updatePhotoSize() {\n            var verticalShrink = $(window).height() - 52 - 2 * options.padding,\n                horizontalShrink = ($(window).width() - 2 * options.padding) * $(element).height() / $(element).width(),\n                noShrink = element[0].naturalHeight;\n            $(element).attr(\"height\", Math.min(verticalShrink, horizontalShrink, noShrink));\n        }\n    };\n\n}(jQuery));\n"
  },
  {
    "path": "nimbus/templates/admin/base_site.html",
    "content": "{% extends \"admin/base.html\" %}\n\n{% block title %}\n    Nimbus Admin - {{ title|escape }}\n{% endblock %}\n\n{% block branding %}\n    <h1 id=\"site-name\">Nimbus Admin</h1>\n{% endblock %}\n\n{% block nav-global %}{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/accounts/dashboard.html",
    "content": "{% extends \"nimbus/page_base.html\" %}\n{% load staticfiles %}\n{% load subdomainurls %}\n\n{% block title %}\n    {{ block.super }} - Dashboard\n{% endblock %}\n\n{% block css %}\n    {{ block.super }}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/dashboard.css' %}\" />\n{% endblock %}\n\n{% block js %}\n    {{ block.super }}\n    <script src=\"//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js\"></script>\n    <script src=\"{% static 'js/lib/dropzone.min.js' %}\"></script>\n    <script src=\"{% static 'js/lib/moment.min.js' %}\"></script>\n    <script src=\"{% static 'js/lib/livestamp.min.js' %}\"></script>\n    <script src=\"{% static 'js/dashboard.js' %}\"></script>\n{% endblock %}\n\n{% block body %}\n    <nav id=\"main-nav\" class=\"navbar navbar-default\" role=\"navigation\">\n        <div class=\"container-fluid\">\n            <div class=\"navbar-header\">\n                <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\"#navbar-collapse\">\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                </button>\n                <a class=\"navbar-brand\" href=\"/\"><span class=\"glyphicon glyphicon-cloud cloud-logo\"></span> Nimbus</a>\n            </div>\n\n            <div class=\"collapse navbar-collapse\" id=\"navbar-collapse\">\n                <ul class=\"nav navbar-nav navbar-right\">\n                    <li class=\"navbar-text\">Welcome, {{ request.user.username }}</li>\n                    <li><a href=\"/logout\">Logout</a></li>\n                </ul>\n            </div>\n        </div>\n    </nav>\n\n    <div class=\"container\">\n        <div class=\"row\" id=\"main-content\">\n            <span class=\"col-md-2\">\n                <form id=\"upload-dropzone\" class=\"dropzone\" action=\"{% url 'add_file' subdomain='api' %}?include-html\" method=\"post\" enctype=\"multipart/form-data\">\n                    {% csrf_token %}\n                    <span class=\"glyphicon glyphicon-upload upload-icon\"></span>\n                    <span class=\"dz-message\">Drop file or click here to upload</span>\n                    <div class=\"fallback\">\n                    </div>\n                </form>\n                <ul id=\"media-type-selector\" class=\"nav nav-pills nav-stacked-responsive\">\n                    <li{% if media_type = \"all\" %} class=\"active\"{% endif %}><a href=\"{% url 'index' %}\"><span class=\"glyphicon glyphicon-th-large\"></span><span class=\"media-type-label\"> All</span></a></li>\n                    <li{% if media_type = \"images\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='images' %}\"><span class=\"glyphicon glyphicon-picture\"></span><span class=\"media-type-label\"> Images</span></a></li>\n                    <li{% if media_type = \"links\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='links' %}\"><span class=\"glyphicon glyphicon-link\"></span><span class=\"media-type-label\"> Links</span></a></li>\n                    <li{% if media_type = \"text\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='text' %}\"><span class=\"glyphicon glyphicon-font\"></span><span class=\"media-type-label\"> Text</span></a></li>\n                    <li{% if media_type = \"archives\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='archives' %}\"><span class=\"glyphicon glyphicon-compressed\"></span><span class=\"media-type-label\"> Archives</span></a></li>\n                    <li{% if media_type = \"audio\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='audio' %}\"><span class=\"glyphicon glyphicon-music\"></span><span class=\"media-type-label\"> Audio</span></a></li>\n                    <li{% if media_type = \"video\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='video' %}\"><span class=\"glyphicon glyphicon-facetime-video\"></span><span class=\"media-type-label\"> Video</span></a></li>\n                    <li{% if media_type = \"other\" %} class=\"active\"{% endif %}><a href=\"{% url 'filter_media' media_type='other' %}\"><span class=\"glyphicon glyphicon-file\"></span><span class=\"media-type-label\"> Other</span></a></li>\n                </ul>\n            </span>\n            <div id=\"media-list\" class=\"col-md-10\" data-media-type-code=\"{{ media_type_code }}\">\n                <h2>{% if media_type = \"all\" %}All {% endif %}Shared Items{% if media_type != \"all\" %} - {{ media_type.title }}{% endif %}</h2>\n                <button type=\"button\" class=\"btn btn-sm btn-danger delete-selected\" data-delete-api-endpoint=\"{% url 'delete_media' subdomain='api' %}\">Delete Selected</button>\n                {% if media %}\n                    <table class=\"table table-hover\">\n                        {% for media_item in media %}\n                            {% include \"nimbus/accounts/media_table_row.html\" %}\n                        {% endfor %}\n                    </table>\n                {% else %}\n                    <table class=\"table empty-state\">\n                        <tr>\n                            <td>\n                                Nothing here yet\n                            </td>\n                        </tr>\n                    </table>\n                {% endif %}\n\n            </div>\n\n            {% if media.paginator.num_pages > 1 %}\n                <ul class=\"pager col-md-10 col-md-push-2\">\n                    <li class=\"{% if not media.has_previous %}disabled{% endif %}\"><a{% if media.has_previous %} href=\"?p={{ media.previous_page_number }}\"{% endif %}>&larr; Previous</a></li>\n                    <li>Page {{ media.number }} of {{ media.paginator.num_pages }}</li>\n                    <li class=\"{% if not media.has_next %}disabled{% endif %}\"><a{% if media.has_next %} href=\"?p={{ media.next_page_number }}\"{% endif %}>Next &rarr;</a></li>\n                </ul>\n            {% endif %}\n        </div>\n    </div>\n    {{ block.super }}\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/accounts/login.html",
    "content": "{% extends \"nimbus/page_base.html\" %}\n{% load staticfiles %}\n{% load widget_tweaks %}\n\n{% block title %}\n    {{ block.super }} - Login\n{% endblock %}\n\n{% block css %}\n    {{ block.super }}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{% static \"css/login.css\" %}\" />\n{% endblock %}\n\n{% block js %}\n    {{ block.super }}\n    <script type=\"text/javascript\">\n        $(document).ready(function() {\n            /* Input */\n            var $username = $(\"input[name=username]\");\n            var $password = $(\"input[name=password]\");\n            if(!$username.hasClass(\"error\") && $password.hasClass(\"error\")) {\n                $password.focus();\n            } else {\n                $username.focus();\n            }\n        });\n    </script>\n{% endblock %}\n\n{% block body %}\n    <a href=\"https://github.com/ethanal/Nimbus\"><img style=\"position: absolute; top: 0; right: 0; border: 0;\" src=\"https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67\" alt=\"Fork me on GitHub\" data-canonical-src=\"https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png\"></a>\n    <div class=\"container\">\n        <div class=\"row\">\n            <div class=\"login col-md-4 col-md-offset-4\">\n                <div id=\"login-heading\">\n                    <img id=\"cloud-logo\" src=\"{% static 'img/exports/login_logo@2x.png' %}\" />\n                    <h1>Nimbus</h1>\n                </div>\n                {% if request.GET.next %}\n                    <div class=\"message message-next\">\n                        Log in to access this page.\n                    </div>\n                {% endif %}\n                <form id=\"login-form\" {% if auth_form.errors %}autocomplete=\"off\"{% endif %} action=\"/login{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}\" method=\"post\">\n                    {% csrf_token %}\n                    {{ auth_form.username|add_class:\"form-control\" }}\n                    {{ auth_form.password|add_class:\"form-control\" }}\n                    <input class=\"btn btn-lg btn-primary btn-block\" type=\"submit\" value=\"Login\" />\n                </form>\n            </div>\n        </div>\n    </div>\n    {{ block.super }}\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/accounts/media_table_row.html",
    "content": "{% load subdomainurls %}\n\n<tr data-url_hash=\"{{ media_item.url_hash }}\">\n    <td>\n        <input type=\"checkbox\" class=\"delete-checkbox\">\n        <a href=\"{% url 'share' subdomain=None url_hash=media_item.url_hash %}\" title=\"{{ media_item.name }}\">\n            {{ media_item.name|truncatechars:60 }}\n        </a>\n    </td>\n    <td title=\"{{ media_item.upload_date|date:\"j N Y, P\" }}\"><span data-livestamp=\"{{ media_item.upload_date|date:'c' }}\"></span></td>\n    <td class=\"view-count\" title=\"{{ media_item.view_count }} View{{ media_item.view_count|pluralize }}\">{{ media_item.view_count }}</td>\n</tr>\n"
  },
  {
    "path": "nimbus/templates/nimbus/media/share_base.html",
    "content": "{% extends \"nimbus/page_base.html\" %}\n{% load staticfiles %}\n\n{% block title %}{{ media_item.name }}{% endblock %}\n\n{% block css %}\n    {{ block.super }}\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/share_preview.css' %}\" />\n{% endblock %}\n\n\n{% block body %}\n    <nav id=\"main-nav\" class=\"navbar navbar-default\" role=\"navigation\">\n        <div class=\"container-fluid\">\n            <div class=\"navbar-header\">\n                <a class=\"navbar-brand\" href=\"/\"><span class=\"glyphicon glyphicon-cloud cloud-logo\"></span> Nimbus</a>\n            </div>\n            <div class=\"navbar-text\" id=\"media-name\">\n                {{ media_item.name }}\n            </div>\n\n            <a href=\"{{ media_item.raw_url }}\" id=\"download-original\" class=\"pull-right navbar-link\">\n                <span class=\"glyphicon glyphicon-download\"></span>\n            </a>\n        </div>\n\n    </nav>\n\n    {% block media_preview %}\n        <a href=\"{{ media_item.raw_url }}\">{{ media_item.name }}</a>\n    {% endblock %}\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/media/share_download.html",
    "content": "{% extends \"nimbus/media/share_base.html\" %}\n\n{% block media_preview %}\n    <div id=\"file-download\" class=\"wrapper\">\n        <span id=\"file-icon\" class=\"glyphicon glyphicon-file\"></span>\n        <a href=\"{{ media_item.raw_url }}\" class=\"btn btn-primary btn-lg\">\n            <strong>{{ media_item.name }}</strong>\n        </a>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/media/share_img_preview.html",
    "content": "{% extends \"nimbus/media/share_base.html\" %}\n{% load staticfiles %}\n\n{% block js %}\n    {{ block.super }}\n    <script src=\"{% static 'js/jquery-photo-resize.js' %}\"></script>\n    <script type=\"text/javascript\">\n        $(function() {\n            $(\".wrapper img\").photoResize({\n                padding: 30\n            });\n        });\n    </script>\n{% endblock %}\n\n{% block media_preview %}\n    <div id=\"img-preview\" class=\"wrapper\">\n        <img src=\"{{ media_item.raw_ssl_url }}\" alt=\"{{ media_item.name }}\"/>\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/media/share_txt_preview.html",
    "content": "{% extends \"nimbus/media/share_base.html\" %}\n\n{% block css %}\n    {{ block.super }}\n    <style>\n        .highlight .hll { background-color: #d6d6d6 }\n        .highlight  { background: #ffffff; color: #4d4d4c }\n        .highlight .c { color: #8e908c } /* Comment */\n        .highlight .err { color: #c82829 } /* Error */\n        .highlight .k { color: #8959a8 } /* Keyword */\n        .highlight .l { color: #f5871f } /* Literal */\n        .highlight .n { color: #4d4d4c } /* Name */\n        .highlight .o { color: #3e999f } /* Operator */\n        .highlight .p { color: #4d4d4c } /* Punctuation */\n        .highlight .cm { color: #8e908c } /* Comment.Multiline */\n        .highlight .cp { color: #8e908c } /* Comment.Preproc */\n        .highlight .c1 { color: #8e908c } /* Comment.Single */\n        .highlight .cs { color: #8e908c } /* Comment.Special */\n        .highlight .gd { color: #c82829 } /* Generic.Deleted */\n        .highlight .ge { font-style: italic } /* Generic.Emph */\n        .highlight .gh { color: #4d4d4c; font-weight: bold } /* Generic.Heading */\n        .highlight .gi { color: #718c00 } /* Generic.Inserted */\n        .highlight .gp { color: #8e908c; font-weight: bold } /* Generic.Prompt */\n        .highlight .gs { font-weight: bold } /* Generic.Strong */\n        .highlight .gu { color: #3e999f; font-weight: bold } /* Generic.Subheading */\n        .highlight .kc { color: #8959a8 } /* Keyword.Constant */\n        .highlight .kd { color: #8959a8 } /* Keyword.Declaration */\n        .highlight .kn { color: #3e999f } /* Keyword.Namespace */\n        .highlight .kp { color: #8959a8 } /* Keyword.Pseudo */\n        .highlight .kr { color: #8959a8 } /* Keyword.Reserved */\n        .highlight .kt { color: #eab700 } /* Keyword.Type */\n        .highlight .ld { color: #718c00 } /* Literal.Date */\n        .highlight .m { color: #f5871f } /* Literal.Number */\n        .highlight .s { color: #718c00 } /* Literal.String */\n        .highlight .na { color: #4271ae } /* Name.Attribute */\n        .highlight .nb { color: #4d4d4c } /* Name.Builtin */\n        .highlight .nc { color: #eab700 } /* Name.Class */\n        .highlight .no { color: #c82829 } /* Name.Constant */\n        .highlight .nd { color: #3e999f } /* Name.Decorator */\n        .highlight .ni { color: #4d4d4c } /* Name.Entity */\n        .highlight .ne { color: #c82829 } /* Name.Exception */\n        .highlight .nf { color: #4271ae } /* Name.Function */\n        .highlight .nl { color: #4d4d4c } /* Name.Label */\n        .highlight .nn { color: #eab700 } /* Name.Namespace */\n        .highlight .nx { color: #4271ae } /* Name.Other */\n        .highlight .py { color: #4d4d4c } /* Name.Property */\n        .highlight .nt { color: #3e999f } /* Name.Tag */\n        .highlight .nv { color: #c82829 } /* Name.Variable */\n        .highlight .ow { color: #3e999f } /* Operator.Word */\n        .highlight .w { color: #4d4d4c } /* Text.Whitespace */\n        .highlight .mf { color: #f5871f } /* Literal.Number.Float */\n        .highlight .mh { color: #f5871f } /* Literal.Number.Hex */\n        .highlight .mi { color: #f5871f } /* Literal.Number.Integer */\n        .highlight .mo { color: #f5871f } /* Literal.Number.Oct */\n        .highlight .sb { color: #718c00 } /* Literal.String.Backtick */\n        .highlight .sc { color: #4d4d4c } /* Literal.String.Char */\n        .highlight .sd { color: #8e908c } /* Literal.String.Doc */\n        .highlight .s2 { color: #718c00 } /* Literal.String.Double */\n        .highlight .se { color: #f5871f } /* Literal.String.Escape */\n        .highlight .sh { color: #718c00 } /* Literal.String.Heredoc */\n        .highlight .si { color: #f5871f } /* Literal.String.Interpol */\n        .highlight .sx { color: #718c00 } /* Literal.String.Other */\n        .highlight .sr { color: #718c00 } /* Literal.String.Regex */\n        .highlight .s1 { color: #718c00 } /* Literal.String.Single */\n        .highlight .ss { color: #718c00 } /* Literal.String.Symbol */\n        .highlight .bp { color: #4d4d4c } /* Name.Builtin.Pseudo */\n        .highlight .vc { color: #c82829 } /* Name.Variable.Class */\n        .highlight .vg { color: #c82829 } /* Name.Variable.Global */\n        .highlight .vi { color: #c82829 } /* Name.Variable.Instance */\n        .highlight .il { color: #f5871f } /* Literal.Number.Integer.Long */\n    </style>\n{% endblock %}\n\n{% block media_preview %}\n    <div id=\"text-preview\" class=\"wrapper\">\n        {{ media_item.syntax_highlighted|safe }}\n    </div>\n{% endblock %}\n"
  },
  {
    "path": "nimbus/templates/nimbus/page_base.html",
    "content": "{% load staticfiles %}\n\n<!doctype html>\n<html lang='en'>\n<head>\n    <title>{% block title %}Nimbus{% endblock %}</title>\n    <meta charset='UTF-8' />\n    <meta name=\"robots\" content=\"noindex\">\n    \n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    {% block css %}\n        <link rel=\"stylesheet\" href=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css\">\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"{% static \"css/base.css\" %}\" />\n    {% endblock %}\n\n    {% block js %}\n        <script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js\"></script>\n        <script src=\"//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js\"></script>\n    {% endblock %}\n\n    {% block head %}\n    {% endblock %}\n</head>\n<body>\n    {% block body %}\n    {% endblock %}\n</body>\n</html>\n"
  },
  {
    "path": "nimbus/templates/rest_framework/api.html",
    "content": "{% extends \"rest_framework/base.html\" %}\n\n{% block title %}\nNimbus API - {{request.path}}\n{% endblock %}\n\n {% block branding %}\n <a class=\"brand\" href=\"/\">Nimbus API</a>\n {% endblock %}\n"
  },
  {
    "path": "nimbus/templates/rest_framework/login.html",
    "content": "{% extends \"rest_framework/login_base.html\" %}\n\n{% block branding %}\n    <h3 style=\"margin: 0 0 20px;\">Nimbus API</h3>\n{% endblock %}\n\n{% block style %}\n    {# hacky way to add to head tag #}\n    <title>Nimbus API - Login</title>\n    {{ block.super }}\n{% endblock %}\n"
  },
  {
    "path": "nimbus/utils.py",
    "content": "from corsheaders import defaults as settings\nfrom corsheaders.middleware import (\n    CorsPostCsrfMiddleware, CorsMiddleware)\nfrom rest_framework.authentication import (\n    SessionAuthentication as RFSessionAuthentication)\n\n\n\nclass PatchDepatchRefererCsrf(CorsMiddleware, CorsPostCsrfMiddleware):\n    \"\"\"\n    Helper class to provide access to _https_referer_replace\n    and _https_referer_replace_reverse.\n    \"\"\"\n\n    def patch(self, request):\n        if self.is_enabled(request) and settings.CORS_REPLACE_HTTPS_REFERER:\n            self._https_referer_replace(request)\n\n    def depatch(self, request):\n        self._https_referer_replace_reverse(request)\n\n\nclass SessionAuthentication(RFSessionAuthentication):\n    \"\"\"\n    SessionAuthentication that patchess the HTTP_REFERER before checking\n    CSRF and depatch it after checking it.\n\n    corsheaders supplies middleware but DRF doesn't use the middleware\n    when checking CSRF for itself. This creates a problem when using https.\n    \"\"\"\n    def enforce_csrf(self, request):\n        patch_depatch = PatchDepatchRefererCsrf()\n        patch_depatch.patch(request)\n        super(SessionAuthentication, self).enforce_csrf(request)\n        patch_depatch.depatch(request)\n"
  },
  {
    "path": "nimbus/wsgi.py",
    "content": "\"\"\"\nWSGI config for nimbus project.\n\nThis module contains the WSGI application used by Django's development server\nand any production WSGI deployments. It should expose a module-level variable\nnamed ``application``. Django's ``runserver`` and ``runfcgi`` commands discover\nthis application via the ``WSGI_APPLICATION`` setting.\n\nUsually you will have the standard Django WSGI application here, but it also\nmight make sense to replace the whole Django WSGI application with a custom one\nthat later delegates to the Django one. For example, you could introduce WSGI\nmiddleware here, or combine a Django application with an application of another\nframework.\n\n\"\"\"\nimport os\n\ntry:\n    import newrelic.agent\n    newrelic.agent.initialize(\"newrelic.ini\")\nexcept ImportError:\n    pass\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"nimbus.settings\")\n\n# This application object is used by any WSGI server configured to use this\n# file. This includes Django's development server, if the WSGI_APPLICATION\n# setting points here.\nfrom django.core.wsgi import get_wsgi_application\napplication = get_wsgi_application()\n\n# Apply WSGI middleware here.\n# from helloworld.wsgi import HelloWorldApplication\n# application = HelloWorldApplication(application)\n"
  },
  {
    "path": "requirements/base.txt",
    "content": "Django==1.6.5\nMarkdown==2.4.1\nPygments==1.6\nboto==2.31.1\n-e git+https://github.com/ottoyiu/django-cors-headers.git#egg=Package\ndjango-storages==1.1.8\ndjango-subdomains==2.0.4\ndjango-widget-tweaks==1.3\ndjangorestframework==2.3.14\n"
  },
  {
    "path": "requirements/local.txt",
    "content": "-r base.txt\n\ndjango-debug-toolbar==1.2.1\ndjango-extensions==1.3.8\n"
  },
  {
    "path": "requirements/production.txt",
    "content": "-r base.txt\n\ngunicorn==19.0.0\nMySQL-python==1.2.5\nnewrelic==2.40.0.34\n"
  }
]